Wiki 9Minecraft Wiki 9Minecraft

Using Block States in Commands and Custom Blocks

How to syntax, query, and define block states for vanilla and custom blocks in Bedrock Edition.

6Sections
5Code examples
4Known errors

Block states are key-value properties attached to a block instance in the world that dictate its orientation, variant, or mechanical behavior, such as which way a stair faces or whether a lamp is lit. In Bedrock Edition, following the flattening of block IDs and the retirement of numeric data values in format version 1.19.70 and above, explicit block state arrays are the mandatory way to place, test, and replace specific block configurations in commands and functions. They are also the foundational tool for custom block creators who want a single block identifier to shift models, textures, or collision shapes dynamically using block permutations.

Block State Syntax in Commands

Since Bedrock Edition updated its command parser in 1.19.70, numeric metadata values (like writing `/setblock ~ ~ ~ wool 14` to get red wool) are no longer accepted in commands with a current `min_engine_version` or in the in-game chat. Instead, many former numeric variants have been split into distinct block identifiers (such as `minecraft:red_wool`), while behavioral and rotational properties are controlled via a bracketed array of block states directly following the block ID.

The syntax uses square brackets `[]` containing comma-separated `"state_name"=value` pairs. Notice that in Bedrock's command parser, the state name should be wrapped in double quotes, although the parser in recent versions often tolerates unquoted keys for vanilla states. However, custom block states always contain a namespace colon (for example, `"wiki:lit"`), which strictly requires quotation marks so the command parser does not fail on the colon character. Because of this, wrapping every state key in double quotes is the safest habit to form.

When you omit the bracketed state list entirely in a placement command like `/setblock` or `/fill`, the game places the block using its default state values. When you omit a state in a testing command like `/execute if block` or `/fill ... replace`, the game treats the omitted states as wildcards, matching any block of that identifier regardless of what values those unmentioned states currently hold.

BP/functions/state_examples.mcfunction
# Place an oak log lying horizontally along the X axis
setblock ~ ~1 ~ minecraft:oak_log ["pillar_axis"="x"]

# Fill a region with upside-down stone brick stairs facing north
fill ~1 ~ ~1 ~5 ~ ~5 minecraft:stone_brick_stairs ["upside_down_bit"=true, "weirdo_direction"=2]

# Replace only waterlogged lanterns with air, ignoring non-waterlogged ones
# (Note: testing specific states in replace filters matches unspecified states as wildcards)
fill ~-5 ~-5 ~-5 ~5 ~5 ~5 minecraft:air [] replace minecraft:lantern ["hanging"=true]

# Execute a command if the player is standing on a fully grown wheat crop
execute as @a at @s if block ~ ~ ~ minecraft:wheat ["growth"=7] run title @s actionbar Crop is ready!

Data Types and Vanilla State Quirks

Every block state in Bedrock Edition belongs to one of three strict data types: boolean, integer, or string. Getting the type wrong in a command or a JSON file is the single most common reason a command fails to parse. If a state expects a boolean, passing `"true"` in quotes (a string) or `1` (an integer) will throw a syntax error. Conversely, string values must always be enclosed in double quotes.

One peculiarity of Bedrock Edition's vanilla block states is that many of them are direct exposes of the game's internal C++ NBT serialization names, which dates back to early Pocket Edition. Consequently, you will encounter state names ending in `_bit` (which are always booleans, despite the name suggesting a binary integer `0` or `1`) and unconventional directional names like `weirdo_direction` on stairs or `facing_direction` vs `minecraft:cardinal_direction` depending on when the vanilla block was added to the game.

When working inside a `.mcfunction` file or an add-on script, there is no auto-complete prompt to tell you whether a block uses `facing_direction` (an integer from 0 to 5) or `minecraft:cardinal_direction` (a string like `"north"`). The most reliable way to discover the exact states and value types for a vanilla block is to open a world with cheats enabled, type `/setblock ~ ~ ~ <block_name> [` into the chat bar, and read the auto-complete suggestions provided by the client's command UI.

