File Location and Basic Structure
Every spawn rule is a standalone JSON file stored inside the `BP/spawn_rules/` directory of your behavior pack. While you can organize them into subfolders, the file name itself does not determine which mob it affects. Instead, the game reads the `identifier` inside the `description` block, which must match the identifier of a registered entity (and that entity must have `is_spawnable` or valid runtime behavior).
A spawn rule file has two main sections inside the `minecraft:spawn_rules` object: `description` and `conditions`. The `description` links the rule to an entity and assigns it to a mob cap pool. The `conditions` array holds one or more sets of requirements. Each object inside the `conditions` array represents an independent spawning pass; for an entity to spawn via a specific condition block, every component inside that single block must evaluate to true at the chosen block coordinate.
{
"format_version": "1.8.0",
"minecraft:spawn_rules": {
"description": {
"identifier": "my_pack:custom_boar",
"population_control": "animal"
},
"conditions": [
{
"minecraft:spawns_on_surface": {},
"minecraft:brightness_filter": {
"min": 7,
"max": 15,
"adjust_for_weather": false
},
"minecraft:weight": {
"default": 10
},
"minecraft:herd": {
"min_size": 2,
"max_size": 4
},
"minecraft:biome_filter": {
"test": "has_biome_tag",
"operator": "==",
"value": "forest"
}
}
]
}
}Population Control Pools
The `population_control` field in the description dictates which global and local mob cap the entity counts toward. Bedrock Edition stops attempting to spawn entities from a specific pool once the number of loaded entities in that category reaches its cap. Choosing the wrong pool can either flood the world with your mob or prevent vanilla mobs in that category from appearing.
Vanilla usage strictly separates hostile monsters, passive land animals, aquatic life, and ambient creatures like bats. If you omit `population_control` or misspell the pool name, the spawn rule will fail to parse.
| Pool Value | What it does | Vanilla Examples |
|---|---|---|
| monster | Counts toward the hostile mob cap; evaluated every tick in valid light/surface conditions. | Zombie, Skeleton, Creeper, Spider |
| animal | Counts toward the passive creature cap; spawns much less frequently than monsters. | Cow, Pig, Sheep, Chicken |
| water_animal | Counts toward the aquatic mob cap; typically paired with `minecraft:spawns_underwater`. | Cod, Salmon, Squid, Dolphin |
| ambient | Counts toward the ambient cap; used for non-interactive atmosphere mobs. | Bat |
| pillager | Counts toward the illager patrol and outpost cap. | Pillager, Vindicator |
Core Condition Components
Each entry in the `conditions` array is built from a set of filter and configuration components. If a condition block does not include a location component such as `minecraft:spawns_on_surface` or `minecraft:spawns_underground`, the game will not know where along the Y-axis to test for valid spawn spaces, and the mob will never spawn.
You also need `minecraft:weight` in almost every condition block. Weight is relative to all other mobs attempting to spawn in the same biome and `population_control` pool. For example, a weight of `100` in the `monster` pool makes a mob as common as a Zombie or Spider, whereas a weight of `5` makes it as rare as an Enderman.
| Component | What it does | Notes |
|---|---|---|
| minecraft:spawns_on_surface | Allows the mob to spawn on the highest solid block at a given X/Z coordinate. | Takes an empty object `{}`. |
| minecraft:spawns_underground | Allows the mob to spawn in caves or beneath ceilings. | Takes an empty object `{}`. Can be combined with `minecraft:spawns_on_surface` in the same block. |
| minecraft:spawns_underwater | Allows the mob to spawn inside water blocks. | Takes an empty object `{}`. |
| minecraft:spawns_lava | Allows the mob to spawn inside lava blocks. | Used by vanilla Striders. |
| minecraft:weight | Sets how likely this mob is chosen relative to other mobs in the same pool. | Uses `"default": <int>`. Higher numbers spawn more often. |
| minecraft:herd | Controls how many mobs spawn together in a single cluster. | Uses `min_size` and `max_size`. Can also take an `event` string to fire on the entity upon spawn. |
| minecraft:brightness_filter | Restricts spawning to a light level range (`min` and `max`, from 0 to 15). | Includes boolean `adjust_for_weather` to treat thunderstorms as dark. |
| minecraft:height_filter | Restricts spawning to a specific Y-coordinate range. | Uses `min` and `max` integers. |
| minecraft:difficulty_filter | Restricts spawning to world difficulties (`peaceful`, `easy`, `normal`, `hard`). | Uses `min` and `max` difficulty strings. Required on most hostile mobs so they do not spawn in Peaceful. |
| minecraft:spawns_on_block_filter | Limits spawning to specific ground blocks. | Accepts a single block string or an array of block identifiers (e.g., `"minecraft:grass_block"`). |
| minecraft:spawns_on_block_prevented_filter | Prevents spawning if the ground block is in this list. | Accepts a block string or array of block identifiers. |
| minecraft:density_limit | Caps how many of this specific entity can exist in the local area. | Uses `surface` and/or `underground` integer keys. |
Filtering Biomes with Biome Tags
The `minecraft:biome_filter` component determines which biomes the condition applies to. It uses the standard Bedrock filter syntax with `test`, `operator`, and `value`, along with `all_of` and `any_of` groups for complex logic. In almost all vanilla spawn rules, the test used is `has_biome_tag`.
Rather than checking for explicit biome names like `birch_forest` or `plains`, vanilla spawn rules check for tags attached to biomes, such as `monster`, `animal`, `overworld`, `nether`, `ocean`, or `cold`. It is best practice in vanilla usage to exclude biomes like `mooshroom_island` and `deep_dark` when configuring standard Overworld monsters so your custom mobs respect the safe zones players expect.
{
"format_version": "1.8.0",
"minecraft:spawn_rules": {
"description": {
"identifier": "my_pack:forest_stalker",
"population_control": "monster"
},
"conditions": [
{
"minecraft:spawns_on_surface": {},
"minecraft:spawns_underground": {},
"minecraft:brightness_filter": {
"min": 0,
"max": 7,
"adjust_for_weather": true
},
"minecraft:difficulty_filter": {
"min": "easy",
"max": "hard"
},
"minecraft:weight": {
"default": 80
},
"minecraft:herd": {
"min_size": 1,
"max_size": 2
},
"minecraft:biome_filter": {
"all_of": [
{
"test": "has_biome_tag",
"operator": "==",
"value": "overworld"
},
{
"test": "has_biome_tag",
"operator": "!=",
"value": "mooshroom_island"
},
{
"test": "has_biome_tag",
"operator": "!=",
"value": "deep_dark"
},
{
"any_of": [
{
"test": "has_biome_tag",
"operator": "==",
"value": "forest"
},
{
"test": "has_biome_tag",
"operator": "==",
"value": "taiga"
}
]
}
]
}
}
]
}
}Overriding and Disabling Vanilla Spawn Rules
Because Bedrock merges behavior packs from lowest to highest priority, you can alter how vanilla mobs spawn by creating a file with the exact same path and identifier as the vanilla file (for example, `BP/spawn_rules/zombie.json` targeting `minecraft:zombie`).
If you want to completely disable a vanilla mob from spawning naturally without editing its entity file, provide its `description` block and leave the `conditions` array completely empty (`"conditions": []`). Do not delete the `conditions` key itself, as the schema validator expects the array to be present.
{
"format_version": "1.8.0",
"minecraft:spawn_rules": {
"description": {
"identifier": "minecraft:phantom",
"population_control": "monster"
},
"conditions": []
}
}Which versions this applies to
Applies to Minecraft Bedrock 1.8.0 and all current versions up to 1.21+. Almost all vanilla and custom spawn rule files declare "format_version": "1.8.0" or "1.12.0" at the root. No experimental toggles are required to use custom or overridden spawn rules.
When it does not work
| What you see | Why | The fix |
|---|---|---|
| The custom mob spawns fine from a spawn egg or `/summon`, and no Content Log errors appear, but it never spawns naturally in the world. | The condition block is missing a placement component (`minecraft:spawns_on_surface`, `minecraft:spawns_underground`, or `minecraft:spawns_underwater`) or `minecraft:weight`. Without both a placement type and a weight, the game silently skips the condition. | Ensure every object inside the `conditions` array includes `"minecraft:weight": { "default": <number> }` and at least one of the `minecraft:spawns_*` location components. |
| Content Log displays a schema error such as: `[Json][error] spawn_rules/my_mob.json | minecraft:spawn_rules | description | population_control: value is not a valid population control type`. | You used an invalid string in `population_control`, such as `hostile`, `passive`, or `water` instead of the exact vanilla pool names. | Change `population_control` to one of the supported strings: `monster`, `animal`, `water_animal`, `ambient`, or `pillager`. |
| Passive custom mobs using `"population_control": "animal"` only seem to appear in newly generated chunks and almost never spawn around an existing base. | The `animal` pool has a very low global mob cap and slow spawn cycle compared to `monster`. If vanilla cows, sheep, and pigs are already loaded in the surrounding chunks, the `animal` cap is full. | Add `minecraft:spawns_on_block_filter` set to `"minecraft:grass_block"` so your mob competes properly during chunk generation, increase its `minecraft:weight`, or test your spawn rules in a fresh world after running `/kill @e[type=!player]` to clear the animal cap. |
Reference, straight from the game files
Read out of the game itself, so the ids match the version you are building for.
