Chunk format

Chunks store the terrain and entities within a 16×384×16 area. They also store precomputed lighting, heightmap data for Minecraft's performance, and other meta information.

NBT structure
Chunks are stored as tags in regional Minecraft Anvil files, which are named in the form r.x.z.mca. They are stored in NBT format, with the following structure (updated for 1.18):
 * The root tag.
 * Version of the chunk NBT structure.
 * X position of the chunk (in chunks, from the origin, not relative to region).
 * Z position of the chunk (in chunks, from the origin, not relative to region).
 * Lowest Y section position in the chunk (e.g. -4 in 1.18).
 * Defines the world generation status of this chunk. It is always one of the following: empty, structure_starts, structure_references, biomes, noise, surface, carvers, liquid_carvers, features, light, spawn, heightmaps or full. All status except full are used for chunks called proto-chunks, in other words, for chunks with incomplete generation.
 * Tick when the chunk was last saved.
 * List of compound tags, each tag is a section (also known as sub-chunk). All sections in the world's height are present in this list, even those who are empty (filled with air).
 * An individual section.
 * The Y position of this section.
 * Set of different block states used in this particular section.
 * A block
 * Block resource location
 * List of block state properties, with [name] being the name of the block state property
 * The block state name and its value.
 * A packed array of 4096 indices pointing to the palette, stored in an array of 64-bit integers. If only one block state is present in the palette, this field is not required and the block fills the whole section. All indices are the same length: the minimum amount of bytes required to represent the largest index in the palette. These indices have a minimum size of 4 bits. Since 1.16, the indices are not packed across multiple elements of the array, meaning that if there is no more space in a given 64-bit integer for the next index, it starts instead at the first (lowest) bit of the next 64-bit element.
 * Set of different biomes used in this particular section.
 * Biome resource location
 * A packed array of 64 indices pointing to the palette, stored in an array of 64-bit integers. If only one biome is present in the palette, this field is not required and the biome fills the whole section. All indices are the same length: the minimum amount of bytes required to represent the largest index in the palette. These indices do not have a minimum size.
 * 2048 bytes recording the amount of block-emitted light in each block. Makes load times faster compared to recomputing at load time. 4 bits per block.
 * 2048 bytes recording the amount of sunlight or moonlight hitting each block. 4 bits per block.
 * Each TAG_Compound in this list defines a block entity in the chunk. See Block Entity Format below. If this list is empty, it becomes a list of End tags.
 * Only for proto-chunks (not confirmed for 1.18 format).
 * A series of bits indicating whether a cave has been dug at a specific position, stored in a byte array.
 * A series of bits indicating whether an underwater cave has been dug at a specific position, stored in a byte array.
 * Several different heightmaps corresponding to 256 values compacted at 9 bits per value (lowest being 0, highest being 384, both values inclusive). The 9 bit values are stored in an array of 37 longs, each containing 7 values (long = 64 bits, 7 * 9 = 63; the last bit is unused). In versions prior to 1.16 the heightmaps were stored in 36 long values, where the bits were arranged in an uninterrupted "stream" across all values, resulting in all 2304 bits being used. The 9 bit values are unsigned, and indicate the amount of blocks above the bottom of the world. This means that converting a world to 1.18 adds 64 to every value.
 * The highest block that blocks motion or contains a fluid.
 * The highest block that blocks motion or contains a fluid or is in the  tag.
 * The highest non-air block, solid block.
 * The highest block that is neither air nor contains a fluid, for proto-chunk (worldgen).
 * The highest non-air block.
 * The highest non-air block, for proto-chunk (worldgen).
 * A List of 16 lists that store positions of light sources per chunk section as shorts, only for proto-chunks (not confirmed for 1.18 format).
 * A list of entities in the proto-chunks, used when generating. As of 1.17, this list is not present for fully generated chunks and entities are moved to a separated region files once the chunk is generated, see Entity format for more details (not confirmed for 1.18 format).
 * An entity.
 * Each TAG_Compound in this list is an "active" liquid in this chunk waiting to be updated. See Tile Tick Format below.
 * Each TAG_Compound in this list is an "active" block in this chunk waiting to be updated. These are used to save the state of redstone machines or falling sand, and other activity. See Tile Tick Format below.
 * The cumulative number of ticks players have been in this chunk. Note that this value increases faster when more players are in the chunk. Used for regional difficulty: increases the chances of mobs spawning with equipment, the chances of that equipment having enchantments, the chances of spiders having potion effects, the chances of mobs having the ability to pick up dropped items, and the chances of zombies having the ability to spawn other zombies when attacked. Note that at values 3600000 and above, regional difficulty is effectively maxed for this chunk. At values 0 and below, the difficulty is capped to a minimum (thus, if this is set to a negative number, it behaves identically to being set to 0, apart from taking time to build back up to the positives). See Regional Difficulty for more specifics.
 * A List of 24 (number of sections in the height) TAG_Lists that store positions of blocks that need to receive an update when a proto-chunk turns into a full chunk, packed in TAG_Shorts. See ToBeTicked format below for a description of the coordinate packing format. A common use case for this to is make liquids flow after generating a source block, such as springs in caves.
 * Structure data in this chunk.
 * Coordinates of chunks that contain Starts.
 * Each 64-bit number of this array represents a chunk coordinate (i.e. block coordinate / 16), with its X packed into the low (least significant) 32 bits and Z packed into the high (most significant) 32 bits.
 * Structures that are yet to be generated, stored by general type. Some parts of the structures may have already been generated. Completely generated structures are removed by setting their id to "INVALID" and removing all other tags.
 * Only the structures that can spawn in this dimension are stored, for example, EndCity is stored only in the end chunks.
 * Bounding box of the entire structure (remaining Children). Value is 6 ints: the minimum X, Y, and Z coordinates followed by the maximum X, Y, and Z coordinates. Absent if id is INVALID.
 * The biome id this structure is in. Absent if id is INVALID.
 * List of structure pieces making up this structure, that were not generated yet. Absent if id is INVALID.
 * Structure piece data.
 * Bounding box of the structure piece. (Does not include the part of a village roof that can overhang the road.) Value is 6 ints: the minimum X, Y, and Z coordinates followed by the maximum X, Y, and Z coordinates.
 * The ocean temperature this ocean ruins is in. Valid values are WARM and COLD.
 * (Village "ViSmH") Hut roof type.
 * (Village "ViF" and "ViDF") Crop in the farm plot.
 * Block resource location
 * List of block state properties, with [name] being the name of the block state property
 * The block state name and its value.
 * (Village "ViF" and "ViDF") Crop in the farm plot.
 * Block resource location
 * List of block state properties, with [name] being the name of the block state property
 * The block state name and its value.
 * (Village "ViDF") Crop in the farm plot.
 * Block resource location
 * List of block state properties, with [name] being the name of the block state property
 * The block state name and its value.
 * (Village "ViDF") Crop in the farm plot.
 * Block resource location
 * List of block state properties, with [name] being the name of the block state property
 * The block state name and its value.
 * 1 or 0 (true/false) - (Fortress "NeSCLT" and "NeSCRT") Whether this fortress piece should contain a chest but hasn't had one generated yet. (Stronghold "SHCC") Whether this chest in this stronghold piece was placed. (Village "ViS") Whether the blacksmith chest has been generated.
 * (Mineshaft "MSCrossing") Indicates the "incoming" direction for the crossing.
 * (Temples and huts) Depth of the structure (X/Z).
 * (Mineshaft "MSRoom") List of exits from the room.
 * Bounding box of the exit.
 * (Stronghold) The type of door at the entry to this piece.
 * Appears to be some sort of measure of how far this piece is from the start.
 * 1 or 0 (true/false) - (Desert temple) Whether chest was placed.
 * 1 or 0 (true/false) - (Desert temple) Whether chest was placed.
 * 1 or 0 (true/false) - (Desert temple) Whether chest was placed.
 * 1 or 0 (true/false) - (Desert temple) Whether chest was placed.
 * (Temples and huts) Height of the structure (Y).
 * (Temples, huts and villages) Y level the structure was moved to in order to place it on the surface, or -1 if it hasn't been moved yet.
 * 1 or 0 (true/false) - (Mineshaft "MSCorridor") Whether the corridor has a cave spider spawner.
 * 1 or 0 (true/false) - (Mineshaft "MSCorridor") Whether the corridor has rails.
 * Identifier for the structure piece. Typically a heavily abbreviated code rather than something human-readable.
 * The integrity of this structure (only used by ocean ruins).
 * 1 or 0 (true/false) - If this ocean ruin is big.
 * (Village) List of junction points.
 * Block coordinate.
 * Block coordinate.
 * Block coordinate.
 * One of  or.
 * 1 or 0 (true/false) - (Stronghold "SHS") Whether the corridor has an opening on the left.
 * 1 or 0 (true/false) - (Stronghold "SH5C") Whether the 5-way crossing has an exit on the upper level on the side with the upward staircase.
 * 1 or 0 (true/false) - (Stronghold "SH5C") Whether the 5-way crossing has an exit on the lower level on the side with the upward staircase.
 * (Village "ViSR") Length of the road piece.
 * 1 or 0 (true/false) - (Fortress "NeMT") Whether this fortress piece should contain a Blaze spawner but hasn't had one generated yet. (Stronghold "SHPR") Whether the Silverfish spawner has been placed in this piece.
 * (Mineshaft "MSCorridor") Corridor length.
 * Likely orientation of the structure piece.
 * 1 or 0 (true/false) - (Jungle temple) Whether the hidden chest was placed.
 * 1 or 0 (true/false) - (Jungle temple) Whether the main chest was placed.
 * 1 or 0 (true/false) - (Jungle temple) Whether the hallway arrow trap dispenser was placed.
 * 1 or 0 (true/false) - (Jungle temple) Whether the chest arrow trap dispenser was placed.
 * The X coordinate origin of this village part.
 * The Y coordinate origin of this village part.
 * The Z coordinate origin of this village part.
 * 1 or 0 (true/false) - (Stronghold "SHS") Whether the corridor has an opening on the right.
 * 1 or 0 (true/false) - (Stronghold "SH5C") Whether the 5-way crossing has an exit on the upper level on the side with the downward staircase.
 * 1 or 0 (true/false) - (Stronghold "SH5C") Whether the 5-way crossing has an exit on the lower level on the side with the downward staircase.
 * Rotation of ocean ruins and shipwrecks. Valid values are COUNTERCLOCKWISE_90, NONE, CLOCKWISE_90, and CLOCKWISE_180.
 * 1 or 0 (true/false) - (Mineshaft "MSCorridor") Whether the corridor has cobwebs.
 * (Fortress "NeBEF") Random seed for the broken-bridge fortress piece.
 * 1 or 0 (true/false) - (Stronghold "SHSD") Whether the spiral staircase is the source of the Stronghold or was randomly generated.
 * (Stronghold "SHFC") Length of the corridor
 * (Village "ViSmH") Table: 0 is no table, 1 and 2 place it on either side of the hut.
 * 1 or 0 (true/false) - (Stronghold "SHLi") Whether the library has an upper level.
 * The template of the ocean ruin or shipwreck that was used.
 * 1 or 0 (true/false) - (Village "ViSH") Whether the house has a ladder to the roof and fencing.
 * 1 or 0 (true/false) - (Mineshaft "MSCrossing") Whether the crossing is two floors tall.
 * The X coordinate origin of this ocean ruin or shipwreck.
 * The Y coordinate origin of this ocean ruin or shipwreck.
 * The Z coordinate origin of this ocean ruin or shipwreck.
 * (Village) Village type: 0=plains, 1=desert, 2=savanna, 3=taiga.
 * (Stronghold "SHRC") Indicates whether the room contains a pillar with torches, a fountain, an upper level with a chest, or is just empty room.
 * (Village) Count of villagers spawned along with this piece.
 * (Temples and huts) Width of the structure (X/Z).
 * 1 or 0 (true/false) - (Witch hut) Whether the initial witch has been spawned for the hut.
 * 1 or 0 (true/false) - (Village) Whether this village generated as a zombie village.
 * Chunk X coordinate of the start of the structure. Absent if id is INVALID.
 * Chunk Z coordinate of the start of the structure. Absent if id is INVALID.
 * If there's no structure of this kind in this chunk, this value is "INVALID", else it's the structure name.
 * (Monument only) List of chunks that have had their piece of the structure created. Absent if id is INVALID.
 * A chunk.
 * The chunk's X position (chunk coordinates, not block coordinates).
 * The chunk's Z position.
 * 1 or 0 (true/false) - (Village only) Whether the village generated at least 3 non-roads. Absent if id is INVALID.
 * A chunk.
 * The chunk's X position (chunk coordinates, not block coordinates).
 * The chunk's Z position.
 * 1 or 0 (true/false) - (Village only) Whether the village generated at least 3 non-roads. Absent if id is INVALID.

