Functions & commands

How .mcfunction files work, the full /execute grammar, storing command output, macros, /return, and /schedule — the executable core of every data pack.

.mcfunction files

A function is a plain-text file of commands executed top-to-bottom. Functions are the backbone of a data pack: they are triggered by /function, by function tags (#minecraft:load, #minecraft:tick), by /schedule, by advancement rewards, and by other functions.

Location & naming

Function files live under the function folder of your namespace. The path (minus the .mcfunction extension) becomes the resource id, with subfolders joined by /:

data/<namespace>/function/<name>.mcfunction      # 1.21+ (SINGULAR "function")
data/<namespace>/functions/<name>.mcfunction     # 1.20.6 and earlier (plural)

So data/foo/function/summon/pig.mcfunction has the id foo:summon/pig. Namespaces and paths may use only [a-z0-9_.-] (the path also allows /).

File syntax rules

Example — file + call

data/foo/function/greet.mcfunction

# One command per line, no leading slash, comments with #
say Hello from foo:greet
effect give @a minecraft:glowing 5 0 true

# blank line above is fine; next line uses backslash continuation (1.20.2+)
tellraw @a \
    {"text":"Long message split across lines","color":"gold"}

Run it with /function foo:greet.

⚠ Version differences
  • The folder is singular function/ in 1.21+ (pack_format 48); it was plural functions/ through 1.20.6. A 1.21 pack using functions/ silently fails to register the function.
  • Backslash line continuation: 1.20.2+ only.
  • Macro ($) lines: 1.20.2+ only — older versions treat $… as an invalid command and error.
  • Breaking in 26.2: colour arguments to team modify <name> color and waypoint modify <name> color now accept only lowercase-with-underscore names. dark_purple validates; darkpurple and DarkPurple no longer do. The accepted set now matches the colour names used in text components. A pack that built these arguments by concatenation will fail at command-parse time, not silently. (Site: 26.2)
  • New in 26.2: unpublish, which closes a player’s published integrated server if one is open. Also in 26.2, execute … link=none now treats vexes as owned by their summoning evoker, so a link=none filter that previously matched a vex no longer does. (Site: 26.2)
  • 26.2 also changed advancement grant/revoke output: the result now reports how many advancements changed state across all players, and how many players were affected. Anything parsing that output, or storing it with execute store result, should be re-checked. (Site: 26.2)
💡 Best practice

Namespace everything under your own pack id; never write into minecraft: except the #minecraft:load / #minecraft:tick tags (not the functions themselves). Organize with subfolders (main/, api/, impl/, zzz_internal/) — the / in the id is free structure — and keep one logical action per function, calling sub-functions with function / execute … run function for readability and reuse.

The /execute grammar

/execute chains modifier subcommands that mutate the execution context (executor @s, position, rotation, dimension, anchor), optional condition subcommands (if/unless), and terminates in exactly one run <command> — or ends after a final condition, which then reports success/fail. The modern grammar dates from the 1.13 rework (17w45a). The context fields a subcommand can change are the executor, execution position, execution rotation, execution dimension, and execution anchor.

Modifier subcommands

SubcommandGrammarEffectForks?Added
alignalign <axes>Rounds execution position down to the block grid on the given axes (x/y/z combo, e.g. xz).no1.13
anchoredanchored (eyes|feet)Sets the anchor used by ^ local coords & facing.no1.13
asas <targets>Changes the executor (@s); does NOT change position.yes (per entity)1.13
atat <targets>Sets position, rotation, and dimension to the target's.yes1.13
facingfacing <pos> or facing entity <targets> (eyes|feet)Sets rotation to look at a point/entity.yes (entity form)1.13
inin <dimension>Sets execution dimension (respects overworld/nether coord scaling).no1.13
onon <relation>Re-targets the executor via a relation: attacker, controller, leasher, origin, owner, passengers, target, vehicle.yes (passengers)1.19.4 (23w03a)
positionedpositioned <pos> · positioned as <targets> · positioned over <heightmap>Sets execution position. over uses heightmaps: world_surface, motion_blocking, motion_blocking_no_leaves, ocean_floor.yes (as)1.13; over in 1.19.4 pre1
rotatedrotated <yaw> <pitch> · rotated as <targets>Sets execution rotation.yes (as)1.13
summonsummon <entity_type>Summons a new entity at the execution position and makes it the executor.no1.19.4 (23w06a)
runrun <command>Runs the final command in the built context. Only appears once, at the end.—1.13

Condition subcommands (if / unless)

All support both if (true → continue/succeed) and unless (negated).

ConditionGrammarAdded
block(if|unless) block <pos> <blockPredicate>1.13
blocks(if|unless) blocks <start> <end> <destination> (all|masked) — masked ignores air in the source1.13
data(if|unless) data (block <pos>|entity <target>|storage <source>) <path> — true if the path exists (matches ≥1)1.14 (18w43a)
entity(if|unless) entity <selector> — true if ≥1 entity matches1.13
predicate(if|unless) predicate <predicate_id> — references a predicate resource by id1.15 (19w38a)
score(if|unless) score <t> <tObj> (<|<=|=|>=|>) <s> <sObj> or … <t> <tObj> matches <range>1.13
biome(if|unless) biome <pos> <biome|#biome_tag>1.19.3 (22w46a)
dimension(if|unless) dimension <dimension>1.19.4 (23w03a)
loaded(if|unless) loaded <pos> — true if the chunk is fully (entity-ticking) loaded1.19.4 (23w03a)
items(if|unless) items (block <pos>|entity <source>) <slots> <item_predicate>1.20.5 (24w10a)
function(if|unless) function <function|#tag> — runs the function(s); true if any returns non-zero (non-void via /return). Works as a terminal condition like other if/unless checks.1.20.2 (23w31a), reintroduced 1.20.3 (23w41a)
📌 Note

The matches <range> ranges are inclusive: 5 (exactly 5), 1..10, 5.. (≥5), ..5 (≤5). And on versioning — execute if function has existed since 1.20.2 (23w31a); there is no separate 1.21.9 introduction, so treat it as available in every 1.21 version.

Examples

data/foo/function/execute_demo.mcfunction

# Loop over all zombies, at each one's feet check the block below
execute as @e[type=minecraft:zombie] at @s if block ~ ~-1 ~ minecraft:grass_block \
    run particle minecraft:flame ~ ~ ~ 0 0 0 0 1

# Relation: give the vehicle of every player glowing
execute as @a on vehicle run effect give @s minecraft:glowing 3 0 true

# 'if items' with an item predicate (both 1.20.5+): any main-hand item with a damage component
execute if items entity @s weapon.mainhand *[minecraft:damage] run say holding a damageable item
⚠ Version differences
  • on, dimension, loaded, positioned over: 1.19.4.
  • summon: 1.19.4 (23w06a).
  • biome: 1.19.3.
  • if function: 1.20.2 / 1.20.3.
  • if items + inline predicate objects: 1.20.5.
💡 Best practice

Order matters: put the cheapest, most-selective condition first (if entity @s[…] before if data …) to short-circuit. execute as … at @s is the canonical "for-each entity, at its position" idiom, and positioned over motion_blocking snaps to the top solid block for surface spawning.

🎩 Trick

A bare execute … if <cond> (no run) is itself a command whose success drives the enclosing execute store success or another if — a compact way to compose conditions into a 0/1 flag.

execute store result | success

store captures the terminal command's result (its numeric return value) or success (1 if it succeeded, else 0) into a data sink, evaluated AFTER the run command finishes.

execute store (result|success) <sink> … run <command>

Sinks

SinkGrammarNotes
blockstore (result|success) block <targetPos> <path> <type> <scale>Writes into a block entity's NBT. type ∈ byte/short/int/long/float/double; value ×scale.
bossbarstore (result|success) bossbar <id> (value|max)Sets a bossbar's current value or max. (Added 18w05a.)
entitystore (result|success) entity <target> <path> <type> <scale>Writes into a single entity's NBT (cannot target UUID-sensitive fields on some paths).
scorestore (result|success) score <targets> <objective>Sets a scoreboard value (integer).
storagestore (result|success) storage <target> <path> <type> <scale>Writes into command storage NBT. (Added 19w38a.)
📌 Note

The store targets are block, bossbar, entity, score, storage — the four NBT-style targets plus score. There is no bunch target; that spelling is a typo for bossbar.

Examples

data/foo/function/store_demo.mcfunction

# Count nearby armor stands into a score
execute store result score #count temp run execute if entity @e[type=armor_stand,distance=..10]

# Read an entity's Y-position (×1) into storage as a double
execute store result storage mypack:tmp pos.y double 1 run data get entity @s Pos[1]

# Store command success (0/1) into a block entity flag
execute store success block ~ ~ ~ CustomFlag byte 1 run scoreboard players test #x obj 1 1
⚠ Version differences
  • Core store: since the 1.13 rework.
  • bossbar sink: 1.13 (18w05a).
  • storage sink: 1.15 (19w38a).
🎩 Trick

store result runs the command; store success records whether it succeeded — great for turning any conditional into a 0/1 flag. Scale + int truncation lets you do fixed-point math: multiply a float by 100, store as int, for cheap 2-decimal fixed-point. And store result storage … <type> <scale> is the standard bridge from scoreboard → NBT that feeds macros.

Macros 1.20.2+

Macros let a function build commands from runtime data. A macro line starts with $ and contains $(key) placeholders; before each execution the placeholders are substituted from the arguments passed to the function, and the resulting string is parsed as a command at call time. Added in 1.20.2 (23w31a) and unavailable before it.

Syntax

Calling forms

function <name>                                   # no args (error if the function has macro lines needing args)
function <name> {key:"value", n:10}               # inline SNBT compound as arguments
function <name> with block   <sourcePos> [<path>]  # args = NBT compound read from a block entity
function <name> with entity  <source>   [<path>]  # args = NBT compound read from an entity
function <name> with storage <source>   [<path>]  # args = NBT compound read from command storage

The optional [<path>] narrows to a sub-compound of the source. The source compound's top-level keys become the available $(key) names.

Worked example A — inline compound

data/foo/function/spawn.mcfunction

$summon $(mob) ~ ~ ~ {CustomName:'{"text":"$(name)"}'}

Call it with a compound of arguments:

/function foo:spawn {mob:"minecraft:cow", name:"Bessie"}

Worked example B — with storage (scoreboard → macro)

Build the argument compound in the caller, then invoke the macro function in a separate file:

data/example/function/summon/pig.mcfunction

# 1) build the argument compound in storage from scores
execute store result storage example:macro pos.x int 1 run scoreboard players get X pos
execute store result storage example:macro pos.y int 1 run scoreboard players get Y pos
execute store result storage example:macro pos.z int 1 run scoreboard players get Z pos
# 2) call the macro function, feeding storage path pos
function example:summon/pig_macro with storage example:macro pos

data/example/function/summon/pig_macro.mcfunction

$summon minecraft:pig $(x) $(y) $(z) {Tags:["custom_pig"]}
$tellraw @a "Pig summoned at $(x) $(y) $(z)"
🚧 Workaround

You cannot read macro args in the same function that sets them. Arguments are bound when the function … with … call is made, so the setup (store result storage …) and the $ macro lines must live in separate functions — hence the two-file split above.

⚠ Version differences
  • The entire feature is 1.20.2+ — no macros in 1.20.1 or earlier.
  • with (block|entity|storage) and the inline {…} form all arrived together in 23w31a.
  • Before macros, "dynamic" commands required precomputed lookup tables of execute if score … run <specific command> for every possible value, or NBT-tree binary-search selectors; macros collapse these to one templated line.
💡 Best practice

Keep macro functions tiny — one or two $ lines — and put all data-prep in the caller. Macros re-parse the command each call (a small perf cost), so don't macro a line whose values never change. Always sanitize string args that flow into JSON/SNBT (quotes/backslashes) to avoid broken commands or injection when args come from player input (sign text, book, rename).

/return 1.20.3+

/return ends the current function immediately and sets the function's success and result (return value). It is how a function reports a value to execute … run function, execute if function, or return run function.

Syntax & semantics

return <value>        # end function, success=true, result = <value> (32-bit int, -2147483648..2147483647)
return fail           # end function, success=false, result = 0
return run <command>  # run <command>, then end function using THAT command's success & result

Example

data/foo/function/is_day.mcfunction

execute unless predicate foo:is_daytime run return fail
return 1

data/foo/function/caller.mcfunction

# Use is_day as a boolean:
execute if function foo:is_day run say It is daytime

# Return the first matching entity's Health, short-circuiting a fork:
execute as @e[tag=target] run return run data get entity @s Health
⚠ Version differences
  • The /return command shipped in 1.20.3 (pack_format 26). return run first appeared in 23w31a, was pulled during the 1.20.2 pre-releases, and was restored in 1.20.3 (23w41a); return fail was added in 23w44a.
  • Treat all three forms of /return as 1.20.3+ — no /return in 1.20.2 or earlier.
💡 Best practice

Use return fail / return 1 to build reusable boolean helper functions callable from execute if function. return run <command> forwards a command's own result — ideal for wrapping data get, scoreboard players get, or another function so the wrapper transparently yields that value. Guard clauses at the top (execute unless … run return fail) keep the happy path unindented.

/schedule

Delays a function to run later, measured in game time. Schedules survive as pending timers and fire during the scheduled-functions phase of a tick.

schedule function <function> <time> [append|replace]
schedule clear <function>

Arguments

Time — a float with a unit suffix:

append vs replace — the mode for stacking timers on the same function id:

schedule clear <function> removes all pending schedule(s) for that function id.

⚠ Gotcha

1t does not always equal exactly one real tick of delay. Called from a #minecraft:tick function it can run within the same tick's processing; called from the scheduled-function phase it lands on the next tick. Don't rely on 1t for exact single-tick precision.

Example — a self-rescheduling clock

data/foo/function/clock.mcfunction

say tick every second
schedule function foo:clock 1s replace

Kick it off once from load with function foo:clock. Using replace prevents timer pile-up if clock is ever triggered twice.

⚠ Version differences
  • Added 1.14 (18w43a). Permission level 2.
  • clear and the append|replace argument were added 1.15 (19w38a).
💡 Best practice

Prefer a replace self-schedule over #minecraft:tick when you need coarse timing (every N ticks/seconds) — far cheaper than running every tick and counting. Use append only when you genuinely want several overlapping timers. Always schedule clear on shutdown/reset routines so stale timers don't fire after a reload — pending schedules persist across /reload unless you clear them.

Recursion & per-entity loops

A function may call itself. Combined with a terminating condition, this gives you loops without a per-tick counter.

🎩 Trick

Per-entity loop: execute as @e[…] at @s run function … forks the callee once per matching entity, running it in each entity's context. For a value-carrying loop, use a macro counter: pass $(i) in the compound, decrement it into storage, and function self with storage … until a guard fails. Pair a recursive function with execute if for the terminating condition, or with /return to short-circuit on the first match.

data/foo/function/countdown.mcfunction

# Recurse with a scoreboard guard: stop when #i reaches 0
scoreboard players remove #i foo.loop 1
say counting...
execute if score #i foo.loop matches 1.. run function foo:countdown

Sources