Data TypeCommand Syntax ExampleJSON Array DefinitionNotes & Vanilla Examples
Boolean["open_bit"=true][false, true]Never wrap true or false in quotes. Many older vanilla states end in '_bit' (e.g., 'upside_down_bit', 'toggle_bit') but still require literal true/false.
Integer["growth"=7][0, 1, 2, 3, 4, 5, 6, 7]Unquoted whole numbers. In custom blocks, you can also define a sequential range using an object: {"min": 0, "max": 7}.
String["pillar_axis"="y"]["y", "x", "z"]Both the state name and the string value must be wrapped in double quotes in commands.

Declaring Custom Block States in JSON

When building a custom block in a behavior pack, you can define your own states inside the `description` object under the `states` key (Note: in very old format versions prior to 1.19.40, this key was named `properties`, which is now deprecated). Every custom state name must include a namespace prefix separated by a colon, typically matching your add-on's namespace, such as `"my_pack:power_level"`. The only exception to this rule is when you are using built-in `minecraft:` traits, which automatically inject official `minecraft:` states onto your block.

Each state you declare is assigned an array of valid values. The first value listed in the array becomes the default state of the block when it is placed in the world without explicit command arguments or before any placement traits run. All values in a single state's array must share the same data type—you cannot mix integers and strings in the same state.

You must also pay close attention to the permutation limit. Behind the scenes, Bedrock pre-calculates every possible combination of your block's states when loading the world. The total number of combinations is found by multiplying the number of values in each state together. For example, a block with a 4-value direction state, a 2-value boolean state, and an 8-value integer state has `4 × 2 × 8 = 64` total combinations. Bedrock enforces a hard ceiling on the total number of state combinations a single custom block can have (64 combinations in standard format versions). If your states multiply to a number above the engine's ceiling, the block will fail to register and vanish from the game.

BP/blocks/industrial_lamp.json
{
  "format_version": "1.20.80",
  "minecraft:block": {
    "description": {
      "identifier": "wiki:industrial_lamp",
      "menu_category": {
        "category": "construction"
      },
      "states": {
        "wiki:lit": [
          false,
          true
        ],
        "wiki:color_mode": [
          "warm",
          "cool",
          "alert"
        ],
        "wiki:dimmer": {
          "values": {
            "min": 0,
            "max": 3
          }
        }
      }
    },
    "components": {
      "minecraft:destructible_by_mining": {
        "seconds_to_destroy": 1.5
      },
      "minecraft:geometry": "geometry.wiki.industrial_lamp",
      "minecraft:material_instances": {
        "*": {
          "texture": "wiki_lamp_off",
          "render_method": "opaque"
        }
      },
      "minecraft:light_emission": 0
    }
  }
}

Driving Permutations with Block States and Molang

Declaring a state in the `description` does nothing on its own; the block simply stores the value in the world save. To make the block actually react to its state—by changing its texture, rotating its geometry, emitting light, or altering its collision box—you use the `permutations` array in your block's JSON file.

Each entry in the `permutations` array contains a `condition` string written in Molang and a `components` object. Whenever a block's state changes in the world, the game evaluates the `condition` of every permutation from top to bottom. For every condition that evaluates to true, the components inside that permutation override the base components defined at the root of the block.

To read a block state inside a Molang condition, use the query `q.block_state('namespace:state_name')`. Notice that inside the Molang string, the state name is wrapped in single quotes so it does not break the surrounding JSON double quotes. If the state is a boolean, `q.block_state('wiki:lit')` returns `1.0` for true and `0.0` for false, so you can use it directly as a condition or compare it with `== true` or `!q.block_state('wiki:lit')`. If the state is a string, compare it against another single-quoted string, such as `q.block_state('wiki:color_mode') == 'alert'`.

