Custom block models: from Blockbench to a resource pack

Build a block model in Blockbench, ship it in a Java resource pack, and learn what a pack can change and what needs a plugin. Checked against Java 26.3.

Updated 28 October 2026Tools: Blockbench

A Java resource pack can give any item a new 3D model and can swap the look of blocks that already exist. It cannot create a block with its own id or behaviour. This guide builds a small lamp post model, packs it, and shows it in game, then explains where a pack stops and what the usual workarounds are.

What you end up with

  • A resource pack folder (or zip) that loads in Java Edition 26.3.
  • A custom model, made in Blockbench or written by hand, that an item or a display entity shows.
  • A clear idea of which custom block ideas need only a pack and which need a plugin.

What a resource pack can and cannot do

You wantResource pack alone?How
New look for an existing blockYesOverride its model or blockstate file, or its texture. Every block of that type changes for everyone using the pack.
New look for an itemYesItem model definition, picked by the item_model component or by custom_model_data.
A decoration placed in the worldMostlyAn item display entity showing an item that uses your model. It is an entity, not a block: it does not collide or behave like a block.
A new block id, with its own drops, hardness or behaviourNoBlocks are registered by the game. A data pack cannot register one, and a pack only changes how existing blocks are drawn.
The same block with a second lookNo, not by itselfA blockstate file maps existing block states to models. Telling two stone brick blocks apart needs a plugin or mod that places different states.

So for a truly new placeable block, a server-side tool has to do the work. The common approach is a plugin that reuses block states players rarely meet, such as note block, tripwire and chorus plant states, and points each state at your model through the pack. Oraxen's documentation, for example, lists about 800 note block variations, 127 tripwire and 63 chorus plant. Those plugins ship the pack for you; you still write the models and textures as below.

Before you start

  • Java Edition. The latest release is 26.3 (15 September 2026); its resource pack format is 97.1. Bedrock uses a different pack system, not covered here.
  • Blockbench, free and open source (GPL-3.0), as a desktop app or in the browser. See the Blockbench toolbox page.
  • A text editor with JSON highlighting. The game parses pack JSON strictly, so a trailing comma breaks the file.
  • Textures as PNG files. This guide uses vanilla textures so you can skip drawing for now.

Step 1: create the pack folder

Create a folder in .minecraft/resourcepacks/ with this layout. Everything under assets/lamp/ belongs to your own namespace, here lamp. Names are lowercase, with no spaces.

lamp-pack/
  pack.mcmeta
  pack.png
  assets/
    lamp/
      items/
        lamp_post.json
      models/
        block/
          lamp_post.json
      textures/
        block/
          lamp_glass.png
          lamp_glass.png.mcmeta
  • lamp-pack/
  • pack.mcmetaRequired: the pack formats it supports
  • pack.pngThe icon in the pack list
  • assets/
  • lamp/Your namespace
  • items/
  • lamp_post.jsonThe item model definition
  • models/
  • block/
  • lamp_post.jsonThe model Blockbench exports
  • textures/
  • block/
  • lamp_glass.pngYour own texture
  • lamp_glass.png.mcmetaIts animation settings
Each file in the folder and what it does, with the model that models/block/lamp_post.json describes.Drawn by BlockLab

The only required file is pack.mcmeta (pack.png is the optional icon). Since 1.21.9 it declares the range of pack formats it supports with min_format and max_format; pack_format is optional and only needed for packs that also support older versions. A whole number means any minor version of that format.

{
  "pack": {
    "description": "Lamp post",
    "min_format": 97,
    "max_format": 97
  }
}

Each game version has its own format number, and it keeps rising: 26.1 uses 84, 26.2 uses 88 and 26.3 uses 97.1. Look your version up on the pack format table and raise max_format after you have tested on a newer version.

Step 2: build the model in Blockbench

  1. Start a new project and choose the Java Block/Item format.
  2. Keep your PNG files inside the pack, under assets/lamp/textures/block/, before you load them in Blockbench: it reads the texture path (lamp:block/lamp_glass) from where the file sits. Check it in the texture's properties if a path comes out wrong.
  3. Add elements (cuboids) in the outliner and import or draw their textures. Blocks are 16 units across; elements may reach from -16 to 32.
  4. Export with File, Export, Export Block/Item Model.
