# LISTEN and NOTIFY > Send a message to every client that listens on a channel when a transaction commits - over the PostgreSQL port (LISTEN) or HTTP (GET /listen, server-sent events). - Category: Postgres protocol - Keywords: LISTEN, NOTIFY, UNLISTEN, UNLISTEN \*, pg\_notify, notification, notifications, pub/sub, pubsub, publish, subscribe, PUBLISH, SUBSCRIBE, PSUBSCRIBE, pattern, pmessage, redis, push, event, events, channel, payload, NotificationResponse, GET /listen, /listen, server-sent events, SSE, EventSource, text/event-stream, payload string too long, channel name cannot be empty, 54000, trigger notify, LISTEN needs a connection that stays open - See also: [PostgreSQL protocol (port 8832)](postgres-protocol.md), [Triggers](triggers.md), [Transactions](transactions.md), [Run SQL over HTTP (/exec, /exp)](http-exec.md), [CREATE TABLE (row-ttl)](create-table.md#row-ttl), [Key-value store (Redis-like) (kv-pubsub)](kv.md#kv-pubsub) `NOTIFY` sends a short message on a **channel**. Every client that listens on that channel gets it, the moment the sending transaction commits. It works as in PostgreSQL 14, and web pages can listen over HTTP too. | | How | |---|---| | Send | `NOTIFY orders, 'order 42 paid'` or `SELECT pg_notify('orders', 'order 42 paid')`, from any client, a [trigger](triggers.md) or a procedure | | Listen (PostgreSQL port) | `LISTEN orders` on a connection that stays open ([below](#listen-pg)) | | Listen (HTTP, web pages) | `GET /listen?channel=orders`: server-sent events ([below](#listen-http)); `?pattern=price.*` for every channel a pattern matches | | Redis-style | `PUBLISH`, `PUBSUB` and keyspace events through `POST /kv` ([key-value store](kv.md#kv-pubsub)): the same channels, sent at once | The rules, the same as PostgreSQL's: - A message is delivered when its transaction **commits**, never after a `ROLLBACK`. `ROLLBACK TO SAVEPOINT` drops the ones sent after the savepoint. - The same channel and payload sent twice in one transaction arrive **once**. Otherwise the order is kept. - Channels belong to one database: a `NOTIFY` in `market` never reaches a listener of `app`. - A message is a signal for clients connected **now**: nothing is stored, and nothing is sent again after a restart. Read the table after a message to get the data. ## NOTIFY and pg_notify() Syntax: ```sql NOTIFY channel [, 'payload'] pg_notify(channel_text, payload_text) ``` | Part | Meaning | |---|---| | `channel` | a name. Without quotes it is lower case (`NOTIFY Orders` goes to `orders`); `"Orders"` keeps its case | | `payload` | text of at most 7999 bytes; none = empty | | `pg_notify(...)` | the same as a function, for a value made in the query. It takes the channel as written (no lower case) | - **Returns:** `NOTIFY`; `pg_notify()` gives `NULL`. - **Errors:** `payload string too long`, `channel name cannot be empty`, `channel name too long` (more than 63 bytes). - Anyone who may read the database may send and listen, as in PostgreSQL. **Example: Send inside a transaction: it goes out at COMMIT** ```sql BEGIN; NOTIFY orders, 'order 42 paid'; SELECT pg_notify('orders', 'order ' || 43 || ' paid'); COMMIT; ``` Result: `BEGIN` ```text transaction started ``` `NOTIFY orders, 'order 42 paid'` ```text notification on channel 'orders': sent to its listeners when the transaction commits ``` `SELECT pg_notify('orders', 'order ' || 43 || ' paid')` | pg_notify('orders', 'order ' \|\| 43 \|\| ' paid') (STRING) | |---| | NULL | (1 row) `COMMIT` ```text transaction committed: 0 change(s) saved ``` **Example: A payload that is too long** (shows an error) ```sql SELECT pg_notify('orders', repeat('x', 8000)); ``` Result: Error: `line 1, column 8: pg_notify: payload string too long` ### From a trigger A [trigger](triggers.md) can send a message for each new row. It is part of the statement's transaction: a failed insert sends nothing. **Example: Tell the listeners about every paid order** ```sql CREATE TABLE payments (id LONG PRIMARY KEY, amount DOUBLE); CREATE TRIGGER tell_paid AFTER INSERT ON payments EXECUTE BEGIN SELECT pg_notify('payments', 'paid ' || id) FROM NEW; END; INSERT INTO payments VALUES (1, 250.0), (2, 99.5); ``` Result: `CREATE TABLE payments (` ```text table 'payments' created ``` `CREATE TRIGGER tell_paid AFTER INSERT ON payments EXECUTE BEGIN` ```text trigger 'tell_paid' created on table 'payments' ``` `INSERT INTO payments VALUES (1, 250.0), (2, 99.5)` ```text 2 row(s) inserted ``` `SELECT pg_notify('payments', 'paid ' || id) FROM NEW` | pg_notify('payments', 'paid ' \|\| id) (STRING) | |---| | NULL | | NULL | (2 rows) ## LISTEN on the PostgreSQL port Syntax: ```sql LISTEN channel UNLISTEN channel | * ``` - The connection gets a `NotificationResponse` (channel, payload, the sender's process id) for each message. Drivers show them their own way: psql prints `Asynchronous notification "orders" with payload "..." received from server process with PID 17.`, pgx has `WaitForNotification`, psycopg `conn.notifies()`, node-pg the `notification` event. - An idle connection gets it at once. A connection inside `BEGIN ... COMMIT` gets it when that transaction ends, as in PostgreSQL. Its own messages come right after its `COMMIT`. - `LISTEN` inside `BEGIN ... COMMIT` starts at `COMMIT`, and not at all after `ROLLBACK`. `DISCARD ALL` stops every listen. ## GET /listen: server-sent events Syntax: ```sql GET /listen?channel=orders[&channel=payments][&pattern=price.*][&db=name] ``` The reply is `text/event-stream` and stays open. A browser reads it with `EventSource`: ```js const es = new EventSource('/listen?channel=orders'); es.onmessage = (e) => { const n = JSON.parse(e.data); // {"channel":"orders","payload":"order 42 paid","pid":0} refreshOrders(); }; ``` | Event | When | |---|---| | `listen` | once, when listening started: `{"channels":[...],"patterns":[...],"database":"..."}` | | (message) | one per notification: `{"channel","payload","pid"}`; `pid` is 0 for a sender that is not a PostgreSQL connection; `"pattern"` too when it came through a pattern | | `: ping` (a comment) | every 15 s, so a proxy keeps the stream open | | `error` | the stream ends after it (see [limits](#limits)) | - It needs a login, like [/exec](http-exec.md) (`Authorization: Bearer ...`, or the console's cookie). Up to 64 channels and patterns in one stream; the names are taken as written. - `channel=` is Redis's `SUBSCRIBE`, `pattern=` its `PSUBSCRIBE`: a glob as `KEYS` takes it (`*` any text, `?` one character, `[abc]`, `\` before a special character). `/listen?pattern=price.*` gets `price.NABIL`, `price.HDL`, ... A message that matches a channel and a pattern of the same stream comes once for each. - Over HTTP a channel may be up to 4096 bytes long (a [keyspace event](kv.md#kv-events) holds the whole key); `NOTIFY` keeps PostgreSQL's 63. - `LISTEN` sent through `/exec` is refused with the way to do it: a request has no connection that stays open to be told. ## Limits - A listener that does not read keeps up to 32 MB of messages. Past that, it is **cut off**: the PostgreSQL connection ends with SQLSTATE `54000`, the HTTP stream with an `error` event. Nothing is lost quietly: connect again, `LISTEN` again, and read the table. - At most 256 HTTP streams at once (`503` beyond). - Messages of one sending connection arrive in commit order. Messages of two connections that commit at the same moment may arrive in either order.