Chapter 9 — Building Your First Data Pack
What You’ll Build
Back in Chapter 6 you hit the wall: command blocks run your commands, but they’re buried in the world, can’t be shared as a download, and don’t scale. The answer is a function: the commands you’ve been typing since Chapter 1, saved in a file the game runs for you, no leading slash required. In Chapter 7 you learned that Minecraft is data-driven: the game reads files to decide what blocks, items, and recipes exist. In Chapter 8 you set up your editor and learned to read JSON and write identifiers like mypack:greeting. Now you put it all together in your Creative test world from Chapter 1.
By the end of this chapter you will have a real, working data pack. It will live inside your test world, it will announce itself in chat every time the world loads, and it will add a brand-new crafting recipe: a chainmail helmet you can craft from nine iron nuggets, which the game has never let you do before. You will turn the pack on, reload it, watch it greet you, and craft your helmet. And because things will break the first few times, you’ll also learn where Minecraft writes down what went wrong, so you can read the message and fix it yourself.
This is the pack you build the rest of the book on top of. Every later chapter adds files to this pack, the one you make right now. We’ll call it mypack from here on.
Concepts
A data pack is a folder (or a .zip file) full of data that configures features of Minecraft: things like advancements, recipes, loot tables, functions, and more. The vanilla game’s own features are defined by a built-in data pack, so when you make one, you’re doing exactly what Minecraft does to itself. (You learned this idea in Chapter 7; now you’ll build one.)
Three new things show up in this chapter:
pack.mcmeta: a small text file, written in JSON, whose presence is what tells Minecraft “this folder is a data pack.” Without it, the game ignores your folder entirely. It also holds the pack’s version info and a description.- A function: a plain-text file ending in
.mcfunctionthat holds a list of commands, one per line. Running the function runs all those commands in order. This is how you tell the game to do something. - A recipe: a JSON file that defines a new way to transform items, like a crafting recipe. This is how you tell the game what a new thing is.
You’ll also meet the minecraft:load function tag, a built-in list the game checks on startup. Any function whose name you add to that list runs automatically when the world loads or reloads. That’s how your greeting will fire on its own.
The Folder Hierarchy
A data pack has a strict shape. Get the folder names right and the game finds everything; get one wrong and the game silently skips it. Here’s the whole tree you’re about to build. Don’t type it yet, just look at the shape:
mypack/
├── pack.mcmeta
└── data/
├── mypack/
│ ├── function/
│ │ └── load.mcfunction
│ └── recipe/
│ └── chainmail_helmet.json
└── minecraft/
└── tags/
└── function/
└── load.json
Three rules explain that entire picture:
pack.mcmetasits at the very top, right next to (not inside) thedatafolder. It is the only mandatory file: it’s what makes the folder a data pack at all.- Everything else lives under
data/, sorted into namespace folders. A namespace (from Chapter 8, the part before the colon innamespace:path) keeps your files from colliding with anyone else’s. Your namespace ismypack, so most of your files go underdata/mypack/. The specialminecraftnamespace is for files that hook into or override vanilla, which is why the load tag lives underdata/minecraft/. - Inside a namespace, each kind of file gets its own folder named after the registry it belongs to. Functions go in
function/. Recipes go inrecipe/. The game loads the filedata/<namespace>/<registry name>/<path>.jsonas the thing named<namespace>:<path>. Sodata/mypack/recipe/chainmail_helmet.jsonbecomes the recipemypack:chainmail_helmet.
Modern Minecraft Some older tutorials show folder names with an s:
functions,recipes,advancements. Current Java Edition uses the singular form:function,recipe,advancement. If you copy an old tutorial and your files don’t load, a stray s on a folder name is a very common reason. The folder list in this book is the current one.
Writing pack.mcmeta
Create a folder named mypack somewhere easy to find, then make a file inside it called exactly pack.mcmeta. Type this into it:
mypack/pack.mcmeta
{
"pack": {
"description": "My first data pack",
"min_format": 107,
"max_format": 107
}
}
Here’s what each field means:
descriptionis a text component (you met those in Chapter 5). For now, a plain string in quotes is fine. This is the text that appears next to your pack’s name on the Data Packs screen and in the output of the/datapack listcommand.min_formatandmax_formatdescribe the range of pack versions your pack is built for. Each is a single number (or, if you ever need to be precise, a[major, minor]pair). The game compares these numbers against its own to decide whether your pack fits.min_formatis the lowest version you support, andmax_formatis the highest.
Why 107? The pack format is a number that changes when Minecraft changes how it reads data-pack files. For Minecraft 26.2, the recommended pack.mcmeta uses min_format: 107 and max_format: 107, so 107 is the known-good current value this book uses throughout.
Don’t memorize a number for any one version, though. The pack format changes over time, and the surest value is the one your copy of Minecraft expects. To read it, run the /version command in-game, or press F3 + V. If the number you get is different from 107, use that number for both min_format and max_format.
Modern Minecraft You will see a LOT of older tutorials use a single field called
pack_formatinstead, like"pack_format": 48. That field still works for backward compatibility, but since the snapshot 25w31a it was replaced by themin_format/max_formatpair. There’s also a related legacy field calledsupported_formats. You only needpack_formatorsupported_formatsif you’re trying to support game versions older than the new scheme, and they must be left out for a pack that only targets new versions. For everything in this book, usemin_format/max_formatand ignore the old field. (Chapter 46 covers the legacy fields in detail, for the day you need them.)
Under the Hood (skippable) The
pack.mcmetafile can hold more than this: sections for experimentalfeatures, filefilters, andoverlaysthat swap in different files for different game versions. None of that matters yet: adescriptionand a version range is a complete, valid data pack. We come back to the rest in Chapter 46.
Where the pack lives
A data pack belongs inside a world, in that world’s datapacks folder. The full path is your .minecraft/saves/<your world>/datapacks/ folder. Move your whole mypack folder into the datapacks folder of your test world (the Creative, cheats-on world you’ve used since Chapter 1).
To find that folder quickly: open Minecraft, go to Singleplayer, select your test world, click Edit, then Open World Folder. Inside is a folder called datapacks; drop mypack in there. When you’re done it should look like:
<your test world>/
└── datapacks/
└── mypack/
├── pack.mcmeta
└── data/
└── ...
Try It! You can also add a data pack while creating a new world: on the Create New World screen, open the More tab and click Data Packs, then drag your pack’s folder into the window. Either way works; the
datapacksfolder is just where the game keeps them.
At this point you have a valid (if empty) data pack. The game will recognize it. But it doesn’t do anything yet. Let’s fix that.
Your First Function
A function is a text file ending in .mcfunction that contains a list of commands (one command per line) which run top to bottom when the function is called. There are two rules about writing them that trip up everyone at first:
- No leading slash. When you type a command into the chat bar you start it with
/, like/say hi. Inside a.mcfunctionfile you write the command without the slash, justsay hi. The slash is only for the chat bar. - Lines starting with
#are comments. The game ignores them. Use comments to leave notes to yourself.
Functions live in the function/ folder inside your namespace. Create the file:
mypack/data/mypack/function/load.mcfunction
# This function runs when the pack loads or reloads.
# It announces that mypack is active.
say mypack is loaded! Welcome back.
That’s a complete function. Its name, its identifier, is built from where it sits: namespace mypack, registry folder function, file load → the function mypack:load.
But right now nothing calls it. You could run it by hand by typing /function mypack:load, and it would print your message. Try that if you like. What we actually want, though, is for it to fire automatically every time the world loads.
Wiring it to minecraft:load
Minecraft keeps a built-in list called the minecraft:load function tag. Every function named in that list runs once when the world loads, when the server starts, and every time the data packs are reloaded. (There’s a sibling list, minecraft:tick, that runs functions every single tick; we’ll use that later.)
A tag is itself a small JSON file. Function tags go in the tags/function/ folder, and because we’re adding to Minecraft’s load tag, the file goes under the minecraft namespace, at data/minecraft/tags/function/load.json. Create it:
mypack/data/minecraft/tags/function/load.json
{
"values": [
"mypack:load"
]
}
The values array is just a list of function names to add to the tag. We’re adding one: mypack:load. (You’ll learn the full tag format, including the replace field and how tags from different packs merge, in Chapter 14. For now, this one-line list is all you need.)
Under the Hood (skippable) Why does adding your function name to the
minecraft:loadtag run it, instead of overwriting Minecraft’s own load functions? Because tag files merge by default: when several packs each add to#minecraft:load, the game combines all their lists rather than letting the last one win. That’s special to tags; most other files override each other. So yourload.jsonquietly joins the party instead of kicking everyone else out.
What Went Wrong? One important catch: functions in
minecraft:loadrun before any player has joined the world. That’s fine forsay, which broadcasts to chat. But it means commands that need to target a player won’t find one at load time. Keep that in mind much later when you write fancier load functions. For now,sayworks perfectly.
Save both files. We’ll turn the pack on shortly, but first let’s add the recipe so we have something to craft.
Your First Recipe
A recipe is a JSON file that tells the game about a new item transformation. Crafting, smelting, stonecutting, and smithing are all recipes. We’re making the simplest interesting kind: a shaped crafting recipe, where the ingredients have to be placed in a specific pattern on the crafting grid.
Recipe files go in the recipe/ folder of your namespace. Create:
mypack/data/mypack/recipe/chainmail_helmet.json
{
"type": "minecraft:crafting_shaped",
"category": "equipment",
"pattern": [
"NNN",
"N N"
],
"key": {
"N": "minecraft:iron_nugget"
},
"result": {
"id": "minecraft:chainmail_helmet",
"count": 1
}
}
Let’s read it field by field. Every one of these is a real recipe field, copied from the recipe format:
typesays which kind of recipe this is.minecraft:crafting_shapedmeans “a shaped crafting-table recipe.”categorycontrols which group it appears under in the recipe book. The allowed values areequipment,building,misc, andredstone; a helmet isequipment. (This field is optional: leave it out and it defaults tomisc.)patternis the shape, drawn as rows of text. Each string is one row of the crafting grid. Our pattern has a full top row ("NNN") and a middle row with a gap ("N N"); a space means “leave this slot empty.” That’s the classic helmet shape: across the top and down the sides. Every row string must be the same length, and a recipe can be up to 3×3.keyexplains what each letter in the pattern means. We used the letterN, and here we sayNisminecraft:iron_nugget. You can pick any single character except a space for a key.resultis what you get.idis the item it produces (minecraft:chainmail_helmet) andcountis how many (one helmet).countis optional and defaults to1, but writing it is clearer.
The file is named chainmail_helmet.json, so the recipe’s identifier is mypack:chainmail_helmet.
Modern Minecraft Older recipe tutorials often write the result as
"result": {"item": "minecraft:chainmail_helmet"}. Current Java Edition usesid, notitem, insideresult. If your recipe loads but produces nothing, an old-styleitemkey is a likely culprit.
Try It! The
keycan point at a tag instead of a single item (for example"#minecraft:planks"to accept any kind of wooden plank) or at a list of allowed items. That, plus shapeless, smelting, stonecutting, and smithing recipes, is all coming in Chapter 15. For now, one item per key is plenty.
Loading the Pack
Your folder is complete. Time to turn it on. Open your test world and press T (or /) to open the chat bar. You’ll type these commands into chat, with the leading slash:
First, check that the game can see your pack:
/datapack list
This lists every data pack the game found, split into available and enabled. You should see mypack in the list. (Hover over it in the chat output to see the description you wrote in pack.mcmeta.) If mypack isn’t there at all, the game didn’t recognize your folder; jump to “What Can Go Wrong” below.
Now enable it:
/datapack enable "file/mypack"
The name to enable is the one shown by /datapack list: packs in your datapacks folder show up as file/mypack. As soon as you enable a pack, the game loads it, and your minecraft:load function fires. You should immediately see your greeting in chat: mypack is loaded! Welcome back.
From now on, whenever you change a file in the pack, you don’t need to disable and re-enable it. Just run:
/reload
/reload re-reads the current data packs so your latest edits take effect without leaving the world, and it re-runs every minecraft:load function, so you’ll see your greeting again each time. This is the command you’ll run hundreds of times while building. (One thing to know: /reload re-reads recipes, functions, tags, loot tables, advancements, and predicates live. A few feature types (the kind marked experimental) need you to fully leave and rejoin the world instead. Recipes and functions, happily, reload live.)
Seeing your recipe
Open a crafting table. Click the recipe book (the little book icon to the left of the grid). Your chainmail helmet recipe is now discoverable there. The quickest way to test it: put nine iron nuggets in your inventory, open a crafting table, and lay them out in the helmet shape: top row full, two on the corners of the middle row, middle slot empty. A chainmail helmet appears in the output. You just crafted something vanilla Minecraft never allowed.
Figure (to be captured). crafting table with iron nuggets arranged in the helmet pattern and a chainmail helmet in the result slot; recipe book open showing the new recipe
Under the Hood (skippable) A recipe normally has to be “discovered” before it shows in your book, usually by picking up one of its ingredients. You can ignore discovery while testing: unless the
doLimitedCraftinggame rule is turned on, you can craft any recipe whether or not you’ve discovered it. So even before the book shows it, laying out the pattern works.
Practice
These extend the exact pack you just built, so keep working in mypack.
-
Make the greeting your own. Open
load.mcfunctionand change thesayline to a message you like. Add a secondsayline below it with another message (remember, one command per line, no slash). Run/reloadand watch both lines print. -
Add a second recipe. Copy
chainmail_helmet.jsonto a new file,chainmail_chestplate.json, in the samerecipe/folder. Change theresultidtominecraft:chainmail_chestplateand change thepatternto a chestplate shape (sides down both edges, full bottom rows):["N N", "NNN", "NNN"]. Run/reloadand craft it. (Don’t forget: the new recipe’s identifier comes from its file name, so the file must be named differently from the first.) -
Break it on purpose, then read the error. This is the most useful exercise in the chapter, and it builds the habit you’ll lean on for the rest of the book. Delete the comma after the
patternarray’s closing]so the JSON is invalid, run/reload, and watch the game complain. Then put the comma back and reload to confirm it’s fixed. The next section explains exactly what the complaint is telling you.
What Can Go Wrong
When a data pack misbehaves, Minecraft almost always tells you why; you just have to know where it writes it down. The game keeps a running log of what it’s doing, errors included, and that log is the first place to look when something doesn’t work. Exactly where that log lives on your computer, and how to read it, is the very first thing we cover in Chapter 10 (Debugging), so for now just hold on to the idea that the answer is written down somewhere; you’re never only guessing.
Here are the three failures you’ll hit most, and what each one means. (The exact wording of these messages can shift between Minecraft versions, so learn to recognize the kind of problem rather than memorizing the precise text.)
What Went Wrong? — “Expected value” / JSON syntax errors A message about an unexpected character or expected value, usually with a position number, means your JSON is malformed: a missing comma, an extra comma after the last item in a list, a missing quote, or a mismatched bracket. The position points roughly at where the parser got confused (often just after the real mistake). Open the file, find that spot, and check the punctuation. This is the error you triggered in Practice 3. (If your editor highlights JSON, set up in Chapter 8, it usually flags these before you even reload.)
What Went Wrong? — “Unknown resource location” / unknown item This means you named something the game can’t find, most often a typo in an item ID, like
minecraft:iron_nuget(missing a g) orminecraft:chainmail_helemt. The game looks upminecraft:iron_nuggetin its registry, doesn’t find your misspelling, and reports it. Fix the spelling of the identifier. The same error appears if you reference a tag or other resource that doesn’t exist.
What Went Wrong? — “Could not find function” / wrong folder structure If a function won’t run, or the game says it can’t find
mypack:load, the file is almost certainly in the wrong place or has the wrong name. Re-check the path letter by letter: it must bedata/mypack/function/load.mcfunction: singularfunction, the.mcfunctionextension spelled exactly, and the namespace folder namedmypack. The same applies if your greeting never appears on load: make suredata/minecraft/tags/function/load.jsonexists, is spelled correctly, and lists"mypack:load"in itsvalues.
A fourth, sneakier failure: the pack doesn’t appear in /datapack list at all. That means the game didn’t accept the folder as a data pack. The usual cause is a missing, misnamed, or invalid pack.mcmeta. Check it’s named exactly pack.mcmeta (no .txt on the end, which some editors add silently), sits at the top of mypack next to data, and contains valid JSON.
What You Know Now
You built a complete, working data pack from nothing. You know that pack.mcmeta is the file that makes a folder a data pack, and that it carries a description plus a min_format/max_format version range (the modern replacement for the old single pack_format). You know the folder shape (pack.mcmeta at the top, everything else under data/<namespace>/<registry>/) and where packs live inside a world’s datapacks folder. You wrote a .mcfunction file (commands, one per line, no slash, # for comments) and wired it into the minecraft:load tag so it announces your pack automatically. You added a shaped crafting recipe with type, pattern, key, and result, and crafted a chainmail helmet from iron nuggets. And you can turn it all on with /datapack enable, refresh it with /reload, and read latest.log to fix the errors that come up.
You can now build a data pack that runs your own commands on load and adds your own recipes to the game. Everything in the rest of this book extends this same mypack. Next, in Chapter 10, you’ll sharpen the debugging skills you just started using so the inevitable mistakes cost you seconds instead of hours.