BP/blocks/industrial_lamp.json
{
  "format_version": "1.20.80",
  "minecraft:block": {
    "description": {
      "identifier": "wiki:industrial_lamp",
      "states": {
        "wiki:lit": [false, true],
        "wiki:dimmer": [0, 1, 2, 3]
      }
    },
    "components": {
      "minecraft:geometry": "geometry.wiki.industrial_lamp",
      "minecraft:material_instances": {
        "*": {
          "texture": "wiki_lamp_off",
          "render_method": "opaque"
        }
      },
      "minecraft:light_emission": 0
    },
    "permutations": [
      {
        "condition": "q.block_state('wiki:lit') && q.block_state('wiki:dimmer') == 1",
        "components": {
          "minecraft:light_emission": 5,
          "minecraft:material_instances": {
            "*": {
              "texture": "wiki_lamp_low",
              "render_method": "opaque"
            }
          }
        }
      },
      {
        "condition": "q.block_state('wiki:lit') && q.block_state('wiki:dimmer') == 2",
        "components": {
          "minecraft:light_emission": 10,
          "minecraft:material_instances": {
            "*": {
              "texture": "wiki_lamp_med",
              "render_method": "opaque"
            }
          }
        }
      },
      {
        "condition": "q.block_state('wiki:lit') && q.block_state('wiki:dimmer') == 3",
        "components": {
          "minecraft:light_emission": 15,
          "minecraft:material_instances": {
            "*": {
              "texture": "wiki_lamp_high",
              "render_method": "opaque"
            }
          }
        }
      }
    ]
  }
}

Using Built-in Block Traits for Orientation

Before format version 1.19.80, making a custom block face the player when placed required registering custom states and intercepting the placement event using experimental features or Scripting APIs to calculate the player's rotation. Today, Bedrock provides `traits` inside the block `description` block, which automatically attach official `minecraft:` block states to your custom block and set their values during placement without needing any scripts.

The two placement traits currently available are `minecraft:placement_direction` and `minecraft:placement_position`. When you enable `minecraft:placement_direction`, you specify which `enabled_states` you want in an array: `"minecraft:cardinal_direction"` (gives a 4-way horizontal string state: `"north"`, `"south"`, `"east"`, `"west"`) and/or `"minecraft:facing_direction"` (gives a 6-way string state that adds `"up"` and `"down"`). You can also set a `y_rotation_offset` in increments of 90 degrees if your block's model in Blockbench faces a different default direction than the trait expects.

Similarly, `minecraft:placement_position` provides `"minecraft:block_face"` (which side of the existing block the player clicked against) and `"minecraft:vertical_half"` (`"bottom"` or `"top"`, useful for slabs and stairs). Because these traits inject real block states onto your block, you query them in your `permutations` array using `q.block_state('minecraft:cardinal_direction')` and can also set or test them directly in `/setblock` and `/execute if block` commands just like custom states.

BP/blocks/directional_crate.json
{
  "format_version": "1.20.80",
  "minecraft:block": {
    "description": {
      "identifier": "wiki:directional_crate",
      "traits": {
        "minecraft:placement_direction": {
          "enabled_states": [
            "minecraft:cardinal_direction"
          ],
          "y_rotation_offset": 180.0
        }
      }
    },
    "components": {
      "minecraft:geometry": "geometry.wiki.crate",
      "minecraft:material_instances": {
        "*": {
          "texture": "wiki_crate_side"
        },
        "north": {
          "texture": "wiki_crate_front"
        }
      }
    },
    "permutations": [
      {
        "condition": "q.block_state('minecraft:cardinal_direction') == 'north'",
        "components": {
          "minecraft:transformation": {
            "rotation": [0, 0, 0]
          }
        }
      },
      {
        "condition": "q.block_state('minecraft:cardinal_direction') == 'south'",
        "components": {
          "minecraft:transformation": {
            "rotation": [0, 180, 0]
          }
        }
      },
      {
        "condition": "q.block_state('minecraft:cardinal_direction') == 'west'",
        "components": {
          "minecraft:transformation": {
            "rotation": [0, 90, 0]
          }
        }
      },
      {
        "condition": "q.block_state('minecraft:cardinal_direction') == 'east'",
        "components": {
          "minecraft:transformation": {
            "rotation": [0, 270, 0]
          }
        }
      }
    ]
  }
}

Reading and Writing States via the Script API

While commands and functions can replace an entire block with `/setblock`, doing so destroys and recreates the block, which resets any other states you didn't explicitly type into the command and triggers block placement sounds or particles. When you want to toggle a single state on a block in place—for example, flipping `"wiki:lit"` from `false` to `true` when a player interacts with the block, while preserving whatever `"minecraft:cardinal_direction"` or `"wiki:dimmer"` value the block currently has—the `@minecraft/server` Script API is the cleanest tool for the job.

