File Location and Basic Structure
All loot tables live inside the `loot_tables` folder of your behavior pack. Unlike entity or block definitions, loot tables do not have a `format_version` key or an identifier block at the top of the file. Instead, the game references them directly by their file path relative to the behavior pack root, always starting with `loot_tables/` and ending with `.json`.
To override a vanilla drop, place a file at the exact same relative path the base game uses, such as `BP/loot_tables/entities/zombie.json`. For custom content, create a subfolder named after your project inside `BP/loot_tables/` to keep your files organized and avoid collisions with other packs.
At its root, a loot table JSON contains a single `pools` array. Each object inside `pools` represents an independent group of rolls. When the game evaluates the table, it processes every pool in the list from top to bottom.
{
"pools": [
{
"rolls": 1,
"entries": [
{
"type": "item",
"name": "minecraft:gold_nugget",
"weight": 3,
"functions": [
{
"function": "set_count",
"count": {
"min": 1,
"max": 4
}
}
]
},
{
"type": "item",
"name": "minecraft:emerald",
"weight": 1
},
{
"type": "empty",
"weight": 2
}
]
}
]
}Pools, Rolls, and Entries
A pool controls how many times the game picks from a specific list of items. The `rolls` property sets the number of draws; it can be a fixed integer (like `1`) or an object with `min` and `max` integers for a random range. If you want a mob to always drop bones AND have a separate chance to drop a rare weapon, you create two separate pools in the same file.
Inside a pool, the `entries` array holds the possible outcomes for each roll. Every entry needs a `type`. The most common is `"item"`, which requires a `name` field set to a valid item identifier. You can also use `"empty"` to add a chance that a roll drops nothing at all, or `"loot_table"` to point `name` at another loot table file path, allowing you to share sub-tables across multiple mobs.
When a pool has multiple entries, the `weight` integer determines how likely each entry is to be chosen on any given roll. The game adds up the weights of all eligible entries in that pool, and an entry's chance is its own weight divided by the total. In the example above, the total weight is 6 (3 + 1 + 2), giving gold nuggets a 3 in 6 chance, emeralds a 1 in 6 chance, and nothing a 2 in 6 chance.
Modifying Drops with Functions
Entries by themselves only drop a single, unmodified item. To change stack sizes, apply durability damage, add enchantments, or set custom names, you attach a `functions` array to the item entry. Functions run in order after the item entry is selected by a roll.
| Function Name | What it does | Notes |
|---|---|---|
| set_count | Sets the stack size of the dropped item. | Takes a `count` field as an integer or a `{"min": x, "max": y}` object. |
| looting_enchant | Increases stack count based on the killer's Looting level. | Uses a `count` object with `min` and `max` added per level of Looting. |
| set_damage | Sets remaining durability on tools and armor. | Uses a `damage` float from 0.0 (broken) to 1.0 (full durability) in Bedrock. |
| enchant_with_levels | Enchants the item as if using an enchanting table. | Uses `levels` (`min`/`max`) and a boolean `treasure` flag. |
| enchant_randomly | Applies one random compatible enchantment to the item. | Accepts an optional `treasure` boolean to allow treasure enchantments. |
| set_name | Applies a custom display name to the item. | Uses the `name` string field; supports standard formatting codes. |
| set_lore | Adds lore text lines underneath the item name. | Uses a `lore` array of strings. |
| set_data | Sets the data value on older aux-value items. | Rarely used for modern items, which use distinct identifiers instead. |
Filtering with Conditions
A `conditions` array can be placed on an entire pool or on an individual entry. All conditions in the array must pass for the pool to roll or the entry to be included in the selection pool. This is how vanilla mobs restrict rare drops to player kills or adjust drop rates based on difficulty.
The `killed_by_player` condition takes no extra parameters and ensures traps or fall damage cannot farm the drop. For simple percentage chances where weights feel clumsy, `random_chance` takes a `chance` float between `0.0` and `1.0`. If you want Looting to improve that flat chance, `random_chance_with_looting` adds a `looting_multiplier` float that is added to `chance` for each level of the enchantment.
{
"pools": [
{
"rolls": 1,
"conditions": [
{
"condition": "killed_by_player"
},
{
"condition": "random_chance_with_looting",
"chance": 0.1,
"looting_multiplier": 0.05
}
],
"entries": [
{
"type": "item",
"name": "minecraft:diamond_sword",
"functions": [
{
"function": "enchant_with_levels",
"treasure": true,
"levels": {
"min": 20,
"max": 30
}
}
]
}
]
}
]
}Connecting Loot Tables to Entities and Blocks
A loot table does nothing until something references it. In an entity behavior file, add the `minecraft:loot` component inside `components` or a component group, and set its `table` property to your file path. In a block behavior file, use the `minecraft:loot` component as a simple string value pointing to the table path.
You can also trigger a loot table directly during gameplay using commands or scripts. The `/loot` command allows you to spawn drops in the world or insert them directly into a player's inventory or container using `/loot spawn` or `/loot give`.
{
"format_version": "1.20.80",
"minecraft:block": {
"description": {
"identifier": "custom:cracked_crate"
},
"components": {
"minecraft:destructible_by_mining": {
"seconds_to_destroy": 1.5
},
"minecraft:loot": "loot_tables/blocks/cracked_crate_drops.json"
}
}
}Which versions this applies to
Stable in all current Bedrock versions (1.16.0 through 1.21+). No experimental toggles are required for loot tables or the `minecraft:loot` component.
When it does not work
| What you see | Why | The fix |
|---|---|---|
| Mob or block drops nothing at all, and Content Log shows a JSON parse error or missing file warning for the loot table. | The path inside the `minecraft:loot` component is missing the `loot_tables/` prefix, omits the `.json` extension, or uses backslashes (`\`) instead of forward slashes (`/`). | Ensure the path starts from the behavior pack root and uses forward slashes, for example: `"loot_tables/entities/my_mob.json"`. |
| One pool drops items as expected, but another pool in the same file never drops anything. | An item identifier inside `entries` is misspelled or missing its namespace, or a condition on the pool (such as `killed_by_player` when testing with `/kill`) is evaluating to false. | Check the Content Log for `Failed to find item` warnings, verify all custom items use their exact `namespace:name`, and test mob drops with a sword rather than `/kill` if conditions are present. |
| A custom block drops a single copy of itself instead of running your custom loot table. | The `minecraft:loot` component was placed inside `description` instead of `components`, or formatted as an object `{"table": "..."}` on a modern block version that expects a direct string. | Move `minecraft:loot` into the `components` block of your block JSON and assign the path directly as a string value. |
Reference, straight from the game files
Read out of the game itself, so the ids match the version you are building for.
