Skip to main content
Version: 4.x

Postgres adapter

How it works

The Postgres adapter relies on the NOTIFY and LISTEN commands.

Every packet that is sent to multiple clients (e.g. io.to("room1").emit() or socket.broadcast.emit()) is:

  • sent to all matching clients connected to the current server
  • if the packet contains binary data or is above the 8000 bytes limit, the packet is:
    • encoded with msgpack and inserted in an auxiliary table
    • the row ID is sent within a NOTIFY command
    • this row ID is received by the other Socket.IO servers of the cluster, which query the table, decode the packet and then broadcast it to their own set of connected clients
  • else, the packet is simply sent within a NOTIFY command and received by the other Socket.IO servers of the cluster
Diagram of how the Postgres adapter worksDiagram of how the Postgres adapter works

The source code of this adapter can be found here.

Supported features

Featuresocket.io versionSupport
Socket management4.0.0✅ YES (since version 0.1.0)
Inter-server communication4.1.0✅ YES (since version 0.1.0)
Broadcast with acknowledgements4.5.0✅ YES (since version 0.3.0)
Connection state recovery4.6.0❌ NO

Installation

npm install @socket.io/postgres-adapter pg

For TypeScript users, you might also need @types/pg.

Usage

import { Server } from "socket.io";
import { createAdapter } from "@socket.io/postgres-adapter";
import pg from "pg";

const io = new Server();

const pool = new pg.Pool({
user: "postgres",
host: "localhost",
database: "postgres",
password: "changeit",
port: 5432,
});

pool.query(`
CREATE TABLE IF NOT EXISTS socket_io_attachments (
id bigserial UNIQUE,
created_at timestamptz DEFAULT NOW(),
payload bytea
);
`);

pool.on("error", (err) => {
console.error("Postgres error", err);
});

io.adapter(createAdapter(pool));
io.listen(3000);

Options

NameDescriptionDefault value
uidthe ID of this nodea random ID
channelPrefixthe prefix of the notification channelsocket.io
tableNamethe name of the table for payloads over the 8000 bytes limit or containing binary datasocket_io_attachments
payloadThresholdthe threshold for the payload size in bytes8000
requestsTimeoutthe timeout for inter-server requests such as fetchSockets() or serverSideEmit() with ack5000
heartbeatIntervalthe number of ms between two heartbeats5000
heartbeatTimeoutthe number of ms without heartbeat before we consider a node down10000
cleanupIntervalthe number of ms between two cleanup queries30000

Common questions

Do I still need to enable sticky sessions when using the Postgres adapter?

Yes. Failing to do so will result in HTTP 400 responses (you are reaching a server that is not aware of the Socket.IO session).

More information can be found here.

What happens when the Postgres server is down?

In case the connection to the Postgres server is severed, the packets will only be sent to the clients that are connected to the current server.

Latest releases

VersionRelease dateRelease notesDiff
0.3.1February 2023link0.3.0...0.3.1
0.3.0April 2022link0.2.0...0.3.0
0.2.0December 2021link0.1.1...0.2.0
0.1.1June 2021link0.1.0...0.1.1
0.1.0June 2021link

Complete changelog

Emitter

The Postgres emitter allows sending packets to the connected clients from another Node.js process:

Diagram of how the Postgres emitter worksDiagram of how the Postgres emitter works

Installation

npm install @socket.io/postgres-emitter pg

Usage

const { Emitter } = require("@socket.io/postgres-emitter");
const { Pool } = require("pg");

const pool = new Pool({
user: "postgres",
host: "localhost",
database: "postgres",
password: "changeit",
port: 5432,
});

const emitter = new Emitter(pool);

setInterval(() => {
emitter.emit("ping", new Date());
}, 1000);

Please refer to the cheatsheet here.

Latest releases

VersionRelease dateRelease notesDiff
0.1.0June 2021link

Complete changelog