Wiki 9Minecraft Wiki 9Minecraft

Java Datapack Functions vs Bedrock Behavior Packs

How to translate Java Edition datapack .mcfunction files, tick tags, and commands into Bedrock add-ons.

5Sections
3Code examples
3Known errors

If you are moving from Java Edition datapacks to Minecraft Bedrock add-ons, your first instinct will be to look for a functions folder and a load.json tag. Bedrock Behavior Packs do support .mcfunction files, but the folder structure, command syntax, and execution triggers work quite differently. More importantly, many mechanics that require complex scoreboard math and raycasting functions in Java are handled natively in Bedrock using entity JSON files or the TypeScript/JavaScript Script API.

Structural Differences: Where Files Live

In a Java Edition datapack, almost everything is organized under namespaces inside the data/ folder. You can have multiple namespaces inside a single datapack, and a function is called using its namespace prefix, such as /function my_namespace:subfolder/my_func. This structure gives Java creators strict separation between different modules or libraries within the same pack.

Bedrock Behavior Packs flatten this structure completely. There is no data/ folder and no concept of folder-based namespaces for functions. Instead, you place all of your .mcfunction files directly inside a top-level functions/ directory at the root of your Behavior Pack (typically abbreviated as BP/functions/).

Because there is no namespace folder, you call your functions using only their path relative to the functions/ directory. If you create a file at BP/functions/arena/start_wave.mcfunction, you run it in-game using /function arena/start_wave. If two different Behavior Packs installed on the same world both have a file named functions/init.mcfunction, they can collide. To prevent this, seasoned Bedrock developers simulate namespaces by putting all of their function files inside a uniquely named subfolder, such as BP/functions/my_pack/init.mcfunction, and calling /function my_pack/init.

Another major structural shift is the pack registration file. Where Java uses a very simple pack.mcmeta file with a pack_format integer, Bedrock requires a manifest.json file at the root of the Behavior Pack. This manifest must contain two completely unique UUIDs (one in the header and one in the modules array) and specifies a min_engine_version array like [1, 20, 80]. This engine version directly controls how your commands are parsed; if you use an older engine version in your manifest, Bedrock will actually revert to legacy command syntax for the functions inside that pack.

ConceptJava DatapackBedrock Behavior Pack
Pack metadata filepack.mcmetamanifest.json (requires unique UUIDs)
Function file locationdata/<namespace>/functions/foo.mcfunctionfunctions/foo.mcfunction
In-game command syntax/function <namespace>:foo/function foo (or /function subfolder/foo)
Ticking configurationdata/minecraft/tags/functions/tick.jsonfunctions/tick.json
On-load configurationdata/minecraft/tags/functions/load.jsonNot natively supported in tick.json; handled via scoreboards or Script API

Ticking Functions and the Missing Load Tag

Java datapack creators rely heavily on function tags, specifically minecraft:tick to run commands 20 times per second, and minecraft:load to initialize scoreboards and setup logic when the world starts or /reload is executed.

Bedrock has a direct equivalent for ticking functions, though the file sits in a different location. If you create a file named tick.json directly inside your BP/functions/ folder, the game will read its values array and execute every listed function once per game tick. The paths listed inside tick.json are relative to the functions/ folder and do not include the .mcfunction file extension.

However, Bedrock has no direct equivalent to Java's load.json tag. There is no built-in JSON file that runs a function solely when the world loads or when packs are reloaded. If you need an initialization function in a pure command-based Behavior Pack, the standard workaround is to call your setup function from inside your ticking function, gated behind a dummy scoreboard check on a fake player name. Once the setup function runs, it sets that fake player's score to 1 so the execute condition fails on all subsequent ticks.

Keep in mind that ticking functions in Bedrock run from the world's origin point at (0, 0, 0) in the Overworld, without an executing entity. If you use target selectors with distance arguments like r=10 or rm=1 without changing the execution position first, it will measure from the world origin rather than from players.

BP/functions/tick.json
{
  "values": [
    "my_pack/main_loop",
    "my_pack/check_init"
  ]
}

Command Syntax and NBT Limitations

