zero-cache Config

zero-cache is configured either via CLI flag or environment variable. There is no separate zero.config file.

You can also see all available flags by running zero-cache --help.

Required Flags

Upstream DB

The "upstream" authoritative postgres database. In the future we will support other types of upstream besides PG.

flag: --upstream-db
env: ZERO_UPSTREAM_DB
required: true

Admin Password

A password used to administer zero-cache server, for example to access the /statz endpoint and the inspector.

This is required in production (when NODE_ENV=production) because we want all Zero servers to be debuggable using admin tools by default, without needing a restart. But we also don't want to expose sensitive data using them.

The admin password also grants access to everything that the operator password does.

flag: --admin-password
env: ZERO_ADMIN_PASSWORD
required: in production (when NODE_ENV=production)

Optional Flags

Allow Legacy Queries

Allows clients to send query ASTs directly to zero-cache. Ad-hoc queries (also called legacy queries) work this way.

When this is false, zero-cache rejects client-sent ASTs without parsing them and closes the connection with an error. Keep it disabled when you use queries.

flag: --allow-legacy-queries
env: ZERO_ALLOW_LEGACY_QUERIES
default: false

App ID

Unique identifier for the app.

Multiple zero-cache apps can run on a single upstream database, each of which is isolated from the others, with its own permissions, sharding (future feature), and change/cvr databases.

