NBT

The Named Binary Tag (NBT) file format is an extremely simple, albeit annoying (did we really need yet another format?)[See Discussion] structured binary format used by the Minecraft game for a variety of things. Due to this, several third-party utilities now also utilize the format. You may find example files at the bottom of this article.

Mojang has also released a reference implementation along with their Anvil conversion tool, available from https://mojang.com/2012/02/new-minecraft-map-format-anvil/

Current Uses
The NBT format is currently used in several places, chiefly:
 * In the Protocol as part of Slot Data
 * Multiplayer saved server list.
 * Player data (both single player and multiplayer, one file per player). This includes such things as inventory and location.
 * Saved worlds (both single player and multiplayer).
 * World index file that contains general information (spawn point, time of day, etc...)
 * Chunk data (see Region Files)

Unfortunately, the NBT files you can encounter as a developer will be stored in three different ways, just to make things interesting.
 * Uncompressed,
 * gzip'd,
 * zlib'd (aka DEFLATE with a few bytes extra)

Libraries
There are many, many libraries for manipulating NBT, written in several languages, and often several per language. For example,


 * C,
 * C#,
 * D,
 * Go (New),
 * Go (Old, without TagLongArray),
 * Java (Old, without TagLongArray),
 * Javascript,
 * PHP,
 * Python,
 * Ruby,
 * Rust,
 * Scala,
 * Kotlin (Extremely simple, 200 lines),
 * Kotlin Multiplatform,
 * You get the idea…

Unless you have specific goals or licence requirements, it is extremely recommended to go with one of the existing libraries.

Utilities
Almost every 3rd-party Minecraft application uses NBT on some level. There also exist several dedicated NBT editors, which will likely be useful to you if you are developing an NBT library of your own. These include:
 * NBTEdit (C#, Mono-capable), one of the very first NBT editors.
 * NEINedit (Obj-C), an OS X specific editor.
 * nbt2yaml (Python), provides command-line editing of NBT via the YAML format, as well as a fast and minimalist NBT parsing/rendering API.
 * nbted (Rust; CC0), provides command-line editing of NBT files via your $EDITOR
 * nbt2json (Golang; MIT) Command-line utility for NBT to JSON/YAML conversion and back. MCPE-NBT support. Can be used as library.

Specification
The NBT file format is extremely simple, and writing a library capable of reading/writing it is a simple affair. There are 13 datatypes supported by this format, one of which is used to close compound tags. It is strongly advised to read this entire section or you may run into issues.

There are a couple of simple things to remember:
 * The datatypes representing numbers are in big-endian in the PC version, but Pocket Version is in little-endian. Unless you're using Java, you will most likely have to swap it to little-endian. See the Wikipedia article on Endianness.
 * Every NBT file will always implicitly be inside a tag compound, and also begin with a TAG_Compound
 * The structure of a NBT file is defined by the TAG_List and TAG_Compound types, as such a tag itself will only contain the payload, but depending on what the tag is contained within may contain additional headers. I.e. if it's inside a Compound, then each tag will begin with the TAG_id, and then a string (the tag's name), and finally the payload. While in a list it will be only the payload, as there is no name and the tag type is given in the beginning of the list.

For example, here's the example layout of a  on disk:

If this  had been in a , it would have been nothing more than the payload, since the type is implied and tags within the first level of a list are nameless.

Examples
There are two defacto example files used for testing your implementation ( &  ), originally provided by Markus. The example output provided below was generated using PyNBT's debug-nbt tool.

test.nbt
This first example is an uncompressed "Hello World" NBT example. Should you parse it correctly, you will get a structure similar to the following:

TAG_Compound('hello world'): 1 entry {   TAG_String('name'): 'Bananrama' }

Here is the example explained:

