The Three-Part Generation Pipeline
Unlike blocks or entities, which only need a single behavior file to exist, placing a custom structure into the world requires three separate files working together inside your Behavior Pack. If any link in this chain is missing or misnamed, the game will silently skip generation without crashing.
First, you need the binary structure file itself, stored in the BP/structures/ folder. Second, you need a Feature file in BP/features/, which wraps that structure and defines how it interacts with the blocks already in the world. Third, you need a Feature Rule file in BP/feature_rules/, which acts as the scheduler—deciding which biomes get the feature, how often it attempts to spawn, and at what altitude.
| Component | Pack Path | Role in Generation |
|---|---|---|
| Structure File | BP/structures/<namespace>/<name>.mcstructure | Stores the physical blocks, block states, and optionally entities. |
| Feature | BP/features/<name>.json | Loads the structure file, sets rotation, and checks placement constraints. |
| Feature Rule | BP/feature_rules/<name>.json | Determines biome filtering, generation pass, frequency, and coordinates. |
1. Exporting the .mcstructure File
Before writing any JSON, build your structure in a creative world. Give yourself a structure block by running /give @s structure_block. Place it near your build, open its interface, and set the mode to Save. Adjust the bounding box size and offset until your entire build fits inside the wireframe preview.
When naming the structure inside the UI, type a namespace prefix using a colon, such as wiki:desert_shrine. Using a namespace is essential; if you omit one, the game assumes the default mystructure namespace. If your build relies on empty air spaces that should not overwrite existing terrain (like the corners around a rounded ruin), place Structure Void blocks (/give @s structure_void) in those spots before saving.
Click the Export button at the bottom of the menu to save a .mcstructure file to your device. Move this file into your behavior pack under BP/structures/wiki/desert_shrine.mcstructure. Note how the colon in the UI name becomes a subfolder inside BP/structures/.
2. Creating the Structure Template Feature
With the binary file in place, create a JSON file in BP/features/. For structures, you use the minecraft:structure_template_feature type. The most important rule in the feature system is that the file name (minus .json) must match the identifier declared inside the file's description block. If your identifier is wiki:desert_shrine_feature, the file must be named desert_shrine_feature.json.
The adjustment_radius property is your best tool for preventing structures from floating in the air or burying themselves into hillsides. It tells the engine to scan outward up to that many blocks to find a valid vertical level that satisfies your constraints.
{
"format_version": "1.13.0",
"minecraft:structure_template_feature": {
"description": {
"identifier": "wiki:desert_shrine_feature"
},
"structure_name": "wiki:desert_shrine",
"adjustment_radius": 8,
"facing_direction": "random",
"constraints": {
"grounded": {},
"unburied": {},
"block_intersection": {
"block_allowlist": [
"minecraft:air",
"minecraft:sand",
"minecraft:deadbush"
]
}
}
}
}Understanding Feature Constraints
The constraints object inside minecraft:structure_template_feature acts as a safety check before a single block is placed. If the target location fails any constraint you include, the generation attempt is cancelled for that spot.
Be careful when combining constraints. Requiring both grounded and unburied on a very wide structure in a steep mountain biome will cause almost every placement attempt to fail, because the terrain drops off faster than the adjustment_radius can compensate for. For underground dungeons, leave out grounded and unburied entirely, and omit block_intersection so the room can carve directly into solid stone.
| Constraint | What it does | Notes |
|---|---|---|
| grounded | Requires the entire bottom layer of the structure's bounding box to rest on solid blocks. | Prevents edges from hanging over cliffs or water. |
| unburied | Requires the top layer of the bounding box to be exposed to air. | Prevents surface buildings from spawning inside hills. |
| block_intersection | Defines which existing world blocks the structure's bounding box is allowed to replace. | Uses a block_allowlist array of block identifiers. |
3. Writing the Feature Rule
The feature rule connects your feature to the world generator. Create a JSON file in BP/feature_rules/. Unlike features, feature rules do not strictly require the filename to match the identifier, though keeping them identical is good practice for organization.
Inside the conditions block, minecraft:placement_pass dictates when in the chunk creation lifecycle your structure is placed. For buildings, ruins, and custom trees on the surface, surface_pass is standard. The minecraft:biome_filter uses standard filter syntax to target biomes by their tags—in this example, any biome tagged as a desert.
The distribution block controls the math of placement. Setting scatter_chance to a fraction (via numerator and denominator) with iterations set to 1 is the cleanest way to make rare structures. An iteration of 1 with a 1-in-50 scatter chance means the game picks one random X/Z coordinate in every valid desert chunk, and rolls a 50-sided die to see if the shrine spawns there.
{
"format_version": "1.13.0",
"minecraft:feature_rules": {
"description": {
"identifier": "wiki:desert_shrine_feature_rule",
"places_feature": "wiki:desert_shrine_feature"
},
"conditions": {
"placement_pass": "surface_pass",
"minecraft:biome_filter": [
{
"test": "has_biome_tag",
"operator": "==",
"value": "desert"
}
]
},
"distribution": {
"iterations": 1,
"scatter_chance": {
"numerator": 1,
"denominator": 50
},
"x": {
"distribution": "uniform",
"extent": [ 0, 16 ]
},
"y": "query.heightmap(variable.worldx, variable.worldz)",
"z": {
"distribution": "uniform",
"extent": [ 0, 16 ]
}
}
}
}Controlling Placement Depth and Offsets
In the feature rule above, the y coordinate uses the Molang expression query.heightmap(variable.worldx, variable.worldz). This evaluates to the Y level of the highest solid block at the chosen X and Z coordinates. Because a structure places from its lowest corner upward, placing it directly at the heightmap value sets it cleanly on the surface.
If your structure has a basement, foundation, or roots that should sink into the ground, you can subtract from the heightmap directly in the feature rule's Molang string. For example, setting y to "query.heightmap(variable.worldx, variable.worldz) - 4" buries the bottom four layers of your .mcstructure below the surface. Note that if you sink a structure this way, you must either remove the unburied and block_intersection constraints from your feature file or add ground blocks like dirt and stone to the block_allowlist, otherwise the underground foundation will fail the intersection test against the existing terrain.
Which versions this applies to
Applies to Bedrock Edition 1.13.0 and newer. The format_version 1.13.0 remains the standard schema for features and feature rules even in modern 1.20+ and 1.21+ releases. No experimental toggles are required to use structure template features or feature rules.
When it does not work
| What you see | Why | The fix |
|---|---|---|
| Content Log shows: [Features][error]-feature_name | Feature identifier 'wiki:desert_shrine_feature' does not match file name | The game engine enforces a strict naming convention on all files in the BP/features/ directory. If the JSON file is named shrine.json, the identifier must be <namespace>:shrine. | Rename your .json file in BP/features/ so that the filename (excluding the .json extension and any subfolders) exactly matches the part of the identifier after the colon. |
| The feature and feature rule load without any Content Log errors, and testing the structure via /structure load works, but it never spawns naturally. | Your constraints in the feature file are likely too strict for the terrain, or the structure_name path does not match the subfolder layout in BP/structures/. | Temporarily remove the entire constraints block from your feature file and set scatter_chance in your feature rule to 1/1. Fly around newly generated chunks. If it spawns now, re-introduce constraints one by one and expand your block_allowlist to include grass, tallgrass, snow_layer, or leaves that might be blocking placement. |
| Parts of the structure get cut off cleanly at chunk borders, or the structure fails to place whenever it crosses a chunk boundary. | Structure template features are evaluated per chunk and have a practical size limit. A single structure template feature that extends well beyond a 16x16 footprint risks overhanging into adjacent chunks that have not reached the required placement pass yet. | Keep natural generation structures via structure_template_feature compact (ideally within 16x16 on X and Z, or slightly larger with adjustment_radius accounted for). For massive multi-chunk structures, split the build into smaller pieces and chain them together using an aggregate_feature or snap-to-surface features. |
Reference, straight from the game files
Read out of the game itself, so the ids match the version you are building for.
