Four levels. Zero confusion.
Every message in NoLag flows through a four-level hierarchy. Each level exists for a specific reason. Skip one, and you'd lose an important boundary.
A logistics platform with chat, GPS tracking, a live dashboard, and notifications, all within one project.
Project: Your Product Boundary
A project is the top-level container. It represents your product or a specific environment of your product. Everything inside (apps, actors, rooms, access scopes) belongs to that project.
Isolation and limits
Each project's rooms resolve to their own internal topics, so one project's traffic never reaches another. Connection and message-size limits come from your auth backend and are enforced by the broker.
Actor home
Actors (your end users) are created within a project and granted access to specific apps.
Environment separation
Most teams create separate projects for production and staging so test traffic never touches real data.
App: A Distinct Real-time Feature
Inside a project, each app represents a separate real-time capability. Apps have their own topic definitions, room configurations, and webhooks.
Why separate apps instead of one big app?
Because different features have fundamentally different requirements:
Chat app
Needs messages that people read and reply to, plus ephemeral typing indicators that nobody needs to keep.
GPS tracking app
Needs low-latency fire-and-forget delivery. Stale coordinates are useless.
Dashboard app
Needs retained snapshots so a new viewer sees the latest numbers at once, plus widget configuration updates.
Notifications app
Needs a private room per user so each person receives only their own alerts, with read state synced across tabs.
By splitting these into separate apps, each one gets its own topics, rooms, and webhooks without compromise. Chat's webhooks never fire for GPS pings, and tracking's per-driver rooms never clutter the chat room list. When you need a new feature later, you add a new app without touching the others.
Room: Scoped Data Isolation
Rooms give each user, team, device, or session their own isolated instance of an app's topics. Without rooms, every subscriber to "messages" would see every message from every conversation. Rooms scope the data.
Chat app
Each room is a conversation: dispatch-team, drivers-east, support.
Tracking app
Each room is a tracked entity: driver-42, vehicle-108.
Dashboard app
Each room is a view: overview, region-north.
Static vs Dynamic Rooms
Rooms can be static (defined in your app configuration for permanent channels like general) or dynamic (created at runtime through @nolag/core or your own auth service when a new driver signs up or a new team is formed). With @nolag/core, rooms are never created implicitly: the broker refuses an unknown room rather than inventing one, so a typo is a visible error.
Public vs Private Rooms
With @nolag/core, rooms are public by default, meaning any actor with access to the app can connect. When you attach specific actors to a room, that room automatically becomes private. Only the attached actors can access it.
This is how you implement per-user or per-team data isolation without writing any authorization logic:
- Attach a driver to their tracking room, and no other driver can see their GPS stream
- Attach team members to a chat room, and outsiders can't join
- Attach a user to their notification room, and only they receive their alerts
Topic: The Message Channel
Topics are the actual pub/sub channels within a room. Each topic carries one type of data. Subscribers choose which topics to listen to, so a client in the dispatch-team chat room might subscribe to messages but not _typing.
messagesChat messages people read and reply to
_typingEphemeral typing indicators, fire-and-forget
locationsGPS coordinates streamed in real-time
metricsAggregated dashboard data points
Topic Inheritance
Topics are defined at the app level and inherited by every room. All rooms in your chat app share the same topic structure (messages and _typing), so you configure once and scale to thousands of rooms.
Putting It All Together
| Level | Example | Purpose |
|---|---|---|
| Project | logistics-prod | Isolation and connection limits, actor management, environment boundary |
| Apps | chat, tracking, dashboard, notify | Separate features with independent config |
| Rooms | dispatch-team, driver-42, overview | Per-user/team/device data isolation |
| Topics | messages, locations, metrics | Individual message channels within a room |
A dispatcher with access to all four apps can simultaneously:
dispatch-teamdriver-42overviewdispatcher-7All through one connection, with each app's data cleanly separated.
Ready to build?
Run the broker locally and start publishing messages in under 5 minutes.