sql 303 lines · 2 tabs

PostgreSQL LISTEN/NOTIFY for pub-sub messaging

Maria Garcia Feb 2026
2 tabs
-- Publisher: Send notification
NOTIFY new_order, 'Order #12345 created';

-- Subscriber: Listen for notifications
LISTEN new_order;

-- In another connection, will receive notification
-- Client libraries handle notification delivery

-- Unlisten
UNLISTEN new_order;
UNLISTEN *;  -- Unlisten all channels

-- Send notification with JSON payload
SELECT pg_notify(
  'user_updates',
  json_build_object(
    'user_id', 123,
    'action', 'updated',
    'timestamp', NOW()
  )::TEXT
);

-- Trigger-based notifications
CREATE OR REPLACE FUNCTION notify_new_order()
RETURNS TRIGGER AS $$
BEGIN
  PERFORM pg_notify(
    'new_order',
    json_build_object(
      'order_id', NEW.id,
      'user_id', NEW.user_id,
      'total', NEW.total,
      'created_at', NEW.created_at
    )::TEXT
  );
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER order_notification
AFTER INSERT ON orders
FOR EACH ROW
EXECUTE FUNCTION notify_new_order();

-- Now every insert sends notification
INSERT INTO orders (user_id, total) VALUES (123, 99.99);
-- Listeners receive: {"order_id": 456, "user_id": 123, ...}

-- Cache invalidation pattern
CREATE OR REPLACE FUNCTION notify_cache_invalidation()
RETURNS TRIGGER AS $$
BEGIN
  PERFORM pg_notify(
    'cache_invalidate',
    json_build_object(
      'table', TG_TABLE_NAME,
      'id', NEW.id,
      'operation', TG_OP
    )::TEXT
  );
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER users_cache_invalidation
AFTER INSERT OR UPDATE OR DELETE ON users
FOR EACH ROW
EXECUTE FUNCTION notify_cache_invalidation();

-- Application listens and clears cache
/*
// Node.js example
const client = new Client();
await client.connect();

client.on('notification', (msg) => {
  const payload = JSON.parse(msg.payload);
  console.log('Cache invalidation:', payload);

  // Clear cache
  cache.del(`user:${payload.id}`);
});

await client.query('LISTEN cache_invalidate');
*/

-- Real-time dashboard updates
CREATE OR REPLACE FUNCTION notify_metrics_update()
RETURNS TRIGGER AS $$
BEGIN
  PERFORM pg_notify(
    'metrics_update',
    json_build_object(
      'metric_name', NEW.metric_name,
      'value', NEW.value,
      'timestamp', NEW.timestamp
    )::TEXT
  );
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER metrics_notification
AFTER INSERT ON metrics
FOR EACH ROW
EXECUTE FUNCTION notify_metrics_update();

-- Transactional notifications
BEGIN;

INSERT INTO orders (user_id, total) VALUES (123, 99.99);
-- Notification not sent yet

COMMIT;
-- Notification sent after commit

-- If rolled back:
BEGIN;
INSERT INTO orders (user_id, total) VALUES (123, 99.99);
ROLLBACK;
-- Notification NOT sent

-- Multiple channels
LISTEN orders;
LISTEN inventory;
LISTEN user_activity;

-- Conditional notifications
CREATE OR REPLACE FUNCTION notify_high_value_order()
RETURNS TRIGGER AS $$
BEGIN
  IF NEW.total > 1000 THEN
    PERFORM pg_notify(
      'high_value_order',
      json_build_object('order_id', NEW.id, 'total', NEW.total)::TEXT
    );
  END IF;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;
2 files · sql Explain with highlit

LISTEN/NOTIFY provides real-time pub-sub messaging. Publishers send notifications via NOTIFY. Subscribers receive notifications via LISTEN. I use it for cache invalidation, real-time updates, inter-process communication. Payloads up to 8000 bytes carry small messages. Notifications are transactional—committed before delivery. Understanding connection-based nature prevents missed messages. LISTEN/NOTIFY is simpler than external message queues for database events. Proper use enables reactive architectures. Essential for real-time features, event-driven systems, microservices coordination. PostgreSQL LISTEN/NOTIFY rivals dedicated message brokers for many use cases.


Related snips

sql
-- Simple function
CREATE OR REPLACE FUNCTION get_full_name(
  first_name VARCHAR,
  last_name VARCHAR
)
RETURNS VARCHAR AS $$

Stored procedures and functions in PostgreSQL

postgresql stored-procedures functions
by Maria Garcia 2 tabs
sql
-- EXPLAIN ANALYZE (actual execution statistics)
EXPLAIN ANALYZE
SELECT u.username, COUNT(o.id) AS order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.created_at >= '2024-01-01'

Advanced query optimization techniques

database optimization query-performance
by Maria Garcia 2 tabs
ruby
class Comment < ApplicationRecord
  belongs_to :article
  belongs_to :author, class_name: "User"

  validates :body, presence: true, length: { maximum: 2_000 }

Live comments with model broadcasts + turbo_stream_from

rails hotwire turbo
by codesnips 4 tabs
erb
<%# private stream: turbo signs the serialized record name %>
<%= turbo_stream_from current_user %>

<section class="notifications">
  <h1>Notifications</h1>

Turbo Streams + authorization: signed per-user stream name

rails turbo hotwire
by codesnips 3 tabs
java
package com.example.demo.config;

import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.common.serialization.StringDeserializer;
import org.apache.kafka.common.serialization.StringSerializer;

Messaging with Apache Kafka

java kafka messaging
by David Kumar 3 tabs
javascript
// Basic event listener
const button = document.getElementById('myButton');

button.addEventListener('click', function(event) {
  console.log('Button clicked!');
  console.log('Event type:', event.type);

Event handling and event delegation patterns in JavaScript

javascript events event-delegation
by Alex Chang 1 tab

Share this code

Here's the card — post it anywhere.

PostgreSQL LISTEN/NOTIFY for pub-sub messaging — share card
Link copied