Now that we have items working, it is time to create a custom block. Blocks in Minecraft are closely tied to their items (the BlockItem is what you hold in your inventory), so our registry helper will handle registering both at once.
ItemRegistry here to register the BlockItem automatically.Creating the Block Registry
Create a new BlockRegistry class in your registry package. We will add a private helper method called registerBlock that simultaneously registers the block and its corresponding BlockItem. We will also create another helper method getBlockProperties to set the properties of the block itself, as well as setting the ID of the block:
The registerBlock helper registers the block under your mod's namespace, then immediately registers a matching BlockItem so the block is obtainable as an item. Both share the same registry name, which is the standard Minecraft convention.
In 26.1, every block (just like items) must be given an explicit registry key via Block.Properties.setId(). Without it the game throws at startup when it tries to look up the block's key. The key is a ResourceKey<Block> built from your mod ID and the block's registry name, and it must match the name you pass to BLOCKS.register(). Passing the name as a parameter to the helper keeps them in sync automatically.
Defining a Block
Add a public static final field for your first block. We will create a simple dirt variant called New Dirt by copying all properties from vanilla dirt:
ofFullCopy copies every property from the target block, including hardness, blast resistance, sound, and tool requirement. You can also use the builder pattern (BlockBehaviour.Properties.of()...) to set properties manually.
Call BlockRegistry.init() from CommonClass.init():
Block Model and Texture
Create the block model JSON at src/main/resources/assets/examplemod/models/block/new_dirt.json:
The cube_all parent applies the same texture to every face. Create a 16x16 PNG texture at src/main/resources/assets/examplemod/textures/block/new_dirt.png.
As introduced in the Items tutorial, 26.1 uses an items/ definition file to control how the block looks in your inventory. Create src/main/resources/assets/examplemod/items/new_dirt.json:
For blocks, the item definition points straight at the block model rather than a separate item model. The block model already describes the full cube geometry, so the inventory slot renders it directly without needing a dedicated models/item/ file.
Blockstate File
The blockstate file maps block property combinations to model variants. For a simple block with no properties, there is just one variant with an empty string key. Create src/main/resources/assets/examplemod/blockstates/new_dirt.json:
Creative Tab for Blocks
Open CreativeTabRegistry and add a second tab for your blocks, or add the block to the existing items tab. Here we will keep them separate:
Language File
Add display names for the block, its item, and the new creative tab to your en_us.json language file:
Testing In-Game
Run the Fabric Client or NeoForge Client. Open creative mode and you should see your new Blocks tab with New Dirt in it. Place the block and verify it renders correctly with your texture. You can also use:
Breaking the block will not drop anything yet, as that requires a loot table. We cover that in the Data Generation tutorials coming up next.
You can find the source for this tutorial here:
View Source on GitHubData Generation: Block & Item Models (MultiLoader 26.1+)
Configure NeoForge datagen to write resources into the common project, create a ModelProvider using BlockModelGenerators, and hook it into GatherDataEvent.Client to auto-generate blockstate, model, and item definition files.
Continue →