Wiki 9Minecraft Wiki 9Minecraft

Bedrock Protocol

How the RakNet-based Bedrock network layer syncs add-ons, states, and Script API events.

5Sections
2Code examples
3Known errors

The Bedrock Protocol is the UDP and RakNet-based network layer that connects Minecraft Bedrock clients to integrated and dedicated servers. As an add-on creator, you do not craft raw binary packets directly; instead, you design your behavior packs, entity properties, and Script API code around how this protocol serializes and transmits state. Understanding what crosses the wire helps you prevent client-server desyncs, lower bandwidth usage on multiplayer worlds, and route data safely between the server and connected players.

Transport Layer and Connection Lifecycle

Unlike architectures that rely on TCP, Minecraft Bedrock communicates over UDP using the RakNet protocol library. RakNet provides reliability and ordering streams on top of standard UDP datagrams, allowing the game to send high-priority events reliably while letting continuous movement updates drop if a packet arrives too late. Every singleplayer world actually runs an internal server, meaning your add-on is always operating across this network boundary even when only one person is playing.

When a player joins a server, the protocol runs through a strict handshake and login sequence before any world chunks or entity actors are spawned. During this handshake, the server informs the client about the required resource packs and behavior pack definitions. If you mandate resource packs in your server configuration, the protocol handles chunking and streaming those zip archives directly over the game connection before the player's entity is initialized in the dimension.

How Add-on Definitions Cross the Wire

A common misconception among new creators is that the entire behavior pack is downloaded by joining clients. In reality, the server retains almost all behavior logic—such as loot tables, spawn rules, AI goals, and server scripts—on the host machine. The client only receives the visual and structural half of the contract: resource packs for textures, geometries, and sounds, along with lightweight registry tables for custom blocks, items, and entity identifiers.

When the world initializes, the server compiles registries of block permutations and item components and transmits them in startup synchronization packets. For example, if you define a custom block with `minecraft:geometry` and `minecraft:material_instances`, the server sends the block's runtime state IDs and visual component payloads to the client so it knows how to render the block and calculate client-side collision prediction. Server-only behavior components, or your custom Script API handlers, never leave the host.

Add-on Asset or DataNetwork DirectionProtocol Behavior
Resource Packs (RP)Server to Client (on join)Prompted and streamed in chunks during login, or fetched via CDN if configured on the server.
Block & Item RegistriesServer to Client (on start)Sent as runtime numeric IDs mapped to string identifiers like minecraft:destructible_by_mining.
Entity PropertiesServer to Client (on change)Synced in actor data packets only when client_sync is explicitly set to true.
Loot Tables & Spawn RulesNever transmittedEvaluated purely on the server; clients only see the resulting spawned actors or item stacks.
Script API (@minecraft/server)Never transmittedExecutes in the server's QuickJS sandbox; communicates with clients via mutated entity/world state.

Entity Properties and State Synchronization

Because the client handles all rendering, animations, and Molang evaluations for visuals, you frequently need a way to send custom server-side state across the protocol to trigger a client-side effect. Historically, creators abused vanilla actor flags (like `minecraft:is_baby` or `minecraft:is_sheared`) or `minecraft:variant` components to smuggle integers to the client. Modern Bedrock replaces that pattern with Entity Properties declared in the behavior pack entity description.

When you define a property inside the `properties` object of a `minecraft:entity` definition, you control whether the Bedrock Protocol serializes it into actor data packets using the `client_sync` boolean. If `client_sync` is `false`, the property stays entirely in server memory and costs zero network bandwidth. Setting `client_sync` to `true` instructs the server to include the property in the initial entity spawn packet and broadcast delta packets whenever its value changes, making it readable by client-side Molang queries via `q.property()`.

BP/entities/networked_turret.json
{
  "format_version": "1.20.80",
  "minecraft:entity": {
    "description": {
      "identifier": "wiki:networked_turret",
      "is_spawnable": true,
      "is_summonable": true,
      "properties": {
        "wiki:charge_level": {
          "type": "int",
          "range": [0, 100],
          "default": 0,
          "client_sync": true
        },
        "wiki:internal_cooldown": {
          "type": "int",
          "range": [0, 200],
          "default": 0,
          "client_sync": false
        }
      }
    },
    "components": {
      "minecraft:physics": {},
      "minecraft:health": {
        "value": 40,
        "max": 40
      }
    }
  }
}

