Skip to content

Registry Builder

The RegistryBuilder is the core API for registering content from common code that works on both Fabric and NeoForge. It provides a simple, unified interface for registering items, blocks, block entities, sounds, creative tabs, and more with automatic mod ID prefixing.

Instead of creating a RegistryBuilder directly, extend the specific registry classes for better organization and type safety. Matthiesen Lib provides abstract registry classes for different content types:

  • AbstractItemRegistry - For registering items
  • AbstractBlockRegistry - For registering blocks
  • AbstractBlockEntityRegistry - For registering block entity types
  • AbstractMenuTypeRegistry - For registering menu/container types
  • AbstractCommandRegistry - For registering commands
  • AbstractSoundRegistry - For registering sound events
  • AbstractCreativeModeTabRegistry - For registering creative mode tabs
  • AbstractDataComponentTypeRegistry - For registering custom data component types
  • AbstractCriteriaTriggerRegistry - For registering advancement criterion triggers
  • AbstractStatsRegistry - For registering custom statistics
  • AbstractEntityEffectRegistry - For registering enchantment entity effects
package dev.matthiesen.common.mymod.registry;
import dev.matthiesen.common.matthiesen_lib.registry.AbstractItemRegistry;
import net.minecraft.world.item.Item;
import java.util.function.Supplier;
public class ItemRegistry extends AbstractItemRegistry {
private static final ItemRegistry INSTANCE = new ItemRegistry();
protected ItemRegistry() {
super("mymod"); // Your mod ID
}
public static void init() {
// Called to trigger static initialization
}
// Register your items
public static final Supplier<Item> MY_ITEM;
static {
MY_ITEM = INSTANCE.register("my_item", () -> new Item(new Item.Properties()));
}
}

The mod ID is automatically prefixed to all registered content, so you only need to provide the item/block name.

Register items by extending AbstractItemRegistry:

import dev.matthiesen.common.matthiesen_lib.registry.AbstractItemRegistry;
import net.minecraft.world.item.Item;
import java.util.function.Supplier;
public class ItemRegistry extends AbstractItemRegistry {
private static final ItemRegistry INSTANCE = new ItemRegistry();
protected ItemRegistry() {
super("mymod");
}
public static void init() {}
public static final Supplier<Item> EXAMPLE_ITEM;
public static final Supplier<Item> CUSTOM_ITEM;
static {
EXAMPLE_ITEM = INSTANCE.register("example_item", () -> new Item(new Item.Properties()));
CUSTOM_ITEM = INSTANCE.register("custom_item", CustomItem::new);
}
}

In your mod initializer, call ItemRegistry.init() to trigger registration.

Register blocks by extending AbstractBlockRegistry:

import dev.matthiesen.common.matthiesen_lib.registry.AbstractBlockRegistry;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockBehaviour;
import java.util.function.Supplier;
public class BlockRegistry extends AbstractBlockRegistry {
private static final BlockRegistry INSTANCE = new BlockRegistry();
protected BlockRegistry() {
super("mymod");
}
public static void init() {}
public static final Supplier<Block> EXAMPLE_BLOCK;
static {
EXAMPLE_BLOCK = INSTANCE.register("example_block",
() -> new Block(BlockBehaviour.Properties.of()
.strength(3.0f, 3.0f)
)
);
}
}

Register commands using AbstractCommandRegistry:

import dev.matthiesen.common.matthiesen_lib.registry.AbstractCommandRegistry;
public class CommandRegistry extends AbstractCommandRegistry {
private static final CommandRegistry INSTANCE = new CommandRegistry();
protected CommandRegistry() {
super();
}
public static void init() {}
static {
INSTANCE.register(new MyCommand());
}
}

See the Commands page for details on creating commands.

Register menu types for container screens using AbstractMenuTypeRegistry:

