Send and receive custom network messages with full control.
Needle Engine provides a low-level API for sending and receiving messages. We call this "manual networking". The principles are the same as automatic networking, but you're in full control of when to send messages, what data to send, and how to handle incoming messages.
When to Use Manual Networking
Use manual networking when you need:
Custom message formats
Complex data structures
Fine-grained control over when messages are sent
High-performance binary messages
Custom server-side logic
For simple field synchronization, use @syncField instead.
::: warning Advanced - Not Needed for Most Use Cases Binary messages with FlatBuffers are an advanced optimization for very high-frequency updates (100+ messages per second). Most applications should use JSON messages which are simpler and easier to work with. :::
For extreme performance scenarios, send binary (Flatbuffer) messages:
You can subscribe to events in the room using a specific key. Typically, you want to match subscribing with unsubscribing:
Option 1: Enable/Disable Lifecycle Subscribe in onEnable and unsubscribe in onDisable. With this approach, no messages will be received while the object is disabled.
Option 2: Start/Destroy Lifecycle Subscribe in start and unsubscribe in onDestroy. With this approach, messages will still be received while the object is disabled.
Unsubscribe from Messages
Always unsubscribe when you're done listening:
Message Persistence
When sending network messages, you can control whether messages should be saved in the room state (persistent) or only sent to users currently in the room (non-persistent).
Persistent Messages
To persist a message, include a guid field. This field typically identifies which object the message applies to:
Non-Persistent Messages
Messages without a guid field are only sent to users currently in the room:
Prevent Persistence (with guid)
To target a specific object (include a guid) but still prevent persistence, set dontSave to true:
Delete on Disconnect
To persist a message but delete it when the user disconnects, use deleteOnDisconnect:
Delete Specific State
To delete state for a specific guid from the backend storage:
Debug Flags
Use these URL parameters to understand network messages:
Flag
Description
?debugnet
Log all incoming and outgoing network messages
?debugowner
Log all ownership requests and changes
?debugnetbin
Log binary message details
Example:
Using Flatbuffers (Advanced)
::: warning Advanced Feature - Not Necessary for Most Projects You probably don't need this. FlatBuffers are an advanced optimization for extreme performance scenarios (e.g., 100+ network messages per second).
For most multiplayer applications, JSON messages are:
Much easier to implement and debug
Fully sufficient for typical gameplay (movement, interactions, chat, etc.)
Already optimized by Needle Engine
Only consider FlatBuffers if you have profiled your application and confirmed that JSON message serialization is a bottleneck. :::
Binary messages using Flatbuffers can be faster and more efficient than JSON messages for very high-frequency updates or extremely large data structures.
Requirements:
Define custom FlatBuffer schemas (.fbs files)
Compile schemas to TypeScript using the FlatBuffers compiler
Register schemas with the networking system
Write custom serialization/deserialization code
Register a Schema
Send Binary Messages
Receive Binary Messages
Unsubscribe from Binary Messages
Built-in Flatbuffer Schemas
Needle Engine uses these binary schemas internally:
SyncedCamera ('SCAM') - Camera position/rotation sync
Vec2/3/4 - Optimized vector types
::: tip Custom Binary Messages Currently, custom binary messages can't be automatically persisted on the networking server. To enable persistence, you need to modify the networking server to process your custom flatbuffer schemas. :::
// This message will be saved in room state
// and sent to users who join later
this.context.connection.send("my-message", {
guid: this.guid,
myData: "myValue"
});
// This message will NOT be saved in room state
// Only current users receive it
this.context.connection.send("my-message", {
myData: "myValue"
});
// Send to a specific object but don't persist
this.context.connection.send("my-message", {
guid: this.guid,
myData: "myValue",
dontSave: true
});
// Persist until the user disconnects
this.context.connection.send("my-message", {
guid: this.guid,
myData: "myValue",
deleteOnDisconnect: true
});