blk.dat files
blk.dat files hold the raw blocks that Bitcoin Core stores on disk. Learn where they are, how a record is laid out, and why v28.0 scrambles them.
By Dimitar Zurnov · Updated 4 Nov 2026
Adapted from Learn Me a Bitcoin by Greg Walker.
The blk*.dat files hold the raw data of every block your node has received. Bitcoin Core writes each block to these files as it arrives. Together, the files store the whole blockchain on your disk, in the order the blocks arrived.
Where are the files?
They sit in a blocks folder inside the node's data directory. The default locations are:
- Linux:
~/.bitcoin/blocks/ - macOS:
~/Library/Application Support/Bitcoin/blocks/ - Windows:
C:\Users\[username]\AppData\Local\Bitcoin\blocks\from Bitcoin Core 28.0 onwards. Older versions usedAppData\Roaming.
The datadir setting in bitcoin.conf moves the folder somewhere else. The Bitcoin Core files guide lists every file the node writes.
How are the blocks split across files?
A single file would grow without limit, so Bitcoin Core splits the data across several. The first file is blk00000.dat. When it fills, the node starts blk00001.dat, then blk00002.dat, and so on. Each file is at most 128 MiB, which is 134,217,728 bytes. The limit is set by MAX_BLOCKFILE_SIZE in the Bitcoin Core source.
The rev*.dat files next to them hold undo data. The node uses it to roll back the spending of coins during a chain reorganization.
What does one record look like?
Each block is stored as a record of five parts. The values below are the plain ones, as they read after the XOR described further down.
- Magic bytes, 4 bytes. This marks the start of a record. On mainnet the value is
f9beb4d9, and magic bytes explains how the network uses it. - Block size, 4 bytes, little-endian. It counts the bytes of the block that follow. The genesis block's size is
1d010000, which is 285 bytes. - Block header, 80 bytes. These are the six fields from the block structure page.
- Transaction count, a compact size integer. The genesis block has one transaction, so the count is
01. - Transactions, the raw bytes of every transaction in the block, one after another.
The size field tells a reader where the record ends. The genesis block's 285 bytes are 80 for the header, 1 for the count and 204 for its one transaction.
The first bytes of the genesis record look like this, after the XOR is undone:
f9beb4d9 1d010000 01000000 0000000000000000000000000000000000000000000000000000000000000000 3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a 29ab5f49 ffff001d 1dac2b7c 01 ...
Those spaces mark the fields, and the remaining transaction bytes are cut off here. You can read the whole block from your own node with bitcoin-cli getblock 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f 0. That command returns the block as hex, with no magic bytes or size. Our explorer's block 0 page shows the same block in readable form.
Why are the blocks out of order?
The files store blocks in the order the node received them, not in height order. A node downloads blocks in parallel, and it fetches a window of blocks ahead of the one it is working on. So a block further up the chain can land in the file before one below it.
If you read the files yourself, rebuild the order from the previous block links. Do not assume the file order is the chain order.
Why is the data scrambled in v28.0 and later?
Since Bitcoin Core 28.0, the node XORs the raw block data before it writes it to disk. The XOR uses an 8-byte key stored in blocks/xor.dat. The pull request gives the reason. Antivirus and other scanners could quarantine or delete block files, because anyone can put arbitrary bytes into a transaction. Scrambling the stored bytes keeps them from looking like that kind of data to a scanner.
To undo the scrambling, XOR each byte with the key byte at its offset from the start of the file. The key repeats every 8 bytes, so byte N uses key byte N mod 8. Count from the first byte of the file, so the magic bytes and the size field are scrambled too.
The example above is the first eight bytes of the genesis block data, at file offset 8. XORing 16 with 17 gives 01, and every other byte XORs to 00. A new node makes its own random key, so your files look different from someone else's. A node that synced before v28.0 keeps an all-zero key, so its files stay plain. Older tools that read blk*.dat files will not understand scrambled data, and they need the key to work.
How should you read the raw blocks?
Use bitcoin-cli if you can. It returns the block already unscrambled, and it works on any node that still has the block. A node set to prune its old blocks deletes the older blk*.dat files, so a pruned node cannot serve every block. You can set blocksxor=0 to turn the XOR off, but only for a new data directory. A node that already has a random key cannot turn it off.
If you do parse the files yourself, follow the record layout above, undo the XOR when the node is v28.0 or later, and handle the out-of-order blocks.
What comes next?
This is the last page of the section. Return to the block structure page for the full list of fields in header order.
In this section: Block structure
Something look wrong? Tell us