import dev.matthiesen.common.matthiesen_lib.registry.AbstractMenuTypeRegistry;
import net.minecraft.world.inventory.MenuType;
import java.util.function.Supplier;
public class MenuTypesRegistry extends AbstractMenuTypeRegistry {
private static final MenuTypesRegistry INSTANCE = new MenuTypesRegistry();
protected MenuTypesRegistry() {
super("mymod");
}
public static void init() {}
public static Supplier<MenuType<CustomMenu>> CUSTOM_MENU;
public static Supplier<MenuType<AnotherMenu>> ANOTHER_MENU;
static {
CUSTOM_MENU = INSTANCE.register("custom_menu", CustomMenuFactory::create);
ANOTHER_MENU = INSTANCE.register("another_menu", AnotherMenuFactory::create);
}
}

Register custom sounds using AbstractSoundRegistry:

import dev.matthiesen.common.matthiesen_lib.registry.AbstractSoundRegistry;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.core.registries.BuiltInRegistries;
import java.util.function.Supplier;
public class SoundRegistry extends AbstractSoundRegistry {
private static final SoundRegistry INSTANCE = new SoundRegistry();
protected SoundRegistry() {
super("mymod");
}
public static void init() {}
public static Supplier<SoundEvent> MY_SOUND;
static {
MY_SOUND = INSTANCE.register("my_sound",
() -> SoundEvent.createVariableRangeEvent(
ResourceLocation.fromNamespaceAndPath("mymod", "my_sound")
)
);
}
}

Register custom creative mode tabs using AbstractCreativeModeTabRegistry:

import dev.matthiesen.common.matthiesen_lib.registry.AbstractCreativeModeTabRegistry;
import dev.matthiesen.common.matthiesen_lib.MatthiesenLib;
import net.minecraft.world.item.CreativeModeTab;
import java.util.function.Supplier;
public class CreativeTabRegistry extends AbstractCreativeModeTabRegistry {
private static final CreativeTabRegistry INSTANCE = new CreativeTabRegistry();
protected CreativeTabRegistry() {
super("mymod");
}
public static void init() {}
public static Supplier<CreativeModeTab> MY_TAB;
static {
MY_TAB = INSTANCE.register("my_tab", () ->
new MatthiesenLib.RegistryBuilder("mymod").newCreativeTabBuilder()
.title(Component.translatable("itemGroup.mymod.my_tab"))
.icon(() -> new ItemStack(ItemRegistry.MY_ITEM.get()))
.displayItems((parameters, output) -> {
output.accept(ItemRegistry.MY_ITEM.get());
output.accept(ItemRegistry.ANOTHER_ITEM.get());
})
.build()
);
}
}

Register block entity types using AbstractBlockEntityRegistry:

import dev.matthiesen.common.matthiesen_lib.registry.AbstractBlockEntityRegistry;
import net.minecraft.world.level.block.entity.BlockEntityType;
import java.util.function.Supplier;
public class BlockEntityRegistry extends AbstractBlockEntityRegistry {
private static final BlockEntityRegistry INSTANCE = new BlockEntityRegistry();
protected BlockEntityRegistry() {
super("mymod");
}
public static void init() {}
public static Supplier<BlockEntityType<MyBlockEntity>> MY_BLOCK_ENTITY;
static {
MY_BLOCK_ENTITY = INSTANCE.register("my_block_entity",
() -> BlockEntityType.Builder.of(
MyBlockEntity::new,
BlockRegistry.MY_BLOCK.get()
).build(null)
);
}
}

Register custom data component types for item NBT data:

import dev.matthiesen.common.matthiesen_lib.registry.AbstractDataComponentTypeRegistry;
import net.minecraft.core.component.DataComponentType;
import java.util.function.Supplier;
public class DataComponentRegistry extends AbstractDataComponentTypeRegistry {
private static final DataComponentRegistry INSTANCE = new DataComponentRegistry();
protected DataComponentRegistry() {
super("mymod");
}
public static void init() {}
public static Supplier<DataComponentType<Integer>> MY_COMPONENT;
static {
MY_COMPONENT = INSTANCE.register("my_component",
() -> DataComponentType.<Integer>builder()
.persistent(Codec.INT)
.networkSynchronized(ByteBufCodecs.VAR_INT)
.build()
);
}
}