The lamp post model in Blockbench: a stone brick base, an oak post, a pale green lamp and an iron cap, with the lamp element selected and its position, size and pivot point shown in the Transform panel.
The lamp post built from four elements in Blockbench: the position and size of the selected element become its from and to corners in the exported model file.Screenshot: Blockbench, from web.blockbench.net

The model below is the kind of file Blockbench writes: a stone brick base, an oak post, a glowing lamp and an iron cap, built from four elements and four vanilla textures.

The lamp post model, drawn from the JSON below. Drag it to turn it.Drawn by BlockLab
{
  "parent": "block/block",
  "textures": {
    "brick": "block/stone_bricks",
    "wood": "block/oak_planks",
    "glow": "block/sea_lantern",
    "metal": "block/iron_block",
    "particle": "block/stone_bricks"
  },
  "elements": [
    {
      "from": [3, 0, 3],
      "to": [13, 2, 13],
      "faces": {
        "down": {"texture": "#brick", "cullface": "down"},
        "up": {"texture": "#brick"},
        "north": {"texture": "#brick"},
        "south": {"texture": "#brick"},
        "west": {"texture": "#brick"},
        "east": {"texture": "#brick"}
      }
    },
    {
      "from": [7, 2, 7],
      "to": [9, 13, 9],
      "faces": {
        "down": {"texture": "#wood", "uv": [7, 7, 9, 9]},
        "up": {"texture": "#wood", "uv": [7, 7, 9, 9]},
        "north": {"texture": "#wood", "uv": [7, 3, 9, 14]},
        "south": {"texture": "#wood", "uv": [7, 3, 9, 14]},
        "west": {"texture": "#wood", "uv": [7, 3, 9, 14]},
        "east": {"texture": "#wood", "uv": [7, 3, 9, 14]}
      }
    },
    {
      "from": [5, 13, 5],
      "to": [11, 15, 11],
      "light_emission": 15,
      "faces": {
        "down": {"texture": "#glow"},
        "up": {"texture": "#glow"},
        "north": {"texture": "#glow"},
        "south": {"texture": "#glow"},
        "west": {"texture": "#glow"},
        "east": {"texture": "#glow"}
      }
    },
    {
      "from": [4, 15, 4],
      "to": [12, 16, 12],
      "faces": {
        "down": {"texture": "#metal"},
        "up": {"texture": "#metal"},
        "north": {"texture": "#metal"},
        "south": {"texture": "#metal"},
        "west": {"texture": "#metal"},
        "east": {"texture": "#metal"}
      }
    }
  ]
}

Paste it into the model viewer to turn it around, change a number, and see the result before it goes in a pack.

How the model file works

  • textures defines variables. A face points at one with a hash, so #brick reads the brick variable. The value block/stone_bricks means assets/minecraft/textures/block/stone_bricks.png; leave off the folder prefix and the .png. A custom texture is written lamp:block/lamp_glass.
  • particle is the texture used for break particles. Set it, or breaking the thing shows the missing texture.
  • Each element has from and to corners in 1/16 block units, and faces for the sides you want drawn. A face you leave out is invisible.
  • uv is [x1, y1, x2, y2] on a 16 by 16 grid, whatever the real texture size. Swap x1 and x2 to mirror the texture. Leave it out and the game derives it from the element position.
  • cullface hides a face when a solid block touches that side. Use it on faces that sit on the block edge.
  • light_emission (0 to 15) makes an element render at that minimum light level. It does not light the world around it.
  • rotation turns an element: { "origin": [8, 8, 8], "axis": "y", "angle": 45 }. Since 1.21.6 the angle is no longer limited to multiples of 22.5 degrees, and since 1.21.11 an element can turn on several axes with x, y and z angles instead of axis and angle.
  • parent inherits another model. block/block brings the standard display transforms, which is why the item looks right in the inventory and in the hand.

