Wiki 9Minecraft Wiki 9Minecraft

Add-on Style Guide and Project Conventions

Standard rules for naming, folder layouts, identifiers, and JSON formatting in Bedrock packs.

7Sections
5Code examples
4Known errors

A consistent style guide keeps your Behavior Pack and Resource Pack readable, prevents collisions when players combine multiple add-ons in one world, and stops silent loading failures across different operating systems. You should adopt these conventions at the start of any new project or when refactoring a messy prototype before release. While Minecraft Bedrock allows some flexibility in where files live, sticking to strict naming and structural patterns saves hours of debugging down the line.

Namespaces and Identifiers

Every custom content piece in a Bedrock add-on—whether it is an entity, block, item, block state, or particle effect—requires an identifier formatted as `namespace:name`. The single most important rule in Bedrock development is to never use the `minecraft` namespace for custom identifiers, unless you are deliberately overriding a vanilla file (such as altering `minecraft:cow` behavior). The game reserves `minecraft` for base game assets, and newer versions will actively reject custom blocks or items that try to register under it.

Pick a short, unique namespace of two to six characters that represents your team or project, such as `studio` or `myth`. If you are working on a large team or publishing multiple packs that players might install together, use a studio prefix followed by the project name in the identifier path, like `studio:myth_goblin`, or use a project-specific namespace like `studio_myth:goblin`. Consistency here ensures your packs will never overwrite someone else's `custom:sword`.

All namespaces and identifier names must be strictly lowercase `snake_case`, using only characters `a-z`, `0-9`, and underscores. Never use camelCase, PascalCase, spaces, or hyphens inside an identifier. While the engine might tolerate a hyphen in an entity name in some versions, it will break Molang queries, command parsing, and block state definitions.

ElementGood ExampleBad ExampleWhy the bad example fails
Entity Identifierstudio:forest_trollStudio:ForestTrollUppercase letters cause lookup failures in commands and spawn eggs.
Block Identifierstudio:cracked_basaltminecraft:cracked_basaltUsing the vanilla namespace for new blocks is blocked by the engine.
Block Statestudio:rotation_indexrotation_indexCustom block states without a namespace are rejected by the parser.
Geometry Identifiergeometry.studio.forest_trollgeometry.trollToo generic; another pack in the world could easily overwrite this model.
Animation Identifieranimation.studio.forest_troll.walkanimation.walkCollides with common names if not scoped to your namespace and entity.

File Names and Directory Layout

File and folder names inside both your Behavior Pack (`BP`) and Resource Pack (`RP`) must be entirely lowercase `snake_case`. Do not use spaces or uppercase characters in file paths. While Windows is case-insensitive and will happily load `RP/textures/items/RubySword.png` when referenced as `textures/items/rubysword`, Android, iOS, Linux dedicated servers, and consoles use case-sensitive file systems. On those platforms, a capitalization mismatch results in a missing purple-and-black checkerboard texture or a silent failure.

Mirror your subfolder structure between your Behavior Pack and Resource Pack. If your custom goblin entity behavior lives at `BP/entities/monsters/forest_goblin.json`, its client entity definition should live at `RP/entity/monsters/forest_goblin.entity.json`, its model at `RP/models/entity/monsters/forest_goblin.geo.json`, and its texture at `RP/textures/entity/monsters/forest_goblin.png`. When a project grows to fifty entities, mirrored folders let you find every asset related to a feature without hunting through flat directories.

For resource pack files, use Compound Extensions (also known as dot-suffixes) to tell different JSON types apart at a glance in your code editor. Even though the game only cares that the file ends in `.json`, naming a client entity `.entity.json`, a geometry file `.geo.json`, an animation `.animation.json`, and a render controller `.render_controllers.json` prevents you from accidentally editing the behavior file when you meant to edit the client entity file.

Pack & Asset TypeRecommended DirectoryRecommended File Suffix
BP EntityBP/entities/.json (e.g., goblin.json)
RP Client EntityRP/entity/.entity.json
RP GeometryRP/models/entity/ or RP/models/blocks/.geo.json
RP AnimationRP/animations/.animation.json
RP Animation ControllerRP/animation_controllers/.animation_controllers.json
RP Render ControllerRP/render_controllers/.render_controllers.json

JSON Formatting and Key Ordering

Although recent Bedrock versions allow C-style `//` and `/* */` comments in many JSON files, you should stick to strict, standard JSON without comments or trailing commas in your final files. External build tools, Python scripts, linters, and some specific sub-parsers inside the game itself can still choke on non-standard JSON. Use 2 spaces or 4 spaces for indentation, and configure your editor to format on save so diffs in version control stay clean.