Register custom advancement criterion triggers:

import dev.matthiesen.common.matthiesen_lib.registry.AbstractCriteriaTriggerRegistry;
import net.minecraft.advancements.CriterionTrigger;
import java.util.function.Supplier;
public class CriteriaTriggerRegistry extends AbstractCriteriaTriggerRegistry {
private static final CriteriaTriggerRegistry INSTANCE = new CriteriaTriggerRegistry();
protected CriteriaTriggerRegistry() {
super("mymod");
}
public static void init() {}
public static Supplier<CriterionTrigger<MyTrigger.TriggerInstance>> MY_TRIGGER;
static {
MY_TRIGGER = INSTANCE.register("my_trigger", () -> new MyTrigger());
}
}

Register custom statistics for player tracking:

import dev.matthiesen.common.matthiesen_lib.registry.AbstractStatsRegistry;
import net.minecraft.resources.ResourceLocation;
import java.util.function.Supplier;
public class StatsRegistry extends AbstractStatsRegistry {
private static final StatsRegistry INSTANCE = new StatsRegistry();
protected StatsRegistry() {
super("mymod");
}
public static void init() {}
public static Supplier<ResourceLocation> MY_STAT;
static {
MY_STAT = INSTANCE.register("my_stat",
() -> ResourceLocation.fromNamespaceAndPath("mymod", "my_stat")
);
}
}

Always use Supplier<T> for your registered content. This ensures lazy initialization and prevents null pointer exceptions:

// Good
public static final Supplier<Item> MY_ITEM;
static {
MY_ITEM = INSTANCE.register("my_item", () -> new Item(new Item.Properties()));
}
// Avoid
public static final Item MY_ITEM = INSTANCE.register(...).get(); // Don't call .get() during static init
  • Use snake_case for registry names: "gui_item", "example_block"
  • This automatically becomes mymod:gui_item in-game
  • Use descriptive names that clearly indicate what the item/block is

Organize your registrations by type in dedicated registry classes:

public class ItemRegistry extends AbstractItemRegistry {
// All item registrations
}
public class BlockRegistry extends AbstractBlockRegistry {
// All block registrations
}
public class MenuTypesRegistry extends AbstractMenuTypeRegistry {
// All menu type registrations
}

Make sure to call init() on all your registry classes during mod initialization to trigger static initialization:

public class MyMod {
public void initialize() {
ItemRegistry.init();
BlockRegistry.init();
MenuTypesRegistry.init();
CommandRegistry.init();
PermissionRegistry.init();
}
}
Registry ClassPurposeRegister Method
AbstractItemRegistryRegister itemsregister(name, supplier)
AbstractBlockRegistryRegister blocksregister(name, supplier)
AbstractBlockEntityRegistryRegister block entity typesregister(name, supplier)
AbstractMenuTypeRegistryRegister menu typesregister(name, supplier)
AbstractSoundRegistryRegister sound eventsregister(name, supplier)
AbstractCreativeModeTabRegistryRegister creative mode tabsregister(name, supplier)
AbstractDataComponentTypeRegistryRegister data component typesregister(name, supplier)
AbstractCriteriaTriggerRegistryRegister criterion triggersregister(name, supplier)
AbstractStatsRegistryRegister custom statisticsregister(name, supplier)
AbstractEntityEffectRegistryRegister enchantment entity effectsregister(name, supplier)
AbstractCommandRegistryRegister commandsregister(command)
Learn how to set up Matthiesen Lib in your development environment with the Installation Guide.
Check out the Commands page to learn how to create cross-platform commands.
Find out how to implement permissions with the Permissions system.
Discover how to register client-side features like screens and renderers in the Client-Side Features section.
Integrate with the Embers Text API for immersive messaging with the Embers Integration guide.
Utilize helpful utilities like the ItemBuilder in the Utilities section.