Wiki 9Minecraft Wiki 9Minecraft

Trade Tables

Define custom merchant offers, pricing tiers, and item pools for entities in Behavior Packs.

5Sections
3Code examples
4Known errors

Trade tables are Behavior Pack JSON files that control what items an entity offers for sale, what currency it demands in return, and how its inventory unlocks as the player trades with it. You reach for a trade table whenever you are creating a custom shopkeeper NPC, building a wandering merchant, or overriding the default trade pools of vanilla villagers.

Attaching a Trade Table to an Entity

Trade tables live in the BP/trading/ directory of your Behavior Pack. You can organize them into subfolders, such as BP/trading/economy_trades/ or BP/trading/custom/, to keep your project tidy. A trade table does nothing on its own; it must be referenced by an entity behavior file using a trading component.

For modern villagers that use the Village and Pillage leveling UI, you attach the table using the minecraft:economy_trade_table component. For simpler merchants or legacy entities that do not need XP bars and profession badges, you can use the basic minecraft:trade_table component instead. Both components point to the trade table file using a path relative to the Behavior Pack root, starting with trading/.

BP/entities/custom_merchant.json
{
  "format_version": "1.20.80",
  "minecraft:entity": {
    "description": {
      "identifier": "my_pack:custom_merchant",
      "is_spawnable": true,
      "is_summonable": true
    },
    "components": {
      "minecraft:economy_trade_table": {
        "display_name": "entity.my_pack:custom_merchant.name",
        "table": "trading/custom_merchant_trades.json",
        "new_screen": true,
        "persist_trades": true,
        "convert_trades_economy": false
      }
    }
  }
}

Tiers and Trade Groups

A trade table file consists of a root tiers array. Each object inside this array represents a trading level (such as Novice, Apprentice, Journeyman, Expert, and Master). When using minecraft:economy_trade_table, you define the total_exp_required on each tier to dictate how much trader XP the entity needs before that tier unlocks. The first tier always requires 0 XP.

Inside a tier, you can either list a flat trades array—which unlocks every single trade in that list when the tier is reached—or you can wrap your trades inside a groups array. A group contains a pool of potential trades and a num_to_select property. When the entity generates its offers for that tier, it randomly picks num_to_select trades from the group and discards the rest. This is how two villagers of the same profession end up offering different items at the same level.

BP/trading/custom_merchant_trades.json
{
  "tiers": [
    {
      "total_exp_required": 0,
      "groups": [
        {
          "num_to_select": 1,
          "trades": [
            {
              "wants": [
                {
                  "item": "minecraft:emerald",
                  "quantity": 2
                }
              ],
              "gives": [
                {
                  "item": "minecraft:bread",
                  "quantity": 6
                }
              ],
              "trader_exp": 2,
              "max_uses": 12,
              "reward_exp": true
            },
            {
              "wants": [
                {
                  "item": "minecraft:wheat",
                  "quantity": {
                    "min": 18,
                    "max": 22
                  }
                }
              ],
              "gives": [
                {
                  "item": "minecraft:emerald",
                  "quantity": 1
                }
              ],
              "trader_exp": 2,
              "max_uses": 16,
              "reward_exp": true
            }
          ]
        }
      ]
    },
    {
      "total_exp_required": 10,
      "trades": [
        {
          "wants": [
            {
              "item": "minecraft:emerald",
              "quantity": 5
            },
            {
              "item": "minecraft:apple",
              "quantity": 1
            }
          ],
          "gives": [
            {
              "item": "minecraft:golden_apple",
              "quantity": 1
            }
          ],
          "trader_exp": 5,
          "max_uses": 6,
          "reward_exp": true
        }
      ]
    }
  ]
}

Defining Individual Trades

Each trade object inside a trades array defines a single transaction row in the merchant UI. The transaction is split into a wants array (what the player must pay) and a gives array (what the player receives). While a trade can ask for one or two input items in the wants array, the gives array only ever dispenses its first item entry in the standard trading UI.

Quantities can be written as a fixed integer or as an object with min and max keys. If you use a range, the game rolls a fixed number within that range at the moment the trade is unlocked by the entity. If you want to specify a block or item variant that still relies on data values, you append a colon and the data integer directly to the item identifier string, such as "minecraft:planks:2", though modern flattened identifiers are strongly preferred.

