Server-Side Filters
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 | |
|---|---|---|
| How | Server sends all events; SDK filters locally | Server evaluates filters; only matching events sent |
| Bandwidth | Higher — all events transmitted | Lower — only matching events |
| CPU | Client evaluates | Server evaluates |
| Flexibility | Any filter logic | 8 operators, max 5 conditions per type |
| Best for | Development, low-traffic tables | Production, high-traffic tables |
Quick Start
- JavaScript
- Dart/Flutter
- Swift
- Kotlin
- C#
- C++
const unsubscribe = client.db('app').table('posts')
.where('status', '==', 'published')
.onSnapshot((event) => {
console.log('Published post changed:', event.data);
}, { serverFilter: true });
final subscription = client.db('app').table('posts')
.where('status', '==', 'published')
.onSnapshot((event) {
print('Published post changed: ${event.data}');
}, serverFilter: true);
let subscription = client.db("app").table("posts")
.where("status", "==", "published")
.onSnapshot(serverFilter: true) { event in
print("Published post changed: \(event.data)")
}
val subscription = client.db("app").table("posts")
.where("status", "==", "published")
.onSnapshot(serverFilter = true) { event ->
println("Published post changed: ${event.data}")
}
var sub = client.Db("app").Table("posts")
.Where("status", "==", "published")
.OnSnapshot(change => {
Console.WriteLine($"Published post changed: {change.Data}");
}, serverFilter: true);
int subId = client.db().onSnapshot("posts",
{{"status", "==", "published"}},
[](const eb::DbChange& change) {
std::cout << "Published post changed" << std::endl;
},
eb::SnapshotOptions{.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
| Operator | Description | Example |
|---|---|---|
== | 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] |
in | Contained in array | ['category', 'in', ['tech', 'science']] |
contains | Array 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
nullto clear that filter type - No need to unsubscribe and resubscribe — filters are updated in-place
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
| Limit | Value |
|---|---|
| AND filter conditions | 5 max per subscription |
| OR filter conditions | 5 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:
- Access rule check — The table's
readrule was evaluated at subscribe time. - AND filter evaluation — Every AND condition must match the event data.
- OR filter evaluation — At least one OR condition must match (if OR filters exist).
- Delivery — Only if both AND and OR filters pass, the event is sent to the subscriber.
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.