Block format
In the Anvil format, block positions are ordered YZX for compression purposes.

The coordinate system is as follows:
 * X increases East, decreases West
 * Y increases upward, decreases downward
 * Z increases South, decreases North

This means indices are ordered like in a book, with its top to the North, read from beneath and with words written backward: each letter is a different X-index, each line a Z-index, and each page a Y-index. In case of a flat 2D array, the Y-index is omitted, and the array reads like a single page.

Each section is a 16×16×16-block area, with up to 16 sections in a chunk : from 0 at the bottom, to 15 on top. Empty sections are not saved. Each section has a "Y" byte for its Y-index (0 to 15), a "Palette" list linking IDs to block states, and a "BlockStates" long array storing the IDs per block location, compressed by fitting multiple IDs inside each entry (see NBT_structure above for details on the compression). There is an additional section at the top and bottom of the world used to store light, so that light travels properly over and under the world limits.

The "BlockLight" byte array is for block light levels. The "SkyLight" byte array stores the maximum sky light that reaches each block, regardless of current time. Each of them are 2048 bytes long, and both are omitted if no light reaches this section of the chunk. Light level is stored as 4 bits per block, 2 blocks sharing a byte : starting at 0, even blocks take the first nibble, and odd blocks the second one. This is the only known instance of data storage in Java Edition.

