Loot tables

Loot tables are data-driven JSON files that decide what item stacks a block, entity, chest, fishing rod or command produces — built from pools, weighted entries, item-modifying functions, gating conditions and number providers.

File location

Each loot table is one JSON file under the singular 1.21+ folder:

data/<namespace>/loot_table/<path>.json

data/mypack/loot_table/blocks/lucky_ore.json     → referenced as mypack:blocks/lucky_ore
data/mypack/loot_table/entity/boss_drop.json     → referenced as mypack:entity/boss_drop

The table ID is namespace:path (without the .json). Vanilla tables live in the minecraft namespace and can be overridden by placing a same-named file in your pack.

Top-level schema

data/<namespace>/loot_table/example.json

{
  "type": "minecraft:block",
  "random_sequence": "minecraft:blocks/diamond_ore",
  "modifier": { /* table-wide item modifier applied to every dropped stack; an array is also accepted */ },
  "pools": [ { /* pool */ } ]
}
FieldTypeMeaning
typestring (enum)The loot context the table is invoked in (optional, default generic). Validates which context parameters functions/conditions may reference. See the enum below.
poolsarrayList of pools; each pool is rolled independently.
functionsarrayTable-level item modifiers applied in order to every stack the whole table produces (shorthand for repeating functions in each pool).
random_sequenceresource locationNames a deterministic random sequence 1.20+ so per-table RNG is reproducible. Omit for fully random behaviour.

Loot context type enum

The context determines which parameters (the killed entity, the mined block, the tool, the origin position, etc.) are available to functions and conditions.

typeContext / provided parameters
emptyNo parameters.
genericSupplies all parameters (most permissive).
chestOrigin + opening entity.
blockBlock state, position, tool, explosion radius, (block entity, direct killer).
entityDying entity, position, damage source, (attacker / direct attacker / attacking player).
equipmentSpawned entity + position (mob equipment on spawn).
fishingBobber position, fishing rod tool, hooked-in entity.
archaeologySuspicious block center, brushing player, brush tool.
vaultVault center; optional opener entity + key item.
giftGiver location + gifting mob (cat/villager gifts).
barterThe piglin trading.
shearingSheared entity, position, shears tool.
advancement_rewardPlayer + location on advancement grant.
advancement_entityEntity + location (predicate/context use).
advancement_locationLocation context (predicate use).
command/loot and command-driven contexts.
selectorEntity-selector-driven contexts (predicates/item modifiers).
entity_interact / block_interactInteraction target + tool.
📌 Note

Not every value is a valid loot-table-invoking context. Several (command, selector, advancement_entity, advancement_location, the interact types) primarily scope predicates and item modifiers rather than tables that drop items.

Pool schema

One entry in the pools array

{
  "rolls": 1,
  "bonus_rolls": 0.0,
  "condition": { /* ONE condition; the pool is skipped unless it passes. Combine with all_of */ },
  "modifier": { /* applied to every stack from this pool; an array is also accepted */ },
  "entries": [ /* one is chosen per roll (weighted) */ ]
}
FieldTypeMeaning
rollsnumber providerHow many entries to pick from this pool.
bonus_rollsnumber providerExtra rolls per level of luck (default 0.0).
entriesarrayCandidate entries; per roll one is selected by weight.
conditionsarrayAll must pass or the whole pool is skipped (see conditions).
functionsarrayItem modifiers applied to every stack from this pool (see functions).

Both rolls and bonus_rolls accept the full number-provider syntax — a plain number, a {min,max} uniform shorthand, or an explicit provider object (see below).

Entry types

⚠ Pools and entries changed shape at 26.3

This is a shape change, not a rename — the plural arrays became single values, and the new modifier takes an item modifier rather than a list of functions:

Up to 26.2From 26.3
functions: array of functionsmodifier: one item modifier
conditions: array of conditionscondition: one predicate reference