In older versions of Bedrock, the /execute command used a completely different syntax involving the detect keyword. As of Bedrock 1.19.50 (provided your manifest's min_engine_version is set to 1.19.50 or higher), Bedrock uses the modern Java-style /execute syntax, including as, at, positioned, align, anchored, if, unless, and run. This makes translating basic positional logic from Java much easier than it used to be.

Despite the unified /execute command, you will quickly hit the biggest wall when coming from Java: Bedrock commands do not give you access to raw NBT data. There is no /data command in Bedrock. You cannot use nbt={} inside target selectors, you cannot read a player's SelectedItem tag via commands, and you cannot modify an entity's motion vector or health by editing its data tags on the fly. The few JSON-like components that do exist in Bedrock commands—such as minecraft:can_place_on, minecraft:can_destroy,minecraft:item_lock, and minecraft:keep_on_death in the /give command—are strictly limited to those specific item properties.

Target selector arguments also have subtle differences. While Java uses distance=..10 to select entities within 10 blocks, Bedrock still uses two separate arguments: r=10 for maximum radius and rm=1 for minimum radius. Similarly, level ranges use l and lm instead of level=.., and score ranges inside the scores={} selector argument use .. just like Java. However, /execute store does not exist in Bedrock. You cannot easily pipe the success count or result of a command directly into a scoreboard objective.

Because you cannot read NBT in selectors, you have to invert your thinking. Instead of checking if an entity has a specific NBT state using a function, you use Bedrock's entity behavior files to evaluate conditions via Molang queries or entity filters, and then add a tag or run a command from the entity itself.

Java Command FeatureBedrock Command EquivalentWorkaround / Notes
Selector distance=5..10Selector rm=5,r=10Bedrock uses separate minimum (rm) and maximum (r) arguments
Selector nbt={OnGround:1b}None in commandsUse Molang query.is_on_ground in an entity file or the Script API
/data get & /data modifyNoneDirect NBT manipulation is impossible; use entity components or scripts
/execute store result score...NoneMust use binary search with scoreboards or handle math in the Script API
/scoreboard objectives add ... dummyIdentical syntaxBedrock only supports the 'dummy' criteria; no stat-tracking criteria exist
Selector predicate=...hasitem={} selector argumentFor inventory checks, Bedrock's hasitem selector replaces many Java predicates

The hasitem Selector and Function Examples

While the lack of NBT access is limiting, Bedrock includes a very capable selector argument that Java lacks: hasitem. In Java, checking if a player is holding a specific item or carrying enough of a currency item in their inventory requires either an advancement, a predicate, or an nbt={Inventory:[...]} check. In Bedrock, you can do this directly inside any @a, @p, or @e selector.

The hasitem argument accepts an item identifier, a data value, a quantity range, a location (such as slot.weapon.mainhand, slot.armor.head, or slot.inventory), and a slot range. You can even pass an array of multiple item conditions inside a single hasitem=[] block to check for several items at once.

Below is an example of a valid Bedrock .mcfunction file that runs every tick. It initializes a scoreboard objective if it does not exist, checks if any player is holding a diamond sword in their main hand while standing within 8 blocks of an armor stand, and applies an effect and a scoreboard tag.

BP/functions/my_pack/main_loop.mcfunction
# Initialize scoreboard safely every tick (harmless if it already exists)
scoreboard objectives add mana dummy "Mana"
scoreboard players add @a mana 0

# Grant strength to players holding a diamond sword near a specific marker
execute at @e[type=minecraft:armor_stand,name=buff_totem] as @a[r=8,hasitem={item=minecraft:diamond_sword,location=slot.weapon.mainhand}] run effect @s strength 2 0 true

# Deduct 10 mana from players sneaking with an emerald in their offhand
execute as @a[scores={mana=10..},hasitem={item=minecraft:emerald,location=slot.weapon.offhand}] at @s if block ~~-1~ minecraft:gold_block run tag @s add trigger_spell

execute as @a[tag=trigger_spell] at @s run particle minecraft:totem_particle ~~1~
scoreboard players remove @a[tag=trigger_spell] mana 10
tag @a[tag=trigger_spell] remove trigger_spell

Moving Beyond Functions: Entities and the Script API

The biggest mistake Java datapack creators make when moving to Bedrock is trying to build everything inside .mcfunction files. In Java, datapacks use functions for everything because you cannot easily add new entities, custom blocks, or event-driven scripts without requiring players to install client-side mods. In Bedrock, the Behavior Pack format is natively designed to define custom entities, items, blocks, and JavaScript code.

For example, in a Java datapack, if you want a custom boss with special attacks, you summon a vanilla mob with custom NBT tags and run a ticking function every tick to check its scoreboards, teleport invisible armor stands around it, and force it to attack. In Bedrock, you simply create a new entity file in BP/entities/, give it components like minecraft:behavior.delayed_attack or minecraft:shooter, and let the game's C++ engine run the AI natively without a single ticking command.

Similarly, for complex game loops, raycasting, inventory manipulation, UI menus, or math, Bedrock provides the @minecraft/server Script API. Instead of running hundreds of /execute commands in a .mcfunction file every tick, you write standard JavaScript or TypeScript. The Script API can listen to exact events—like a player breaking a block, an entity taking damage, or an item being used—so your code only runs when something actually happens, rather than polling for conditions 20 times a second.

Even better, you can bridge the two systems using the scriptevent command. Inside a .mcfunction file, an entity event, or an animation controller, you can run /scriptevent my_pack:spawn_boss arena_1. Your JavaScript file listens for that specific message ID via the system.afterEvents.scriptEventReceive event, reads the payload string, and executes complex logic that would be impossible in standard Bedrock commands.

BP/scripts/main.js
import { world, system } from "@minecraft/server";

// Replace a Java 'load.json' function using the worldLoad event
world.afterEvents.worldLoad.subscribe(() => {
    const overworld = world.getDimension("overworld");
    overworld.runCommand("scoreboard objectives add initialized dummy");
    world.sendMessage("Pack initialized via Script API!");
});

// Listen for /scriptevent triggers coming from .mcfunction files
system.afterEvents.scriptEventReceive.subscribe((event) => {
    if (event.id === "my_pack:heal_player" && event.sourceEntity) {
        const healthComp = event.sourceEntity.getComponent("minecraft:health");
        if (healthComp) {
            healthComp.resetToMaxValue();
        }
    }
});

Which versions this applies to

Applies to Bedrock Edition 1.19.50 and newer for modern /execute syntax. Basic .mcfunction files and tick.json work in any modern Bedrock version with no experimental toggles required. Using the @minecraft/server Script API as an alternative requires adding a script module to manifest.json, though stable APIs do not require experimental toggles.

When it does not work

What you seeWhyThe fix
Function 'my_pack/init' not found, or part of the function stops executing partway through.Unlike Java, if a Bedrock .mcfunction file contains even a single syntax error on one line, the game often refuses to parse and register the entire file. This frequently happens when accidentally pasting a Java selector like distance=..5 or nbt={} into a Bedrock function.Enable the Content Log GUI in Creator Settings and reload the world. The log will state the exact line number and syntax error that caused the .mcfunction file to fail registration.
Syntax error: Unexpected 'as': at 'execute >>as<< @a...'Your Behavior Pack's manifest.json has a min_engine_version set below [1, 19, 50] (or is missing the field entirely). Bedrock defaults old manifests to legacy command versions to prevent old marketplace maps from breaking, which forces the legacy /execute @a ~ ~ ~ syntax.Open BP/manifest.json and update min_engine_version inside the header object to at least [1, 20, 80] or whatever current version of Bedrock you are targeting.
Functions listed in tick.json never run automatically, even though they work when typed manually with /function.You either placed tick.json in a subfolder instead of directly at BP/functions/tick.json, or you included the .mcfunction file extension inside the JSON strings.Ensure the file is located at BP/functions/tick.json and that the strings in the 'values' array omit the file extension, such as 'my_pack/loop' instead of 'my_pack/loop.mcfunction'.

Reference, straight from the game files

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