bigtest.nbt
This second example is a gzip compressed test of every available tag. If your program can successfully parse this file, then you've done well. Note that the tags under TAG_List do not have a name, as mentioned above. TAG_Compound('Level'): 11 entries {   TAG_Compound('nested compound test'): 2 entries {     TAG_Compound('egg'): 2 entries {       TAG_String('name'): 'Eggbert' TAG_Float('value'): 0.5 }     TAG_Compound('ham'): 2 entries {       TAG_String('name'): 'Hampus' TAG_Float('value'): 0.75 }   }    TAG_Int('intTest'): 2147483647 TAG_Byte('byteTest'): 127 TAG_String('stringTest'): 'HELLO WORLD THIS IS A TEST STRING \xc3\x85\xc3\x84\xc3\x96!' TAG_List('listTest (long)'): 5 entries {     TAG_Long(None): 11 TAG_Long(None): 12 TAG_Long(None): 13 TAG_Long(None): 14 TAG_Long(None): 15 }   TAG_Double('doubleTest'): 0.49312871321823148 TAG_Float('floatTest'): 0.49823147058486938 TAG_Long('longTest'): 9223372036854775807L TAG_List('listTest (compound)'): 2 entries {     TAG_Compound(None): 2 entries {       TAG_Long('created-on'): 1264099775885L TAG_String('name'): 'Compound tag #0' }     TAG_Compound(None): 2 entries {       TAG_Long('created-on'): 1264099775885L TAG_String('name'): 'Compound tag #1' }   }    TAG_Byte_Array('byteArrayTest (the first 1000 values of (n*n*255+n*7)%100, starting with n=0 (0, 62, 34, 16, 8, ...))'): [1000 bytes] TAG_Short('shortTest'): 32767 }

servers.dat
The servers.dat file contains a list of multiplayer servers you've added to the game. To mix things up a bit, this file will always be uncompressed. Below is an example of the structure seen in servers.dat. TAG_Compound( '' ): 1 entry {   TAG_List('servers'): 2 entries {     TAG_Compound(None): 3 entries {       TAG_Byte('acceptTextures'): 1 (Automatically accept resourcepacks from this server) TAG_String('ip'): '199.167.132.229:25620' TAG_String('name'): 'Dainz1 - Creative' }     TAG_Compound(None): 3 entries {       TAG_String('icon'): 'iVBORw0KGgoAAAANUhEUgAAAEAAAABACA...' (The base64-encoded server icon. Trimmed here for the example's sake) TAG_String('ip'): '76.127.122.65:25565' TAG_String('name'): 'minstarmin4' }   }  }