Always order the top-level keys of your definition files the same way. Put `format_version` on the very first line, followed by the main definition object (`minecraft:entity`, `minecraft:block`, or `minecraft:item`). Inside that object, always place `description` first, followed by static `components`, and then dynamic sections like `component_groups` and `events` (for entities) or `permutations` (for blocks).

Inside `components`, group related components together rather than dropping them in at random. For blocks, put visual and geometry components first, then physical properties (collision, destructibility, friction), and finally interactive or technical components. For entities, group core health and movement components first, followed by AI goals (`minecraft:behavior.*`), and combat sensors last.

BP/blocks/decor/polished_basalt_bricks.json
{
  "format_version": "1.20.80",
  "minecraft:block": {
    "description": {
      "identifier": "studio:polished_basalt_bricks",
      "menu_category": {
        "category": "construction"
      },
      "states": {
        "studio:mossy": [
          false,
          true
        ]
      }
    },
    "components": {
      "minecraft:geometry": "minecraft:geometry.full_block",
      "minecraft:material_instances": {
        "*": {
          "texture": "studio_polished_basalt_bricks",
          "render_method": "opaque"
        }
      },
      "minecraft:destructible_by_mining": {
        "seconds_to_destroy": 2.0
      },
      "minecraft:destructible_by_explosion": {
        "explosion_resistance": 6.0
      },
      "minecraft:map_color": "#3a3a3e"
    },
    "permutations": [
      {
        "condition": "q.block_state('studio:mossy') == true",
        "components": {
          "minecraft:material_instances": {
            "*": {
              "texture": "studio_mossy_basalt_bricks",
              "render_method": "opaque"
            }
          }
        }
      }
    ]
  }
}

Texture Atlas Shortnames

In your Resource Pack, blocks and items do not reference PNG file paths directly inside their JSON definitions. Instead, they reference shortnames defined in `RP/textures/terrain_texture.json` (for blocks) and `RP/textures/item_texture.json` (for items). Because all active resource packs merge their atlas files into a single global pool when a world loads, un-prefixed shortnames are a prime source of cross-pack conflicts.

Prefix every single shortname in `terrain_texture.json` and `item_texture.json` with your namespace followed by an underscore, such as `studio_ruby_ore` or `studio_iron_dagger`. Do not use colons in texture shortnames; stick to underscores. Match the shortname to the actual file name of the PNG so you never have to guess which shortname points to which texture.

RP/textures/terrain_texture.json
{
  "resource_pack_name": "studio_pack",
  "texture_name": "atlas.terrain",
  "padding": 8,
  "num_mip_levels": 4,
  "texture_data": {
    "studio_polished_basalt_bricks": {
      "textures": "textures/blocks/decor/polished_basalt_bricks"
    },
    "studio_mossy_basalt_bricks": {
      "textures": "textures/blocks/decor/mossy_basalt_bricks"
    }
  }
}

Client Entity decoupling and Shortnames

Client entity files (`RP/entity/*.entity.json`) map long global identifiers for geometries, textures, materials, animations, and render controllers to local shortnames used only within that entity's scope. Keep these local shortnames simple and standardized across all your mobs. For instance, always name the base geometry shortname `default` and the base texture shortname `default`. That way, a generic render controller can reference `Geometry.default` and `Texture.default` and be reused across dozens of simple entities without writing a new render controller for every mob.

While local shortnames inside `description` should be simple (`default`, `walk`, `attack`), the global identifiers they point to must still carry your full studio namespace (`animation.studio.forest_troll.walk`). This gives you the best of both worlds: clean, readable animation controllers and render controllers, with zero risk of colliding with another creator's animations in the global pool.

RP/entity/monsters/forest_troll.entity.json
{
  "format_version": "1.10.0",
  "minecraft:client_entity": {
    "description": {
      "identifier": "studio:forest_troll",
      "materials": {
        "default": "entity_alphatest"
      },
      "textures": {
        "default": "textures/entity/monsters/forest_troll"
      },
      "geometry": {
        "default": "geometry.studio.forest_troll"
      },
      "animations": {
        "walk": "animation.studio.forest_troll.walk",
        "idle": "animation.studio.forest_troll.idle"
      },
      "scripts": {
        "animate": [
          "idle",
          {
            "walk": "q.modified_move_speed > 0.1"
          }
        ]
      },
      "render_controllers": [
        "controller.render.default"
      ],
      "spawn_egg": {
        "base_color": "#2d4c1e",
        "overlay_color": "#6e5233"
      }
    }
  }
}

