Wiki 9Minecraft Wiki 9Minecraft

Execute Logic Gates in Minecraft Bedrock Functions

Build AND, OR, NOT, XOR, and NAND boolean logic in .mcfunction files using the modern /execute syntax.

6Sections
5Code examples
4Known errors

Minecraft Bedrock commands do not have native `||` (OR) or `^^` (XOR) operators inside the `/execute` command. When you need a function to run a command only when a complex combination of block states, scores, and entity tags line up, you construct boolean logic gates by chaining `if` and `unless` subcommands with temporary entity tags or scoreboard tallies. Reach for these patterns when writing `.mcfunction` scripts that must stay pure data-driven without adding a Script API dependency.

How /execute evaluates conditions

Since the modern `/execute` overhaul introduced in Bedrock 1.19.50, a single command can chain any number of subcommands before finally terminating in a `run` clause. The two conditional subcommands are `if` and `unless`. Both accept the exact same four test types: `block`, `blocks`, `entity`, and `score`. If a test passes, execution continues down the chain toward `run`. If any single test fails, the entire command aborts immediately for that execution context.

Because every subcommand in the chain must pass for the final command to run, a chain of `/execute` conditions is naturally an AND gate. Likewise, `unless` is a native NOT gate—it succeeds only when its test fails (zero matching entities found, block does not match, or score comparison is false). All other boolean gates—OR, NAND, NOR, and XOR—are built by combining those two primitives with either a temporary tag on `@s` or an arithmetic counter on a scoreboard objective.

When writing logic gates inside a behaviour pack function file, you almost always want the function to run `as` a specific entity so you can attach and strip temporary tags on `@s` within the same game tick. Tags added and removed inside the same `.mcfunction` file never escape to the next tick, making them free of side effects as long as you clean them up at the top or bottom of the file.

GateTruth conditionBedrock /execute implementation
ANDBoth A and B are trueChain `if <A> if <B> run ...` in a single command
NOTA is falseUse `unless <A> run ...` or inverted selector `[tag=!a]`
NANDNot both A and BSet a pass tag when `if <A> if <B>` holds, then run `unless entity @s[tag=...]`
ORAt least one of A or B is trueApply a shared temporary tag if A is true, apply the same tag if B is true, then run on the tag
NORNeither A nor B is trueChain `unless <A> unless <B> run ...` in a single command
XORExactly one of A or B is trueAdd 1 to a dummy score for each true input, then test for a final score of `1`

AND, NOT, and NOR in a single command

You never need helper tags or scoreboard math for AND, NOT, or NOR. Because `/execute` stops at the first failing subcommand, placing multiple `if` clauses back-to-back produces a strict logical AND. If both conditions check properties of the same entity (`@s`), you can often fold the AND gate directly into a single target selector argument list—every argument inside square brackets (`[tag=ready,scores={mana=10..}]`) is also evaluated as a logical AND.

Use chained `if` subcommands instead of selector arguments when the two conditions inspect different things, such as checking a block underneath the player AND checking a scoreboard value on a global dummy player, or checking the existence of two completely separate entities in the world.

NOR ('neither A nor B') is mathematically identical to '(NOT A) AND (NOT B)' by De Morgan's laws. In `/execute`, that translates directly to `unless <A> unless <B>`. Only if the first test fails AND the second test also fails will execution reach `run`.

BP/functions/logic/direct_gates.mcfunction
# --- AND GATE (A AND B) ---
# Condition A: Player is standing on emerald_block
# Condition B: Player has at least 5 levels of experience
execute as @a at @s if block ~~-1~ minecraft:emerald_block if entity @s[lm=5] run effect @s regeneration 5 1 true

# --- NOT GATE (NOT A) ---
# Condition A: A boss entity is currently alive within 32 blocks
execute as @a at @s unless entity @e[type=minecraft:wither,r=32] run title @s actionbar Area is clear

# --- NOR GATE (NEITHER A NOR B) ---
# Condition A: Player has tag 'in_safezone'
# Condition B: Player is in creative mode
execute as @a unless entity @s[tag=in_safezone] unless entity @s[m=c] run scoreboard players add @s danger_ticks 1

OR and NAND gates using temporary tags

Why can you not write an OR gate in one line? If you duplicate the final `run` command across two separate `execute if` lines—one for condition A and one for condition B—and both conditions happen to be true at the same time, the `run` command fires twice in the same tick. For an idempotent command like `tag @s add poisoned`, running twice does no harm. For a command like `give @s apple 1`, `summon`, or `scoreboard players add`, running twice when both A and B are true is a critical bug.

