Server: Collections
Collections let you define and expose dynamic groups of records. These groups update automatically when underlying records change, and clients receive diffs of added or removed members.
This is ideal for collaborative apps, dashboards, and filtered views.
Expose collections
To make a collection subscribable, use exposeCollection(...)
:
server.exposeCollection("collection:all-tasks", async () => {
return await server.listRecordsMatching("task:*");
});
The second argument is a resolver that returns an array of recordId
s for the given collection. It runs:
- Immediately when a client subscribes
- Again any time a record changes (added, removed, or updated)
Collections can use dynamic patterns too:
server.exposeCollection(
/^collection:user:(\d+):tasks$/,
async (conn, collectionId) => {
const userId = collectionId.split(":")[2];
return await server.listRecordsMatching(`user:${userId}:task:*`);
}
);
You can also apply access control logic by inspecting conn
inside the resolver.
Redis search helper
Use listRecordsMatching(...)
to list all records matching a pattern:
const allTasks = await server.listRecordsMatching("task:*");
Internally, this performs a Redis key scan against stored records.
Record changes trigger diffs
Whenever a record is added, removed, or updated, Mesh will:
- Rerun the resolver
- Compare new and old record IDs
- Send a diff to all subscribed clients
If a record is removed from Redis but was previously part of the collection, clients will receive a removed
diff.
Resync logic
Mesh tracks a version
number per collection per connection. If a client receives a diff with a skipped version (e.g. expected v3, got v5), it auto-resubscribes and fetches the full list again.
This ensures correctness across reconnects, network drops, or inter-instance propagation delays.
Collection-only updates
Collections do not automatically subscribe the client to each record. You can:
- Use the
onUpdate
callback to observe changes to collection members - Or subscribe to specific records manually if fine-grained tracking is needed
See Client: Collections for full usage examples.
Use cases
- Task lists — real-time filters across shared boards
- Projects — dynamic membership as records are created/deleted
- Views — multi-tenant views per user, team, or org