Skip to main content
Version: 4.x

Namespaces

A Namespace is a communication channel that allows you to split the logic of your application over a single shared connection (also called "multiplexing").

Namespace diagramNamespace diagram

Introduction​

Each namespace has its own:

io.of("/orders").on("connection", (socket) => {
socket.on("order:list", () => {});
socket.on("order:create", () => {});
});

io.of("/users").on("connection", (socket) => {
socket.on("user:list", () => {});
});
const orderNamespace = io.of("/orders");

orderNamespace.on("connection", (socket) => {
socket.join("room1");
orderNamespace.to("room1").emit("hello");
});

const userNamespace = io.of("/users");

userNamespace.on("connection", (socket) => {
socket.join("room1"); // distinct from the room in the "orders" namespace
userNamespace.to("room1").emit("hola");
});
const orderNamespace = io.of("/orders");

orderNamespace.use((socket, next) => {
// ensure the socket has access to the "orders" namespace, and then
next();
});

const userNamespace = io.of("/users");

userNamespace.use((socket, next) => {
// ensure the socket has access to the "users" namespace, and then
next();
});

Possible use cases:

  • you want to create a special namespace that only authorized users have access to, so the logic related to those users is separated from the rest of the application
const adminNamespace = io.of("/admin");

adminNamespace.use((socket, next) => {
// ensure the user has sufficient rights
next();
});

adminNamespace.on("connection", (socket) => {
socket.on("delete user", () => {
// ...
});
});
  • your application has multiple tenants, so you want to dynamically create one namespace per tenant
const workspaces = io.of(/^\/\w+$/);

workspaces.on("connection", (socket) => {
const workspace = socket.nsp;

workspace.emit("hello");
});

Main namespace​

Until now, you interacted with the main namespace, called /. The io instance inherits all of its methods:

io.on("connection", (socket) => {});
io.use((socket, next) => { next() });
io.emit("hello");
// are actually equivalent to
io.of("/").on("connection", (socket) => {});
io.of("/").use((socket, next) => { next() });
io.of("/").emit("hello");

Some tutorials may also mention io.sockets, it's simply an alias for io.of("/").

io.sockets === io.of("/")

Custom namespaces​

To set up a custom namespace, you can call the of function on the server-side:

const nsp = io.of("/my-namespace");

nsp.on("connection", (socket) => {
console.log("someone connected");
});

nsp.emit("hi", "everyone!");

Client initialization​

Same-origin version:

const socket = io(); // or io("/"), the main namespace
const orderSocket = io("/orders"); // the "orders" namespace
const userSocket = io("/users"); // the "users" namespace

Cross-origin/Node.js version:

const socket = io("https://example.com"); // or io("https://example.com/"), the main namespace
const orderSocket = io("https://example.com/orders"); // the "orders" namespace
const userSocket = io("https://example.com/users"); // the "users" namespace

In the example above, only one low-level connection will be established, and the packets will automatically be routed to the right namespace.

Please note that multiplexing will be disabled in the following cases:

  • multiple creations for the same namespace
const socket1 = io();
const socket2 = io(); // no multiplexing, two distinct WebSocket connections
  • different domains
const socket1 = io("https://first.example.com");
const socket2 = io("https://second.example.com"); // no multiplexing, two distinct WebSocket connections
const socket1 = io();
const socket2 = io("/admin", { forceNew: true }); // no multiplexing, two distinct WebSocket connections

Dynamic namespaces​

Usage​

It is also possible to dynamically create namespaces, either with a regular expression:

io.of(/^\/dynamic-\d+$/);

or with a function:

io.of((name, auth, next) => {
// name is the requested namespace, for example "/workspace-123"
// auth is the authentication payload sent by the client
next(null, true); // or false, when the creation is denied
});

You can access the newly created namespace in the connection event:

io.of(/^\/dynamic-\d+$/).on("connection", (socket) => {
const namespace = socket.nsp;
});

Priority​

Existing namespaces have priority over dynamic namespaces. For example:

// register "dynamic-101" namespace
io.of("/dynamic-101");

io.of(/^\/dynamic-\d+$/).on("connection", (socket) => {
// will not be called for a connection on the "dynamic-101" namespace
});

Security considerations​

Prefer function-based dynamic namespaces when namespace creation depends on user identity, permissions, or tenant membership.

For example, this pattern:

io.of(/^\/\w+$/);

allows any client to create a new namespace by connecting to a matching name. Depending on your application, this could lead to unexpected namespace creation or resource usage.

You can use a function-based dynamic namespace to explicitly authorize or deny the creation:

io.of((name, auth, next) => {
// validate both the namespace name and the auth payload
next(null, true); // or false, when the creation is denied
});

Parent namespace​

The return value of the of() method is what we call the parent namespace, from which you can:

const parentNamespace = io.of(/^\/dynamic-\d+$/);

parentNamespace.use((socket, next) => {
next();
});

The middleware will automatically be registered on each child namespace.

const parentNamespace = io.of(/^\/dynamic-\d+$/);

parentNamespace.emit("hello"); // will be sent to users in /dynamic-1, /dynamic-2, ...

Cleanup of empty child namespaces​

By default, dynamically created child namespaces are kept in memory even after the last socket disconnects.

You can enable automatic cleanup with the cleanupEmptyChildNamespaces option (available since v4.6.0):

const io = new Server(httpServer, {
cleanupEmptyChildNamespaces: true,
});

With this option enabled, a child namespace created from a dynamic namespace is removed once it has no connected sockets anymore.

Complete API​

The complete API exposed by the Namespace instance can be found here.