---
title: "Production Checklist"
description: "Checklist for deploying Rivet Actors to production."
skill: true
---

<Tip>
We recommend passing this page to your coding agent to verify your configuration before deploying.
</Tip>

## Environment

- **Set `NODE_ENV=production`.** Ensures optimized performance and disables development-only behavior.
- **Ensure log level is not set to debug.** Leave `RIVET_LOG_LEVEL` at its default or explicitly set it to `warn` to avoid excessive logging. See [Logging](/docs/general/logging).
- **Do not set `RIVET_EXPOSE_ERRORS=1` in production.** This exposes internal error details to clients. It is automatically enabled when `NODE_ENV=development`. See [Errors](/docs/actors/errors).

## Runtime Mode

- **Configure a runner version.** Required for graceful upgrades and draining of old actors. Applies to both serverless and runner modes. See [Versions & Upgrades](/docs/actors/versions).

### Serverless

- **Check platform timeouts.** Rivet handles migration between invocations automatically, but shorter timeouts increase migration frequency. See [Timeouts](/docs/general/runtime-modes#timeouts).
- **Verify `/api/rivet/start` body size limits.** Serverless actor starts carry actor config and preloaded KV or SQLite startup data in the request body. Keep `serverless.maxStartPayloadBytes` and your platform or proxy body limit at **16 MiB or higher**, or lower the preload budget if your platform cannot accept that size. See [Limits](/docs/actors/limits#kv-preloading).
- **Configure max runners.** Go to Settings > Providers > Edit Provider > Max Runners to set the limit. The default is 100,000 runners. This is effectively your max actor count.
- **Verify your platform rate limit accommodates your actor create and wake frequency.** Actor start requests are sent from Rivet's servers, so they all originate from the same IP. Per-IP rate limits will throttle the engine well before they would throttle real end-user traffic. Size your platform's rate limit to your peak actor create and wake rate, not your end-user request rate.
- **Set the per-instance max concurrent actor limit.** Each serverless instance hosts one actor per in-flight `/api/rivet/start` request, so your platform's per-instance concurrency (e.g. GCP Cloud Run `--concurrency`, AWS Lambda reserved concurrency, Vercel `maxDuration` + concurrency) directly caps actors per instance. Pick a value based on per-actor memory and CPU; the platform autoscales out additional instances once existing ones hit the cap.
- **Tune `requestLifespan` to your platform's hard request timeout.** `requestLifespan` (default `3600`, 60 minutes) is the total lifespan of each serverless request before actors migrate to a fresh instance. Set it just below your platform's hard timeout (e.g. `295` for Vercel Hobby, `3595` for Vercel Pro, `840` for Cloud Run's 15-min cap). Configure via [`configurePool`](/docs/general/registry-configuration). See [Timeouts](/docs/general/runtime-modes#timeouts).
- **Tune `drainGracePeriod` to cover graceful actor shutdown.** Time reserved at the end of `requestLifespan` for actors to stop gracefully before the request is forcibly closed. Default is 30 minutes from the engine; lower it for short-lived stateless actors, raise it if your actors do non-trivial cleanup or final SQLite writes. Configure via [`configurePool`](/docs/general/registry-configuration). See [Limits](/docs/actors/limits).

### Runner

- **Set a graceful shutdown period of at least 35 minutes.** Runners need up to 30 minutes to drain actors during upgrades, plus buffer for shutdown overhead. In Kubernetes, set `terminationGracePeriodSeconds: 2100` on the pod spec.

## Actors

### Design Patterns

- **Do not use god actors.** Avoid putting all logic into a single actor type. See [Design Patterns](/docs/actors/design-patterns).
- **Do not use actor-per-request patterns.** Avoid creating a new actor for each request. See [Design Patterns](/docs/actors/design-patterns).

### Lifecycle

- **Do not rely on `onSleep` for critical cleanup.** `onSleep` is not called during crashes or forced terminations. See [Lifecycle](/docs/actors/lifecycle).

### State

- **Verify `c.state` does not grow unbounded.** Avoid using arrays or objects that grow over time in state. Use [SQLite](/docs/actors/sqlite) for unbounded or append-heavy data instead.
- **Verify actor data does not exceed 10 GB.** Contact [enterprise support](https://rivet.dev/sales) if you need more storage.
- **Use input parameters and `createState` for actor initialization.** See [Input Parameters](/docs/actors/input).

### Events

- **Use `conn.send()` instead of `c.broadcast()` for private events.** `c.broadcast()` sends to all connected clients. Use `conn.send()` to send events to a specific connection. See [Realtime](/docs/actors/events).

### Actions

- **Review action timeout configuration.** The default `actionTimeout` is 60 seconds. Increase it if you have long-running actions like API calls or file processing. See [Actor Configuration](/docs/general/actor-configuration).
- **Review message size limits.** The default `maxIncomingMessageSize` is 64 KiB and `maxOutgoingMessageSize` is 1 MiB. Increase if your actors send or receive large JSON payloads. See [Registry Configuration](/docs/general/registry-configuration).

### Queues

- **Review queue limits.** The default `maxQueueSize` is 1,000 messages and `maxQueueMessageSize` is 64 KiB. Increase if you expect burst traffic or large queue payloads. See [Actor Configuration](/docs/general/actor-configuration).
- **Ensure queue handlers are idempotent.** If processing fails before `message.complete()`, the message will be retried. See [Queues](/docs/actors/queues).

### Workflows

- **Verify workflows do not generate infinite steps.** Use `ctx.loop` to avoid creating unbounded step histories. See [Workflows](/docs/actors/workflows).

## Security

### Authentication

- **Validate connections in `createConnState` or `onBeforeConnect`.** Do not trust client input without validation. See [Authentication](/docs/actors/authentication).

### CORS

- **Configure CORS for production.** Restrict allowed origins instead of allowing all. See [CORS](/docs/general/cors).

### Tokens (Rivet Cloud)

- **Use `pk_*` tokens for `RIVET_PUBLIC_ENDPOINT`.** Public tokens are safe to expose to clients.
- **Use `sk_*` tokens for `RIVET_ENDPOINT`.** Secret tokens should only be used server-side.
- **Do not leak your secret token.** Never expose `sk_*` tokens in client-side code, public repositories, or browser environments. See [Endpoints](/docs/general/endpoints).
- **Verify you're connecting to the correct region.** Use the nearest datacenter endpoint (e.g. `api-us-west-1.rivet.dev`) for lowest latency.

### Access Control

Access control is only needed if you want granular permissions for different clients. For most use cases, basic authentication in `onBeforeConnect` or `createConnState` is sufficient.

- **Use deny-by-default rules.** Reject unknown roles in `onBeforeConnect`, action handlers, `canPublish`, and `canSubscribe`. See [Access Control](/docs/actors/access-control).
- **Authorize actions explicitly.** Check the caller's role in each action handler and throw `forbidden` for unauthorized access.
- **Gate event subscriptions and queue publishes.** Use `canSubscribe` and `canPublish` hooks to restrict which clients can subscribe to events or publish to queues.

## Clients

- **Dispose connections and/or client when not in use (JavaScript client).** Call `conn.dispose()` or `client.dispose()` when no longer needed to free resources. React and SwiftUI clients handle this automatically. See [Connection Lifecycle](/docs/clients/javascript#connection-lifecycle).