The pseudo-code below shows how to access individual block information from a single section.

byte Nibble4(byte[] arr, int index){ return index%2 == 0 ? arr[index/2]&0x0F : (arr[index/2]>>4)&0x0F; } int BlockPos = y*16*16 + z*16 + x; compound Block = Palette[change_array_element_size(BlockStates,Log2(length(Palette)))[BlockPos]]; string BlockName = Block.Name; compound BlockState = Block.Properties; byte Blocklight = Nibble4(BlockLight, BlockPos); byte Skylight = Nibble4(SkyLight, BlockPos);

Block entity format
A block entity (not related to entity) is used by Minecraft to store information about a block that can't be stored in the block's block states. Block entities were called "tile entities" until the 1.8 snapshots and that term is still used in some command usage.

Tile tick format
Tile Ticks represent block updates that need to happen because they could not happen before the chunk was saved. Examples reasons for tile ticks include redstone circuits needing to continue updating, water and lava that should continue flowing, recently placed sand or gravel that should fall, etc. Tile ticks are not used for purposes such as leaf decay, where the decay information is stored in the leaf block data values and handled by Minecraft when the chunk loads. For map makers, tile ticks can be used to update blocks after a period of time has passed with the chunk loaded into memory.


 * A Tile Tick

ToBeTicked format
This TAG_List is always present, and contains 16 TAG_lists, each representing one of the "sections" of the chunk. Those inside lists may contain TAG_Shorts, each representing a packed coordinate relative to the section : The 4 most significant bits are always 0, then each group of 4 bits (or nibble) represents a section-relative coordinate, from 0 to 15. The order of sections in the list appear to be ordered from bottom to top, and the packing order of the coordinates is 0ZYX. When converting proto-chunks to full chunks, only coordinates that are stored in PostProcessing appear to receive a tick update, tick updates stored in block_ticks and fluid_ticks are ignored.

