Skip to main content

Server-Side Filters

Beta

This feature is in beta. Core behavior is stable and ready to try, but some APIs or configuration may still evolve 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. On the JavaScript/TypeScript SDK, filtered table subscriptions use server-side filtering by default. Other client SDKs can opt in with serverFilter: true or the equivalent language-specific option.

Client-SideServer-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 forOpt-out compatibility or local debuggingProduction, high-traffic tables

Quick Start

const unsubscribe = client.db('app').table('posts')
.where('status', '==', 'published')
.onSnapshot((snapshot) => {
console.log('Published posts:', snapshot.items);
});

JavaScript Default

On JavaScript/TypeScript, any filtered table subscription created with .where() or .whereOr() now uses server-side filtering automatically.

If you intentionally want the old client-side behavior, opt out explicitly:

const unsubscribe = client.db('app').table('posts')
.where('status', '==', 'published')
.onSnapshot(handler, { serverFilter: false });

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);

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);

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);

// 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.