How Feature Files Are Structured
Every file inside `BP/features/` contains a `format_version` and a single feature type object as its root child. The key of that object tells the engine which placement algorithm or proxy behavior to run. Inside that object is a mandatory `description` block containing an `identifier`. A critical rule in Bedrock is that the namespace-stripped part of the `identifier` must match the file's name on disk (ignoring directory paths and the `.json` extension).
Features do not place themselves into the world automatically. Either a feature rule (`BP/feature_rules/`) must call a feature at the start of a generation pass, or another proxy feature must invoke it as part of a chain.
{
"format_version": "1.13.0",
"minecraft:single_block_feature": {
"description": {
"identifier": "mypack:custom_blue_flower_feature"
},
"places_block": "minecraft:cornflower",
"enforce_survivability_rules": true,
"enforce_placement_rules": true,
"may_replace": [
"minecraft:air"
],
"may_attach_to": {
"bottom": [
"minecraft:grass_block",
"minecraft:dirt"
]
}
}
}Direct Placement Feature Types
Placement features are the leaves of your feature tree: they actually alter block states in the world. They check local block conditions—such as what block is currently at the target coordinate or what block is directly underneath—and write new blocks if those checks pass.
When building custom biomes or adding content to vanilla ones, you will spend most of your time configuring these core placement types before wrapping them in proxy features.
| Feature Type | What it does | Notes |
|---|---|---|
| minecraft:single_block_feature | Places one block at the origin if attachment and replacement conditions pass. | Ideal for custom plants, boulders, or single-block traps. |
| minecraft:ore_feature | Generates a cluster or vein of blocks replacing specified target blocks. | Used for mineral veins, dirt pockets, and stone variants underground. |
| minecraft:structure_template_feature | Loads and places a saved `.mcstructure` file from `BP/structures/`. | Supports rotation, integrity checks, and grounding constraints. |
| minecraft:tree_feature | Procedurally builds a tree from trunk, canopy, and root definitions. | Complex schema; for fixed-shape trees, structure templates are often easier. |
| minecraft:growing_plant_feature | Places a vertical column of blocks with an age or body/head split. | Used for cave vines, kelp, and weeping vines. |
| minecraft:multiface_feature | Spreads a multiface block across adjacent solid surfaces. | Used for glow lichen and sculk veins. |
| minecraft:geode_feature | Carves and fills a layered spherical geode with inner, middle, and outer shells. | Highly configurable layer blocks and crack generation. |
{
"format_version": "1.13.0",
"minecraft:ore_feature": {
"description": {
"identifier": "mypack:ruby_ore_feature"
},
"count": 8,
"replace_rules": [
{
"places_block": "mypack:ruby_ore",
"may_replace": [
"minecraft:stone",
"minecraft:andesite",
"minecraft:diorite",
"minecraft:granite"
]
},
{
"places_block": "mypack:deepslate_ruby_ore",
"may_replace": [
"minecraft:deepslate",
"minecraft:tuff"
]
}
]
}
}Proxy and Control Flow Features
Proxy features do not place blocks themselves. Instead, they take an input coordinate, transform it, test it, or multiply it, and then pass the resulting coordinate(s) down to another feature identifier. By chaining proxy features together, you can build complex placement logic without writing script code.
For example, to generate a patch of flowers, a feature rule might call a `minecraft:scatter_feature` that picks 16 random offsets around a center point and passes each offset to a `minecraft:single_block_feature`.
| Feature Type | What it does | Notes |
|---|---|---|
| minecraft:scatter_feature | Distributes placement attempts across X, Y, and Z using Molang expressions or distributions. | Can duplicate what a feature rule's distribution block does, or cluster sub-features. |
| minecraft:weighted_random_feature | Picks one feature from a weighted list of identifiers. | Great for varying structure variants or mixing flower colors in one patch. |
| minecraft:aggregate_feature | Executes a list of features in exact sequential order at the same origin. | Supports `early_out` to stop the sequence if a step fails or succeeds. |
| minecraft:sequence_feature | Passes the output coordinate of one feature as the input origin to the next. | Useful when placing a canopy or topper on top of a variable-height column. |
| minecraft:search_feature | Scans a 3D volume around the origin until it finds a valid spot for the target feature. | Helps snap features to cave ceilings, walls, or shorelines. |
| minecraft:snap_to_surface_feature | Moves the placement Y coordinate up or down to the nearest floor or ceiling. | Essential for cave decorations when starting from an arbitrary underground Y level. |
| minecraft:surface_relative_threshold_feature | Only runs the sub-feature if the origin is below the terrain surface by a given margin. | Prevents underground features from poking out into the sky. |
Chaining Features Together
The real power of the feature system comes from combining proxy features with placement features. Suppose you want to spawn a patch of mixed mushrooms. Your feature rule picks once per chunk, calling a `minecraft:scatter_feature` to spread 12 tries around the initial point. That scatter feature then calls a `minecraft:weighted_random_feature`, which chooses between red and brown single-block features.
When chaining features, keep coordinate evaluation order in mind. In `minecraft:scatter_feature`, the `coordinate_eval_order` setting (`xyz`, `xzy`, `yxz`, etc.) controls which axis is calculated first. Evaluating `xzy` is standard when your `y` expression uses a Molang query like `query.heightmap(variable.worldx, variable.worldz)`, because X and Z must be finalized before the heightmap can be queried.
{
"format_version": "1.13.0",
"minecraft:scatter_feature": {
"description": {
"identifier": "mypack:mixed_flower_patch_feature"
},
"places_feature": "mypack:random_flower_selector_feature",
"iterations": 16,
"scatter_chance": 100.0,
"coordinate_eval_order": "xzy",
"x": {
"distribution": "gaussian",
"extent": [ -4, 4 ]
},
"z": {
"distribution": "gaussian",
"extent": [ -4, 4 ]
},
"y": "query.heightmap(variable.worldx, variable.worldz)"
}
}Choosing Between Features and Feature Rules
Because `minecraft:scatter_feature` uses the exact same distribution syntax as a feature rule's `distribution` block, creators often wonder where to put their scatter math. If you only need to place one feature per attempt—such as a single ore vein—put the distribution directly in the `feature_rules` file and point it straight at your `minecraft:ore_feature`. This saves you an extra JSON file.
Reach for `minecraft:scatter_feature` when you need a two-tier distribution: for example, the feature rule decides if a flower patch spawns in the chunk at all, and the scatter feature handles placing the 16 individual flowers inside that patch.
{
"format_version": "1.13.0",
"minecraft:weighted_random_feature": {
"description": {
"identifier": "mypack:random_flower_selector_feature"
},
"features": [
[ "mypack:custom_blue_flower_feature", 3 ],
[ "minecraft: dandelion_feature", 1 ]
]
}
}Which versions this applies to
Applies to Bedrock Edition 1.13.0 and above. Most core feature types use format_version 1.13.0, while cave and cliff additions like geode_feature, multiface_feature, and snap_to_surface_feature require 1.16.220 or 1.18.0+. No experimental toggles are required for standard feature types in current releases.
When it does not work
| What you see | Why | The fix |
|---|---|---|
| Content Log Error: [Features] Feature <identifier> does not match expected file name. | Unlike entities or blocks, Bedrock strictly enforces that the identifier name (the part after the colon) matches the JSON file's name on disk. | Rename your JSON file so it matches the string after the namespace colon in `description.identifier`, or update the identifier to match the file name. |
| Features using `query.heightmap` in `scatter_feature` always generate at Y=0 or at the original input Y. | By default, axes are evaluated in X, Y, Z order. When Y is evaluated before Z, `variable.worldz` has not been offset yet or fails to resolve the target column properly. | Add `"coordinate_eval_order": "xzy"` to your `minecraft:scatter_feature` so both X and Z are calculated before the heightmap query runs on Y. |
| A custom `single_block_feature` or `ore_feature` loads without errors in the Content Log, but never places blocks in the world. | Either no feature rule is calling the feature, or the `may_replace` / `may_attach_to` block lists do not match the blocks actually present at the generation pass and coordinates. | Verify that a valid file in `BP/feature_rules/` references your feature, and check that `may_replace` includes `minecraft:air` (for surface features) or `minecraft:stone` / `minecraft:deepslate` (for underground features). |
Reference, straight from the game files
Read out of the game itself, so the ids match the version you are building for.
