What NBT Is and How Bedrock Uses It
NBT is essentially a binary equivalent of JSON, designed to be compact and fast for the game engine to read and write. Every piece of data in an NBT tree is a tag consisting of a numeric type ID, a string name, and a payload. While JSON is used for static definitions inside your behaviour and resource packs, NBT is used by the engine to save the live state of a world.
Unlike Java Edition, which stores chunks in region files and uses Big-Endian byte ordering for its NBT, Bedrock Edition stores nearly all world, entity, and chunk NBT payloads inside a LevelDB key-value database using Little-Endian byte ordering. The only standalone NBT files you will regularly encounter on disk are level.dat (which holds global world settings and contains an 8-byte header before the binary payload begins) and exported .mcstructure files inside a behaviour pack.
NBT Tag Types
When inspecting a .mcstructure file or a world save in an external NBT editor, every node in the tree has a specific data type. Unlike JSON, which treats all numbers as generic values, NBT strictly separates integers by bit width and distinguishes floating-point precision.
Understanding these types matters if you use external tools to modify structure files—for example, changing a tag from a Byte to an Int will cause the game engine to ignore the value when it loads the file.
| ID | Tag Name | Payload Description |
|---|---|---|
| 0 | TAG_End | Marks the end of a TAG_Compound; has no name or payload. |
| 1 | TAG_Byte | An 8-bit signed integer (-128 to 127), also used for boolean flags (0 or 1). |
| 2 | TAG_Short | A 16-bit signed integer. |
| 3 | TAG_Int | A 32-bit signed integer. |
| 4 | TAG_Long | A 64-bit signed integer, commonly used for unique entity IDs and timestamps. |
| 5 | TAG_Float | A 32-bit single-precision floating-point number, used for rotations and health. |
| 6 | TAG_Double | A 64-bit double-precision floating-point number. |
| 7 | TAG_Byte_Array | A length-prefixed array of signed 8-bit bytes. |
| 8 | TAG_String | A UTF-8 string prefixed by its byte length as an unsigned 16-bit integer. |
| 9 | TAG_List | An ordered list of unnamed tags that must all share the exact same Tag ID. |
| 10 | TAG_Compound | A dictionary of named tags of any type, closed by a TAG_End. |
| 11 | TAG_Int_Array | A length-prefixed array of 32-bit signed integers. |
| 12 | TAG_Long_Array | A length-prefixed array of 64-bit signed integers. |
Where Add-on Creators Encounter NBT
Inside a standard behaviour pack, the only raw NBT files are structure files located in the BP/structures/ folder. When you save a region of blocks and entities using a Structure Block in-game and export it to disk, Bedrock writes an uncompressed Little-Endian TAG_Compound with the .mcstructure extension.
A .mcstructure file contains the dimensions of the saved volume, a block palette mapping runtime indices to block names and their block states, a 3D positional grid of those indices, block entity data (such as chest inventories or sign text), and full entity snapshots. Add-on creators occasionally open these files in an NBT editor to strip out unwanted entities, clean up temporary structure_void blocks, or manually edit a loot table path inside a saved container.
Command JSON Equivalents to NBT
Creators coming from other platforms often try to pass raw NBT strings into commands like /give or /replaceitem to set item lore, enchantments, or custom names. Bedrock Edition does not parse raw NBT in commands. Instead, its command parser accepts a strict JSON object with a tiny set of supported item components.
Through commands, you can only assign minecraft:can_place_on, minecraft:can_destroy, minecraft:item_lock, and minecraft:keep_on_death. To apply custom names, lore, or enchantments without external NBT editors, you must use the Script API or define a loot table inside your behaviour pack.
{
"pools": [
{
"rolls": 1,
"entries": [
{
"type": "item",
"name": "minecraft:diamond_pickaxe",
"functions": [
{
"function": "set_name",
"name": "Excavator's Pick"
},
{
"function": "set_lore",
"lore": [
"Can break deepslate",
"Soulbound to owner"
]
},
{
"function": "enchant_with_levels",
"levels": {
"min": 20,
"max": 30
},
"treasure": true
}
]
}
]
}
]
}Storing Custom Data Without Direct NBT Access
Because you cannot read or write arbitrary NBT tags on entities, items, or worlds during gameplay, Bedrock provides two official systems to persist custom add-on state: Entity Properties (defined in the entity JSON and readable via Molang) and Dynamic Properties (read and written via the @minecraft/server Script API).
When you call setDynamicProperty in script, the Bedrock engine serializes your string, number, boolean, or Vector3 directly into the entity, item stack, or world NBT payload inside the LevelDB save. This gives you the permanence of NBT storage while keeping your data sandboxed to your behaviour pack's manifest UUID.
import { world } from "@minecraft/server";
world.afterEvents.entityHitEntity.subscribe((event) => {
const { damagingEntity, hitEntity } = event;
if (damagingEntity.typeId !== "minecraft:player") return;
const currentHits = hitEntity.getDynamicProperty("my_pack:hit_count") ?? 0;
const nextHits = currentHits + 1;
hitEntity.setDynamicProperty("my_pack:hit_count", nextHits);
damagingEntity.sendMessage(`Target hit count saved to NBT: ${nextHits}`);
});Which versions this applies to
Applies to all modern Bedrock Edition versions. Little-Endian NBT in .mcstructure files and LevelDB world saves is foundational to the engine. Script API Dynamic Properties (the supported way to write custom persistent data) are stable in @minecraft/server 1.7.0+ (Bedrock 1.20.50 and later) and do not require any experimental toggles.
When it does not work
| What you see | Why | The fix |
|---|---|---|
| Syntax error: Unexpected "{": at "diamond_sword 1 0 >>{<<display:{Name..." when running /give or /replaceitem. | You attempted to use Java Edition raw NBT syntax in a Bedrock command. Bedrock commands only accept a small JSON object for item components like minecraft:can_place_on or minecraft:keep_on_death. | Move item customization (custom names, lore, enchantments, durability) into a behaviour pack loot table and spawn the item using /loot, or manipulate the ItemStack via the Script API. |
| A .mcstructure file fails to load via the /structure command or crashes the world after being edited in an external NBT tool. | Many NBT editors default to Java Edition's format (GZip-compressed, Big-Endian byte order). Bedrock .mcstructure files must be saved as uncompressed, Little-Endian NBT. | Ensure your NBT editor is explicitly set to write uncompressed Little-Endian binary before saving changes to any .mcstructure file. |
| World refuses to open or resets its settings after manually editing level.dat. | Bedrock's level.dat is not a pure NBT file; it begins with an 8-byte header consisting of a 32-bit storage version integer and a 32-bit payload byte-length integer. | Only edit level.dat with an NBT editor that natively supports the Bedrock level.dat header and automatically recalculates the byte-length integer upon saving. |
Reference, straight from the game files
Read out of the game itself, so the ids match the version you are building for.
