This post was written for NoLag Cloud, the hosted service, which was retired in October 2026. To run NoLag yourself, start with the self-hosting guide.
Pusher Channels popularised hosted realtime pub/sub, and a lot of apps still run on it. If you are moving to NoLag, the good news is that the mental model is almost identical: you subscribe to a channel, you bind to events, and a publisher sends data to everyone listening. This guide maps Pusher concepts onto NoLag and shows the same subscribe-and-publish flow in both.
Why teams move
NoLag keeps the pub/sub foundation you already rely on and adds a few things Pusher does not focus on:
- Blueprint SDKs for chat, notifications, dashboards, tracking, and more, so common patterns are a few lines instead of a from-scratch build.
- Presence built in, tracked per room, with lobbies for presence across rooms.
- Open source, on your own infrastructure. Pusher runs its service for you; NoLag's kraken broker is Apache-2.0 software you run yourself as a single container, with no vendor lock-in and no bill that grows with your connection count.
Concept map
| Pusher | NoLag |
|---|---|
| App key + cluster | App (a container for rooms and topics) |
| Channel | Room + topic |
channel.bind('event', cb) | room.on('topic', cb) |
pusher.trigger('channel', 'event', data) | room.emit('topic', data) |
| Presence channel | Presence (per room) |
| Private channel + auth endpoint | Actors, access tokens, and per-topic ACL |
Before: Pusher
import Pusher from 'pusher-js'
const pusher = new Pusher('APP_KEY', { cluster: 'eu' })
const channel = pusher.subscribe('chat')
channel.bind('message', (data) => {
console.log('Received:', data)
})
// On your server, using the pusher server SDK:
// pusher.trigger('chat', 'message', { text: 'Hello!' })
After: NoLag
import { NoLag } from '@nolag/js-sdk'
// KRAKEN_URL is your broker, for example ws://localhost:8080/ws.
// The `chat` app and its `general` room are granted to both tokens in your
// auth config (kraken's auth.json or a @nolag/core project document).
const APP_SLUG = 'chat'
// Browser: subscribe as one actor
const client = NoLag('your_access_token', { url: KRAKEN_URL })
const room = client.setApp(APP_SLUG).setRoom('general')
room.on('message', (data) => {
console.log('Received:', data)
})
// Subscribe in the connect handler: it runs after every reconnect too
client.on('connect', () => room.subscribe('message'))
await client.connect()
// Server (or any other authorised actor): publish. Publishers never receive
// their own messages, so publish from a different actor than the one listening.
const server = NoLag('service_access_token', { url: KRAKEN_URL })
await server.connect()
server.setApp(APP_SLUG).setRoom('general').emit('message', { text: 'Hello!' })
The shape is the same. The main differences are that NoLag groups topics inside a room (so you get natural namespacing and presence per room), access is controlled with actors and tokens rather than a per-channel auth endpoint, and any authorised actor can publish from the client side, not only your server. A NoLag publisher never hears its own message back, so append it to your UI locally when you send.
Auth: delete your auth endpoint
Pusher private and presence channels call back to an auth endpoint you host, on every subscribe. NoLag does not need one. A connection authenticates once with an actor access token, and what that actor can read or write is enforced at the broker with per-topic ACL, which kraken caches, so there is no auth round-trip on every subscribe. Every credential resolves to a typed actor, such as user, device, service or session.
For browser clients running against @nolag/core, mint a short-lived JWT (client token) on your backend, signed with a project signing key. Issuing one is a local signing step with no network call, and it expires on its own within minutes, so a long-lived secret never reaches the browser.
Presence
Pusher presence channels map to NoLag presence, tracked per room. A client joins the member list by calling room.setPresence(data), and everyone else gets presence:join, presence:leave and presence:update events on the client, plus room.fetchPresence() for the current member list, without standing up your own tracking.
Next steps
- Follow the 5-minute quick start to connect for the first time.
- If you are building chat, the chat blueprint gives you rooms, who-is-online presence, typing indicators and streamed messages out of the box. It keeps an in-memory cache of the messages it has seen; message history is yours to store.
- Compare the platforms in more detail: NoLag vs Pusher.