Molang and Localization Style

When writing Molang expressions inside permutations, client entities, or animation controllers, always prefer the short aliases `q.`, `v.`, `t.`, and `c.` over `query.`, `variable.`, `temp.`, and `context.`. They evaluate identically in the engine, but the short prefixes keep complex conditions readable on a single line. Always name your custom Molang variables in `snake_case`, and if a variable is meant to be read across multiple animations or controllers on an entity, give it a clear descriptive name like `v.attack_time` or `v.is_charging`.

Never leave raw identifiers showing in the user interface. Every block, item, and entity must have a matching entry in `RP/texts/en_US.lang` (and any other languages you support). Follow the exact vanilla key structure: `tile.namespace:identifier.name=` for blocks, `item.namespace:identifier=` for items, and `entity.namespace:identifier.name=` for entities. Group your `.lang` file into clear sections using `##` comments so translators and team members can locate strings without scrolling through an unsorted wall of text.

Pay careful attention to trailing spaces in `.lang` files. Anything after the `=` sign is literal, so an accidental space at the end of a line will show up in tooltips and chat messages.

RP/texts/en_US.lang
## Pack Info
pack.name=Studio Mythos RP
pack.description=Resource assets for the Studio Mythos add-on.

## Entities
entity.studio:forest_troll.name=Forest Troll
item.spawn_egg.entity.studio:forest_troll.name=Spawn Forest Troll

## Blocks
tile.studio:polished_basalt_bricks.name=Polished Basalt Bricks

Script API Conventions

If your Behavior Pack uses JavaScript or TypeScript with the `@minecraft/server` Script API, treat your `BP/scripts/` directory like any modern software project. Keep your entry file (usually `BP/scripts/main.js`) strictly as a router that imports event listeners and system initializers from dedicated feature modules. Never dump thousands of lines of unrelated block, item, and entity logic into `main.js`.

Follow standard JavaScript conventions inside scripts: use `camelCase` for variable and function names, `PascalCase` for classes, and `UPPER_SNAKE_CASE` for constants (such as storing your identifier strings at the top of a file). When attaching dynamic properties to entities or the world, always namespace the property key (`studio:mana_count`) just like you would a block state.

BP/scripts/main.js
import { world } from "@minecraft/server";

const TROLL_ID = "studio:forest_troll";

world.afterEvents.entityDie.subscribe((event) => {
  const deadEntity = event.deadEntity;
  if (deadEntity.typeId !== TROLL_ID) {
    return;
  }
  deadEntity.dimension.spawnParticle("minecraft:huge_explosion_emitter", deadEntity.location);
});

Which versions this applies to

Applies to all modern Minecraft Bedrock versions (1.16.0 through 1.21+). No experimental toggles are required to follow these conventions, and the example JSON and Script API snippets use stable format versions.

When it does not work

What you seeWhyThe fix
Content Log shows `[Json][error] Failed to parse JSON` or `syntax error - unexpected '}'` and the block or entity does not appear in the game.A trailing comma was left after the last item in an array or object, or an unclosed quotation mark broke the file structure.Run the file through a strict JSON validator or enable JSON schema validation in your code editor, and remove any trailing commas before closing brackets `]` or braces `}`.
Block or item loads into the world with a purple-and-black missing texture checkerboard, or an entity is invisible on Android, iOS, or Realms while working fine on Windows.The file path in `terrain_texture.json`, `item_texture.json`, or the `.entity.json` file uses different capitalization than the actual folder or `.png` file on disk (for example, `textures/blocks/Polished_Basalt.png` vs `textures/blocks/polished_basalt`).Rename all directories and texture files on disk to strictly lowercase `snake_case`, and verify every texture path string in your JSON matches character-for-character.
Content Log reports `Invalid block identifier` or `Namespace cannot be 'minecraft'` when loading a world.You used `minecraft:` as the namespace for a custom block, custom item, or custom block state, or included uppercase letters and invalid symbols in the identifier.Change the namespace in `description.identifier` and all state keys to your own lowercase namespace (such as `studio:my_block`).
Two different add-ons installed in the same world overwrite each other's models, animations, or block textures.Generic shortnames were used in `terrain_texture.json` (like `ruby_ore`) or un-namespaced geometry/animation identifiers were used (like `geometry.goblin` or `animation.walk`).Prefix all texture atlas keys with your namespace (`studio_ruby_ore`) and include your namespace in every geometry, animation, and controller identifier (`geometry.studio.goblin`).

Reference, straight from the game files

Read out of the game itself, so the ids match the version you are building for.