Chapter 38 — Villager Trades and Other Data-Driven Registries
What You’ll Build
Way back in Chapter 7 you learned that a data pack works by adding files to registries (the game’s master lists of one kind of thing each) and that some registries are dynamic, meaning data packs are allowed to add to them. Since then you’ve filled a lot of those lists: the recipe registry, the loot table registry, the advancement registry, the tag registries. This chapter pulls back and shows you the whole map, the full folder list of every registry a data pack can write to, and then teaches the most interesting new one in modern Minecraft from top to bottom.
By the end you’ll have read the complete registry map, and you’ll have built
a working sulfur_cube_archetype: a JSON file that defines how a sulfur cube behaves, whether
it floats, what it eats, how hard it hits, and whether it explodes. You’ll attach that behavior to an
item, add a custom banner pattern definition, and take a guided tour of how villager trades
became data-driven (the villager_trade and trade_set folders, grouped by trade tags). You’ll
also learn something just as important: which registries the book can teach you to fill in today,
and which ones the game only names, so you know exactly where to look when you need them.
Figure (to be captured). a custom sulfur cube bouncing in water next to a banner showing a custom forge-mark pattern
The Registry Map
Open your data pack’s data/mypack/ folder in your mind. Every folder you’ve made so far (function,
recipe, loot_table, advancement, tags/) sits at the same level. Each one is a registry
folder: a folder named after a registry, whose .json files become entries in that registry.
Registry folder. A folder under
data/<namespace>/<registry name>/. The rule is exact: the filedata/<namespace>/<registry name>/<path>.jsonis loaded into the registry name registry with ID<namespace>:<path>. So a file atdata/mypack/recipe/forge_blade.jsonbecomes the recipemypack:forge_blade. The folder name is the registry name. (Both the registry name and the path can contain slashes, which just makes extra sub-folders.)
That one rule is the whole secret of data packs. You already know it in your hands; now you’ll see the full list of folder names you’re allowed to use. Here is the registry folder list, straight from the Data pack page (worldgen folders are grouped at the bottom and belong to Part XI):
data/<namespace>/
function .mcfunction files with lists of commands
structure .nbt files defining a saved structure of blocks
tags/ collections of things (one sub-folder per registry)
advancement definitions of advancements
banner_pattern * textures and names to use for banner patterns
cat_variant * textures and spawn conditions of cat variants
chat_type * formatting of chat messages
chicken_variant * textures and spawn conditions of chicken variants
cow_variant * textures and spawn conditions of cow variants
damage_type * attributes of damage and death messages
dialog * definitions of dialogs (Chapter 39)
dimension * biome layout and terrain of dimensions
dimension_type * properties of dimensions
enchantment * enchantment effects, supported items, level cost, etc.
enchantment_provider * selection of enchantments for specific uses
frog_variant * textures and spawn conditions of frog variants
instrument * instruments for goat horns
item_modifier loot functions used to modify items
jukebox_song * jukebox song definitions
loot_table loot from mobs, blocks, chests, etc.
painting_variant * size and texture of paintings
pig_variant * textures and spawn conditions of pig variants
predicate tests for specific conditions
recipe recipes for crafting, smelting, etc.
sulfur_cube_archetype * defines Sulfur Cube archetypes
test_environment * groups GameTests with their preconditions
test_instance * a test the GameTest framework can run
timeline * events/attributes according to the time of day
trade_set * a set of trades selected by villagers / wandering traders
trial_spawner * configuration of trial spawners
trim_material * colors, ingredients, name of trim materials
trim_pattern * textures and name of trim patterns
villager_trade * trades of villagers and wandering traders
wolf_sound_variant * sound variants of wolves
wolf_variant * textures and spawn conditions of wolf variants
world_clock * clocks used to keep track of internal time
worldgen/ * the world-generation registries (Part XI)
That little red * is doing real work. Let’s talk about it.
Experimental-settings folder (the
*). Some folders are marked with an asterisk because having a valid file inside any of them will mark the data pack as using experimental settings. A pack that uses experimental settings shows a warning screen when you open the world in singleplayer, and it cannot be uploaded to Realms. For example: defining a custom instrument inside theinstrument/folder counts as experimental, but doing the same thing through item components does not.
So most of the shiny new registry folders in that list (including sulfur_cube_archetype) are
experimental folders. That’s not a reason to avoid them. It just means: expect the warning screen, and
remember the rule below in What Can Go Wrong about reloading them.
Modern Minecraft. Older tutorials talk about “experimental features” as if they’re half-broken betas you toggle on. In modern Minecraft, an experimental setting is simpler than that: it’s just a flag the game raises because your pack put a file in one of these folders. The reason is precise: internally, most experimental settings use dynamic registries, and dynamic registries can’t be hot-reloaded (more on that at the end of the chapter). The feature itself is shipped and real; the label is about how the game loads it, not about whether it works.
Trades Are Data-Driven Now
Here’s a change worth pausing on. For most of Minecraft’s life, what a villager would sell you was
baked into the program. Look at the registry map again: there are now three trade-related entries,
villager_trade, trade_set, and (under tags/) villager trade tags.
Modern Minecraft. If you followed an old guide that summoned villagers with giant
OffersNBT blobs to fake custom trades, that still describes the runtime shape: when the trade menu is first opened, the game generates anOfferscompound holding aRecipeslist, where each recipe has abuycost item, an optionalbuyBsecond cost, asellitem, amaxUses, and so on. But you no longer have to hand-build that. The trades themselves are now data pack files.
The three pieces fit together like this, and the Data pack folder list tells us what each one is for:
villager_trade(thevillager_trade/folder) — “Trades of villagers and wandering traders.” One file describes one trade offer.trade_set(thetrade_set/folder) — “A set of trades selected by villagers and wandering traders.” A group of trades chosen together.- villager trade tag (under
tags/) — the grouping and selection layer. In one line: a villager trade tag is a group of villager trades.
Villager trade tag. A tag, exactly like the block and function tags you built in Chapter 14 (a
.jsonfile with avalueslist), that groups villager trades together. The vanilla trade tags follow a clear pattern: one tag per profession and level, likearmorer/level_1,cleric/level_3,farmer/level_5, plus special ones such ascommon_smith/level_1(shared smith trades) andwandering_trader/common. A villager who is a level-3 cleric draws its offers from thecleric/level_3trade tag.
So the modern pipeline is: you write trade offers as villager_trade (and group them with trade_set),
and a trade tag like #minecraft:villager_trade/cleric/level_3 decides which villager gets them.
To add a cleric trade, you’d add your trade to that tag: the same “extend a vanilla tag without
replacing it” move you learned in Chapter 14.
One thing this chapter won’t do is make you memorize the exact JSON field names inside a villager_trade
or trade_set file. They’re new 26.x registries, and a file format like that is the kind of detail you
should read off a reference each time, not carry in your head. So when you build custom trades for real,
open the villager_trade / trade_set page on the live wiki (or copy a vanilla example file) and write
the field names you find there.
What you can carry in from here is the shape of the idea. The Villager page’s runtime Offers/Recipes
data (buy, buyB, sell, maxUses, priceMultiplier, demand, rewardExp, xp) tells you what
a trade contains conceptually: a cost (sometimes two), a result, and limits on how often it can be
used. That’s the entity’s saved NBT rather than the pack file, so don’t copy it field-for-field, but it’s
a faithful mental model of what your trade file will need to express.
That’s the working rule for this whole chapter, and it’s the one that keeps your packs correct: when a registry is brand-new and its file format isn’t settled documentation yet, this book teaches you what the folder is for and points you at the reference for the exact fields, rather than guessing them. Now let’s build the one new registry we can walk all the way through.
Walkthrough: A Sulfur Cube Archetype
The sulfur cube is a 26.x entity, and it’s the perfect teaching example because its whole behavior
lives in a data pack file. Sulfur cubes use “archetypes” to define their
behavior, and those archetypes are stored as JSON files within a data pack in the path
data/<namespace>/sulfur_cube_archetype.
sulfur_cube_archetype. A registry file defining how a sulfur cube of that archetype behaves: what attributes it has, whether it floats, what it eats, how it damages things it touches, whether it explodes, how knockback affects it, and what sounds it makes. The file’s ID is<namespace>:<path>, just like every other registry entry.
Let’s build one called mypack:bouncing_bomb: a cube that floats in water, eats gunpowder, lightly
shoves anything it touches, and explodes when ignited. Here is the complete file. Every field in it
comes straight from the JSON format for this registry, and after the listing we’ll walk
through each one.
mypack/data/mypack/sulfur_cube_archetype/bouncing_bomb.json
{
"attribute_modifiers": [
{
"attribute": "minecraft:max_health",
"id": "mypack:bouncing_bomb_health",
"amount": 4.0,
"operation": "add_value"
}
],
"buoyant": true,
"contact_damage": {
"amount": 2.0,
"attribute_to_source": true,
"damage_type": "minecraft:mob_attack"
},
"explosion": {
"causes_fire": false,
"fuse": 30,
"power": 3
},
"items": "minecraft:gunpowder",
"knockback_modifiers": {
"horizontal_power": 1.5,
"vertical_power": 1.0
},
"sound_settings": {
"hit_sound": "minecraft:entity.tnt.primed",
"push_sound": "minecraft:block.sand.step",
"push_sound_cooldown": 0.5,
"push_sound_impulse_threshold": 0.1
}
}
Now the field-by-field tour. The root object has these seven keys:
-
attribute_modifiers— “A list of attribute modifiers to apply to sulfur cubes of this archetype.” You met attribute modifiers on items back in Chapter 23, and the shape here is the same family: each modifier is an object with anattribute(the id of the attribute to modify, hereminecraft:max_health), a uniqueidfor the modifier, anamount, and anoperation. There are three operations:add_value,add_multiplied_base, andadd_multiplied_total. We usedadd_valueto give the cube +4 health. -
buoyant— a true/false value: “Whether or not a sulfur cube of this archetype floats in liquids.” We set ittrue, so our bomb bobs on top of water instead of sinking. -
contact_damage— this one is optional: if present, sulfur cubes of this archetype will damage entities on contact. Inside it:amount(the damage caused, here2.0, one heart),attribute_to_source(whether the damage is attributed to the sulfur cube, which affects who “killed” the victim), anddamage_type(which damage type to use; we pickedminecraft:mob_attack). -
explosion— also optional: “if present, sulfur cubes of this archetype can explode when ignited.” Three fields:causes_fire(true/false: does the blast light fires; we said no),fuse(the fuse time in game ticks;30ticks is 1.5 seconds), andpower(the power of the explosion;3is roughly creeper-sized). -
items— “An item or an item tag containing all items that can be fed to sulfur cubes of this archetype.” We gave a single item,minecraft:gunpowder. Because it accepts an item tag too, you could instead write"#minecraft:coals"(a tag, with the#you learned in Chapter 14) to let the cube eat any coal-like item. -
knockback_modifiers— “Modifiers to the knockback received by sulfur cubes of this archetype,” withhorizontal_powerandvertical_power. These scale how far the cube gets shoved when it’s hit;1.5horizontal makes it skittish and easy to push around. -
sound_settings— the sounds the cube makes, with four fields:hit_sound(a sound event played when the cube is hit),push_sound(played when it’s pushed),push_sound_cooldown(the cooldown for the push sound, in seconds), andpush_sound_impulse_threshold(the smallest impulse needed to trigger the push sound). The two sound fields take sound-event ids of the kind you worked with in Chapter 30.
Save the file and /reload. Because sulfur_cube_archetype/ is an experimental folder, you may see
the experimental-settings warning when you open the world. That’s expected (and there’s a reloading
nuance in What Can Go Wrong). Your archetype now exists in the registry as
mypack:bouncing_bomb, ready for any sulfur cube assigned to it.
Under the Hood (skippable). The wiki itself is still pinning down the precise in-game effect of some of these settings: exactly which behavior each archetype setting controls is not fully nailed down yet. The fields are documented and correct (that’s what we built); the exact gameplay feel of, say, a particular
knockback_modifiersvalue is the kind of thing you confirm by testing in-game. That’s normal for a brand-new feature.
Putting the Cube Inside an Item
A sulfur cube can hold an item, and there’s an item component for that: sulfur_cube_content.
sulfur_cube_content. An item component storing “the item stored inside the sulfur cube.” The game adds gray italic tooltip text reading “Contains: <item>” on an item, and on a sulfur cube entity it doubles as the body armor slot. It’s the bridge between an ordinary item and the sulfur cube’s contents.
This is an item component, so you set it with the bracket syntax from Chapter 21. Here’s a /give that
hands you a sulfur cube item carrying a diamond inside it (typed in chat, so it keeps its leading /):
/give @s minecraft:sulfur_cube[minecraft:sulfur_cube_content={id:"minecraft:diamond",count:1}]
Heads-up on the item id. The component name
sulfur_cube_contentis exact, but a carrier item’s resource location is the kind of thing to confirm in-game rather than take on faith from a book. The line above uses the naturalminecraft:sulfur_cube; if your game rejects it, turn on advanced tooltips (F3+H) and read the real id straight off a sulfur cube in your inventory.
A Real Banner Pattern Definition
A few of these registries (besides the sulfur cube) have fully documented fields, and
banner_pattern is the simplest, so let’s build one to prove the pattern.
Banner pattern definition (
banner_pattern). A banner pattern is a shape that can be added to a banner, defined by files in thebanner_patternfolder. The format has just two fields:asset_id(the resource location for the texture asset) andtranslation_key(the translation key used to display the banner’s tooltip).
mypack/data/mypack/banner_pattern/forge_mark.json
{
"asset_id": "mypack:forge_mark",
"translation_key": "block.minecraft.banner.forge_mark.mypack"
}
The asset_id points at a texture you’d supply on the resource-pack side (the kind of art file you
learned to place in Chapter 29); the translation_key is the name that shows in the banner’s tooltip.
That’s the entire file, and it’s a clean example of the rhythm you’ll use for any documented
registry: read the field list off its page, write exactly those fields, nothing invented.
The Rest of the Map: What Each Folder Is For
The registry map listed more folders than any one project will use. You don’t need the full field list for every one to be productive. You need to know what each folder is for and how to recognize when a build calls for it. Here’s that tour. When you’re ready to author one of these files, open the matching page on the live wiki, or crack open a vanilla data pack and read a real example, and write exactly the fields you find there: the same read-the-fields-then-write-them move you used above.
enchantment_provider— a “selection of enchantments for specific uses” (for example, choosing which enchantment a particular tool or loot source applies).jukebox_song— “jukebox song definitions.” Its partner is the item componentjukebox_playable, which is fully documented: it points an item at a jukebox song definition to play when inserted into a jukebox, and adds the song’s artist and title to the tooltip. So you already know exactly how an item uses a song.instrument— “instruments for goat horns.” Its partner componentinstrumentis documented (it shows the instrument description in an item’s tooltip), and defining an instrument in this folder counts as experimental while doing it through the component does not.painting_variant— “size and texture of paintings.” Its partner componentpainting/variantsets which painting an item shows, displaying the name, artist, and size in the tooltip.trim_material/trim_pattern— “colors, ingredients, and name of materials for trimming” and “textures and name of patterns for trimming.” You already met armor trims from the item side: thetrimcomponent back in Chapter 24, and thesmithing_trimrecipe type in Chapter 15; these two folders are where the materials and patterns themselves are defined.trial_spawner— “configuration of trial spawners” (the wave and reward setup behind trial chambers).timeline— “a timeline which specifies events and attributes according to the time of day.”world_clock— “clocks used to keep track of internal time.”
Notice the pattern: several registries come in pairs, a definition folder (the registry) plus an
item component that points at it. jukebox_song ↔ jukebox_playable, painting_variant ↔
painting/variant, instrument ↔ instrument, banner_pattern ↔ the banner’s pattern data,
sulfur_cube_archetype ↔ sulfur_cube_content. When you meet a new registry, ask “what component points
at it?” The component side is usually the better-documented half, and it tells you half the story for
free before you ever open the definition file.
Practice
-
A gentle floating cube. Make a second archetype,
mypack/data/mypack/sulfur_cube_archetype/water_buddy.json, that floats (buoyant: true) and eats bread ("items": "minecraft:bread") but has nocontact_damageand noexplosion(just leave those two optional fields out entirely, since both are optional). Give it a gentlesound_settingsusing soft sound events. Reload and confirm it loads with no errors. This proves you understand which fields are required and which you can omit. -
Your own banner pattern. Write
mypack/data/mypack/banner_pattern/your_mark.jsonwith anasset_idofmypack:your_markand atranslation_keyyou choose. You don’t need the texture to exist yet for the file to load. You’re practicing the definition file, the same two-field shape every banner pattern uses. -
Read the map. Without looking back, list three registry folders that are marked experimental (
*) and one that is not. Then, for one registry the chapter only points you toward (saytrial_spawner), write one sentence saying what its folder is for (straight from the map) and one sentence saying where you’d go to find its actual fields. This is the skill the chapter is really teaching: knowing the difference between “I can build this now” and “I know what this is and where to learn it.”
What Can Go Wrong
The experimental-settings warning screen appears. As soon as you put a valid file in an
experimental folder (like sulfur_cube_archetype/), the game flags your whole pack as using
experimental settings and warns you when you open the world in singleplayer. This is expected, not an
error, so click through it. Just remember the two consequences: the warning will keep
appearing, and you won’t be able to upload that world to Realms.
/reload doesn’t pick up your archetype change. This is the big one. Experimental settings
use dynamic registries, and any changes regarding these features cannot be
loaded using the reload command: the world must be exited and reopened (singleplayer), or the server
rebooted (multiplayer) for the changes to take effect. So if you edit bouncing_bomb.json and
/reload seems to do nothing, that’s not a bug: fully exit the world and re-enter (or reboot the
server). Compare that to recipes, loot tables, and tags from earlier chapters, which /reload
can refresh live. Dynamic-registry folders are the exception.
A path typo silently makes the wrong ID. Remember the registry rule: the folder name is the
registry name and the file path is the ID. If you save your archetype to
data/mypack/sulfur_cube_archetypes/ (plural) or misspell the folder, the game won’t find a registry
by that name and your file just won’t load as an archetype, often with no obvious complaint. Double-
check the folder is spelled exactly as it appears in the map: sulfur_cube_archetype, singular. The
same goes for banner_pattern, villager_trade, and the rest: copy the names from the map, don’t
trust your memory.