Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/miguelmartinezmestre/listen-postgres-changes-viewer/llms.txt

Use this file to discover all available pages before exploring further.

Overview

This guide will help you set up PostgreSQL Realtime Monitor from scratch. You’ll have a working real-time database monitor with a React frontend in just a few steps.
Make sure you have Bun and Docker installed before starting.

Installation

1

Install Dependencies

Install all required packages using Bun:
bun install
This installs:
  • postgres - PostgreSQL client with logical replication support
  • react & react-dom - UI framework (v19.2.0)
  • typescript - Type safety and developer experience
2

Start PostgreSQL

Launch PostgreSQL with Docker Compose. This starts a PostgreSQL 16 instance with logical replication enabled:
docker-compose up -d
The database starts with:
  • Host: localhost:5432
  • Database: appdb
  • User: appuser
  • Password: secret
  • Logical Replication: Enabled (wal_level=logical)
  • Publication: alltables (created automatically via init.sql)
docker-compose.yml
version: "3.9"

services:
  db:
    image: postgres:16-alpine
    container_name: postgres-realtime
    restart: unless-stopped
    environment:
      POSTGRES_DB: appdb
      POSTGRES_USER: appuser
      POSTGRES_PASSWORD: secret
    ports:
      - "5432:5432"
    command: >
      postgres
        -c wal_level=logical
        -c max_wal_senders=10
        -c max_replication_slots=10
        -c max_connections=100
    volumes:
      - db-data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
3

Start the Application

Run the Bun development server:
bun run dev
This starts:
  • HTTP Server on http://localhost:3000
  • WebSocket Server on ws://localhost:3000/ws
  • Hot Module Reloading for React components
You should see output like:
🚀 Server running at http://localhost:3000
📡 WebSocket available at ws://localhost:3000/ws
✅ Realtime subscription ready (connected or reconnected)
4

Open in Browser

Navigate to http://localhost:3000You’ll see:
  • A connection status indicator (should show “Connected”)
  • An empty table waiting for database changes
  • Total changes counter at 0

Testing Real-time Updates

Now let’s see the real-time monitoring in action by making database changes.
1

Connect to PostgreSQL

Open a new terminal and connect to the running PostgreSQL container:
docker exec -it postgres-realtime psql -U appuser -d appdb
You should see the PostgreSQL prompt:
psql (16.x)
Type "help" for help.

appdb=#
2

Create a Test Table

Create a simple todos table:
CREATE TABLE todos (
  id SERIAL PRIMARY KEY,
  title TEXT NOT NULL,
  done BOOLEAN NOT NULL DEFAULT false,
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
Watch your browser - the table columns will automatically appear once you insert data!
3

Insert Data

Add some todo items and watch them appear instantly in the browser:
INSERT INTO todos (title) VALUES ('Build real-time monitor');
INSERT INTO todos (title) VALUES ('Write documentation');
INSERT INTO todos (title) VALUES ('Deploy to production');
Each INSERT operation will:
  • Appear in the browser immediately
  • Show operation type as INSERT (green badge)
  • Display all column values including auto-generated id and created_at
  • Increment the total changes counter
4

Update and Delete

Try UPDATE and DELETE operations:
-- Mark a todo as done (UPDATE shows in blue)
UPDATE todos SET done = true WHERE id = 1;

-- Delete a todo (DELETE shows in red)
DELETE FROM todos WHERE id = 3;
Watch how:
  • UPDATE operations show in blue badges
  • DELETE operations show in red badges
  • All changes appear instantly without page refresh

Understanding the Architecture

Here’s how the system captures and streams changes:
import postgres from "postgres"

const sql = postgres({
    host: 'localhost',
    port: 5432,
    database: 'appdb',
    username: 'appuser',
    password: 'secret',
    publications: 'alltables', // Subscribe to all tables
})

Interactive Features

The React frontend includes powerful table features:
Click any column header to sort:
  • First click: Sort ascending ↑
  • Second click: Sort descending ↓
  • Third click: Remove sorting
Supports intelligent sorting for:
  • Numbers (numeric comparison)
  • Dates (timestamp comparison)
  • Strings (alphabetical)
Each column has a filter input below the header:
  • Type to filter rows matching that column
  • Multiple filters work together (AND logic)
  • Case-insensitive matching
  • Active filters show count and clear button
The table automatically detects columns from your data:
  • No configuration needed
  • Works with any table structure
  • Columns appear as data arrives
Operations are color-coded for quick identification:
  • INSERT: Green (#10b981)
  • UPDATE: Blue (#3b82f6)
  • DELETE: Red (#ef4444)

API Endpoints

The server exposes two endpoints:
# Get all accumulated changes
curl http://localhost:3000/api/changes

Configuration

To connect to a different PostgreSQL instance, edit db.ts:
db.ts
export const sql = postgres({
    host: 'your-host',
    port: 5432,
    database: 'your-database',
    username: 'your-user',
    password: 'your-password',
    publications: 'alltables',
})
Your PostgreSQL instance must have:
  • wal_level=logical in postgresql.conf
  • A publication created: CREATE PUBLICATION alltables FOR ALL TABLES;

Troubleshooting

Check that the Bun server is running:
bun run dev
Verify the server started successfully and shows:
✅ Realtime subscription ready (connected or reconnected)
Ensure PostgreSQL is configured correctly:
-- Check wal_level
SHOW wal_level; -- Should be 'logical'

-- Check publication exists
SELECT * FROM pg_publication;
If the publication is missing:
CREATE PUBLICATION alltables FOR ALL TABLES;
Change the port in src/index.ts:
const server = serve({
  port: 3001, // Change to any available port
  // ...
});
Update the WebSocket URL in src/App.tsx to match:
const ws = new WebSocket("ws://localhost:3001/ws");
Check if port 5432 is already in use:
lsof -i :5432
To use a different port, edit docker-compose.yml:
ports:
  - "5433:5432"  # Host:Container
Then update db.ts accordingly:
port: 5433,

Next Steps

Architecture Deep Dive

Learn how the real-time system works under the hood

API Reference

Explore WebSocket messages and REST endpoints

Configuration Guide

Customize database connections and server settings

Usage Examples

Learn common workflows and usage patterns