Both apply to pools and to entries. Singleton entries lose functions outright. A related trap reported from production: at 26.3 an item modifier file whose root is a bare list is rejected — a list is valid only inside a modifier field — and the world fails to load.

Common entry fields: type, conditions, functions, plus for weighted (singleton) entries weight (default 1) and quality (default 0).

📌 Note

Effective weight = max(floor(weight + quality × luck), 0). A higher quality makes an entry more likely as the player's luck attribute rises.

typeKindKey fields
minecraft:itemsingletonname (item ID), functions, weight, quality.
minecraft:tagsingleton / expandingname (item #tag), expand (bool). expand:true = one entry per item in the tag (each weighted); expand:false = drops the whole tag's items as one entry.
minecraft:loot_tablesingletonvalue — a referenced table ID or an inline loot-table object (nested tables, 1.20.2+).
minecraft:dynamicsingletonname — context-supplied contents (minecraft:contents for block entities like shulker boxes; minecraft:sherds for decorated pots).
minecraft:emptysingletonDrops nothing (use for a weighted "chance of nothing").
minecraft:groupcompositechildren — evaluate all children as a unit.
minecraft:alternativescompositechildren — first child whose conditions pass (logical OR).
minecraft:sequencecompositechildren — run children in order until one's conditions fail (logical AND-until-fail).

Loot functions (full catalogue)

Every item-modifier object is {"type": "minecraft:<id>", ...params, "condition": {...}} — condition is optional on any modifier. At 26.3 the discriminator is type, not function, and the field holding them is modifier, not functions: vanilla’s own 1,447 loot tables use type 1,098 times and function never. This catalogue is identical to the standalone item modifier schema (an item-modifier file is just a reusable loot function or array of functions).

FunctionFields
set_countcount (number provider), add (bool, default false).
set_damagedamage (number provider), add (bool, default false).
set_componentscomponents (component map).
set_custom_datatag (SNBT string or object) — writes the custom_data component.
set_lorelore (array of text components), mode (append/insert/replace_all/replace_section), entity (ctx, optional), offset (int), size (int).
set_namename (text component), entity (ctx, optional), target (custom_name/item_name, default custom_name).
set_enchantmentsenchantments (map ID→level, each a number provider), add (bool).
enchant_randomlyoptions (array/#tag, optional), only_compatible (bool, default true).
enchant_with_levelslevels (number provider), options (optional).
enchanted_count_increaseenchantment (ID), count (number provider), limit (int, default 0). The looting_enchant replacement.
apply_bonusenchantment (ID), formula (uniform_bonus_count/ore_drops/binomial_with_bonus_count), parameters (extra/probability/bonusMultiplier).
furnace_smelt(none) — outputs the smelted form.
explosion_decay(none) — randomly removes items per explosion radius.
limit_countlimit (int, or {min,max} clamp).
set_attributesmodifiers (array of {attribute, id, amount(np), operation, slot}), replace (bool, default true).
set_stew_effecteffects (array of {type, duration}).
set_potionid (potion ID).
set_ominous_bottle_amplifieramplifier (number provider).
set_instrumentoptions (instrument #tag).
set_book_coverauthor, title (text component), generation (0–3) — all optional.
set_written_book_pages / set_writable_book_pagespages (array), mode, offset, size.
set_banner_patternpatterns (array), append (bool).
set_firework_explosionshape, colors (ints), fade_colors (ints), has_trail, has_twinkle.
set_fireworksexplosions (list op: values/mode/offset/size), flight_duration (0–255).
set_custom_model_datafloats/flags/strings/colors (each a list op) — structured CMD 1.21.4+.
set_contentsentries (array), component (container/bundle_contents/charged_projectiles).
modify_contentscomponent (container-like), modifier (item modifier(s) applied to contents).
set_loot_tablename (table ID), type (block-entity type), seed (optional) — for container block items.
set_itemitem (ID) — replaces the stack's item type.
copy_componentssource (block_entity), include/exclude (arrays, optional).
copy_custom_datasource (context/storage/block_entity), ops (array of {source, target, op}).
copy_namesource (context: block_entity/entity).
copy_stateblock (ID), properties (array of state names) — copies mined block states into block_state.
exploration_mapdestination (structure tag — bare id up to 26.2, #tag from 26.3, and the field became required at 26.3; see below), decoration, zoom (int, def 2), search_radius (int, def 50), skip_existing_chunks (bool, def true).
fill_player_headentity (ctx ref) — writes the profile of a player from context.
filtereditem_filter (item predicate), modifier (item modifier applied on match).
toggle_tooltipstoggles (booleans: attribute_modifiers, can_break, can_place_on, dyed_color, enchantments, stored_enchantments, trim, unbreakable).
set_random_dyes / set_random_potionRandomised dye / potion helpers.
referencename (referenced item-modifier ID or array).
sequencefunctions (array run in order).

exploration_map: destination changed shape at 26.3

destination names a structure tag, and how you write that tag depends on the version. There is no single value that is correct on both sides of 26.3, which makes this the rare field where a pack spanning the two needs an overlay.

Up to 26.2 (format ≤ 110)From 26.3 (format ≥ 111) — current release since 2026-09-15
Required?Optional — defaults to buried treasure.Required. Omitting it is an error.
Tag reference"minecraft:on_treasure_maps" — bare. A leading # is a parse error."#minecraft:on_treasure_maps" — prefixed.
Bare id meansthe tag of that name.a single structure of that name — not the tag.
List form—["ns:structure", "…"] is also accepted.

Measured, not inferred, and re-checked as 26.3 progressed. The same vanilla file — villager_trade/cartographer/2/emerald_and_compass_village_desert_map.json — reads minecraft:on_desert_village_maps at format 110 and #minecraft:on_desert_village_maps at format 111. Across shipped 26.2 all 10 distinct destination values are bare and none are prefixed. The change has since held through 26.3-pre-1 (format 119), where all 28 occurrences across 23 distinct values are prefixed and none are bare — so it shipped unchanged in the 26.3 release (format 121).

Up to 26.2 — bare, and the tag is implied
{
  "function": "minecraft:exploration_map",
  "destination": "minecraft:on_woodland_explorer_maps",
  "decoration": "woodland_mansion"
}
From 26.3 — the tag is referenced explicitly, and the key is type
{
  "type": "minecraft:exploration_map",
  "destination": "#minecraft:on_woodland_mansion_maps",
  "decoration": "woodland_mansion"
}
⚠ Both directions fail, and only one of them is loud

Using # on 26.2 or earlier does not merely disable the map — the file fails to parse, because the # is read as part of the namespace:

Couldn't parse data file 'example:cartographer/dungeon_map':
  Not a valid resource location: #example:on_dungeon_maps
  Non [a-z0-9_.-] character in namespace of identifier

A loot table that fails to parse is never registered, so every reference to it dangles at once — villager trades, chest pools and item tables pointing at it all go silently empty, with nothing in-game naming the file at fault.

The reverse is worse, because it is silent. A bare tag-style name on 26.3 parses cleanly and then resolves to a structure of that name. For a name like on_treasure_maps, where no structure shares the tag's name, there is nothing to find and no error is raised. Packs whose tag and structure happen to share a name keep working across the change by coincidence, not design.

💡 Shipping across the boundary

Keep the bare form in the base pack and put the # form in a 26.3 overlay. Naming the structure and its tag identically also survives the jump, but the meaning quietly changes from "any of these" to "this one", so it is a workaround rather than a fix.

📌 Note

A bare array in a loot modifier field (or in an item-modifier file) behaves exactly like sequence — vanilla uses the array form in 374 places and a single object in 724.

Loot conditions (full list)

Every condition is {"type": "minecraft:<id>", ...}, and it sits in the singular condition field. This is the same system as standalone predicate files — the full field breakdown of each condition lives on that page.

ConditionPurpose
all_ofterms — passes if all terms pass (AND).
any_ofterms — passes if any term passes (OR).
invertedterm — negates a single condition.
random_chancechance (float 0–1; a number provider since 1.21).
random_chance_with_enchanted_bonusLevel-scaled chance (1.21 rename of the old looting-based chance).
killed_by_playerRequires attacking_player in context.
entity_propertiesentity (context ref) + predicate (entity sub-predicate).
entity_scoresentity + scores (map objective → int range).
block_state_propertyblock + properties (state map, exact or {min,max}).
table_bonusenchantment + chances (array indexed by level).
survives_explosionPasses with probability 1 / explosion_radius.
match_toolpredicate (item sub-predicate) — the mining/relevant tool.
weather_checkraining (bool), thundering (bool).
time_checkvalue (range) + period (int modulo, optional).
value_checkvalue (number provider) + range (int range).
location_checkpredicate (location sub-predicate) + optional offsetX/Y/Z.
damage_source_propertiespredicate (damage-source sub-predicate).
enchantment_active_checkactive (bool) — inside enchantment-provided effects.
referencename (resource location of another predicate file).

Number providers & ranges

Number providers generate a value for rolls, bonus_rolls, set_count.count, set_damage.damage, enchant levels, value_check, random_chance, and more. The four core providers are universal:

ProviderFieldsNotes
constantvalue (number)Fixed value.
uniformmin, max (each a number provider)Inclusive random.
binomialn (trials, np), p (probability 0–1, np)Binomial distribution.
scoretarget ({type:"fixed", name} or {type:"context", target}), score (objective), scale (float, optional)Reads a scoreboard value.
📌 Note

Three further providers — storage (storage + path), enchantment_level (amount, a per-level value) and sum (summands array) — are documented but less common. The four above are the safe, universal set.

Shorthand forms

Int / float ranges

Distinct from number providers: a range tests a value rather than generating one. Used by predicate comparisons (count, distance, time_check.value, entity_scores, effects.amplifier, …). A range is a single number (exact match) or an object with optional min and/or max:

"count": { "min": 2, "max": 5 }     // 2..5 inclusive
"count": 3                           // exactly 3
"level": { "min": 10 }               // >= 10 (open upper bound)
"rolls": { "type": "minecraft:binomial", "n": 3, "p": 0.5 }
"count": { "type": "minecraft:score",
           "target": { "type": "context", "target": "this" },
           "score": "kills", "scale": 0.5 }

Examples

Block drop with a fortune bonus

data/mypack/loot_table/blocks/lucky_ore.json

{
  "type": "minecraft:block",
  "pools": [
    {
      "rolls": 1,
      "entries": [
        {
          "type": "minecraft:item",
          "name": "minecraft:diamond",
          "modifier": [
          { "type": "minecraft:apply_bonus",
              "enchantment": "minecraft:fortune",
              "formula": "minecraft:ore_drops"
            },
            { "type": "minecraft:explosion_decay" }
          ]
        }
      ],
      "condition": { "type": "minecraft:survives_explosion" }
    }
  ]
}

Weighted entity drop, gated on a player kill

data/mypack/loot_table/entity/boss_drop.json

{
  "type": "minecraft:entity",
  "pools": [
    {
      "rolls": { "min": 1, "max": 3 },
      "bonus_rolls": 0.5,
      "condition": { "type": "minecraft:killed_by_player" },
      "entries": [
        { "type": "minecraft:item", "name": "minecraft:diamond", "weight": 6,
          "modifier": [
          { "type": "minecraft:set_count",
                           "count": { "type": "minecraft:uniform", "min": 1, "max": 4 } } ] },
        { "type": "minecraft:item", "name": "minecraft:netherite_scrap", "weight": 1, "quality": 2 },
        { "type": "minecraft:empty", "weight": 3 }
      ]
    }
  ]
}

Chest / gift table (generic context)

data/mypack/loot_table/gameplay/enchanted_book_gift.json

{
  "type": "minecraft:generic",
  "pools": [
    {
      "rolls": 1,
      "entries": [
        {
          "type": "minecraft:item",
          "name": "minecraft:enchanted_book",
          "modifier": [
          { "type": "minecraft:enchant_with_levels", "levels": { "min": 20, "max": 39 } }
          ]
        }
      ]
    }
  ]
}

A "custom item" drop via components 1.20.5+

data/mypack/loot_table/entity/starblade_drop.json

{
  "type": "minecraft:entity",
  "pools": [
    {
      "rolls": 1,
      "condition": { "type": "minecraft:killed_by_player" },
      "entries": [
        {
          "type": "minecraft:item",
          "name": "minecraft:netherite_sword",
          "modifier": [
          { "type": "minecraft:set_components",
              "components": {
                "minecraft:custom_name": { "text": "Starblade", "color": "gold" },
                "minecraft:rarity": "epic"
              } },
            { "type": "minecraft:set_custom_data", "tag": "{starblade:1b}" }
          ]
        }
      ]
    }
  ]
}
⚠ Version differences
  • Since 1.21.5 (data pack format 71) — text components are stored as objects in NBT. Write { "text": "Starblade", "color": "gold" }, as above. Many commands, including /tellraw, take SNBT rather than JSON from this version.
  • Before 1.21.5 — the same field took a string containing JSON: "{\"text\":\"Starblade\"}". A pack targeting older clients still needs that form.
⚠ Gotcha

The stale string form is syntactically valid JSON, so a pack carrying it parses cleanly and passes static validation. Nothing complains until the item is generated at runtime and the name renders wrong or not at all. This is the shape that gets whole batches of loot shipped broken: the file is well formed, the schema is satisfied, and only the meaning is wrong.

Tricks & best practices

🎩 Trick

/loot turns any table into a parametric item generator: /loot give @s loot mypack:x, /loot spawn ..., /loot replace block ..., /loot insert .... Call it from functions to hand out randomised kits without hard-coding /give lines.

💡 Best practice

Use a weighted minecraft:empty entry for a "chance of nothing" inside a single roll, rather than a random_chance condition — it keeps the odds visible alongside the real drops.

💡 Best practice

random_sequence guarantees reproducible RNG (deterministic chest loot for map-makers). Omit it when you want fully random behaviour.

🎩 Trick

Dynamic drops: a minecraft:dynamic entry (contents, sherds) emits the block's stored contents — required so shulker boxes and decorated pots keep their data when mined. Nested/inline tables (a loot_table entry with an inline value) plus reference functions/conditions keep shared sub-tables DRY.

📌 Note

apply_bonus formulas: minecraft:uniform_bonus_count (param bonusMultiplier), minecraft:ore_drops (no params — the vanilla fortune ore curve), minecraft:binomial_with_bonus_count (params extra, probability).

Version differences

⚠ Version differences
  • Since 1.20.5 (pack_format 41): item NBT became data components. Loot items use component syntax and set_nbt was split into set_custom_data (the direct successor — writes the custom_data component) and the general set_components (sets any typed component).
  • Since 1.20.5: copy_nbt → copy_custom_data.
  • Since 1.20.5: looting_enchant → enchanted_count_increase (now takes an explicit enchantment, since looting is data-driven).
  • Since 1.21 (pack_format 48): the folder loot_tables was singularised to loot_table.
  • Since 1.21: loot-context entity refs renamed: killer → attacker, direct_killer → direct_attacker, killer_player → attacking_player.
  • Since 1.21: random_chance_with_enchanted_bonus replaced the old looting-based random-chance condition, and random_chance's chance became a number provider.

Sources