Minecraft data packs are the vanilla way to add or change gameplay on a Java server without installing a single plugin. They let you define custom recipes, rewrite loot tables, ship advancements, run scheduled functions, and even shape world generation, all through plain JSON and text files that the game reads straight from the world folder. This guide exists to help server owners, admins, and plugin coders understand how data packs actually work, so you can customize a server safely while keeping it close to vanilla.
We wrote this after building and breaking data packs across several Paper and vanilla server download Java servers, moving them between game versions and watching exactly which folder names, tag names, and format numbers the game accepts. Everything below comes from that hands-on testing: the metadata that decides whether your pack loads at all, the folder layout that decides whether your functions ever run, and the small mistakes that make a pack load silently and then do nothing.
By the end you will be able to build, install, debug, and package a data pack on your own, and you will know when a data pack is the right tool and when a plugin is. If you are brand new to running a Java server, start with our [A Beginner’s Guide to Minecraft Server JARs: Paper, Purpur…] first, then come back here.
What Are Minecraft Data Packs?
A data pack is a folder, or a .zip archive, that lives inside a world and feeds the game structured data. It can add or override functions, tags, recipes, loot tables, advancements, predicates, item modifiers, dimensions, world generation features, and structures. The engine treats the pack exactly like its own built-in data, which is why a well-made pack feels native rather than bolted on.
The key idea to internalize is that data packs change data, not code. They are interpreted by the existing game engine. You are not adding a new Java class or registering a listener; you are describing recipes, rules, and command sequences the engine already knows how to run. That is what makes packs portable and safe, and also what limits them compared to a plugin.
Because data packs are part of the world save, they travel with the world. Copy the world to another machine, run a different server JAR, or open it in singleplayer, and the pack comes along and keeps working as long as the game version matches.
How Data Packs Differ from Plugins and Resource Packs
Plugins are Java code loaded through a server API such as Bukkit, Spigot, Paper, or Purpur. They can react to events, add new commands from scratch, talk to databases, and invent entirely new mechanics. Data packs run inside the vanilla game itself, so they work on any Java server, including vanilla and Realms, with no plugin platform or modloader required. Resource packs are a third thing entirely: they change what players see and hear, meaning textures, sounds, models, and language, and have nothing to do with gameplay logic or rules.
| Aspect | Data Packs | Plugins | Resource Packs |
|---|---|---|---|
| Installed in | world/datapacks | plugins/ folder | resourcepacks/ or a server URL |
| Written in | JSON and .mcfunction | Java or Kotlin | JSON plus images and audio |
| Works on vanilla servers | Yes | No | Yes |
| Adds new Java logic or events | No | Yes | No |
| Changes recipes, loot, advancements | Yes | Yes, through code | No |
| Reloads live | Yes, with /reload | Usually needs a restart | Client reload with F3+T |
| Best used for | Lightweight, vanilla-friendly features | Deep mechanics, APIs, databases | Interface, textures, sounds |
A quick way to remember the difference: data packs change the rules, plugins change the behavior, and resource packs change the appearance. Most healthy servers use a mix of all three, each for the job it does best.
Pack Metadata, pack_format, and Version Compatibility
Every data pack needs a pack.mcmeta file at its root. This small JSON file declares what the pack is and which game versions it supports. If it is missing or malformed, the pack is ignored.
{
"pack": {
"pack_format": 48,
"description": "Example survival data pack"
}
}The pack_format number is the game’s data version gate. If that number falls outside the range your Minecraft version accepts, the game marks the pack as incompatible and will not load its data. Since the 1.20.2 update, packs can also declare a range so a single pack works across several versions:
{
"pack": {
"pack_format": 41,
"supported_formats": [41, 48],
"description": "Example survival data pack"
}
}The table below shows a sample of pack_format values for recent Java versions. Treat it as a starting point, not gospel, because Mojang bumps the number whenever the data format changes. Pack format on the Minecraft Wiki keeps the authoritative, always-current list, and the official Data pack page covers every field.
| Minecraft Java Edition | pack_format (data) |
|---|---|
| 1.13 to 1.14.4 | 4 |
| 1.15 to 1.16.1 | 5 |
| 1.16.2 to 1.16.5 | 6 |
| 1.17 to 1.17.1 | 7 |
| 1.18 to 1.18.2 | 8 |
| 1.19 to 1.19.3 | 10 |
| 1.19.4 | 12 |
| 1.20 to 1.20.1 | 15 |
| 1.20.2 | 18 |
| 1.20.3 to 1.20.4 | 26 |
| 1.20.5 to 1.20.6 | 41 |
| 1.21 to 1.21.1 | 48 |
Checking Loaded Packs with /datapack list
Inside the game or server console, the /datapack command is your fastest diagnostic tool. Use /datapack list to see every enabled pack. The output looks roughly like a list containing vanilla and file/mypack, where vanilla is the built-in data and file/mypack is your pack loaded from the world folder. If your pack does not appear at all, it is either in the wrong folder or its pack.mcmeta is broken. You can also toggle packs at runtime with /datapack enable and /datapack disable followed by the pack name.
One important nuance: because packs are world-scoped, a pack loaded for one world is not active for another. New worlds start with only vanilla data unless you copy the pack into each world’s datapacks folder.
The Folder Structure of a Data Pack
Everything meaningful lives under a data folder, organized by namespace. A namespace is a name you choose, using lowercase letters, digits, and underscores. Vanilla data uses the minecraft namespace, so your pack should always use its own unique namespace to avoid overwriting built-in data by accident. A single pack can contain several namespaces if you need to organize large projects.
my_datapack/
pack.mcmeta
pack.png
data/
mypack/
functions/
tick.json
on_load.mcfunction
tags/
function/
tick.json
load.json
item/
block/
entity_type/
recipes/
loot_tables/
advancements/
predicates/
worldgen/
dimension/
structures/Here is what each folder under your namespace is for:
- functions: the .mcfunction text files that hold batched commands. A .mcfunction runs one command per line with no leading slash.
- tags: JSON files that group other data by type. Function tags drive scheduling, and item, block, and entity_type tags let you target whole families of things at once.
- recipes: crafting, smelting, blasting, smoking, campfire, smithing, and stonecutting recipes that add or replace how items are made.
- loot_tables: drop rules for blocks, entities, chests, fishing, and more. These decide what players actually get.
- advancements: the goals, triggers, and rewards shown in the advancement screen, including custom tabs if you build a root.
- predicates: reusable conditions that reference entity state, location, weather, and more, used inside loot tables and advancements.
- worldgen: biome, feature, configured feature, and placement data for custom terrain decoration.
- dimension and dimension_type: the definitions that create custom dimensions.
- structures: structure definitions that tell the game how to place jigsaw-built structures.
Folder names must match exactly. A folder called functions that you spell funtions, or a file that ends in .json where the engine expects .mcfunction, will be ignored without an error message. If a feature is missing, check spelling before you check logic.
Installing, Loading, and Reloading a Data Pack
Installing a pack is deliberately simple because it is just file placement. Follow these steps on a running Java server:
- Stop the server, or at least be ready to reload, and locate your world folder. On a default server the world is named world, but Paper and Purpur may use a custom level-name in server.properties.
- Create a datapacks folder inside that world folder if it does not already exist.
- Drop your pack in as either an unzipped folder or a .zip file. Both work. A folder is easier to edit on the fly.
- Start the server, or type /reload, so the game reads the new pack.
- Run /datapack list to confirm the pack shows up, then test one recipe or function to verify the data loaded.
Troubleshooting a Pack That Will Not Load
- Pack missing from /datapack list: wrong folder, wrong world, or invalid JSON in pack.mcmeta. Validate your JSON before blaming the server.
- Pack listed but marked incompatible: pack_format is out of range for your game version. Update the number and reload.
- Functions do nothing: wrong namespace inside a tag file. Tags reference functions as namespace:path, and an empty or wrong namespace matches nothing.
- Changes not visible: /reload refreshes data packs, but some changes need a full restart, and world generation changes only apply to newly generated chunks.
- Recipes fail to craft: ingredient IDs or the result format changed between versions. In 1.20.5 and later the result uses id instead of item.
Remember that /reload reloads data packs and the function stack, not plugins. On a mixed server, keep that boundary in mind so you debug the right layer.
Functions, Tags, and Scheduling
Functions are the workhorse of data packs. A Function is a text file with the .mcfunction extension that contains one command per line, no leading slash. You can reference another function from inside a function, and the engine runs them in order. This turns a pile of commands into a reusable script you can call from anywhere, including other functions, advancements, and tags.
Functions run in the order they appear, and each line is treated as a console command. That means you can build small systems: give players effects, teleport them, reward them with items, or run conditional logic using execute commands.
The tick.json and load.json Tag Functions
Two special tag files give functions a sense of time. Both live under data/<namespace>/tags/function/.
- load.json runs its listed functions once when the pack loads or the server reloads. It is perfect for setting up scoreboard objectives, teams, and initial state.
- tick.json runs its listed functions every game tick, twenty times per second. It is how packs implement clocks, timers, and per-tick logic.
data/mypack/tags/function/load.json
{
"values": [
"mypack:on_load"
]
}data/mypack/tags/function/tick.json
{
"values": [
"mypack:clock"
]
}A word of caution: anything in tick.json runs twenty times a second forever. Keep tick functions tiny, and move heavy work behind scoreboard timers so you only run it when needed. A common pattern is a single clock function that increments a scoreboard value and triggers heavier logic every N ticks.
Scoreboards and Schedules as Timers
Scoreboard objectives make excellent timers. Create a dummy objective, increment it each tick, and use execute if score to fire an action at a chosen interval. You can also use the schedule command to run a function once after a delay, or repeatedly with schedule … clear and replace. Between tick tags, scoreboard counters, and the schedule command, you can build everything from boss bar countdowns to automated events without a single plugin.
Tags in Depth
Tags are a foundational feature of data packs and the reason many systems scale. A Tag is a JSON file that lists a set of values of one type. Vanilla itself is built on tags, and your pack can add to them. The main kinds you will touch are:
- item tags: used in recipes, in the /clear and /give commands, and in many vanilla mechanics that treat groups of items the same way.
- block tags: used by tools, by ore and wood detection, and to make a custom block family behave like a known one.
- entity_type tags: group mobs so commands and mechanics treat them as one category, such as all undead or all raid participants.
- function tags: drive scheduling through load.json and tick.json and let you call a whole set of functions by one name.
The power of tags is that other data references the tag name, not the individual items. Add one item to your tag, and every recipe, loot table, and command that uses that tag suddenly includes it. That is how you make additions that feel native instead of long lists of duplicated entries. To extend a vanilla tag, use the “replace”: false flag so your values are merged with the built-in ones.
Practical Use Cases for Data Packs
Data packs shine in the space between a purely vanilla server and a fully plugin-driven one. The following are the features we reach for most often, and each maps cleanly to a folder from the structure above.
- Custom recipes: add a new crafting recipe, tweak smelting outputs, or create smithing upgrades. Great for progression tweaks and quality-of-life crafts.
- Custom advancements: build a progression tree with triggers, hidden goals, and item or experience rewards, all shown in the advancement screen.
- Loot table tweaks: change drop rates, add rare drops to specific mobs, or reshape what comes out of dungeon and structure chests.
- Worldgen and structure tweaks: adjust biome decoration, add configured features, and shape how structures are placed.
- Cross-version behavior: because packs are data, a well-structured pack can span several versions, though you must verify pack_format and any result-format changes each update.
For world generation in particular, packing a data pack together with [How to Pre-Generate Your Minecraft World with Chunky] is a strong combination: you shape the terrain with data, then pre-generate the chunks so players never wait for them.
Hands-On Walkthrough: A Custom Recipe and a Load Function
Let us build a tiny but complete pack. It adds one crafting recipe and prints a welcome message whenever the pack loads. Create a folder named intro_datapack inside world/datapacks, then add these files.
First, the metadata:
intro_datapack/pack.mcmeta
{
"pack": {
"pack_format": 48,
"description": "Intro pack"
}
}Next, a shaped recipe that turns eight paper and one diamond into an enchanted book. Note that on 1.20.5 and later the result uses an id field:
intro_datapack/data/intro/recipes/paper_codex.json
{
"type": "minecraft:crafting_shaped",
"category": "misc",
"pattern": ["PPP", "PDP", "PPP"],
"key": {
"P": { "item": "minecraft:paper" },
"D": { "item": "minecraft:diamond" }
},
"result": { "id": "minecraft:enchanted_book", "count": 1 }
}Then the load function and the tag that runs it:
intro_datapack/data/intro/functions/on_load.mcfunction
tellraw @a {"text":"Intro pack loaded. Happy crafting!","color":"gold"}intro_datapack/data/intro/tags/function/load.json
{
"values": [
"intro:on_load"
]
}Save everything, restart the server or run /reload, then check /datapack list and try crafting the book. If both work, you have built, installed, and validated a complete data pack. From here you can add more recipes, more functions, and more tags following the same rhythm.
Performance, Packaging, and When to Prefer a Plugin
Data packs are lightweight because they are data the engine already knows how to consume, but they are not free. Every function listed in tick.json runs twenty times per second, and a single expensive command on that path can hurt a busy server. The rules of thumb we use in production are straightforward:
- Keep tick functions minimal and gate heavy work behind scoreboard timers.
- Prefer tags over long duplicated lists so the engine can resolve groups efficiently and you avoid bloat.
- Avoid running broad selectors like @e with no filters on a per-tick path.
- Split large packs into multiple namespaces and files so you can disable one feature without touching the rest.
- Validate JSON and test on a copy of the world before deploying to production.
For packaging, ship a folder while you are developing and a .zip when you distribute. Include a pack.png for a clean icon and always keep the pack.mcmeta at the root of the archive, not buried one level deep. That single detail trips up more first-time pack authors than any other.
Data Pack Pros and Cons
- Pros: works on every Java server, including vanilla and Realms; no Java knowledge required; ships with the world; reloads live with /reload; safe and portable; free and open format.
- Cons: cannot add new Java events or true code logic; limited to what the engine already supports; version-sensitive pack_format changes; no support for database or external service integration; complex systems can get unwieldy compared to a plugin.
So when should you choose a plugin instead? If you need custom event handling, a new command implemented in code, database storage, cross-server messaging, or mechanics the engine simply does not express as data, reach for a plugin. On Paper and Purpur you get a mature plugin API, and if you are moving from Spigot it is worth reading [How to Migrate from Spigot to Paper Without Breaking Plugins] so you do not break what you already run. For lighter scripting-style gameplay, a tool like [Minecraft Scripting Guide: Unique Gamification with Skript] can split the difference between data packs and full plugins.
A practical pattern many communities adopt is to start with a data pack, prove the feature, and only graduate to a plugin when a real limitation appears. That keeps your long-term maintenance surface small. The Paper documentation is the best place to check what a plugin API can and cannot do.
Common Mistakes and Expert Tips
Almost every broken data pack we debugged came down to one of these. Save yourself the afternoon.
- Forgetting /reload after editing. The game will happily run your old data until you reload or restart. This single habit prevents most “my change did nothing” reports.
- Wrong pack_format. A stale number silently disables the whole pack. Bump it when you update the server version.
- Mismatched namespace in tags. Tag entries must read namespace:path. A path with no namespace, or the wrong one, matches nothing and fails quietly.
- Overwriting vanilla data. Always use your own namespace and merge tags with “replace”: false instead of replacing the minecraft namespace.
- Result format drift. The 1.20.5 change to id-based results broke countless older recipes. Check the Recipe page for the format your version expects.
- Tick functions doing too much. Running heavy logic in tick.json twenty times a second is the number one cause of lag from data packs. Move it behind a timer.
Expert tips: validate every JSON file with a linter before installing, keep a development copy of the world so you never test on live data, and document each function with a comment line using the hash prefix so future you understands what it does. If you maintain a large pack, generate boilerplate with Misode’s data pack generators to avoid hand-writing structures that must be exact.
Frequently Asked Questions
Yes. Data packs are part of the vanilla game, so any Java server that runs Minecraft, including Paper, Purpur, and Spigot, loads them from world/datapacks. They sit alongside plugins rather than replacing them, and /reload refreshes packs without restarting the server.
pack_format is a number inside pack.mcmeta that tells the game which data format your pack targets. If it falls outside the range your Minecraft version accepts, the pack is treated as incompatible and its data is not loaded. Check the current value on the Pack format page whenever you update the server.
No. Data packs change existing game data and behavior, but they cannot add new Java code, listen to arbitrary events, or integrate with databases and external services. When you need those, a plugin is the right tool. For recipes, loot, advancements, functions, and smaller mechanics, data packs are usually enough.
Place the pack in the world datapacks folder, then run /reload from the console or in-game. It reloads packs and functions without a full restart. Some changes, such as world generation, only affect newly generated chunks, and certain edits still require a genuine restart to take effect. For related reading on drops and rewards, see the Loot table and Advancement pages.
Conclusion: Start Small, Then Scale
Data packs are the fastest, safest way to customize a vanilla Java server. They install as plain files, reload live, travel with your world, and require no Java to ship a real feature. Once you understand pack.mcmeta, the data/<namespace>/ layout, functions, and tags, you can build custom recipes, advancements, loot, and worldgen that feel like part of the game.
Our advice is to start with one small pack. Add a recipe, wire up a load function, confirm it with /datapack list, and only then expand. When a feature genuinely needs code, database access, or event handling, move to a plugin and follow a clean migration path like our [How to Migrate from Spigot to Paper Without Breaking Plugins] walkthrough. If you are still choosing your server software, the [A Beginner’s Guide to Minecraft Server JARs: Paper, Purpur…] will help you pick a stable base first.
Ready to customize your world? Open your world folder, create a datapacks directory, drop in a pack.mcmeta and your first .mcfunction, and run /reload. That first successful reload is the moment data packs click, and from there your server becomes yours to shape.

Leave a Reply