In the Script API, a `Block` object in a dimension does not hold its states directly on the `Block` class. Instead, every block has a `.permutation` property, which returns a `BlockPermutation` object representing that exact combination of states. From that `BlockPermutation`, you can call `.getState('state_name')` to read a single state's current value, or `.getAllStates()` to get a JavaScript object containing all key-value state pairs on that block.

Because `BlockPermutation` instances are immutable in the Script API, calling `.withState('state_name', newValue)` does not modify the block in the world right away. Instead, `.withState()` returns a brand-new `BlockPermutation` copy with that one state updated and all other existing states preserved. To actually apply that change to the world, you pass the newly returned permutation into `block.setPermutation(newPermutation)`.

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

// Example: Toggle the 'wiki:lit' state when a player interacts with the custom lamp using a stick
world.beforeEvents.playerInteractWithBlock.subscribe((event) => {
  const { block, itemStack, player } = event;

  if (block.typeId !== "wiki:industrial_lamp") return;
  if (!itemStack || itemStack.typeId !== "minecraft:stick") return;

  // Prevent default interaction if necessary
  event.cancel = true;

  // Read current permutation and state
  const currentPerm = block.permutation;
  const isLit = currentPerm.getState("wiki:lit");
  const currentDimmer = currentPerm.getState("wiki:dimmer");

  // Mutating world state must happen outside the read-only beforeEvent execution context
  // or via system.run in modern @minecraft/server versions:
  import("@minecraft/server").then(({ system }) => {
    system.run(() => {
      if ( player.isSneaking ) {
        // Cycle the dimmer state from 0 to 3 while preserving 'wiki:lit'
        const nextDimmer = (currentDimmer + 1) % 4;
        const updatedPerm = currentPerm.withState("wiki:dimmer", nextDimmer);
        block.setPermutation(updatedPerm);
      } else {
        // Flip the boolean 'wiki:lit' state while preserving 'wiki:dimmer'
        const updatedPerm = currentPerm.withState("wiki:lit", !isLit);
        block.setPermutation(updatedPerm);
      }
    });
  });
});

Which versions this applies to

Applies to Minecraft Bedrock Edition 1.19.80 and above (tested through 1.20.80 and 1.21.x). Bracketed block state syntax in commands became standard in 1.19.70, and custom block 'states' alongside placement 'traits' have been stable since 1.19.80. No experimental toggles are required for custom block states, permutations, or placement traits.

When it does not work

What you seeWhyThe fix
Command fails in chat or Content Log with: "Syntax error: Unexpected ':': at ..."You used a custom block state or a namespaced vanilla state (such as minecraft:cardinal_direction) inside a command without wrapping the state name in double quotes. The command parser sees the colon character and breaks before reading the '=' sign.Wrap all state names inside the square brackets in double quotes, for example: /setblock ~ ~ ~ wiki:industrial_lamp ["wiki:lit"=true] instead of [wiki:lit=true].
Command fails with: "Block state 'open_bit' has invalid value type" or "Cannot set block state"You passed the wrong data type to the state—most commonly passing 0 or 1 to a state ending in '_bit', or wrapping a boolean or integer in double quotes like "true" or "7".Match the exact primitive type expected by the state. States ending in '_bit' are booleans and require unquoted true or false. Integer states require unquoted numbers, and string states require double quotes around the value.
Custom block does not appear in the creative menu, cannot be placed with /setblock, and the Content Log reports that the block exceeded the maximum number of permutations.The product of all value counts across every state in your block's 'states' (plus any states added by 'traits') exceeds 64. For instance, two integer states of 0-9 produce 10 x 10 = 100 state combinations, even if your 'permutations' array only lists two conditions.Reduce the number of states or the number of allowed values per state on that block so that multiplying the lengths of all state arrays together equals 64 or less. If you need more combinations, split the block into multiple block identifiers.
Content Log shows a Molang error or the block never changes appearance when its state changes.Inside the permutation condition, you either used the old 'q.block_property()' query with a mismatched name, forgot single quotes around the state name inside 'q.block_state()', or omitted the namespace prefix on a custom state.Ensure your condition string uses single quotes inside the JSON string and includes the full namespace, such as: "condition": "q.block_state('wiki:color_mode') == 'alert'".

Reference, straight from the game files

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