The metadata of an app is stored in an upstream schema with the same name, e.g. zero, and the metadata for each app shard, e.g. client and mutation ids, is stored in the {app-id}_{#} schema. (Currently there is only a single "0" shard, but this will change with sharding).

The CVR and Change data are managed in schemas named {app-id}_{shard-num}/cvr and {app-id}_{shard-num}/cdc, respectively, allowing multiple apps and shards to share the same database instance (e.g. a Postgres "cluster") for CVR and Change management.

Due to constraints on replication slot names, an App ID may only consist of lower-case letters, numbers, and the underscore character.

Note that this option is used by both zero-cache and zero-deploy-permissions.

flag: --app-id
env: ZERO_APP_ID
default: zero

App Publications

Postgres PUBLICATIONs that define the tables and columns to replicate. Publication names may not begin with an underscore, as zero reserves that prefix for internal use.

If unspecified, zero-cache will create and use an internal publication that publishes all tables in the public schema, i.e.:

CREATE PUBLICATION _{app-id}_public_0 FOR TABLES IN SCHEMA public;

Note that changing the set of publications will result in resyncing the replica, which may involve downtime (replication lag) while the new replica is initializing. To change the set of publications without disrupting an existing app, a new app should be created.

To use a custom publication, you can create one with:

CREATE PUBLICATION zero_data FOR TABLES IN SCHEMA public;
-- or, more selectively:
CREATE PUBLICATION zero_data FOR TABLE users, orders;

Then set the flag to that publication name, e.g.: ZERO_APP_PUBLICATIONS=zero_data. To specify multiple publications, separate them with commas, e.g.: ZERO_APP_PUBLICATIONS=zero_data1,zero_data2.

flag: --app-publications
env: ZERO_APP_PUBLICATIONS
default: _{app-id}_public_0

Auth Revalidate Interval Seconds

How often zero-cache re-checks that each live connection is still authorized to use your /query endpoint.

On each interval, zero-cache sends a lightweight validation request using that connection's current auth context, such as forwarded cookies or an opaque auth token. If your query endpoint rejects that auth with a 401/403, the connection is disconnected.

Use this to bound how long already-open connections can continue after logout, session expiry, token revocation, or other server-side auth changes that happen without a reconnect. Lower values enforce auth changes faster, but send more validation requests to /query.

flag: --auth-revalidate-interval-seconds
env: ZERO_AUTH_REVALIDATE_INTERVAL_SECONDS
default: 300

Auth Retransform Interval Seconds

How often zero-cache refreshes a client group's synced or named query transformations using one validated connection from that group.

This re-runs auth-sensitive query expansion even when the query set itself has not changed. It is useful when your query endpoint generates different ZQL based on current auth or server-side session state, such as roles, organization membership, feature flags, or other permissions-derived context.

Use this to bound how long a client group can keep using stale auth-derived query shapes after backend auth state changes. Lower values pick up those changes faster, but do more /query transform work.

If clients already call updateAuth whenever auth changes, this mainly serves as a background safety net for out-of-band auth changes.

flag: --auth-retransform-interval-seconds
env: ZERO_AUTH_RETRANSFORM_INTERVAL_SECONDS
default: 300

Auto Reset

Automatically wipe and resync the replica when replication is halted. This situation can occur for configurations in which the upstream database provider prohibits event trigger creation, preventing the zero-cache from being able to correctly replicate schema changes. For such configurations, an upstream schema change will instead result in halting replication with an error indicating that the replica needs to be reset. When auto-reset is enabled, zero-cache will respond to such situations by shutting down, and when restarted, resetting the replica and all synced clients. This is a heavy-weight operation and can result in user-visible slowness or downtime if compute resources are scarce.

flag: --auto-reset
env: ZERO_AUTO_RESET
default: true

Change DB

The Postgres database used to store recent replication log entries, in order to sync multiple view-syncers without requiring multiple replication slots on the upstream database. If unspecified, the upstream-db will be used.

flag: --change-db
env: ZERO_CHANGE_DB

Change Streamer Back Pressure Limit Heap Proportion

The percentage of --max-old-space-size to use as a buffer for absorbing replication stream spikes. When the estimated amount of queued data exceeds this threshold, back pressure is applied to the replication stream, delaying downstream sync as a result.

The threshold was determined empirically with load testing. Higher thresholds have resulted in OOMs. Note also that the byte-counting logic in the queue is strictly an underestimate of actual memory usage (but importantly, proportionally correct), so the queue is actually using more than what this proportion suggests.

This parameter is exported as an emergency knob to reduce the size of the buffer in the event that the server OOMs from back pressure. Resist the urge to increase this proportion, as it is mainly useful for absorbing periodic spikes and does not meaningfully affect steady-state replication throughput; the latter is determined by other factors such as object serialization and PG throughput.

In other words, the back pressure limit does not constrain replication throughput; rather, it protects the system when the upstream throughput exceeds the downstream throughput.

flag: --change-streamer-back-pressure-limit-heap-proportion
env: ZERO_CHANGE_STREAMER_BACK_PRESSURE_LIMIT_HEAP_PROPORTION
default: 0.04

Change Streamer Flow Control Consensus Timeout Proportion

During periodic flow-control checks, this is the amount of additional time to wait after the majority of serving replicas have acknowledged a checkpoint, expressed as a proportion of the time the majority took. Replication continues after that timeout even if some serving replicas have not acknowledged the checkpoint. A backup replica that is still catching up does not delay caught-up serving replicas; once caught up, the backup must acknowledge the checkpoint before replication continues.

For example, if the majority responds in 2.5 ms, a proportion of 2 waits up to another 5 ms. The default lets a subscriber take roughly five times as long as the majority before early release. This bounds the effect of a lagging or unresponsive subscriber while allowing for normal processing-time variance.

This value is a ratio, not a duration in seconds. Set it to a negative number to disable early releases and wait for all subscribers.

flag: --change-streamer-flow-control-consensus-timeout-proportion
env: ZERO_CHANGE_STREAMER_FLOW_CONTROL_CONSENSUS_TIMEOUT_PROPORTION
default: 4

Change Streamer Flow Control Slow Subscriber Grace Period Seconds

The time a serving subscriber may continuously miss the consensus timeout while processing changes more slowly than healthy subscribers before Zero disconnects it and instructs it to restart. This protects healthy subscribers from zombie or chronically slow tasks while allowing temporary catch-up work to complete.

Only serving replicas are reset; the replication-manager's backup replica is not disconnected by this setting.

Set this to 0 or a negative number to disable slow-subscriber resets.

flag: --change-streamer-flow-control-slow-subscriber-grace-period-seconds
env: ZERO_CHANGE_STREAMER_FLOW_CONTROL_SLOW_SUBSCRIBER_GRACE_PERIOD_SECONDS
default: 30

Change Streamer Port

The port on which the change-streamer runs. This is an internal protocol between the replication-manager and view-syncers, which runs in the same process tree in local development or a single-node configuration. If unspecified, defaults to --port + 1.

flag: --change-streamer-port
env: ZERO_CHANGE_STREAMER_PORT
default: --port + 1

Change Streamer Startup Delay (ms)

The delay to wait before the change-streamer takes over the replication stream (i.e. the handoff during replication-manager updates), to allow load balancers to register the task as healthy based on healthcheck parameters. If a change stream request is received during this interval, the delay will be canceled and the takeover will happen immediately, since the incoming request indicates that the task is registered as a target.

flag: --change-streamer-startup-delay-ms
env: ZERO_CHANGE_STREAMER_STARTUP_DELAY_MS
default: 15000

Change Streamer URI

When set, connects to the change-streamer at the given URI. In a multi-node setup, this should be specified in view-syncer options, pointing to the replication-manager URI, which runs a change-streamer on port 4849.

flag: --change-streamer-uri
env: ZERO_CHANGE_STREAMER_URI

CVR DB

The Postgres database used to store CVRs. CVRs (client view records) keep track of the data synced to clients in order to determine the diff to send on reconnect. If unspecified, the upstream-db will be used.

flag: --cvr-db
env: ZERO_CVR_DB

CVR Garbage Collection Inactivity Threshold Hours

The duration after which an inactive CVR is eligible for garbage collection. Garbage collection is incremental and periodic, so eligible CVRs are not necessarily purged immediately.

Purging a CVR forces the next connection from that client group to sync from scratch. Set this well above how long a typical user goes between sessions.

flag: --cvr-garbage-collection-inactivity-threshold-hours
env: ZERO_CVR_GARBAGE_COLLECTION_INACTIVITY_THRESHOLD_HOURS
default: 168 (one week)

CVR Garbage Collection Initial Batch Size

The initial number of CVRs to purge per garbage collection interval. This number is increased linearly if the rate of new CVRs exceeds the rate of purged CVRs, in order to reach a steady state. Setting this to 0 effectively disables CVR garbage collection.

flag: --cvr-garbage-collection-initial-batch-size
env: ZERO_CVR_GARBAGE_COLLECTION_INITIAL_BATCH_SIZE
default: 25

CVR Garbage Collection Initial Interval Seconds

The initial interval at which to check and garbage collect inactive CVRs. This interval is increased exponentially (up to 16 minutes) when there is nothing to purge.

flag: --cvr-garbage-collection-initial-interval-seconds
env: ZERO_CVR_GARBAGE_COLLECTION_INITIAL_INTERVAL_SECONDS
default: 60

CVR Max Connections

The maximum number of connections to open to the CVR database. This is divided evenly amongst sync workers.

Note that this number must allow for at least one connection per sync worker, or zero-cache will fail to start. See num-sync-workers.

flag: --cvr-max-conns
env: ZERO_CVR_MAX_CONNS
default: 30

Enable Query Planner

Enable the query planner for optimizing ZQL queries.

The query planner analyzes and optimizes query execution by determining the most efficient join strategies.

You can disable the planner if it is picking bad strategies.

flag: --enable-query-planner
env: ZERO_ENABLE_QUERY_PLANNER
default: true

Enable CRUD Mutations

Enables support for legacy CRUD mutations. When this is false, view-syncers do not connect to the upstream database for CRUD writes, and push messages with CRUD mutations return an error response.

flag: --enable-crud-mutations
env: ZERO_ENABLE_CRUD_MUTATIONS
default: true

Enable Telemetry

Zero collects anonymous telemetry data to help us understand usage. We collect:

  • Zero version
  • Uptime
  • General machine information, like the number of CPUs, OS, CI/CD environment, etc.
  • Information about usage, such as number of queries or mutations processed per hour.

This is completely optional and can be disabled at any time. You can also opt-out by setting DO_NOT_TRACK=1.

flag: --enable-telemetry
env: ZERO_ENABLE_TELEMETRY
default: true

Initial Sync Table Copy Workers

The number of parallel workers used to copy tables during initial sync. Each worker uses a database connection, copies a single table at a time, and buffers up to (approximately) 10 MB of table data in memory during initial sync. Increasing the number of workers may improve initial sync speed; however, local disk throughput (IOPS), upstream CPU, and network bandwidth may also be bottlenecks.

flag: --initial-sync-table-copy-workers
env: ZERO_INITIAL_SYNC_TABLE_COPY_WORKERS
default: 5

Lazy Startup

Delay starting the majority of zero-cache until first request.

This is mainly intended to avoid connecting to Postgres replication stream until the first request is received, which can be useful i.e., for preview instances.

Currently only supported in single-node mode.

flag: --lazy-startup
env: ZERO_LAZY_STARTUP
default: false

Litestream Backup URL

The location of the litestream backup, usually an s3:// URL. This is only consulted by the replication-manager. view-syncers receive this information from the replication-manager.

In multi-node deployments, this is required on the replication-manager so view-syncers can reserve snapshots; in single-node deployments it is optional.

With Litestream v5 backups (the default), configure this as a folder URL ending in /, for example s3://acme-zero-backups/v1/. Zero resolves each replica-specific backup path relative to this URL; without the trailing slash, URL resolution replaces the final path segment instead of nesting the replica backup under it.

flag: --litestream-backup-url
env: ZERO_LITESTREAM_BACKUP_URL

Litestream Endpoint

The S3-compatible endpoint URL to use for the litestream backup. This is only required for non-AWS services. The replication-manager and view-syncers must have the same endpoint.

For example, to use Cloudflare R2: https://<id>.r2.cloudflarestorage.com.

flag: --litestream-endpoint
env: ZERO_LITESTREAM_ENDPOINT

Litestream Checkpoint Threshold MB

The size of the WAL file at which Litestream performs background (PASSIVE) SQLite checkpoints to apply the writes in the WAL to the main database file. Each checkpoint creates new files (WAL segments with Litestream v3, LTX files with v5) that are then backed up. PASSIVE checkpoints are skipped while a write is in progress, so high write rates can make the WAL grow.

flag: --litestream-checkpoint-threshold-mb
env: ZERO_LITESTREAM_CHECKPOINT_THRESHOLD_MB
default: 40

Litestream Config Path

Path to the litestream yaml config file. zero-cache will run this with its environment variables, which can be referenced in the file via ${ENV} substitution, for example:

  • ZERO_REPLICA_FILE for the db Path
  • ZERO_LITESTREAM_BACKUP_LOCATION for the db replica url
  • ZERO_LITESTREAM_LOG_LEVEL for the log Level
  • ZERO_LOG_FORMAT for the log type

flag: --litestream-config-path
env: ZERO_LITESTREAM_CONFIG_PATH
default: ./src/services/litestream/config.yml

Litestream Config Path V5

Path to the Litestream v5 YAML config file. zero-cache runs this file with the same environment-variable substitution described for ZERO_LITESTREAM_CONFIG_PATH.

flag: --litestream-config-path-v5
env: ZERO_LITESTREAM_CONFIG_PATH_V5
default: ./src/services/litestream/config-v5.yml

Litestream Executable

Path to the litestream executable. This must be built from the rocicorp/litestream fork. This option has no effect if litestream-backup-url is unspecified.

flag: --litestream-executable
env: ZERO_LITESTREAM_EXECUTABLE

Litestream V5 Executable

Path to the official Litestream v0.5.x executable used for v5 restores and backups. Litestream v0.5.8 and later can restore both legacy WAL backups and LTX backups, choosing the format with the latest data. When a backup URL is configured and ZERO_LITESTREAM_RESTORE_USING_V5 or ZERO_LITESTREAM_BACKUP_USING_V5 is enabled (both are by default), this executable is required. The official Zero Docker image includes Rocicorp's Litestream build 0.5.18-zero.16. Restores fork the source backup with litestream restore -fork-to-url, so a custom executable must support that flag.

flag: --litestream-executable-v5
env: ZERO_LITESTREAM_EXECUTABLE_V5

Litestream Restore Using V5

Use ZERO_LITESTREAM_EXECUTABLE_V5 for restores. Set this to false to force legacy restore behavior. Because v5 backups require v5 restore, running without a v5 executable when a backup URL is configured requires setting both this option and ZERO_LITESTREAM_BACKUP_USING_V5 to false.

Litestream v0.5 cannot restore legacy backups encrypted with Age. Keep legacy restore enabled for those backups or migrate them before enabling v5 restore.

flag: --litestream-restore-using-v5
env: ZERO_LITESTREAM_RESTORE_USING_V5
default: true

Litestream Backup Using V5

Write LTX backups with Litestream v0.5.x. Set this to false to write legacy WAL backups with Litestream v0.3.x instead. This requires ZERO_LITESTREAM_RESTORE_USING_V5, which is enabled by default.

Zero requests an incremental backup every ZERO_LITESTREAM_INCREMENTAL_BACKUP_INTERVAL_SECONDS, and acknowledges upstream changes only after a backup containing them has completed.

Each replication-manager backs up to its own subfolder of the folder URL configured by ZERO_LITESTREAM_BACKUP_URL. Zero does not delete subfolders left by previous replication-managers. The simplest way to remove them is an object-store lifecycle expiration rule. Every file a restore needs is at most about ZERO_LITESTREAM_SNAPSHOT_BACKUP_INTERVAL_HOURS old, so an expiration of at least twice that interval is safe. Rolling back to a server that does not understand replica-specific paths can require a full resync.

flag: --litestream-backup-using-v5
env: ZERO_LITESTREAM_BACKUP_USING_V5
default: true

Litestream Incremental Backup Interval Minutes

The interval between incremental Litestream v3 backups of the replica. Shorter intervals reduce the amount of change history that needs to be replayed when catching up a new view-syncer, at the expense of increasing the number of files needed to download for the initial restore. For v5 backups, use ZERO_LITESTREAM_INCREMENTAL_BACKUP_INTERVAL_SECONDS.

flag: --litestream-incremental-backup-interval-minutes
env: ZERO_LITESTREAM_INCREMENTAL_BACKUP_INTERVAL_MINUTES
default: 15

Litestream Incremental Backup Interval Seconds

The interval between incremental Litestream v5 backups. Zero does not acknowledge upstream changes until the corresponding replica changes are confirmed in backup storage. Shorter intervals increase storage requests; longer intervals retain more upstream WAL while confirmation is pending.

flag: --litestream-incremental-backup-interval-seconds
env: ZERO_LITESTREAM_INCREMENTAL_BACKUP_INTERVAL_SECONDS
default: 15

Litestream Maximum Checkpoint Page Count

The WAL page count at which SQLite performs a RESTART checkpoint, which blocks writers until complete. Defaults to minCheckpointPageCount * 10. Set to 0 to disable RESTART checkpoints entirely. This setting is ignored when backing up with Litestream v5.

flag: --litestream-max-checkpoint-page-count
env: ZERO_LITESTREAM_MAX_CHECKPOINT_PAGE_COUNT
default: minCheckpointPageCount * 10

Litestream Multipart Concurrency

The number of parts (of size --litestream-multipart-size bytes) to upload or download in parallel when backing up or restoring the snapshot.

Leave this unset to use 48, lowered as needed so that the parts fit in a quarter of the memory available to the container.

flag: --litestream-multipart-concurrency
env: ZERO_LITESTREAM_MULTIPART_CONCURRENCY

Litestream Multipart Size

The size of each part when uploading or downloading the snapshot with --litestream-multipart-concurrency. Note that up to concurrency * size bytes of memory are used when backing up or restoring the snapshot.

flag: --litestream-multipart-size
env: ZERO_LITESTREAM_MULTIPART_SIZE
default: 16777216 (16 MiB)

Litestream Log Level

flag: --litestream-log-level
env: ZERO_LITESTREAM_LOG_LEVEL
default: warn values: debug, info, warn, error

Litestream Port

Port on which litestream exports metrics, used to determine the replication watermark up to which it is safe to purge change log records.

flag: --litestream-port
env: ZERO_LITESTREAM_PORT
default: --port + 2

Litestream Region

The AWS region for the litestream backup bucket. Required for non-standard AWS partitions (e.g. GovCloud us-gov-west-1) where Litestream cannot auto-detect the region. The replication-manager and view-syncers must have the same region.

flag: --litestream-region
env: ZERO_LITESTREAM_REGION

Litestream Restore Parallelism

The number of WAL files to download in parallel when performing the initial restore of the replica from the backup.

flag: --litestream-restore-parallelism
env: ZERO_LITESTREAM_RESTORE_PARALLELISM
default: 48

Litestream Snapshot Backup Interval Hours

The interval between snapshot backups of the replica. Snapshot backups make a full copy of the database to a new Litestream generation. Zero retains the previous generation for six additional hours so an active restore can finish before its snapshot and WAL files are removed. This improves restore time and safety at the expense of bandwidth and temporary backup storage. The setting applies to v3 and v5 backups, although v5 generally does not need frequent snapshots for restore speed.

flag: --litestream-snapshot-backup-interval-hours
env: ZERO_LITESTREAM_SNAPSHOT_BACKUP_INTERVAL_HOURS
default: 12

Log Format

Use text for developer-friendly console logging and json for consumption by structured-logging services.

flag: --log-format
env: ZERO_LOG_FORMAT
default: "text"
values: text, json

Log IVM Sampling

How often to collect IVM metrics. 1 out of N requests will be sampled where N is this value.

flag: --log-ivm-sampling
env: ZERO_LOG_IVM_SAMPLING
default: 5000

Log Level

Sets the logging level for the application.

flag: --log-level
env: ZERO_LOG_LEVEL
default: "info"
values: debug, info, warn, error

Log Slow Hydrate Threshold

The number of milliseconds a query hydration must take to print a slow warning.

flag: --log-slow-hydrate-threshold
env: ZERO_LOG_SLOW_HYDRATE_THRESHOLD
default: 100

Log Slow Row Threshold

The number of ms a row must take to fetch from table-source before it is considered slow.

flag: --log-slow-row-threshold
env: ZERO_LOG_SLOW_ROW_THRESHOLD
default: 2

Mutate API Key

An optional secret used to authorize zero-cache to call the API server handling writes. This is sent from zero-cache to your mutate endpoint in an X-Api-Key header.

flag: --mutate-api-key
env: ZERO_MUTATE_API_KEY

Mutate Allowed Client Headers

Comma-separated allowlist of client-provided custom headers to forward to your mutate endpoint. Header names are matched case-insensitively.

By default, no client-provided custom headers are forwarded.

flag: --mutate-allowed-client-headers
env: ZERO_MUTATE_ALLOWED_CLIENT_HEADERS
default: none

Mutate Allowed Request Headers

Comma-separated allowlist of HTTP headers from the request that opened the WebSocket to forward to your mutate endpoint. Use this for proxy- or load-balancer-injected headers such as x-forwarded-for or cf-ray.

Unlike mutate allowed client headers, these values come from the request that established the connection. Header names are matched case-insensitively.

Values are retained for the WebSocket's lifetime, so clients must reconnect to receive changes. The allowlist does not verify the header source - only allow headers that a trusted proxy overwrites or removes from untrusted requests.

No request headers are forwarded by default.

flag: --mutate-allowed-request-headers
env: ZERO_MUTATE_ALLOWED_REQUEST_HEADERS
default: none

Mutate Forward Cookies

If true, zero-cache will forward cookies from the request to zero-cache to your mutate endpoint. This is useful for passing authentication cookies to the API server. If false, cookies are not forwarded.

flag: --mutate-forward-cookies
env: ZERO_MUTATE_FORWARD_COOKIES
default: false

Mutate URL

The URL of the API server to which zero-cache will push mutations. URLs are matched using URLPattern, a standard Web API.

Pattern syntax (similar to Express routes):

  • Exact URL match: "https://api.example.com/mutate"
  • Any subdomain using wildcard: "https://*.example.com/mutate"
  • Multiple subdomain levels: "https://*.*.example.com/mutate"
  • Any path under a domain: "https://api.example.com/*"
  • Named path parameters: "https://api.example.com/:version/mutate"
    • Matches https://api.example.com/v1/mutate, https://api.example.com/v2/mutate, etc.

Advanced patterns:

  • Optional path segments: "https://api.example.com/:path?"
  • Regex in segments (for specific patterns): "https://api.example.com/:version(v\\d+)/mutate" matches only v followed by digits.

Multiple patterns can be specified, for example:

  • https://api1.example.com/mutate,https://api2.example.com/mutate

Query parameters and URL fragments (#) are ignored during matching. See URLPattern for full syntax.

flag: --mutate-url
env: ZERO_MUTATE_URL

Number of Sync Workers

The number of processes to use for view syncing. Leave this unset to use max(1, availableParallelism() - 1), reserving one core for the replicator. If set to 0, the server runs without sync workers, which is the configuration for running the replication-manager in multi-node deployments.

flag: --num-sync-workers
env: ZERO_NUM_SYNC_WORKERS

Operator Password

A password for the diagnostic endpoints that can't expose application data, so the people who run zero-cache can debug it without being able to read the data it serves. It grants access to:

  • /profz and /profrmz: CPU profiles. Profiles served for the operator password have the source of every regular expression redacted, since those can contain LIKE patterns from client queries.
  • /statz: counts and sizes.
  • /plannerz: the replica's schema and planner statistics.

The other protected endpoints, the inspector and /heapz, still require the admin password.

For /profrmz in a multi-node deployment, the replication-manager must be configured with the same operator password.

If the operator password is the same as the admin password, it grants admin access.

flag: --operator-password
env: ZERO_OPERATOR_PASSWORD

Per User Mutation Limit Max

The maximum mutations per user within the specified windowMs.

flag: --per-user-mutation-limit-max
env: ZERO_PER_USER_MUTATION_LIMIT_MAX

Per User Mutation Limit Window (ms)

The sliding window over which the perUserMutationLimitMax is enforced.

flag: --per-user-mutation-limit-window-ms
env: ZERO_PER_USER_MUTATION_LIMIT_WINDOW_MS
default: 60000

PG Replication Slot Failover

For upstream Postgres 17+, creates replication slots with the failover flag enabled so they can be synchronized to a standby and survive a failover. This requires additional Postgres-side configuration on your provider; see High Availability. Has no effect on Postgres versions before 17.

flag: --upstream-pg-replication-slot-failover
env: ZERO_UPSTREAM_PG_REPLICATION_SLOT_FAILOVER
default: false

Port

The port for sync connections.

flag: --port
env: ZERO_PORT
default: 4848

Query API Key

An optional secret used to authorize zero-cache to call the API server handling queries. This is sent from zero-cache to your query endpoint in an X-Api-Key header.

flag: --query-api-key
env: ZERO_QUERY_API_KEY

Query Allowed Client Headers

Comma-separated allowlist of client-provided custom headers to forward to your query endpoint. Header names are matched case-insensitively.

By default, no client-provided custom headers are forwarded.

flag: --query-allowed-client-headers
env: ZERO_QUERY_ALLOWED_CLIENT_HEADERS
default: none

Query Allowed Request Headers

Comma-separated allowlist of HTTP headers from the request that opened the WebSocket to forward to your query endpoint. Use this for proxy- or load-balancer-injected headers such as x-forwarded-for or cf-ray.

Unlike query allowed client headers, these values come from the request that established the connection. Header names are matched case-insensitively.

Values are retained for the WebSocket's lifetime, so clients must reconnect to receive changes. The allowlist does not verify the header source - only allow headers that a trusted proxy overwrites or removes from untrusted requests.

No request headers are forwarded by default.

flag: --query-allowed-request-headers
env: ZERO_QUERY_ALLOWED_REQUEST_HEADERS
default: none

Query Forward Cookies

If true, zero-cache will forward cookies from the request to zero-cache to your query endpoint. This is useful for passing authentication cookies to the API server. If false, cookies are not forwarded.

flag: --query-forward-cookies
env: ZERO_QUERY_FORWARD_COOKIES
default: false

Query Hydration Stats

Track and log the number of rows considered by query hydrations which take longer than log-slow-hydrate-threshold milliseconds.

This is useful for debugging and performance tuning.

flag: --query-hydration-stats
env: ZERO_QUERY_HYDRATION_STATS

Query URL

The URL of the API server to which zero-cache will send synced queries. URLs are matched using URLPattern, a standard Web API.

Pattern syntax (similar to Express routes):

  • Exact URL match: "https://api.example.com/query"
  • Any subdomain using wildcard: "https://*.example.com/query"
  • Multiple subdomain levels: "https://*.*.example.com/query"
  • Any path under a domain: "https://api.example.com/*"
  • Named path parameters: "https://api.example.com/:version/query"
    • Matches https://api.example.com/v1/query, https://api.example.com/v2/query, etc.

Advanced patterns:

  • Optional path segments: "https://api.example.com/:path?"
  • Regex in segments (for specific patterns): "https://api.example.com/:version(v\\d+)/query" matches only v followed by digits.

Multiple patterns can be specified, for example:

  • https://api1.example.com/query,https://api2.example.com/query

Query parameters and URL fragments (#) are ignored during matching. See URLPattern for full syntax.

flag: --query-url
env: ZERO_QUERY_URL

Replica File

File path to the SQLite replica that zero-cache maintains. This can be lost, but if it is, zero-cache will have to re-replicate next time it starts up.

flag: --replica-file
env: ZERO_REPLICA_FILE
default: "zero.db"

Replica Vacuum Interval Hours

Performs a VACUUM at server startup if the specified number of hours has elapsed since the last VACUUM (or initial-sync). The VACUUM operation is heavyweight and requires double the size of the db in disk space. If unspecified, VACUUM operations are not performed.

flag: --replica-vacuum-interval-hours
env: ZERO_REPLICA_VACUUM_INTERVAL_HOURS

Replication Lag Initial Readiness Threshold (ms)

The maximum replication lag that a server can have before it reports that it is ready to serve clients. This keeps a server that is starting up from serving stale data.

This only applies at startup. Once a server is ready, it keeps serving even if replication lag later goes above this threshold.

When lag reporting is disabled, readiness does not wait for replication lag.

flag: --replication-lag-initial-readiness-threshold-ms
env: ZERO_REPLICATION_LAG_INITIAL_READINESS_THRESHOLD_MS
default: 1000

Replication Lag Max Readiness Delay (ms)

The maximum time that a server waits for replication lag to fall below ZERO_REPLICATION_LAG_INITIAL_READINESS_THRESHOLD_MS before it reports ready anyway. This keeps a server from waiting forever, for example when the upstream database is under heavy load or there is a network partition.

flag: --replication-lag-max-readiness-delay-ms
env: ZERO_REPLICATION_LAG_MAX_READINESS_DELAY_MS
default: 600000 (10 minutes)

Replication Lag Report Interval (ms)

The approximate interval at which replication lag reports are written upstream and reported via the zero.replication.total_lag OpenTelemetry metric. If an expected report is not received before the next interval, Zero emits a new report and increments zero.replication.lag_report_retries.

Lag reports are also used at startup: a new server waits for replication lag to fall below ZERO_REPLICATION_LAG_INITIAL_READINESS_THRESHOLD_MS before it reports ready. This interval sets how long the server waits for the next report.

This feature requires write access to upstream Postgres (uses pg_logical_emit_message()). For PostgreSQL 17+, lag measurements accurately reflect committed write latency (single-digit milliseconds). For PostgreSQL 16 and earlier, measurements may appear 50-100ms longer due to flush behavior. A negative or 0 value disables lag reporting and the readiness wait.

Even if otel is not enabled, info and warn-level logs are emitted for large lag values.

flag: --replication-lag-report-interval-ms
env: ZERO_REPLICATION_LAG_REPORT_INTERVAL_MS
default: 10000

Server Version

The version string outputted to logs when the server starts up.

flag: --server-version
env: ZERO_SERVER_VERSION

Shadow Sync Enabled

Periodically exercises the initial-sync code path against a sample of rows from every published table, writing to a throwaway SQLite database. This acts as a canary: if the real initial-sync path breaks because of schema drift, Postgres version quirks, or another full-resync issue, the shadow run fails before a customer actually needs a full reset.

flag: --shadow-sync-enabled
env: ZERO_SHADOW_SYNC_ENABLED
default: false

Shadow Sync Interval Hours

The interval between shadow initial-sync runs, in hours. The first run fires within [2/3, 1) of this interval after startup, so the canary completes at least once per task lifetime while still jittering fleet restarts.

flag: --shadow-sync-interval-hours
env: ZERO_SHADOW_SYNC_INTERVAL_HOURS
default: 12

Shadow Sync Sample Rate

The Bernoulli sampling rate for each table, where 0 < rate <= 1. A value of 1 disables sampling and copies all rows, still subject to --shadow-sync-max-rows-per-table.

flag: --shadow-sync-sample-rate
env: ZERO_SHADOW_SYNC_SAMPLE_RATE
default: 0.1

Shadow Sync Max Rows Per Table

The hard upper bound on rows copied per table per shadow run. This guards against unexpectedly large tables consuming too much disk or upstream bandwidth.

flag: --shadow-sync-max-rows-per-table
env: ZERO_SHADOW_SYNC_MAX_ROWS_PER_TABLE
default: 10000

Storage DB Temp Dir

Temporary directory for IVM operator storage. Leave unset to use os.tmpdir().

flag: --storage-db-tmp-dir
env: ZERO_STORAGE_DB_TMP_DIR

Task ID

Globally unique identifier for the zero-cache instance. Setting this to a platform specific task identifier can be useful for debugging. If unspecified, zero-cache will attempt to extract the TaskARN if run from within an AWS ECS container, and otherwise use a random string.

flag: --task-id
env: ZERO_TASK_ID

Upstream Max Connections

The maximum number of connections to open to the upstream database for committing mutations. This is divided evenly amongst sync workers. In addition to this number, zero-cache uses one connection for the replication stream.

Note that this number must allow for at least one connection per sync worker, or zero-cache will fail to start. See num-sync-workers.

flag: --upstream-max-conns
env: ZERO_UPSTREAM_MAX_CONNS
default: 20

Upstream PG Replication Slot Failover

For upstream PostgreSQL 17 and later, create replication slots with the failover parameter set to true to enable slot synchronization and failover. Additional Postgres-level configuration is required when enabling this option. This option has no effect for PostgreSQL versions before 17.

See the PostgreSQL docs for details: https://www.postgresql.org/docs/current/logicaldecoding-explanation.html#LOGICALDECODING-REPLICATION-SLOTS-SYNCHRONIZATION

flag: --upstream-pg-replication-slot-failover
env: ZERO_UPSTREAM_PG_REPLICATION_SLOT_FAILOVER
default: false

Upstream PG Stream Inbound Timeout

The time, in milliseconds, without an inbound message from the upstream WAL sender after which zero-cache tears down the replication stream to force a reconnect. By default, the threshold is twice the server's wal_sender_timeout.

Increase this value when a healthy WAL sender can remain silent while decoding unpublished WAL or assembling a large transaction. This changes only Zero's inbound timeout; keepalive timing remains derived from wal_sender_timeout. The option has no effect when wal_sender_timeout is 0, which disables inbound liveness detection.

See WAL Sender Timeout.

flag: --upstream-pg-stream-inbound-timeout-ms
env: ZERO_UPSTREAM_PG_STREAM_INBOUND_TIMEOUT_MS

View Syncer Hydration Budget (ms)

A soft time limit for hydrating inactive (cached) queries when a view-syncer hydrates a client group's queries, for example after a client reconnects.

Active queries always finish. Inactive queries are hydrated after them, starting with the ones whose TTL expires last. Once the budget is spent, the inactive queries that were not reached are removed, along with the remaining TTL that would have kept them cached. The budget is only checked between queries, so a query that has started is not cut short by it. Time spent waiting on your query endpoint does not count toward the budget.

A value of 0 disables the budget.

flag: --view-syncer-hydration-budget-ms
env: ZERO_VIEW_SYNCER_HYDRATION_BUDGET_MS
default: 0

View Syncer Query Hydration Timeout (ms)

The maximum processing time that a view-syncer spends hydrating a single query. Time spent yielding to other work is not counted.

If hydrating a query takes longer than this, the hydration is aborted and the query is removed from the client's view. Clients that use the query receive an error for it (see Handling Errors). For the next five minutes, the query is rejected without being run again. After that, it can be retried.

A value of 0 disables the limit.

flag: --view-syncer-query-hydration-timeout-ms
env: ZERO_VIEW_SYNCER_QUERY_HYDRATION_TIMEOUT_MS
default: 0

Websocket Compression

Enable WebSocket per-message deflate compression. Compression can reduce bandwidth usage for sync traffic but increases CPU usage on both client and server. Disabled by default. See: https://github.com/websockets/ws#websocket-compression

flag: --websocket-compression
env: ZERO_WEBSOCKET_COMPRESSION
default: false

Websocket Compression Options

JSON string containing WebSocket compression options. Only used if websocket-compression is enabled. Example: {"zlibDeflateOptions":{"level":3},"threshold":1024}. See https://github.com/websockets/ws/blob/master/doc/ws.md#new-websocketserveroptions-callback for available options.

flag: --websocket-compression-options
env: ZERO_WEBSOCKET_COMPRESSION_OPTIONS

Websocket Max Payload Bytes

Maximum size of incoming WebSocket messages in bytes. Messages exceeding this limit are rejected before parsing.

flag: --websocket-max-payload-bytes
env: ZERO_WEBSOCKET_MAX_PAYLOAD_BYTES
default: 10485760 (10 MiB)

Yield Threshold (ms)

The maximum amount of time in milliseconds that a sync worker will spend in IVM (processing query hydration and advancement) before yielding to the event loop. Lower values increase responsiveness and fairness at the cost of reduced throughput.

flag: --yield-threshold-ms
env: ZERO_YIELD_THRESHOLD_MS
default: 10

Deprecated Flags

Change Max Connections

ZERO_CHANGE_MAX_CONNS is deprecated and no longer controls change database connection usage. Size the database or pooler as described under Change DB.

flag: --change-max-conns
env: ZERO_CHANGE_MAX_CONNS

Change Streamer Mode

ZERO_CHANGE_STREAMER_MODE is deprecated. Set ZERO_CHANGE_STREAMER_URI on view-syncers instead.

The mode for running or connecting to the change-streamer:

  • dedicated: runs the change-streamer and shuts down when another change-streamer takes over the replication slot. This is appropriate in a single-node configuration, or for the replication-manager in a multi-node configuration.
  • discover: connects to the change-streamer as internally advertised in the change-db. This is appropriate for the view-syncers in a multi-node setup. This may not work in all networking configurations (e.g., some private networking or port forwarding setups).

This option is ignored if ZERO_CHANGE_STREAMER_URI is set.

flag: --change-streamer-mode
env: ZERO_CHANGE_STREAMER_MODE
default: dedicated

Litestream Minimum Checkpoint Page Count

ZERO_LITESTREAM_MIN_CHECKPOINT_PAGE_COUNT is deprecated. Use ZERO_LITESTREAM_CHECKPOINT_THRESHOLD_MB instead.

The WAL page count at which SQLite attempts a PASSIVE checkpoint. If unset, it is derived from the checkpoint threshold as checkpointThresholdMB * 256 (4 KiB pages).

flag: --litestream-min-checkpoint-page-count
env: ZERO_LITESTREAM_MIN_CHECKPOINT_PAGE_COUNT
default: checkpointThresholdMB * 256

Auth JWK

A public key in JWK format used to verify JWTs. Only one of jwk, jwksUrl and secret may be set.

flag: --auth-jwk
env: ZERO_AUTH_JWK

Auth JWKS URL

A URL that returns a JWK set used to verify JWTs. Only one of jwk, jwksUrl and secret may be set.

flag: --auth-jwks-url
env: ZERO_AUTH_JWKS_URL

Auth Secret

A symmetric key used to verify JWTs. Only one of jwk, jwksUrl and secret may be set.

flag: --auth-secret
env: ZERO_AUTH_SECRET