MultiLoader 1.21+ · Part 8

Data Generation: Block & Item Tags (MultiLoader 1.21+)

INTERMEDIATE MULTILOADER 1.21-1.21.1 18 min read · Jun 29, 2026
MultiLoader 1.21+ · 28 parts
1 Getting Started with MultiLoader 1.21+ 2 Setting Up RegistrationUtils 3 Creating Items (MultiLoader 1.21+) 4 Creating Blocks (MultiLoader 1.21+) 5 Data Generation: Block & Item Models (MultiLoader 1.21+) 6 Data Generation: Block Loot Tables (MultiLoader 1.21+) 7 Data Generation: Crafting Recipes (MultiLoader 1.21+) 8 Data Generation: Block & Item Tags (MultiLoader 1.21+) 9 Custom Food Items (MultiLoader 1.21+) 10 Custom Tools (MultiLoader 1.21+) 11 Custom Armour (MultiLoader 1.21+) 12 Block Entities (MultiLoader 1.21+) 13 Config Files (MultiLoader 1.21+) 14 Custom Sounds (MultiLoader 1.21+) 15 Events and Listeners (MultiLoader 1.21+) 16 Networking and Custom Packets (MultiLoader 1.21+) 17 Data Generation: Advancements (MultiLoader 1.21+) 18 Data Generation: Language Files (MultiLoader 1.21+) 19 Custom Entities (MultiLoader 1.21+) 20 Ore Generation (MultiLoader 1.21+) 21 Introduction to Mixins (MultiLoader 1.21+) 22 Custom Particles (MultiLoader 1.21+) 23 Menus & Screens (MultiLoader 1.21+) 24 Key Bindings (MultiLoader 1.21+) 25 Custom Potion Effects (MultiLoader 1.21+) 26 Custom Enchantments (MultiLoader 1.21+) 27 Custom Commands (MultiLoader 1.21+) 28 Custom Biomes (MultiLoader 1.21+)

Tags are named sets of blocks, items or other registry objects that game mechanics and recipe ingredients can reference without knowing the exact members. In this tutorial we generate block and item tag files using datagen, add our custom block to the vanilla tool-requirement tags so it can only be harvested correctly, and create a custom mod-scoped item tag for use in recipes.

NOTE
Complete the Data Generation: Crafting Recipes tutorial before continuing. We add two new providers to the existing gatherData method.

Why Tags Matter

Without the correct tool tags, your block will drop its item regardless of what the player digs with. Adding BlockTags.MINEABLE_WITH_PICKAXE tells Minecraft that a pickaxe is the correct tool, and adding BlockTags.NEEDS_IRON_TOOL makes it so that only an iron-tier pickaxe or better actually harvests the block. Without that second tag the block is diggable with any pickaxe, even wooden.

Item tags serve a different purpose: they let recipe ingredients match a group of items rather than a single specific one. We will create an examplemod:mod_items tag containing all items from this mod, which can then be used as a recipe ingredient in future tutorials.

Block Tags Provider

In your NeoForge data package, create a class called ExampleBlockTagsProvider extending BlockTagsProvider:

java
public class ExampleBlockTagsProvider extends BlockTagsProvider {
public ExampleBlockTagsProvider(PackOutput output,
CompletableFuture<HolderLookup.Provider> lookupProvider,
ExistingFileHelper existingFileHelper) {
super(output, lookupProvider, Constants.MOD_ID, existingFileHelper);
}
@Override
protected void addTags(HolderLookup.Provider provider) {
tag(BlockTags.MINEABLE_WITH_PICKAXE)
.add(BlockRegistry.NEW_DIRT.get());
tag(BlockTags.NEEDS_IRON_TOOL)
.add(BlockRegistry.NEW_DIRT.get());
}
}

The tag(...).add(...) pattern appends your block to an existing vanilla tag file without replacing its other members. The replace: false flag is written into the JSON automatically, which is what tells the game to merge rather than overwrite.

TIP
Other useful vanilla block tags include BlockTags.MINEABLE_WITH_AXE, BlockTags.MINEABLE_WITH_SHOVEL, BlockTags.NEEDS_STONE_TOOL and BlockTags.NEEDS_DIAMOND_TOOL. Pick the tool type and tier that fits your block's material.

Item Tags Provider

