Skip to main content

Server-Side Filters

Beta

This feature is in beta. Core behavior is stable, but some APIs or configuration may change before general availability.

Reduce bandwidth and client-side processing by letting the server evaluate filter conditions before sending subscription events.

Overview

EdgeBase supports two filtering modes for database subscriptions:

Client-Side (Default)Server-Side
HowServer sends all events; SDK filters locallyServer evaluates filters; only matching events sent
BandwidthHigher — all events transmittedLower — only matching events
CPUClient evaluatesServer evaluates
FlexibilityAny filter logic8 operators, max 5 conditions per type
Best forDevelopment, low-traffic tablesProduction, high-traffic tables

Quick Start

const unsubscribe = client.db('app').table('posts')
.where('status', '==', 'published')
.onSnapshot((event) => {
console.log('Published post changed:', event.data);
}, { serverFilter: true });

AND Filters

AND filters require all conditions to match. Chain multiple .where() calls:

// Both conditions must be true
const unsubscribe = client.db('app').table('posts')
.where('status', '==', 'published')
.where('authorId', '==', 'user-123')
.onSnapshot(handler, { serverFilter: true });

OR Filters

OR filters require at least one condition to match. Use .whereOr():

// status is 'published' OR 'featured'
const unsubscribe = client.db('app').table('posts')
.where('authorId', '==', 'user-123')
.whereOr('status', '==', 'published')
.whereOr('status', '==', 'featured')
.onSnapshot(handler, { serverFilter: true });

This is equivalent to: WHERE authorId = 'user-123' AND (status = 'published' OR status = 'featured')

Supported Operators

OperatorDescriptionExample
==Equal to['status', '==', 'published']
!=Not equal to['status', '!=', 'draft']
<Less than['price', '<', 100]
<=Less than or equal['price', '<=', 100]
>Greater than['score', '>', 90]
>=Greater than or equal['score', '>=', 90]
inContained in array['category', 'in', ['tech', 'science']]
containsArray field contains value['tags', 'contains', 'featured']

Updating Filters at Runtime

Change your filter conditions without re-subscribing using updateFilters:

// Initially subscribe to published posts
const sub = client.db('app').table('posts')
.where('status', '==', 'published')
.onSnapshot(handler, { serverFilter: true });

// Later, switch to draft posts without reconnecting
sub.updateFilters([
{ field: 'status', op: '==', value: 'draft' },
]);

// Remove all filters (receive everything)
sub.updateFilters(null);
  • Set a field to null to clear that filter type
  • No need to unsubscribe and resubscribe — filters are updated in-place
note

You must already be subscribed to the channel before calling updateFilters. Attempting to update filters on an unsubscribed channel returns a NOT_SUBSCRIBED error.

Limits

LimitValue
AND filter conditions5 max per subscription
OR filter conditions5 max per subscription

Exceeding these limits returns an INVALID_FILTERS error and the subscription is rejected.

Filter Evaluation Order

When the server processes a database change event, it evaluates in this order:

  1. Access rule check — The table's read rule was evaluated at subscribe time.
  2. AND filter evaluation — Every AND condition must match the event data.
  3. OR filter evaluation — At least one OR condition must match (if OR filters exist).
  4. Delivery — Only if both AND and OR filters pass, the event is sent to the subscriber.
info

Filters can only restrict which events you receive — they cannot bypass access rules. If your read rule denies access, no filter combination will override it.

Hibernation Recovery

When a Durable Object hibernates (idle WebSocket) and wakes up, all in-memory filter state is lost. The server sends a FILTER_RESYNC message to all authenticated sockets, and the SDK automatically re-registers all filter conditions.

This happens transparently — your onSnapshot callbacks continue working without interruption.