History
Chunks were first introduced in Java Edition Infdev. Before the addition of the MCRegion format in Beta 1.3, chunks were stored as individual chunk files ".dat" where the file names contained the chunk's position encoded in Base36 - this is known as the Java Edition Alpha level format. MCRegion changed this by storing groups of 32×32 chunks in individual ".mcr" files with the coordinates in Base10, with the goal being to reduce disk usage by cutting down on the number of file handles Minecraft had open at once. MCRegion's successor is the current format, Anvil, which made changes only to the chunk format. The region file technique is still used, but the region file extensions are ".mca" instead.

The major change from MCRegion to Anvil was the division of Chunks into Sections; each chunk has up to 16 individual 16×16×16 block Sections so that completely empty sections are not saved at all. Preparation has also been made to support blocks with IDs in the range 0 to 4095, as compared to the previous 0 to 255 limitation. However, Minecraft is not fully prepared for such blocks to exist as items; many item IDs are already taken in the range 256 to 4095.

The Blocks, Data, BlockLight, and SkyLight arrays are now housed in individual chunk Sections. The Data, SkyLight, and BlockLight are arrays of 4-bit values, and the BlockLight and SkyLight arrays no longer house part of the block ID. The Blocks array is 8 bits per block, and the 4096-blocks support exists in the form of an optional Add byte array of 4-bits per block for additional block ID information. With the Anvil format, the NBT Format was changed from Notch's original specification to include an integer array tag similar to the existing byte array tag. It is currently used only for HeightMap information in chunks.