In the same package, create ExampleItemTagsProvider extending ItemTagsProvider. The item tags provider depends on the block tags provider because it can copy block tags across to matching item tags, so it takes a CompletableFuture<TagLookup<Block>> as a constructor argument:

java
public class ExampleItemTagsProvider extends ItemTagsProvider {
public ExampleItemTagsProvider(PackOutput output,
CompletableFuture<HolderLookup.Provider> lookupProvider,
CompletableFuture<TagLookup<Block>> blockTags,
ExistingFileHelper existingFileHelper) {
super(output, lookupProvider, blockTags, Constants.MOD_ID, existingFileHelper);
}
@Override
protected void addTags(HolderLookup.Provider provider) {
TagKey<Item> modItems = ItemTags.create(
ResourceLocation.fromNamespaceAndPath(Constants.MOD_ID, "mod_items"));
tag(modItems)
.add(ItemRegistry.IRON_STICK.get())
.add(BlockRegistry.NEW_DIRT.get().asItem());
}
}

The modItems tag key declares a new tag under your mod's namespace. You can reference this key anywhere a TagKey<Item> is accepted, for example as an ingredient in a ShapedRecipeBuilder definition.

TIP
Use copy(blockTag, itemTag) inside addTags to mirror a block tag to its item equivalent. This is commonly done for material tags such as Tags.Blocks.STONE so that both the placed block and the item form share the same logical group.

Registering the Providers

Open gatherData and add both providers. The block tags provider must be constructed first so its contentsGetter() can be passed to the item tags provider:

java
public static void gatherData(GatherDataEvent event) {
try {
DataGenerator generator = event.getGenerator();
PackOutput output = generator.getPackOutput();
ExistingFileHelper existingFileHelper = event.getExistingFileHelper();
CompletableFuture<HolderLookup.Provider> registries = event.getLookupProvider();
generator.addProvider(true,
new ExampleItemModelProvider(output, existingFileHelper));
generator.addProvider(true,
new ExampleBlockStateProvider(output, Constants.MOD_ID, existingFileHelper));
generator.addProvider(true,
new LootTableProvider(output, Set.of(),
List.of(new LootTableProvider.SubProviderEntry(
ExampleBlockLootTableProvider::new,
LootContextParamSets.BLOCK
)), registries));
generator.addProvider(true,
new ExampleRecipeProvider(output, registries));
ExampleBlockTagsProvider blockTagsProvider = generator.addProvider(true,
new ExampleBlockTagsProvider(output, registries, existingFileHelper));
generator.addProvider(true,
new ExampleItemTagsProvider(output, registries,
blockTagsProvider.contentsGetter(), existingFileHelper));
} catch (RuntimeException e) {
Constants.LOG.error("Failed to generate data", e);
}
}

Running Datagen

Run the NeoForge Data configuration. Afterwards, check the generated resources folder for two new directories:

  • data/minecraft/tags/block/mineable/pickaxe.json and data/minecraft/tags/block/needs_iron_tool.json should each contain examplemod:new_dirt in their values array.
  • data/examplemod/tags/item/mod_items.json should list both examplemod:iron_stick and examplemod:new_dirt.
json
// data/minecraft/tags/block/mineable/pickaxe.json
{
"replace": false,
"values": ["examplemod:new_dirt"]
}
// data/examplemod/tags/item/mod_items.json
{
"replace": false,
"values": [
"examplemod:iron_stick",
"examplemod:new_dirt"
]
}

Testing In-Game

Launch the client in survival mode and try to break a New Dirt block with your fist and then with a wooden pickaxe. Neither should produce a drop. Switch to an iron pickaxe and break it; the block should drop itself, as expected from the loot table tutorial. This confirms both tool-type and tool-tier tags are working.

WARNING
If the block still drops with the wrong tool, check that your generated tag files are in data/minecraft/tags/block/ (the vanilla namespace) and not in data/examplemod/tags/block/. Tool requirement tags must be in the minecraft namespace to be recognised by the game.

You can find the source for this tutorial here:

View Source on GitHub
NEXT IN SERIES

Custom Food Items (MultiLoader 1.21+)

Build edible items using FoodProperties.Builder, configure nutrition and saturation, apply status effects on eating, and wire up the model and creative tab entries through datagen.

Continue →