level.dat
This final example is of a single player level.dat, which is compressed using gzip. Notice the player's inventory and general world details such as spawn position, world name, and the game seed. TAG_Compound( '' ): 1 entry {   TAG_Compound('Data'): 17 entries {     TAG_Byte('raining'): 0 TAG_Long('RandomSeed'): 3142388825013346304L TAG_Int('SpawnX'): 0 TAG_Int('SpawnZ'): 0 TAG_Long('LastPlayed'): 1323133681772L TAG_Int('GameType'): 1 TAG_Int('SpawnY'): 63 TAG_Byte('MapFeatures'): 1 TAG_Compound('Player'): 24 entries {       TAG_Int('XpTotal'): 0 TAG_Compound('abilities'): 4 entries {         TAG_Byte('instabuild'): 1 TAG_Byte('flying'): 1 TAG_Byte('mayfly'): 1 TAG_Byte('invulnerable'): 1 }       TAG_Int('XpLevel'): 0 TAG_Int('Score'): 0 TAG_Short('Health'): 20 TAG_List('Inventory'): 13 entries {         TAG_Compound(None): 4 entries {           TAG_Byte('Count'): 1 TAG_Byte('Slot'): 0 TAG_Short('id'): 24 TAG_Short('Damage'): 0 }         TAG_Compound(None): 4 entries {           TAG_Byte('Count'): 1 TAG_Byte('Slot'): 1 TAG_Short('id'): 25 TAG_Short('Damage'): 0 }         TAG_Compound(None): 4 entries {           TAG_Byte('Count'): 1 TAG_Byte('Slot'): 2 TAG_Short('id'): 326 TAG_Short('Damage'): 0 }         TAG_Compound(None): 4 entries {           TAG_Byte('Count'): 1 TAG_Byte('Slot'): 3 TAG_Short('id'): 29 TAG_Short('Damage'): 0 }         TAG_Compound(None): 4 entries {           TAG_Byte('Count'): 10 TAG_Byte('Slot'): 4 TAG_Short('id'): 69 TAG_Short('Damage'): 0 }         TAG_Compound(None): 4 entries {           TAG_Byte('Count'): 3 TAG_Byte('Slot'): 5 TAG_Short('id'): 33 TAG_Short('Damage'): 0 }         TAG_Compound(None): 4 entries {           TAG_Byte('Count'): 43 TAG_Byte('Slot'): 6 TAG_Short('id'): 356 TAG_Short('Damage'): 0 }         TAG_Compound(None): 4 entries {           TAG_Byte('Count'): 64 TAG_Byte('Slot'): 7 TAG_Short('id'): 331 TAG_Short('Damage'): 0 }         TAG_Compound(None): 4 entries {           TAG_Byte('Count'): 20 TAG_Byte('Slot'): 8 TAG_Short('id'): 76 TAG_Short('Damage'): 0 }         TAG_Compound(None): 4 entries {           TAG_Byte('Count'): 64 TAG_Byte('Slot'): 9 TAG_Short('id'): 331 TAG_Short('Damage'): 0 }         TAG_Compound(None): 4 entries {           TAG_Byte('Count'): 1 TAG_Byte('Slot'): 10 TAG_Short('id'): 323 TAG_Short('Damage'): 0 }         TAG_Compound(None): 4 entries {           TAG_Byte('Count'): 16 TAG_Byte('Slot'): 11 TAG_Short('id'): 331 TAG_Short('Damage'): 0 }         TAG_Compound(None): 4 entries {           TAG_Byte('Count'): 1 TAG_Byte('Slot'): 12 TAG_Short('id'): 110 TAG_Short('Damage'): 0 }       }        TAG_Short('HurtTime'): 0 TAG_Short('Fire'): -20 TAG_Float('foodExhaustionLevel'): 0.0 TAG_Float('foodSaturationLevel'): 5.0 TAG_Int('foodTickTimer'): 0 TAG_Short('SleepTimer'): 0 TAG_Short('DeathTime'): 0 TAG_List('Rotation'): 2 entries {         TAG_Float(None): 1151.9342041015625 TAG_Float(None): 32.249679565429688 }       TAG_Float('XpP'): 0.0 TAG_Float('FallDistance'): 0.0 TAG_Short('Air'): 300 TAG_List('Motion'): 3 entries {         TAG_Double(None): -2.9778325794951344e-11 TAG_Double(None): -0.078400001525878907 TAG_Double(None): 1.1763942772801152e-11 }       TAG_Int('Dimension'): 0 TAG_Byte('OnGround'): 1 TAG_List('Pos'): 3 entries {         TAG_Double(None): 256.87499499518492 TAG_Double(None): 112.62000000476837 TAG_Double(None): -34.578128612797634 }       TAG_Byte('Sleeping'): 0 TAG_Short('AttackTime'): 0 TAG_Int('foodLevel'): 20 }     TAG_Int('thunderTime'): 2724 TAG_Int('version'): 19132 TAG_Int('rainTime'): 5476 TAG_Long('Time'): 128763 TAG_Byte('thundering'): 1 TAG_Byte('hardcore'): 0 TAG_Long('SizeOnDisk'): 0 TAG_String('LevelName'): 'Sandstone Test World' } }

Download

 * test.nbt/hello_world.nbt (uncompressed),
 * bigtest.nbt (gzip compressed)
 * NaN-value-double.dat (compressed, origin version unknown)