# Database Subscriptions

> Subscribe to live INSERT, UPDATE, and DELETE events on any database table. Broadcasts to all WebSocket subscribers within 200ms.

Subscribe to live changes on any database table. Aerostack's ChangeTracker polls your database every 200ms and broadcasts INSERT, UPDATE, and DELETE events to all subscribers — no `sdk.socket.emit()` required.

## How it works

Use a **bare table name** (no slashes) as the channel topic. Aerostack maps this to the `table/{name}/{projectId}` internal topic and activates ChangeTracker for it.

```ts
// This subscribes to ALL changes on the `orders` table
const channel = realtime.channel('orders')
```

## Listen for changes

```tsx

function OrderDashboard() {
  const { realtime } = useAerostack()
  const [orders, setOrders] = useState([])

  useEffect(() => {
    const channel = realtime.channel('orders')

    channel
      .on('INSERT', ({ data }) => {
        setOrders(prev => [...prev, data])
      })
      .on('UPDATE', ({ data }) => {
        setOrders(prev => prev.map(o => o.id === data.id ? data : o))
      })
      .on('DELETE', ({ data }) => {
        setOrders(prev => prev.filter(o => o.id !== data.id))
      })
      .subscribe()

    return () => channel.unsubscribe()
  }, [realtime])
}
```

## Listen to all events with `*`

```ts
channel.on('*', ({ operation, data, old }) => {
  console.log(`${operation} on orders:`, data)
  // operation: 'INSERT' | 'UPDATE' | 'DELETE'
  // old: previous row state (for UPDATE/DELETE)
})
```

## Event payload shape

```ts
interface RealtimePayload {
  type: 'db_change'
  topic: string          // 'table/orders/<projectId>'
  operation: 'INSERT' | 'UPDATE' | 'DELETE'
  data: Record<string, any>   // new row values
  old?: Record<string, any>   // previous values (UPDATE/DELETE only)
  timestamp: number
}
```

## Filter by column value

Column-level filtering is on the roadmap. Currently all row changes on the subscribed table are broadcast.

## Server-side: no extra code needed

Your server just runs normal SQL queries. ChangeTracker handles the rest:

```ts
// Workers / Node.js — just run your SQL
await sdk.db.query(
  'UPDATE orders SET status = ? WHERE id = ?',
  ['shipped', orderId]
)
// → All clients subscribed to 'orders' receive an UPDATE event automatically
```

## Language support

```tsx
const channel = realtime.channel('orders')
channel.on('INSERT', ({ data }) => console.log('New order:', data))
channel.subscribe()
```

```ts
const channel = realtime.channel('orders')
channel.on('INSERT', ({ data }) => console.log('New order:', data))
channel.subscribe()
```

```go
ch := realtime.Channel("orders")
ch.On("INSERT", func(payload RealtimePayload) {
    fmt.Println("New order:", payload.Data)
})
ch.Subscribe()
```

```python
channel = realtime.channel("orders")
channel.on("INSERT", lambda payload: print("New order:", payload.data))
channel.subscribe()
```

```dart
final channel = realtime.channel('orders');
channel.on('INSERT', (payload) => print('New order: ${payload.data}'));
channel.subscribe();
```

See the [Live Order Dashboard example](/examples/live-order-dashboard) for a complete working implementation.