To build a true OR gate that fires its payload at most once per tick, decouple the condition evaluation from the action. First, remove a temporary marker tag (`logic_or`) from `@s`. Next, run one `execute if <A>` that adds `logic_or`, followed by a second `execute if <B>` that also adds `logic_or`. Because entities cannot hold duplicate copies of the same tag string, having both conditions succeed still leaves the entity with a single `logic_or` tag. Finally, run your payload once on `@s[tag=logic_or]` and clean the tag up.

A NAND gate ('not both A and B') uses the same buffer tag pattern in reverse. First evaluate the AND condition (`if <A> if <B>`) to apply a `both_true` tag, and then fire your payload using `unless entity @s[tag=both_true]`.

BP/functions/logic/or_and_nand.mcfunction
# Assume this function is called via: execute as @a at @s run function logic/or_and_nand

# --- OR GATE (A OR B) ---
# Reset temporary tag
tag @s remove temp_or

# Input A: Holding a torch in the mainhand
execute if entity @s[hasitem={item=minecraft:torch,location=slot.weapon.mainhand}] run tag @s add temp_or
# Input B: Standing in a light block or fire is not needed if wearing a glowing helmet
execute if entity @s[hasitem={item=minecraft:golden_helmet,location=slot.armor.head}] run tag @s add temp_or

# Output: Runs exactly once even if the player has both the torch and the helmet
execute if entity @s[tag=temp_or] run effect @s night_vision 15 0 true
tag @s remove temp_or

# --- NAND GATE (NOT (A AND B)) ---
tag @s remove temp_and
execute if block ~~-1~ minecraft:Magma if entity @s[tag=fire_immune] run tag @s add temp_and

# Output: Fires unless the player is BOTH on magma AND fire_immune
execute unless entity @s[tag=temp_and] run title @s actionbar Standard movement rules apply
tag @s remove temp_and

XOR and multi-input gates using a scoreboard counter

An XOR (exclusive OR) gate returns true when condition A is true or condition B is true, but false when both are true. With tags alone, you would need multiple intermediate tags to track 'A without B' and 'B without A'. A cleaner and much more scalable pattern is to count how many inputs are true using a dummy scoreboard objective.

Initialize a dummy score (for example, `logic_sum`) on `@s` to `0` at the start of the check. For every input condition that passes, add `1` to `logic_sum`. After all input conditions have been tested, the value of `logic_sum` equals the exact number of true conditions. For a standard two-input XOR gate, you then test `if score @s logic_sum matches 1`.

This scoreboard tally pattern scales to any number of inputs without extra complexity. If you have five altars in a boss room and want a door to open only when any three of the five are active (a '3-of-5 threshold gate'), you run five `execute if block ... run scoreboard players add` lines and check `matches 3` at the end. You can also test ranges: `matches 1..` is an N-input OR gate, `matches 0` is an N-input NOR gate, and `matches 2..3` triggers when two or three inputs are active.

BP/functions/logic/xor_and_threshold.mcfunction
# Prerequisite (run once on world load):
# scoreboard objectives add logic_sum dummy

# Reset counter for the current executing entity
scoreboard players set @s logic_sum 0

# Input A: Player has the 'blessing_sun' tag
execute if entity @s[tag=blessing_sun] run scoreboard players add @s logic_sum 1

# Input B: Player has the 'blessing_moon' tag
execute if entity @s[tag=blessing_moon] run scoreboard players add @s logic_sum 1

# --- XOR OUTPUT (Exactly 1 input is true) ---
execute if score @s logic_sum matches 1 run effect @s speed 2 1 true

# --- XNOR / EQUIVALENCE OUTPUT (Both true OR both false: 0 or 2) ---
execute unless score @s logic_sum matches 1 run effect @s slowness 2 0 true

# --- 3-INPUT MAJORITY GATE (At least 2 of 3 levers/blocks active) ---
scoreboard players set #altar logic_sum 0
execute if block 10 64 10 minecraft:redstone_block run scoreboard players add #altar logic_sum 1
execute if block 15 64 10 minecraft:redstone_block run scoreboard players add #altar logic_sum 1
execute if block 20 64 10 minecraft:redstone_block run scoreboard players add #altar logic_sum 1

execute if score #altar logic_sum matches 2.. run setblock 15 65 15 minecraft:air

Short-circuit branching with sub-functions

When you build a large decision tree (such as `if A then X, else if B then Y, else Z`), evaluating every branch with scoreboard counters every tick wastes command execution budget if the first branch already matched. You can emulate `if / else if / else` short-circuiting by pairing a `handled` tag with child `.mcfunction` calls.

