Chapter 46 — Pack Versioning and Compatibility
Part XII — Finishing and Sharing. You’ve built almost everything a data pack can hold. The last two chapters are about shipping it: making it load on the right versions of the game (this chapter), then packaging and sharing it (Chapter 47). After the deep end of world generation, this is a gentle, practical chapter, mostly one small file,
pack.mcmeta, that you already know.
What You’ll Build
Way back in Chapter 9 you wrote a pack.mcmeta file with two version fields, min_format and
max_format, and a description. You set both fields to 107 and moved on. This chapter goes back to
that file and finishes the job.
By the end you’ll understand:
- what a pack format number is, and how to read off the one for your game version;
- how
min_formatandmax_formatdeclare a range of versions your pack supports, and how to write that range two different ways; - when the old
pack_format/supported_formatsfields belong (almost never) and the strict rule about leaving them out; - how to add an overlay — a folder of replacement files the game only loads on certain versions;
- how to add a filter — patterns that hide files coming from other packs;
- how to switch on a feature flag for experimental content.
And you’ll assemble all of that into one mypack/pack.mcmeta that loads cleanly across more than one
Minecraft version.
Deepening, not repeating. Chapters 9 and 28 taught you that
min_format/max_formatexist and what value to use. This chapter teaches you why there are two of them, how to make them span a range, and the four optional sections that live alongside them. Ifmin_format: 107already feels familiar, good: you’re ahead.
Pack format numbers: what they are
Every version of Minecraft can read packs up to a certain age, no older and no newer. The way the game
tracks this is a single whole number called the pack format (sometimes called the pack
version). It’s the number you put in pack.mcmeta to describe which Java versions your pack is
compatible with. Each game version declares which pack formats it supports.
Why does this exist? Because the file formats change between versions. The shape of a loot table, a predicate, or an item component is not the same in every release. The pack format number is how the game checks, before it even reads your files, whether your pack was built for the rules it knows. As the wiki puts it: pack formats help Minecraft identify whether a pack was built for the correct version of the game.
Here’s what happens when the number is wrong. If the format in your pack.mcmeta is higher than
the format the game supports (that is, your pack was built for a newer Minecraft than the one
running), the pack shows up as “incompatible” in the pack list, and the game refuses to load it.
This is a safety feature: it stops new pack features from causing crashes or missing content in an
older game that doesn’t understand them.
Under the Hood (skippable). Each pack format corresponds to specific internal changes in how Minecraft reads data: updates to registries, loot tables, tags, advancements, and model syntax. For example, the wiki notes that upgrading from format 12 to 15, several JSON structures (such as predicates and item components) changed to match new engine rules. Data packs and resource packs use the same numbering system but apply it to different things: data packs to gameplay logic (structures, recipes, tags, loot tables, functions), resource packs to textures, models, block states, sounds, and text.
Finding your version’s number
You don’t have to memorize the table. The game will tell you its pack format directly. Two ways:
- Run the
versioncommand. (In a function file that’s a line readingversion; in chat it’s/version.) - Press the F3 + V debug hotkey.
Either one reports the pack format your current game supports. That’s the number you build for.
Modern Minecraft. Older tutorials hand you a fixed number like “use
pack_format: 48.” That advice rots, because the number changes every version. Reading the number off your own game with/versionor F3 + V is the habit that doesn’t go stale.
Where to look up a format number. Pack formats change every version, so the most reliable “format N = Minecraft version X” lookup is the one your own game reports. The two values worth remembering are 107 (the data pack format for Minecraft 26.2) and 88 (the resource pack format for the same version — the two registries number separately, as Chapter 28 warned). For the full, always-current table, see the wiki’s Pack format page, and for your exact version just run
/version.
min_format and max_format: the modern range
Since the snapshot 25w31a, the pack format is described with two fields working together,
min_format and max_format, instead of the single old pack_format field. This applies to both
data packs and resource packs.
The idea is a range. min_format is the oldest format your pack supports; max_format is the
newest. The game loads your pack only if its own format falls inside that range. This is the
pack.mcmeta you already have in mypack from Chapter 9, built for exactly one version, 26.2:
mypack/pack.mcmeta
{
"pack": {
"description": "Example datapack for Minecraft 26.2",
"min_format": 107,
"max_format": 107
}
}
This is the recommended configuration for Minecraft 26.2. With both fields set to
107, the pack supports exactly format 107.
Two ways to write a version
Each of min_format and max_format can be written in two forms:
- A single integer, like
107. This is read as a major version with the lowest minor version. Put another way: a value82(or[82]) is exactly the same as[82, 0]. - A list of two integers,
[major, minor], like[107, 0]. The first number is the pack (major) version, the second is a minor version. Formin_format, a single integer means “that major version, minor 0.” Formax_format, a single integer means “that major version, any minor version.”
So if you wanted to be explicit and spell out the minor versions, the same pack could read:
mypack/pack.mcmeta
{
"pack": {
"description": "Example datapack for Minecraft 26.2",
"min_format": [107, 0],
"max_format": [107, 0]
}
}
For most packs the single-integer form is all you’ll ever write. The [major, minor] form exists for
the rare case where a pack format gets a minor bump within the same major version and you need to
pin to it precisely.
Try It! Open your game, run
/version, and read off the supported pack format. If it matches themin_format/max_formatin yourmypack/pack.mcmeta, the pack is in range and loads. If your game reports a higher number than yourmax_format, raisemax_formatto match and/reload.
The legacy fields: pack_format and supported_formats
Before 25w31a, packs used a single field called pack_format: just one number, no range. You’ll
still see it everywhere in older tutorials and old packs:
(an old-style pack.mcmeta, for 1.21.8 and earlier)
{
"pack": {
"description": "Example datapack for Minecraft 1.21",
"pack_format": 48
}
}
That’s the streamlined form for Minecraft 1.21.8 and earlier, with pack_format
set to 48. There was also a field called supported_formats for declaring more than one
supported version: it can be a single integer like 42, a two-element list like [42, 45], or an
object { "min_inclusive": 42, "max_inclusive": 45 }.
Here’s the part that trips people up. In current Minecraft, min_format/max_format is the real
mechanism. The old pack_format and supported_formats fields are only kept around for backwards
compatibility, so that a single pack can also be loaded by versions of the game older than the
min/max scheme. And there’s a strict rule attached to them:
These deprecated fields must be absent if the pack does not support old versions, but must be present if the pack does support old versions.
“Old versions” here means a data pack format below 82 (and, for resource packs, below 65). So:
- Your pack is new-only? (Anything in the
min_format/max_formatera, snapshot 25w31a and up.) Thenpack_formatandsupported_formatsmust not appear at all. Use onlymin_format/max_format. This is the normal case, and it’s whymypack/pack.mcmetahas neither field. - Your pack genuinely needs to run on a pre-82 version too? Then you add the legacy fields and
the modern ones, and the legacy field’s range has to match the major versions in
min_format/max_format.
A pack that supports both old and new might look like this:
(a pack.mcmeta that supports both an old version and a new one)
{
"pack": {
"description": "Supports old and new",
"min_format": 48,
"max_format": 107,
"supported_formats": { "min_inclusive": 48, "max_inclusive": 107 }
}
}
Modern Minecraft. If you’re following an old tutorial that tells you to write
"pack_format": 15, stop. On current Minecraft a singlepack_formaton a new-only pack is exactly the wrong thing: the rule above says it must be absent. Replace it withmin_format/max_format. Only reach for the legacy fields if you have a concrete reason to support a years-old version.
Overlays: different files for different versions
What if format 107 wants a recipe written one way, and an older format 106 wants the same recipe written a slightly different way? You don’t want two whole separate packs. You want one pack that quietly swaps a few files depending on which version is loading it. That’s an overlay.
An overlay is a sub-pack: its own little data/ (and, in resource packs, assets/) folder
that sits inside your pack’s root directory and gets applied over the normal contents, but only for a
chosen format range. You declare overlays in pack.mcmeta under an overlays section. Each overlay entry has:
- a
directory— the folder name holding the overlay’s files (allowed characters: lowercase lettersa-z, digits0-9, underscore_, and hyphen-); - a
min_formatandmax_format: the same kind of range as the mainpacksection, saying which game versions this overlay applies on.
Here’s mypack with one overlay that targets the previous format, 106:
mypack/pack.mcmeta
{
"pack": {
"description": "Example datapack for Minecraft 26.2",
"min_format": 106,
"max_format": 107
},
"overlays": {
"entries": [
{
"directory": "v106",
"min_format": 106,
"max_format": 106
}
]
}
}
Two things changed. The main pack range now spans 106 to 107, so the pack itself loads on both
versions. And the overlays.entries list holds one overlay whose directory is v106, active only on
format 106.
The overlay’s files live in a folder named exactly like the directory value, sitting in the pack
root next to data/. Inside it, you mirror the normal data/ structure: its own data/ (and
assets/) folders. So if you want to override one recipe on format 106, the tree looks like this:
mypack/
├── pack.mcmeta
├── data/
│ └── mypack/
│ └── recipe/
│ └── magic_sword.json ← the format-107 version (normal pack)
└── v106/
└── data/
└── mypack/
└── recipe/
└── magic_sword.json ← the format-106 version (overlay)
When the game runs on format 106, it loads the normal pack and then applies the v106 overlay on top,
so the overlay’s magic_sword.json wins. On format 107 the overlay’s range doesn’t match, so it’s
skipped and the normal file is used. One pack, two behaviors, chosen automatically.
Important — no pack.mcmeta inside the overlay. Inside an overlay
directory, the game ignores anypack.mcmetaandpack.png. The overlay is configured entirely from the mainpack.mcmeta’soverlayssection. Don’t put a secondpack.mcmetainv106/; it does nothing.
Under the Hood (skippable). The order of the
entrieslist matters: the first overlay in the list is applied first. If two overlays both match the running version and both touch the same file, the later one in the list ends up on top. With a single overlay, as here, order doesn’t come up.
Filters: hiding files from other packs
Data packs stack. When several packs are enabled, a higher-priority pack can sit on top of a lower-priority one, and files merge. Sometimes you want to remove a file that a pack below you provides, not replace it, just make the game act as if it isn’t there. That’s what a filter does.
A filter is a pack.mcmeta section with a block list. Each entry is a pattern, and any file
that matches one of the patterns is treated as if it was not present in the pack at
all, for any pack applied below this one.
The patterns are regular expressions. A regular expression (or regex) is a small language for describing text patterns: a way to say “any path that looks like this” instead of naming one exact file. (Full regex syntax is a big topic; we’ll keep to simple patterns here.) Each pattern entry can have:
- a
namespace— a regex for the namespace of files to hide. If you leave it out, it applies to every namespace. - a
path— a regex for the file paths to hide. If you leave it out, it applies to every file.
Here’s a filter that blocks everything in the minecraft namespace under the loot_table/ path
coming from lower packs. Handy if you want your loot tables to be the only ones that survive:
mypack/pack.mcmeta
{
"pack": {
"description": "Example datapack for Minecraft 26.2",
"min_format": 107,
"max_format": 107
},
"filter": {
"block": [
{
"namespace": "minecraft",
"path": "loot_table/.*"
}
]
}
}
The path value loot_table/.* is a regex meaning “the text loot_table/ followed by any
characters,” or in plain terms, every file inside the loot_table/ folder. Combined with namespace: "minecraft", this hides all vanilla-namespace loot tables that any lower-priority pack tries to
contribute.
What Went Wrong? A filter only affects packs applied below this one. It does not hide your own files, and it does not touch packs that load with higher priority than yours. If a file you expected to disappear is still there, check the load order with
/datapack list: the pack providing that file may actually be above yours.
Feature flags: turning on experimental content
Some content in Minecraft is gated behind a feature flag: a switch that turns on an experimental
feature that isn’t part of the normal game yet. A feature flag is named by a resource location (the
namespace:path form you’ve used since Chapter 8). You enable feature flags from pack.mcmeta under a
features section with an enabled list:
mypack/pack.mcmeta
{
"pack": {
"description": "Example datapack for Minecraft 26.2",
"min_format": 107,
"max_format": 107
},
"features": {
"enabled": [
"minecraft:some_experimental_feature"
]
}
}
Each string in enabled is the resource location of a feature flag.
There’s one big catch, and it’s important. Feature flags can only be enabled through
a data pack when the world is being created. You cannot switch a feature flag on for an existing
world by enabling a pack later. If you try to /datapack enable a pack that requires a feature flag
that wasn’t turned on at world creation, the game refuses with: “Pack <name> requires enabling a
feature flag that is not enabled via data pack when creating world.” So feature-flag packs have to be
present from the moment the world is made, in place at world creation and kept there.
Finding the real flag names. The mechanism is always the same (
features.enabled, a list of feature-flag resource locations), but the exact flag IDs change from version to version, so the example above uses a placeholder name. To find the real flags for your version, check the experimental-features list in your game’s Create World screen: those toggles are exactly whatfeatures.enabledmirrors.
The assembled pack.mcmeta
Putting the optional sections together, here’s a mypack/pack.mcmeta that uses all four ideas at once:
a version range, an overlay for the older format, a filter, and a feature flag.
mypack/pack.mcmeta
{
"pack": {
"description": "My data pack — works on more than one version",
"min_format": 106,
"max_format": 107
},
"overlays": {
"entries": [
{
"directory": "v106",
"min_format": 106,
"max_format": 106
}
]
},
"filter": {
"block": [
{
"namespace": "minecraft",
"path": "loot_table/.*"
}
]
},
"features": {
"enabled": [
"minecraft:some_experimental_feature"
]
}
}
Read it top to bottom: pack says “I support formats 106 through 107.” overlays says “on format 106,
also apply the files in the v106/ folder.” filter says “hide vanilla loot tables coming from any
pack below me.” features says “this world needs this experimental feature flag turned on.” Every one
of those sections is optional: drop any you don’t need. For most packs, you’ll only ever write the
pack section, exactly as in Chapter 9.
Figure (to be captured). the data pack list showing the pack loaded without an “incompatible” warning, with its description visible on hover
Practice
These extend the mypack/pack.mcmeta you just built. Test each by running /reload (or reopening the
world) and checking /datapack list: your pack should appear enabled, never incompatible.
-
Widen the range. Change the main
packsection tomin_format: 48, max_format: 107and add the matching legacy field so the pack can also load on a pre-82 version:"supported_formats": { "min_inclusive": 48, "max_inclusive": 107 }. Remember the rule: the legacy field is required now precisely because the pack supports old versions. Then change it back to a new-only pack and confirm you removedsupported_formatsagain. -
Add a second overlay. Create a
v48/folder mirroringdata/, and add a second entry tooverlays.entrieswithdirectory: "v48",min_format: 48,max_format: 48. Put a different copy of one file inside it. Now your pack swaps that file three ways: format 48, format 106, and the normal format-107 file. -
Filter by namespace only. Write a
filter.blockentry that leaves outpathentirely and setsnamespace: "mypack". Since a missingpathapplies to every file, this hides allmypackfiles from packs below you. Predict what that does before you reload, then check.
What Can Go Wrong
What Went Wrong? “My pack shows as incompatible.” Your
max_formatis lower than the format your game supports: you built for an older version than you’re running. Run/versionto read your game’s actual pack format and raisemax_formatto at least that number. The opposite mistake (min_formathigher than the game) also makes it incompatible: the game is older than your floor.
What Went Wrong? “I added pack_format and now there are warnings.” On a new-only pack the legacy fields must be absent. If you copied
"pack_format": 48from an old tutorial alongside yourmin_format/max_format, delete thepack_formatline. Only keep legacy fields when you genuinely support a pre-82 version, and then they must match your min/max range.
What Went Wrong? “My overlay isn’t doing anything.” Three things to check. First, the overlay folder name must match the
directoryvalue exactly (lowercase letters, digits,_,-only). Second, the overlay’s range has to include the version you’re testing on. If you’re on format 107 but the overlay ismin_format: 106, max_format: 106, it correctly does nothing. Third, don’t put apack.mcmetainside the overlay folder; it’s ignored, and the overlay is configured only from the mainpack.mcmeta.
What Went Wrong? “My feature-flag pack won’t enable.” Feature flags can only be turned on at world creation. If the game says the pack “requires enabling a feature flag that is not enabled,” the world was made without that flag. You can’t add it to an existing world by enabling the pack. Make a fresh world with the pack (and its flag) present from the start.
Next: Chapter 47 — Publishing and Sharing Your Work. You can load your pack on the right versions; now you’ll give it an icon, a clean namespace, a license, and a home on a sharing site.