Script API Messaging and Scriptevents

When working in the `@minecraft/server` Script API environment, your code runs strictly on the server thread after the protocol has unpacked incoming client actions (such as player movement, block breaking, or item use) and before outgoing state updates are flushed at the end of the tick. While you cannot open raw sockets or construct custom RakNet packets from standard server scripts, you can pass structured messages into and out of the script environment using the `scriptevent` protocol pipeline.

The `/scriptevent` command and the `system.afterEvents.scriptEventReceive` listener act as a general-purpose message bus. Although `/scriptevent` is executed on the server (via functions, NPCs, or external RCON/WebSocket tools connected to the server), it is the standard protocol bridge for external tooling or command blocks to inject string payloads into your JavaScript runtime. To send arbitrary text data from your script back to a specific client's UI layer without modifying entity properties, creators commonly emit formatted strings through `player.onScreenDisplay.setActionBar()` or `player.sendMessage()`, which travel over standard text and title packets that custom JSON UI binds can intercept.

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

// Listen for incoming scriptevent payloads from server commands or external bridges
system.afterEvents.scriptEventReceive.subscribe((event) => {
  if (event.id === "wiki:sync_turret") {
    const target = event.sourceEntity;
    if (!target || target.typeId !== "wiki:networked_turret") return;

    const parsedValue = Number.parseInt(event.message, 10);
    if (!Number.isNaN(parsedValue)) {
      // Mutating a client_sync: true property queues an actor data packet for this tick
      target.setProperty("wiki:charge_level", Math.min(Math.max(parsedValue, 0), 100));
    }
  }
}, { namespaces: ["wiki"] });

// Broadcast a lightweight HUD payload to a specific player over the text packet stream
export function sendClientHudPayload(player, chargeLevel) {
  player.onScreenDisplay.setActionBar(`HUD_DATA:${chargeLevel}`);
}

Bandwidth Budgets and Rate Limiting

Because the Bedrock Protocol must keep mobile devices, consoles, and PCs in sync over varied internet connections, the server enforces strict packet size and frequency budgets. Every time you mutate a synced entity property, update a block permutation via `block.setPermutation()`, or spawn particles, the server queues outgoing packets for all players within simulation and tracking range.

If a script modifies a `client_sync: true` property or swaps block states on hundreds of entities or blocks every single tick, the RakNet send queue will back up. On the client, this manifests as delayed sound effects, rubber-banding movement, or entities freezing in place while chunks stop loading. Always throttle visual state updates to the minimum frequency needed by your animations, and keep internal counters in `client_sync: false` properties or Script API `DynamicProperties`—which are saved to the world database on disk and never transmitted over the network.

Which versions this applies to

Applies to all modern Bedrock Edition versions (1.20.x and 1.21.x). Entity Properties, DynamicProperties, and the system.afterEvents.scriptEventReceive API are stable and require no experimental toggles.

When it does not work

What you seeWhyThe fix
Client animations or Render Controllers using q.property() always evaluate to the default value in multiplayer.The entity property in the behavior pack is missing "client_sync": true (it defaults to false if omitted), so the server never serializes the updated value into outgoing actor data packets.Add "client_sync": true to the property definition inside BP/entities/your_entity.json and rejoin the world.
Joining players are kicked with "Connection Timed Out" or "Disconnected from Server" right as the world finishes loading.The behavior or resource pack registry payload or downloaded pack archive is saturating the RakNet handshake timeout, often caused by an uncompressed multi-megabyte resource pack or thousands of generated block permutations.Reduce the total number of block permutations per custom block, compress PNG textures, or host large resource packs externally using the server's CDN pack configuration rather than streaming them directly over RakNet.
Content Log error: "[Scripting] ScriptEvent message exceeds maximum length of 2048 characters."You attempted to pass a massive JSON string or data dump through a single /scriptevent command or system.sendScriptEvent call.Keep scriptevent payloads under the 2048-character limit by sending compact identifiers or splitting large payloads across multiple messages with a sequence ID.

Reference, straight from the game files

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