Note that running a child function via `execute ... run function` does not pause or abort the parent function; once the child function finishes, the parent function continues on its very next line. However, if the child function adds a `branch_handled` tag to `@s`, every subsequent branch in the parent function can guard itself with `unless entity @s[tag=branch_handled]`. If the child function itself contains twenty commands, putting those twenty commands behind `run function` means Bedrock skips parsing and executing all twenty of them whenever the branch condition is false.

BP/functions/logic/if_else_router.mcfunction
# Run as the target entity: execute as @a at @s run function logic/if_else_router
tag @s remove branch_handled

# IF (Score is 100 or higher)
execute if score @s rank_points matches 100.. run function logic/branches/tier_gold

# ELSE IF (Not handled yet, and score is 50..99)
execute unless entity @s[tag=branch_handled] if score @s rank_points matches 50..99 run function logic/branches/tier_silver

# ELSE (Neither branch above matched)
execute unless entity @s[tag=branch_handled] run function logic/branches/tier_bronze

# Clean up
tag @s remove branch_handled

# (Inside logic/branches/tier_gold.mcfunction and tier_silver.mcfunction,
#  the first line must be: tag @s add branch_handled)

Setting minimum engine version in manifest.json

All `/execute if` and `/execute unless` syntax shown on this page relies on the modern command version introduced in Bedrock 1.19.50. If your behaviour pack `manifest.json` specifies an older `min_engine_version` (such as `[1, 19, 0]` or `[1, 16, 0]`), Minecraft Bedrock falls back to the legacy `/execute <origin> <position> <command>` syntax when compiling your `.mcfunction` files, causing every modern `if`, `unless`, `as`, and `at` subcommand to fail on load.

Always set `min_engine_version` inside the `header` object of `BP/manifest.json` to at least `[1, 19, 50]`—or the current stable release version you are targeting—so the function parser uses the modern `/execute` grammar.

BP/manifest.json
{
  "format_version": 2,
  "header": {
    "name": "Execute Logic Gates Demo BP",
    "description": "Behaviour pack using modern /execute logic gates in functions.",
    "uuid": "a4b89c12-6d4e-4f83-9a15-2c7e8d9f0a1b",
    "version": [1, 0, 0],
    "min_engine_version": [1, 20, 80]
  },
  "modules": [
    {
      "type": "data",
      "uuid": "f1e2d3c4-b5a6-4789-8012-3456789abcde",
      "version": [1, 0, 0]
    }
  ]
}

Which versions this applies to

Applies to Minecraft Bedrock 1.19.50 and newer (when the new /execute syntax replaced the legacy syntax). Requires min_engine_version of at least [1, 19, 50] in BP/manifest.json. No experimental toggles are needed.

When it does not work

What you seeWhyThe fix
Content Log Error: Function logic/or_and_nand failed to load. Syntax error: Unexpected "as": at "execute >>as<< @a"Your behaviour pack's BP/manifest.json has a min_engine_version lower than [1, 19, 50], forcing the game to parse .mcfunction files using the legacy pre-1.19.50 /execute syntax.Update header.min_engine_version in BP/manifest.json to [1, 19, 50] or higher (for example, [1, 20, 80]) and reload the world.
The `unless entity` gate fails when you expect it to pass, or runs once per entity in the world instead of once total.You placed an inverted selector inside `if entity @e[tag=!boss]` instead of using `unless entity @e[tag=boss]`. The command `if entity @e[tag=!boss]` succeeds as long as ANY entity in the world lacks the `boss` tag (such as a chicken or dropped item), whereas `unless entity @e[tag=boss]` checks that ZERO entities have the `boss` tag.Use `execute unless entity @e[tag=boss]` when testing for the complete absence of an entity in the world, and reserve `[tag=!foo]` only for filtering `@s` or narrowing down a specific target group.
Scoreboard-based XOR or threshold gate never triggers and prints: "No targets matched selector" or "Objective 'logic_sum' does not exist".The dummy objective used to tally true conditions was never created in the world, or the entity has no initial score before a comparison is made.Create the objective once via a setup function or `tick.json` init check (`scoreboard objectives add logic_sum dummy`), and always run `scoreboard players set @s logic_sum 0` at the top of the gate before adding to it.
Temporary tags (`temp_or`, `branch_handled`) stay on players permanently and cause gates to misfire on future ticks.A mid-function command changed the execution context or killed/teleported the entity before the cleanup `tag @s remove` line at the bottom of the function could match `@s`.Always place `tag @s remove <temp_tag>` at BOTH the very beginning of the function (before evaluating inputs) and at the end, so stale tags from an interrupted tick are wiped clean on the next run.

Reference, straight from the game files

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