What a Namespace Is
A namespace is a separate communication channel multiplexed over the same underlying transport connection, identified by a path prefix like /admin or /chat, distinct from the default / namespace every Socket.IO server has out of the box. Namespaces share the same physical WebSocket or HTTP long-polling connection when possible, but logically isolate event handlers, middleware, and connected-socket lists — a socket connected to /chat never receives events emitted only on io.of('/admin'), and io.on('connection') for one namespace fires independently from another's.
Cricket analogy: It's like how a single stadium hosts both an IPL match and a separate practice net session simultaneously — same physical ground infrastructure, but completely separate rosters, umpires, and events, the way two namespaces share a server but not event traffic.
// Server: define a custom namespace
const adminNamespace = io.of('/admin');
adminNamespace.use((socket, next) => {
const token = socket.handshake.auth.token;
if (!isValidAdminToken(token)) {
return next(new Error('unauthorized'));
}
next();
});
adminNamespace.on('connection', (socket) => {
console.log('Admin connected:', socket.id);
socket.on('ban-user', (userId) => {
adminNamespace.emit('user-banned', userId);
});
});
// Client
const adminSocket = io('https://api.example.com/admin', {
auth: { token: adminJwt }
});Namespace-Scoped Middleware
Each namespace can register its own middleware chain via namespace.use((socket, next) => {...}), which runs once per connection attempt to that specific namespace before the connection event fires — this is the idiomatic place to authenticate JWTs, check API keys, or reject connections outright by calling next(new Error(...)). Because middleware is namespace-scoped rather than global, you can require strict admin authentication on /admin while leaving the default / namespace open to anonymous guests, without any conditional branching inside a single shared handler.
Cricket analogy: It's like a stadium having a strict credential check at the players' pavilion gate but an open turnstile for the general stand, mirroring how /admin middleware enforces auth while / stays open.
Dynamic Namespaces
Socket.IO also supports dynamic namespaces created from a regular expression or a parent-namespace function, such as io.of(/^\/tenant-\w+$/), which is essential for multi-tenant SaaS applications where you don't know the full set of tenant slugs ahead of time. When a client connects to /tenant-acme, Socket.IO matches it against the pattern, lazily instantiates that specific namespace on first connection, and fires a connection event scoped to it — letting you attach a namespace.name-based lookup to load tenant-specific configuration inside the connection handler.
Cricket analogy: It's like a franchise league auto-generating a new team channel the moment a new city franchise like 'Lucknow Super Giants' is announced, rather than the league pre-creating channels for every conceivable city name in advance.
Namespaces are distinct from rooms: a namespace is chosen at connection time via the URL path and cannot be changed without reconnecting, while rooms are freely joined and left at any point during a connection's lifetime.
Middleware registered on the default / namespace via io.use() does NOT automatically apply to custom namespaces — each namespace's middleware chain is independent, so io.of('/admin').use(...) must be set up separately even if the logic is identical.
Namespaces vs. a Single Namespace with Event Prefixes
Some teams simulate namespacing by prefixing event names on the default namespace (e.g., chat:message, admin:ban-user) instead of using real namespaces, but this loses the built-in benefits: separate middleware chains, separate connected-socket counts (namespace.sockets.size), and separate disconnect events per logical concern. Real namespaces are the better choice whenever different client types (a public web app vs. an internal admin dashboard) need fundamentally different authentication or connection lifecycles, while event prefixing is acceptable for lightweight categorization within a single trusted client type.
Cricket analogy: It's like the difference between running separate leagues for men's and women's cricket with their own boards and rules, versus just labeling matches 'W-' in a single shared calendar — the former gives real independent governance, the latter is just a naming convention.
- A namespace is a logically isolated channel identified by a URL path (e.g., /admin), distinct from the default / namespace.
- Namespaces can share the same underlying transport connection but never leak events or connected-socket state between each other.
- Each namespace can define its own middleware chain via namespace.use(), independent from io.use() on the default namespace.
- Dynamic namespaces (created via a regex or parent-namespace function) support multi-tenant scenarios by lazily instantiating per-tenant channels.
- The client chooses a namespace at connection time via the URL path; switching namespaces requires a new connection.
- Namespaces differ from rooms: namespace is fixed at connect time, rooms are joined/left dynamically within a connection.
- Prefer real namespaces over event-name prefixing when different client types need genuinely different auth or lifecycle handling.
Practice what you learned
1. What identifies a Socket.IO namespace?
2. Does middleware registered with io.use() on the default namespace apply to a custom namespace like /admin?
3. What are dynamic namespaces typically used for?
4. Can a connected socket switch namespaces without reconnecting?
5. How do namespaces differ fundamentally from rooms?
Was this page helpful?
You May Also Like
Joining and Leaving Rooms
Learn how Socket.IO rooms let you group sockets together so you can broadcast to a subset of connected clients, and how sockets join, leave, and get cleaned up automatically on disconnect.
The Socket.IO Adapter
Learn what the Socket.IO adapter is, how it powers rooms and broadcasting under the hood, and why the default in-memory adapter breaks down once you run more than one server process.
Scaling with the Redis Adapter
Learn how the Redis adapter uses Redis's pub/sub to synchronize rooms and broadcasts across multiple Socket.IO server instances, enabling true horizontal scaling.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics