Base Variables and Execution Context
Every target selector begins with an `@` symbol followed by a single-letter variable code. Before adding any bracketed filter arguments, the base variable dictates the initial pool of entities the game engine gathers and the default sorting order applied to that pool. Choosing the wrong base variable is the most common source of performance degradation in repeating function loops, because some variables scan the entire loaded world while others only scan the internal player list.
Understanding the difference between `@s` (the executing entity) and `@p` (the nearest player) is critical in add-on development. When an entity runs a command via its behavior file or an animation controller, that entity is the execution context (`@s`). If you mistakenly use `@p` inside an entity's behavior response, the command will target the nearest human player rather than the mob that triggered the event. Conversely, if a command block runs a command, `@s` evaluates to nothing because a block is not an entity.
In multiplayer or NPC-heavy maps, `@c` and `@v` provide specialized targeting originally built for Education Edition features that also work in standard Bedrock when agents are spawned. However, for 99% of standard behavior pack logic, your workhorse variables will be `@s`, `@e`, and `@a`.
| Variable | Target Pool | Default Sort & Behavior |
|---|---|---|
| @p | Players only (alive) | Selects the single closest player to the execution position. Ignores dead players. |
| @a | All players (alive or dead) | Selects every connected player across all dimensions unless restricted by spatial arguments. |
| @r | Players (by default) | Selects one random living player. Can target non-player entities if the 'type' argument is explicitly set. |
| @e | All loaded entities | Selects every living entity and player in loaded chunks across the active dimension. Does not target dying entities. |
| @s | The executing entity | Selects the single entity or player currently running the command. Fails silently if executed by the server or a command block. |
| @initiator | Interacting player | Selects the player who clicked an NPC button or triggered a block/entity interaction event. |
| @c | Player's Agent | Selects the Education Edition Agent belonging to the executing player. |
| @v | All Agents | Selects all active Education Edition Agents in the world. |
Spatial and Volume Filtering
Spatial arguments narrow down targets based on where they are in the world. Bedrock provides two distinct geometric methods for spatial targeting: spherical radius (`r` and `rm`) and axis-aligned bounding boxes (`dx`, `dy`, `dz`). These arguments evaluate relative to the current execution position, unless you explicitly override the origin point inside the selector using `x`, `y`, and `z`.
Spherical radius checks measure the straight-line Euclidean distance from the execution origin to the target's feet (specifically, the bottom center of their collision box). The `r` argument sets the maximum distance, while `rm` sets the minimum distance, creating a hollow sphere or 'donut' deadzone around the origin. You should always pair `@e` with an `r` value whenever possible to prevent the command from affecting entities hundreds of blocks away in remote ticking areas.
Bounding box arguments (`dx`, `dy`, `dz`) define a rectangular prism starting at the execution coordinates (or the specified `x`, `y`, `z` coordinates) and extending outward by the given delta values. Unlike radius checks, which check a single point at the entity's feet, `dx`, `dy`, and `dz` check for an intersection between the defined volume and the target entity's full hitbox. Be aware that when you supply explicit `x`, `y`, `z` coordinates with `dx`, `dy`, `dz`, the base coordinates snap to the lower North-West corner of the block grid unless you provide decimal values.
| Argument | Value Type | What it does |
|---|---|---|
| x, y, z | Float or Tilde (~) | Shifts the origin point for distance or volume calculations without changing the command's actual execution position. |
| r, rm | Positive Float | Maximum radius (r) and minimum radius (rm) in blocks from the selector's origin point. |
| dx, dy, dz | Float | Defines a box volume extending from the origin point along the X, Y, and Z axes. Checks against entity hitboxes. |
| rx, rxm | Float (-90 to 90) | Maximum (rx) and minimum (rxm) vertical head pitch. -90 is straight up, 90 is straight down. |
| ry, rym | Float (-180 to 180) | Maximum (ry) and minimum (rym) horizontal head yaw. 0 is South, -90 is East, 90 is West, 180/-180 is North. |
| c | Integer (nonzero) | Limits the maximum count of targets returned. Positive values pick the closest targets; negative values (like c=-2) pick the farthest targets. |
Identity, Trait, and State Arguments
Once you have constrained where the selector looks, you filter what it looks for using identity and trait arguments. In add-ons, the three most important identity filters are `type`, `family`, and `tag`. While `type` matches the exact entity identifier (such as `minecraft:zombie` or `custom:mech_suit`), `family` checks the tags defined inside the entity's `minecraft:type_family` behavior component. Using `family=monster` or `family=undead` lets a single command work seamlessly across dozens of vanilla and custom mobs without writing a separate command for each one.
Most identity arguments support negation using the exclamation mark (`!`) prefix. While you can only specify one positive `type` or `name` (since an entity cannot be two types or have two names simultaneously), you can chain multiple negated arguments together. For example, `@e[type=!player,type=!item,type=!xp_orb]` is a standard pattern used in custom weapon logic to hit any living mob while sparing players and dropped loot.
Tags assigned via the `/tag` command or animation controllers act as lightweight boolean flags on an entity. You can check for the presence of multiple tags (`[tag=boss,tag=enraged]`), check for the absence of a tag (`[tag=!invulnerable]`), or test if an entity has no tags at all by passing an empty value (`[tag=]`).
| Argument | Negatable | Multiple Allowed | Notes |
|---|---|---|---|
| type | Yes (!) | Only when negated | Accepts full namespace (custom:boss) or default minecraft namespace (creeper). |
| family | Yes (!) | Yes | Matches strings inside the entity's 'minecraft:type_family' component. |
| tag | Yes (!) | Yes | Matches runtime scoreboard tags added via the /tag command. |
| name | Yes (!) | Only when negated | Matches custom name tags or player usernames. Quote strings if they contain spaces. |
| m | Yes (!) | Only when negated | Game mode filter. Accepts s/survival/0, c/creative/1, a/adventure/2, d/default, or spectator. |
| l, lm | No | No | Maximum (l) and minimum (lm) XP level for players. |
Compound Filters: Scores, Items, Permissions, and Properties
Bedrock selectors feature four compound arguments that accept nested key-value blocks wrapped in curly braces `{}`: `scores`, `hasitem`, `haspermission`, and `has_property`. These allow you to inspect deep entity state directly inside the selector without building complex multi-step scoreboard chains.
The `scores` filter checks scoreboard values for the target entity. It supports exact numbers (`scores={mana=10}`), inclusive ranges using two periods (`scores={mana=10..50}`), open-ended bounds (`scores={mana=..10}` for 10 or less, `scores={mana=10..}` for 10 or more), and negated ranges (`scores={mana=!10..20}`). If an entity does not have a tracked score on the specified objective yet, any positive score check will evaluate to false.
The `hasitem` filter inspects an entity's inventory or equipment slots. It accepts a single block of conditions or an array of blocks `[ {...}, {...} ]` if you need to check multiple items or slots at once. Inside each block, you can specify `item` (the item identifier), `quantity` (supports range syntax like `1..` or `!0` to check for absence), `data` (for item aux values where applicable), `location` (such as `slot.weapon.mainhand`, `slot.armor.head`, or `slot.inventory`), and `slot` (the numeric index within that location, also supporting ranges). Similarly, `has_property` queries custom entity properties defined in the entity's behavior file header, accepting boolean, integer range, float range, or string enum values.
Below is an example `.mcfunction` file demonstrating how these compound filters combine in a real add-on scenario to manage a custom magic staff mechanic.
# Verify the caster (@s) has the staff in mainhand, at least 20 mana, and camera movement enabled
execute as @s[haspermission={camera=enabled},scores={mana=20..},hasitem={item=custom:ember_staff,location=slot.weapon.mainhand}] at @s run tag @s add valid_caster
# Deduct mana and play sound for validated casters
scoreboard players remove @s[tag=valid_caster] mana 20
execute at @s[tag=valid_caster] run playsound mob.ghast.fireball @a[r=16] ~ ~ ~ 1.0 1.2
# Damage up to 4 closest hostile mobs in front of the player that are not fire-immune
execute at @s[tag=valid_caster] positioned ^ ^ ^4 run damage @e[r=3.5,family=monster,family=!fire_immune,type=!player,c=4] 8 fire_tick entity_attack entity @s
# Check for entities with a custom entity property 'custom:shield_charge' and drain it
execute at @s[tag=valid_caster] positioned ^ ^ ^4 run event entity @e[r=3.5,has_property={"custom:is_shielded"=true}] custom:break_shield
# Clean up the temporary execution tag
tag @s remove valid_casterUsing Selectors Inside Behavior Pack JSON
When you move from `.mcfunction` files to JSON files—such as entity definitions, block behaviors, or NPC dialogue files—selector syntax rules remain the same, but you must account for JSON string escaping and how Bedrock evaluates Molang versus slash commands.
If you embed a slash command inside an entity event's `queue_command` object or an animation controller, any quotation marks inside your selector (such as around a custom property name or a display name with spaces) must be escaped with a backslash (`\"`). Furthermore, note that inside an entity's JSON file, the `filters` blocks used by components like `minecraft:target_nearby_sensor` or `minecraft:interact` do NOT use `@` selector strings; they use Bedrock's JSON filter schema (`test`, `subject`, `operator`, `value`). You only write `@e` or `@s` strings inside strings that execute actual slash commands.
The following entity behavior file illustrates how `@s` and `@a` selectors with compound arguments are safely formatted and escaped inside an entity's `queue_command` event response.
{
"format_version": "1.20.40",
"minecraft:entity": {
"description": {
"identifier": "custom:arcanist_totem",
"is_spawnable": true,
"is_summonable": true,
"properties": {
"custom:tier": {
"type": "int",
"range": [1, 3],
"default": 1,
"client_sync": true
}
}
},
"components": {
"minecraft:health": {
"value": 20,
"max": 20
},
"minecraft:type_family": {
"family": ["totem", "inanimate"]
},
"minecraft:timer": {
"looping": true,
"time": 2.0,
"time_down_event": {
"event": "custom:pulse_buff"
}
}
},
"events": {
"custom:pulse_buff": {
"queue_command": {
"command": [
"execute as @s[has_property={\"custom:tier\"=1}] at @s run effect @a[r=8,m=!spectator] regeneration 4 0 true",
"execute as @s[has_property={\"custom:tier\"=2..}] at @s run effect @a[r=12,hasitem={item=custom:totem_charm,location=slot.inventory}] regeneration 4 1 true",
"execute at @s run particle minecraft:villager_happy ~ ~1.5 ~"
]
}
}
}
}
}Selector Evaluation Order and Performance Tips
In large add-ons that run dozens of commands every tick via `tick.json`, selector efficiency determines whether your pack runs at a smooth 20 ticks per second or bogs down the server. Every time you write `@e[...]`, the game engine iterates over the entity list in the current dimension and runs your bracketed filters against each candidate.
Whenever the target of a command is already the entity running the function, always use `@s[...]` instead of `@e[...]` or `@a[...]`. Filtering `@s` only checks a single entity reference in memory, making it orders of magnitude faster than scanning the world with `@e`. Similarly, if you are only looking for players, always use `@a[...]` or `@p[...]` rather than `@e[type=player,...]`, because the engine maintains a separate, much smaller list of player entities.
When combining spatial and compound filters on `@e`, always include a radius (`r`) or bounding box (`dx`, `dy`, `dz`) alongside heavy checks like `hasitem` or `scores`. Distance checks are simple math operations that quickly discard distant mobs before the engine spends time inspecting inventory slots or scoreboard tables.
Which versions this applies to
Applies to Minecraft Bedrock 1.19.50 and newer (utilizing the modern 'execute' command syntax). Selectors like 'hasitem' require 1.18.10+, and 'has_property' requires 1.20.40+ where stable Entity Properties were introduced. No experimental toggles are required.
When it does not work
| What you see | Why | The fix |
|---|---|---|
| Syntax error: Unexpected "type": at "player,type=zombie]" | You included two positive 'type' arguments in the same selector bracket (for example, @e[type=player,type=zombie]). An entity can only have one identifier, so positive type arguments cannot be stacked. | If you want to target multiple types at once, assign them a shared family in their behavior JSON and filter by @e[family=shared_name], or tag them first using two separate /tag commands. Only negated types (type=!player,type=!item) can be stacked in one selector. |
| No targets matched selector | Frequently happens when using 'dx', 'dy', and 'dz' without realizing they require an origin point, or when using '@s' inside a command block or 'tick.json' function where no entity is set as the executor. | When running functions from 'tick.json', wrap your commands in 'execute as @a at @s run ...' before using '@s' or relative spatial arguments. When using 'dx/dy/dz', verify whether negative values are needed if your target volume extends North, West, or downward from the origin. |
| Selector argument 'hasitem' fails to detect an empty hand when using quantity=0 | Setting 'hasitem={item=minecraft:diamond,location=slot.weapon.mainhand,quantity=0}' across the entire entity fails if the player has a diamond anywhere else in their inventory, or behaves unexpectedly because slot-specific zero-quantity checks conflict with global inventory checks. | Check for the absence of an item across the whole inventory using 'quantity=0' without a location, or check for an empty hand by testing via an animation controller Molang query (q.get_equipped_item_name) and applying a tag. |
| Content Log Error: [Json] Failed to parse JSON string in entity queue_command | You copied a command containing quotes (such as @e[name="Goblin King"] or @s[has_property={"custom:state"=1}]) directly into an entity or block JSON file without escaping the inner quotation marks. | Replace every inner double quote inside the JSON command string with an escaped quote (\"), for example: "@e[name=\"Goblin King\"]". |
Reference, straight from the game files
Read out of the game itself, so the ids match the version you are building for.
