Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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_format and max_format declare a range of versions your pack supports, and how to write that range two different ways;
  • when the old pack_format / supported_formats fields 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_format exist 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. If min_format: 107 already 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 version command. (In a function file that’s a line reading version; 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 /version or 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 value 82 (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. For min_format, a single integer means “that major version, minor 0.” For max_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 the min_format/max_format in your mypack/pack.mcmeta, the pack is in range and loads. If your game reports a higher number than your max_format, raise max_format to 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_format era, snapshot 25w31a and up.) Then pack_format and supported_formats must not appear at all. Use only min_format/max_format. This is the normal case, and it’s why mypack/pack.mcmeta has 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 single pack_format on a new-only pack is exactly the wrong thing: the rule above says it must be absent. Replace it with min_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 letters a-z, digits 0-9, underscore _, and hyphen -);
  • a min_format and max_format: the same kind of range as the main pack section, 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 any pack.mcmeta and pack.png. The overlay is configured entirely from the main pack.mcmeta’s overlays section. Don’t put a second pack.mcmeta in v106/; it does nothing.

Under the Hood (skippable). The order of the entries list 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 what features.enabled mirrors.

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.

  1. Widen the range. Change the main pack section to min_format: 48, max_format: 107 and 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 removed supported_formats again.

  2. Add a second overlay. Create a v48/ folder mirroring data/, and add a second entry to overlays.entries with directory: "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.

  3. Filter by namespace only. Write a filter.block entry that leaves out path entirely and sets namespace: "mypack". Since a missing path applies to every file, this hides all mypack files 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_format is lower than the format your game supports: you built for an older version than you’re running. Run /version to read your game’s actual pack format and raise max_format to at least that number. The opposite mistake (min_format higher 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": 48 from an old tutorial alongside your min_format/max_format, delete the pack_format line. 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 directory value 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 is min_format: 106, max_format: 106, it correctly does nothing. Third, don’t put a pack.mcmeta inside the overlay folder; it’s ignored, and the overlay is configured only from the main pack.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.