---
title: Project Hierarchy
description: Understand how Projects, Apps, Rooms, and Topics work together to organize your real-time infrastructure.
---

# Project Hierarchy

How Projects, Apps, Rooms, and Topics work together to organize your real-time infrastructure.

## Overview

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.

```text
project     / app        / room           / topic
─────────────────────────────────────────────────
logistics   / chat       / dispatch-team  / messages
logistics   / tracking   / driver-42      / locations
logistics   / dashboard  / overview       / metrics
```

## 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, usage) belongs to that project.

- **Billing boundary:** usage limits (connections, messages, bandwidth) are tracked per project
- **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

Think of a project the same way you'd think of a Firebase project or a Supabase project: one per product, per environment.

## 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, per-topic webhook settings, and message logging settings.

**Why separate apps instead of one big app?** Because different features have fundamentally different requirements:

- A **chat app** needs message history with 7-day retention and replay
- A **GPS tracking app** needs low-latency fire-and-forget delivery with no logging
- A **dashboard app** needs aggregated metrics with short retention

By splitting these into separate apps, each one gets its own configuration without compromise. Chat doesn't inherit tracking's fire-and-forget QoS. Tracking doesn't pay for chat's message storage. And if you need to add a notifications feature later, you add a new app without touching the others.

Actors are granted access to specific apps within a project. A single actor can be given access to chat, the live dashboard, and notifications, interacting with each through one connection.

## 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.

- In a **chat app**: each room is a conversation: `dispatch-team`, `drivers-east`, `support`
- In a **tracking app**: each room is a tracked entity: `driver-42`, `vehicle-108`
- In a **dashboard app**: each room is a view: `overview`, `region-north`

Rooms can be **static** (defined in your app configuration for permanent channels like `general`) or **dynamic** (created via the REST API when a new driver signs up or a new team is formed).

### Public vs Private Rooms

By default, rooms are **public**, 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 a team to their chat room, and outsiders can't join.

## 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`.

- `messages`: chat messages with history and replay
- `_typing`: ephemeral typing indicators (no logging)
- `locations`: GPS coordinates streamed in real-time
- `metrics`: aggregated dashboard data points

Topics are defined at the app level and inherited by every room. This means all rooms in your chat app have the same topic structure (`messages` and `_typing`), so you configure once and scale to thousands of rooms.

## Putting It All Together

Here's how a logistics platform maps to the hierarchy:

| Level | Example | Purpose |
| --- | --- | --- |
| **Project** | `logistics-prod` | Billing, actor management, environment boundary |
| **Apps** | `chat`, `tracking`, `dashboard` | 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 (actor) with access to all three apps can simultaneously:

- Sends and receives messages in the `chat / dispatch-team / messages` channel
- Watches live GPS updates from `tracking / driver-42 / locations`
- Monitors fleet health on `dashboard / overview / metrics`

All through one connection, with each app's data cleanly separated.

## Next Steps

- [Rooms: static vs dynamic, room types](/docs/concepts/rooms)
- [Topics: pub/sub, logging, replay](/docs/concepts/topics)
- [Presence: tracking who's online](/docs/concepts/presence)
- [Access Control: permissions per actor](/docs/concepts/acl)