FieldWhat it doesNotes
wantsArray of 1 or 2 item objects the player must provide.Adding more than 2 items is ignored by the trading UI.
givesArray containing the 1 item object the player receives.Only the first entry in this array is awarded.
max_usesNumber of times this trade can be completed before locking.Resets when the entity works at its workstation, if configured to resupply.
trader_expAmount of XP added to the merchant's level bar per trade.Only applies when using minecraft:economy_trade_table.
reward_expBoolean that controls whether the player gets green XP orbs.Defaults to true if omitted in most vanilla tables.
price_multiplierFloat placed inside a wants item entry to control demand scaling.Determines how sharply the price rises or falls from reputation and curing.
choiceArray of item objects used inside a wants or gives entry.Picks one item randomly from the array when generating the offer.

Random Choices and Item Functions

If you want a single trade slot to randomly pick between different items without duplicating the entire trade entry, you can replace a standard item definition in wants or gives with a choice array. The game selects one item entry from the choice list at the time the trade is generated.

Like loot tables, item entries inside a gives array support a functions array to modify the output item before handing it to the player. This is essential for selling enchanted gear, enchanted books, or named items. Note that not every loot table function works inside a trade table, and functions placed inside the wants array are generally ignored by the trade matching logic.

BP/trading/blacksmith_trades.json
{
  "tiers": [
    {
      "total_exp_required": 0,
      "trades": [
        {
          "wants": [
            {
              "item": "minecraft:emerald",
              "quantity": {
                "min": 7,
                "max": 12
              },
              "price_multiplier": 0.2
            }
          ],
          "gives": [
            {
              "choice": [
                {
                  "item": "minecraft:iron_sword",
                  "quantity": 1,
                  "functions": [
                    {
                      "function": "enchant_with_levels",
                      "treasure": false,
                      "levels": {
                        "min": 5,
                        "max": 19
                      }
                    }
                  ]
                },
                {
                  "item": "minecraft:iron_axe",
                  "quantity": 1,
                  "functions": [
                    {
                      "function": "enchant_with_levels",
                      "treasure": false,
                      "levels": {
                        "min": 5,
                        "max": 19
                      }
                    }
                  ]
                }
              ]
            }
          ],
          "trader_exp": 3,
          "max_uses": 3,
          "reward_exp": true
        }
      ]
    }
  ]
}

Trade Persistence and Restocking

Once a player opens the trading screen of an entity with persist_trades set to true, the generated trade list is saved directly into that specific entity's NBT data in the world. Editing your JSON file later will not update merchants that have already generated their trades; you must spawn a fresh entity to test changes to your trade table.

When a player exhausts a trade by hitting its max_uses limit, a red X appears over the arrow in the UI. For an economy trader to unlock locked trades, the entity needs AI goals and scheduling components that allow it to pathfind to and interact with a workstation block, just as vanilla villagers do. If you are making a stationary NPC shopkeeper that should never run out of stock, set max_uses to a very high integer such as 999999.

Which versions this applies to

Applies to Bedrock Edition 1.11.0 and newer (including 1.20.x and 1.21.x). No experimental toggles are required to use trade tables or trading components.

When it does not work

What you seeWhyThe fix
The trading UI opens with no trades listed, or right-clicking the entity does nothing at all.The path in the entity's table property does not match the actual file location, or the trade table has a JSON syntax error.Ensure the path in your entity file starts with "trading/" (never include "BP/") and check the Content Log for JSON parse errors in your trade table.
A trade shows an empty slot or an 'Unknown' dirt block icon in the merchant window.An item identifier inside wants or gives is misspelled, uses a Java Edition name, or refers to a custom item whose pack is missing.Verify every item string against valid Bedrock identifiers (for example, use flattened names like "minecraft:oak_planks" on modern versions) and confirm your custom item identifiers include their namespace.
Changes made to the trade table JSON do not show up in-game when testing.You are testing on an already-spawned entity that has cached its old trades via persist_trades.Summon a brand new instance of the entity after reloading the world, or set persist_trades to false temporarily while debugging.
Higher tiers never unlock even after trading with the entity dozens of times.The trades in the lower tiers are missing the trader_exp field, or the entity is using minecraft:trade_table instead of minecraft:economy_trade_table.Switch the entity component to minecraft:economy_trade_table, ensure every tier has total_exp_required defined in ascending order, and give each trade a positive trader_exp value.

Reference, straight from the game files

Read out of the game itself, so the ids match the version you are building for.