Redis
The recommended production store. Live streams are pushed, not polled.
import { createServer } from 'experimental-a2/server'
import { redis } from 'experimental-a2/store-redis'
import { orders } from '@/contracts'
export const ordersServer = createServer({
contract: orders,
store: redis({ url: process.env.REDIS_URL }),
consumers: [
/* ... */
],
})npm install ioredis
Works on a single Redis or Valkey instance and on non-cluster providers such as
Upstash, which is durable by default (use its TCP rediss:// URL). There's
nothing to set up: A2 creates its keys as it writes. For rotating credentials or
custom TLS and reconnect settings, use the same store on node-redis:
Valkey.
Options
| Option | |
|---|---|
url | creates an ioredis client |
client | your own ioredis client instead |
keyPrefix | isolates several apps on one Redis. Default 'a2'; no braces |
clock, ids | test seams for timestamps and generated event ids |
Upgrade
The store records its key layout in <keyPrefix>:schema, and refuses a prefix
marked with another one with STORE_NOT_CONFIGURED. A release that changes
the layout says what to do on its upgrade page. This
release names every key differently from earlier ones, so give the store a
fresh keyPrefix.
How it works
- Each session is a Redis Stream, and every key of a session shares one hash tag.
- Every write is one atomic script over its session's keys. On Upstash, which runs a script under a database-wide lock by default, A2 marks each script to lock only its session's keys. Redis and Valkey run one command at a time, so A2 keeps scripts short instead.
- Every write publishes a wake-up after its script, so live streams are push-driven, and connections scale with your processes, not with your viewers.
- A wake-up is disposable: a safety re-read recovers a lost one within ten seconds.
Cost per command
On providers that bill per command, such as Upstash, appending an event with a consumer and running it takes 19 commands, and an idle live stream takes 6 a minute.