PostgreSQL Realtime Monitor provides a live view of all database changes through a WebSocket-powered dashboard. Changes are captured using PostgreSQL’s logical replication feature and broadcast to all connected clients.
-- Create multiple tablesCREATE TABLE users ( id SERIAL PRIMARY KEY, email TEXT UNIQUE NOT NULL, created_at TIMESTAMPTZ DEFAULT NOW());CREATE TABLE orders ( id SERIAL PRIMARY KEY, user_id INTEGER REFERENCES users(id), total DECIMAL(10,2), status TEXT, created_at TIMESTAMPTZ DEFAULT NOW());-- Insert dataINSERT INTO users (email) VALUES ('[email protected]');INSERT INTO orders (user_id, total, status) VALUES (1, 99.99, 'pending');-- Update dataUPDATE orders SET status = 'completed' WHERE id = 1;
All changes appear in the dashboard, clearly labeled with their table name:
public.users - INSERT
public.orders - INSERT
public.orders - UPDATE
The table name includes the schema (e.g., public.users) to avoid ambiguity in databases with multiple schemas.
import asyncioimport websocketsimport jsonasync def monitor_changes(): uri = "ws://localhost:3000/ws" async with websockets.connect(uri) as websocket: print("Connected to PostgreSQL monitor") async for message in websocket: data = json.loads(message) if data['type'] == 'initial': print(f"Initial state: {len(data['data'])} changes") elif data['type'] == 'change': for change in data['data']: print(f"{change['operation']} on {change['table']}")asyncio.run(monitor_changes())
-- Create a trigger that updates a timestampCREATE OR REPLACE FUNCTION update_modified_column()RETURNS TRIGGER AS $$BEGIN NEW.modified_at = NOW(); RETURN NEW;END;$$ LANGUAGE plpgsql;CREATE TRIGGER update_todos_modtime BEFORE UPDATE ON todos FOR EACH ROW EXECUTE FUNCTION update_modified_column();-- Update a rowUPDATE todos SET title = 'Updated title' WHERE id = 1;
The monitor will show the UPDATE with the modified_at field automatically updated by the trigger.
In-memory storage: All changes are stored in memory and will be lost when the server restarts. This is intentional for monitoring use cases.
Memory Usage
Since changes accumulate in memory, the server’s memory usage will grow over time. For long-running sessions monitoring high-traffic databases, consider:
Periodically restarting the server
Implementing a size limit on the allChanges array
Adding a “clear” feature to reset the change list
Publication Scope
The default alltables publication captures changes from all tables. For fine-grained control:
-- Create a publication for specific tablesCREATE PUBLICATION specific_tables FOR TABLE users, orders;
Then update db.ts:
publications: 'specific_tables'
Replica Identity
For UPDATE and DELETE operations to include all column values, tables may need REPLICA IDENTITY FULL:
ALTER TABLE todos REPLICA IDENTITY FULL;
Without this, only the primary key values may be available for DELETE operations.