Older tutorials set shade: false on elements. Java 26.3 removed shade and added shade_direction_override instead. If you reuse an older model, delete the old key and test it.

Step 3: add your own textures

Textures are PNG files under assets/<namespace>/textures/. 16 by 16 is the usual size for blocks, but larger squares work and non-square images are allowed. To animate a texture, stack the frames vertically in one PNG and add a file with the same name plus .mcmeta:

{
  "animation": {
    "frametime": 4
  }
}

frametime is in game ticks (20 per second). You can also list frames in a custom order and give single frames their own time. If the image size does not divide into the frame size, the game shows the missing texture.

Step 4: link the model to an item

Since 1.21.4 an item picks its model from an item model definition in assets/<namespace>/items/. The definition for the lamp post is tiny:

{
  "model": {
    "type": "minecraft:model",
    "model": "lamp:block/lamp_post"
  }
}

Any item can use it through the item_model component. The item keeps its real id and behaviour; only the look changes:

/give @s minecraft:stone_bricks[item_model="lamp:lamp_post"]

To show it in the world as a decoration, put that item in an item display entity:

/summon minecraft:item_display ~ ~ ~ {item:{id:"minecraft:stone_bricks",count:1,components:{"minecraft:item_model":"lamp:lamp_post"}}}

If you want one item to switch looks, use a different definition type. A select definition reads the strings in the custom_model_data component; range_dispatch reads its numbers and condition its flags. Save this one as the same lamp_post.json: it shows a second model, lamp_post_lit, when the item carries the string lit, and the plain one otherwise.

{
  "model": {
    "type": "minecraft:select",
    "property": "minecraft:custom_model_data",
    "cases": [
      { "when": "lit", "model": { "type": "minecraft:model", "model": "lamp:block/lamp_post_lit" } }
    ],
    "fallback": { "type": "minecraft:model", "model": "lamp:block/lamp_post" }
  }
}
/give @s minecraft:stone_bricks[item_model="lamp:lamp_post",custom_model_data={strings:["lit"]}]

Step 5: retexture an existing block (optional)

A blockstate file in assets/minecraft/blockstates/ maps the states of a vanilla block to models. The file name must match an existing block, since a file with another name affects nothing. This one makes every stone bricks block in the world use the lamp post model:

{
  "variants": {
    "": { "model": "lamp:block/lamp_post" }
  }
}

That is the limit of a pack in one example: it changes how a block is drawn, for every block of that type, and nothing about what the block is. Use it for a retexture or a remodel of a whole block type (a lantern with a nicer frame, an anvil with a new base), not for adding a block.

Step 6: test and share

  1. Enable the pack in Options, Resource Packs. Press F3 + T to reload packs after each change.
  2. Run the commands above in a creative world. Check the item in the inventory, in hand and on the ground.
  3. For a server, host the zip and point server.properties at it. The pack must stay under 250 MiB.
resource-pack=https://example.com/lamp-pack.zip
resource-pack-sha1=<sha1 of the zip>
require-resource-pack=true

Common mistakes

  • Black and magenta cube. The model or texture was not found. Check the folder, the lowercase file name and that the texture value has no .png and no textures/.
  • Item looks unchanged. The item model definition is missing or sits in models/item/. Since 1.21.4 it belongs in items/, and the component must name it as namespace:file_name.
  • Pack ignored or flagged for another version. The format range in pack.mcmeta does not include your game version.
  • Model rejected. A comma too many, an element beyond -16 to 32, or an old key such as shade. Paste the JSON in the model viewer to find the line.
  • Expecting a new block. A pack adds looks, not blocks. Plan the plugin side before you draw forty textures.

Where to go next

  • Pick vanilla textures that match your model: browse blocks by colour or look at a single block such as oak planks.
  • Build with what exists first. Families shows which materials come with stairs, slabs and walls, so you only make a custom model where nothing vanilla fits.
  • Place your finished decorations quickly with the editors in Axiom vs WorldEdit.