In 26.1, enchantments are no longer hard-coded Java objects — they are datapack registry entries, defined entirely in JSON and bootstrapped at startup. This means the datagen system IS how you create a custom enchantment: you define it in Java using a builder-style bootstrap and the generator writes the JSON file. There is no separate runtime registration step.
gatherData listener.How Enchantments Work in 26.1
Enchantments live in a datapack registry (Registries.ENCHANTMENT). Unlike static registries (items, blocks), datapack registries are populated from JSON files at world load, so they exist only after the lookup provider is resolved. NeoForge exposes them through DatapackBuiltinEntriesProvider, which takes a RegistrySetBuilder and writes one JSON file per entry you register.
The actual behaviour of an enchantment (what it does when applied) is controlled by EnchantmentEffectComponents passed to the constructor. This tutorial focuses on defining the enchantment structure and getting the JSON generated. Effect components are covered in a dedicated enchantments tutorial later in the series.
Enchantment Bootstrap
Create a class called ExampleEnchantmentBootstrap in your common module. It declares the ResourceKey for the enchantment and the bootstrap method that populates the registry:
Breaking down the key parameters:
- supportedItems — the tag of items that can receive this enchantment in the enchanting table.
ItemTags.SWORD_ENCHANTABLEallows swords. - primaryItems — items for which this enchantment is considered "primary" (higher weight when randomly selected). Wrap in
Optional.of, or passOptional.empty()to fall back tosupportedItems. - weight — how frequently the enchantment appears. Vanilla common enchantments use 10, rare ones use 1–2.
- dynamicCost(base, perLevel) — the experience level cost formula.
dynamicCost(1, 10)gives a cost of 1 at level 1, 11 at level 2, 21 at level 3. - incompatible enchantments — a
HolderSetof enchantments that cannot appear on the same item. PassHolderSet.empty()for none.
ItemTags in the Minecraft source. Common values are SWORD_ENCHANTABLE, BOW_ENCHANTABLE, ARMOR_ENCHANTABLE, MINING_ENCHANTABLE, and TRIDENT_ENCHANTABLE.Registering via DatapackBuiltinEntriesProvider
Open gatherData and add the provider. It takes a RegistrySetBuilder that maps each datapack registry to its bootstrap method, and a set of mod IDs whose entries should be included in the output:
If you add more datapack registry types in future (biomes, damage types, configured features), chain additional .add(registry, bootstrap) calls on the same RegistrySetBuilder.
Language Keys
The component passed to the Enchantment constructor is the display name. Add the translation key to ExampleLanguageProvider:
Running Datagen
Run the NeoForge Data configuration. Check common/src/generated/resources/data/examplemod/enchantment/ for the new file:
Testing In-Game
Launch the client, open a creative inventory, and use an enchanted book to verify the enchantment appears. You can also apply it directly with a command:
The enchantment will show its name and level but have no active effect yet, since DataComponentMap.EMPTY was passed for the effects. Adding gameplay behaviour via EnchantmentEffectComponents is covered in the custom enchantments tutorial later in the series.
You can find the source for this tutorial here:
View Source on GitHubCustom Food Items (MultiLoader 26.1+)
Create an edible item using FoodProperties.Builder, configure nutrition, saturation, and optional status effects on eating, then wire up the model and creative tab entry through datagen.
Continue →