1. Project Overview & Quickstart (rivet-dev/rivetkit-python)
rivetkit-python
Open-source repository rivet-dev/rivetkit-python
Repository Details
- Repository: rivet-dev/rivetkit-python
- Primary Language: Code
Note: High-volume repository documentation is actively indexed and synchronized by YakaAI.
2. Official Technical Reference & Guides (rivet-dev/website)
File: README.md
Rivet Website
The source for rivet.dev โ marketing pages, docs, and blog.
Each product's documentation is authored in that product's own repository and
vendored in here. See CLAUDE.md for the layout andHIDDEN.md for what is deliberately unpublished.
Develop
pnpm install
pnpm assemble # link each product's docs bundle
pnpm devLicense
File: cloud/docs/content/docs/compute.mdx
title: "Rivet Compute"
Rivet Compute runs your backend for you. You supply a container image; Rivet builds it, pushes it to its own registry, provisions a managed pool, and gives you a URL.
Requirements
- A Rivet Cloud account and project
- Docker running locally
- Your app. If you do not have one yet, start from the Quickstart.
Steps
At your project root:
FROM node:24-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
CMD ["node", "src/server.js"]Your server must listen on the port in RIVET_PORT, which defaults to 3000.
- Open the dashboard and go to your project.
- Click Connect, then Rivet Cloud.
- Copy
RIVET_CLOUD_TOKEN.
This is a cloud_api_* management token, not a pk_* publishable key. See Tokens.
npx @rivetkit/cli deploy --token cloud_api_xxxxxThe token is written to ~/.rivet/credentials, so later deploys can omit the flag. The CLI resolves your project from the token, builds and pushes the image, upserts the managed pool, and prints the deployment URL once the pool is ready.
The dashboard shows live status:
| Status | Meaning |
|---|---|
| Initializing | Starting the runtime environment |
| Deploying | Pulling and launching your container |
| Binding | Connecting the runner to the network |
| Ready | Live, and accepting actor connections |
If you are an agent polling the API rather than watching the dashboard, use the managed-pool endpoint on the Cloud API.
RIVET_CLOUD_TOKEN is a cloud_api_* token scoped to cloud-api.rivet.dev. Send it as Authorization: Bearer .... A pk_* publishable key is scoped to the Engine API at api.rivet.dev and will 401 here.
Substitute $CLOUD_API_URL (usually https://cloud-api.rivet.dev), $PROJECT, $ORG, $CLOUD_NAMESPACE, and $CLOUD_TOKEN. Poll every 5 seconds until status is ready. Stop and investigate if status is error.
curl -s "$CLOUD_API_URL/projects/$PROJECT/namespaces/$CLOUD_NAMESPACE/managed-pools/default?org=$ORG" -H "Authorization: Bearer $CLOUD_TOKEN"Once local deploys work, install the GitHub Actions workflow:
npx @rivetkit/cli setup-ciThis writes .github/workflows/rivet-deploy.yml. Add the token as a repository secret:
gh secret set RIVET_CLOUD_TOKENThe workflow deploys production on push to your default branch and creates an isolated namespace per pull request. See Preview Deployments.
Logs
rivet logs prints the last 100 lines from the default pool in the production namespace, oldest first, then exits.
npx @rivetkit/cli logsToken resolution matches deploy: the --token flag, then RIVET_CLOUD_TOKEN, then ~/.rivet/credentials.
Add --follow (-f) to stream instead of fetching history:
npx @rivetkit/cli logs --followEach line is <timestamp> [<SEVERITY>] <region> <message>:
2026-06-16T18:26:51.160Z [INFO] eu-central-1 server listening on port 3000
2026-06-17T11:24:20.425Z [ERROR] us-east-1 failed to connect to upstreamMore examples:
# Last 200 lines from a specific namespace
npx @rivetkit/cli logs --namespace production -n 200
# A specific compute pool
npx @rivetkit/cli logs --pool my-pool
# Live tail, filtered
npx @rivetkit/cli logs --follow --contains error
# JSON, piped to jq
npx @rivetkit/cli logs -n 50 --json | jq .Troubleshooting
If the status stays in Initializing for more than a few minutes:
- Check that
RIVET_CLOUD_TOKENis set correctly as a repository secret. - Check the GitHub Actions run logs for a failed step.
The container is failing to start or exiting immediately. Test the image locally with docker run first. Common causes:
- The server file never calls
registry.start(). - A runtime crash on startup.
- The server is not listening on
RIVET_PORT(default3000).
Pricing
You are billed for the compute your deployment uses while it is running.
File: cloud/docs/content/docs/index.mdx
title: "Rivet Cloud"
Rivet Cloud runs the control plane for you. You keep writing the same code and deploy it one of two ways:
- Bring your own compute. Run workers on your own infrastructure and point them at Rivet Cloud. Every platform in the Self-Host worker guides works this way.
- Rivet Compute. Hand Rivet a container and it runs your backend as well. See Rivet Compute.
Nothing here is required to use Rivet. If you would rather run the control plane yourself, see Self-Host.
Getting started
- Create a project at dashboard.rivet.dev.
- Open Connect and pick how you want to deploy.
- Copy the endpoint values, or the cloud token if you are deploying with Rivet Compute.
Tokens
Rivet Cloud issues three kinds of token, and mixing them up is the most common source of 401s.
| Token | Prefix | Scope | Used for |
|---|---|---|---|
| Secret | sk_ |
Engine API at api.rivet.dev |
RIVET_ENDPOINT, server-side only |
| Publishable | pk_ |
Engine API at api.rivet.dev |
RIVET_PUBLIC_ENDPOINT, safe for browsers |
| Cloud API | cloud_api_ |
Cloud API at cloud-api.rivet.dev |
rivet deploy, CI, managed-pool APIs |
A pk_ token will fail against the Cloud API, and a cloud_api_ token will fail against the Engine API. They are not interchangeable.
In this section
- Rivet Compute: deploy your backend as a container
- Preview Deployments: an isolated namespace per pull request
File: cloud/docs/content/docs/preview-deployments.mdx
title: "Preview Deployments"
A preview deployment gives each pull request its own Rivet namespace, so branch work never touches production state. The namespace is created when the PR opens and destroyed when it closes.
Which setup you use depends on where your workers run.
With Rivet Compute
setup-ci writes a workflow that already does this:
npx @rivetkit/cli setup-ci
gh secret set RIVET_CLOUD_TOKENThe generated .github/workflows/rivet-deploy.yml deploys production on push to your default branch, creates a namespace per pull request, posts the preview link as a comment, and cleans the namespace up on close. See Rivet Compute.
With Vercel
Use the preview-namespace-action. It creates the namespace and writes RIVET_ENDPOINT and RIVET_PUBLIC_ENDPOINT into the Vercel preview environment, so the deployment picks them up with no manual configuration.
RIVET_CLOUD_TOKENfrom the dashboard under Settings โ Advanced โ Cloud API TokensVERCEL_TOKENfrom Vercel account settings
name: Rivet Preview
on:
pull_request:
types: [opened, synchronize, reopened]
push:
branches: [main]
concurrency:
group: rivet-preview-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
rivet-preview:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: rivet-dev/preview-namespace-action@v1
with:
platform: vercel
rivet-token: ${{ secrets.RIVET_CLOUD_TOKEN }}
vercel-token: ${{ secrets.VERCEL_TOKEN }}The action also configures the Vercel Deployment Protection bypass header, which is otherwise a common source of 401s from Rivet into preview deployments. See Vercel.
On other platforms
Any platform works, as long as the pull-request build gets endpoint values for a fresh namespace instead of production's. Create the namespace with the Cloud API using a cloud_api_* token, inject the resulting endpoints as build-time environment variables, and delete the namespace when the pull request closes.
Next steps
File: packages/icons/README.md
Rivet Icons
โ ๏ธ Legal Notice
This package is licensed exclusively for use in Rivet products and services. Using this package in any other product, project, or commercial application is strictly prohibited and may constitute a violation of Font Awesome's Terms of Service and intellectual property rights.
This package includes icons from Font Awesome Pro, which are licensed to Rivet for use in Rivet products only. If you wish to use Font Awesome Pro icons in your own projects, you must obtain your own license from Font Awesome.
Overview
Rivet Icons is an icon library built on Font Awesome that provides pre-generated SVG icons for use in Rivet products. All icons (including Pro icons) are committed to the repository, making this package work out-of-the-box with no Font Awesome token required for end users.
Installation
pnpm add @rivet-gg/iconsUsage
import { Icon, faCheckCircle } from "@rivet-gg/icons";Contributing
Prerequisites
For maintainers only: Obtain a Font Awesome Pro license and set the FONTAWESOME_PACKAGE_TOKEN environment variable to your Font Awesome Pro token. This is only required when vendoring new icons.
Adding new icons
- Ensure you have a
FONTAWESOME_PACKAGE_TOKENenvironment variable set - Modify scripts/generate-manifest.js to include new icons
- Run
pnpm manifestto generate a newmanifest.jsonfile- If you're getting an error about missing packages, run
pnpm installin thesrcfolder first
- If you're getting an error about missing packages, run
- Run
pnpm vendorto generate icon files:src/index.gen.jssrc/index.gen.tsdist/index.js
- Commit all changes including the generated files
Troubleshooting
Icons not showing up
All icons (including Font Awesome Pro icons) are pre-generated and committed to this repository. If icons aren't showing:
Make sure you have the peer dependencies installed:
@fortawesome/fontawesome-svg-core@fortawesome/free-solid-svg-icons@fortawesome/free-brands-svg-icons@fortawesome/react-fontawesomereactandreact-dom
Check that you're importing icons correctly:
tsximport { Icon, faCheckCircle } from "@rivet-gg/icons";If the problem persists, contact us on Discord
For Maintainers: `Could not find package @fortawesome/pro-solid-svg-icons`
This error occurs when running the vendor script without access to Font Awesome Pro packages. Make sure:
FONTAWESOME_PACKAGE_TOKENenvironment variable is set- Run
pnpm installin thesrcfolder to install FA Pro packages - Run
pnpm vendoragain
File: src/content/self-host/control-plane/aws-ecs.mdx
title: "AWS ECS"
Requirements
- An AWS account with ECS and Fargate available
- An EFS file system, or an RDS PostgreSQL instance, for persistence
- An Application Load Balancer in front of the service
- AWS Secrets Manager, or SSM Parameter Store, for the admin token
Steps
Fargate task storage is ephemeral, so the data directory must live outside the task.
- Single node: create an EFS file system and mount it into the task at
/data. - Multi-node: create an RDS PostgreSQL instance instead and skip the volume. Use the direct endpoint, not RDS Proxy, which is not supported. See
Storage .
aws secretsmanager create-secret \
--name rivet/admin-token \
--secret-string "$(openssl rand -hex 32)"Reference it from the task definition's secrets block rather than putting it in environment.
Use a pinned image tag, expose both ports, and mount the volume.
{
"family": "rivet-engine",
"requiresCompatibilities": ["FARGATE"],
"networkMode": "awsvpc",
"cpu": "1024",
"memory": "2048",
"containerDefinitions": [
{
"name": "rivet-engine",
"image": "rivetdev/engine:2.3.3",
"portMappings": [
{ "containerPort": 6420 },
{ "containerPort": 6421 }
],
"environment": [
{ "name": "RIVET__FILE_SYSTEM__PATH", "value": "/data" }
],
"secrets": [
{
"name": "RIVET__AUTH__ADMIN_TOKEN",
"valueFrom": "arn:aws:secretsmanager:REGION:ACCOUNT:secret:rivet/admin-token"
}
],
"mountPoints": [
{ "sourceVolume": "rivet-data", "containerPath": "/data" }
]
}
],
"volumes": [
{
"name": "rivet-data",
"efsVolumeConfiguration": { "fileSystemId": "fs-XXXXXXXX" }
}
]
}1 CPU and 2 GB of RAM is the recommended minimum per instance.
The ALB default is 60 seconds, which severs long-lived WebSockets and causes reconnect storms.
aws elbv2 modify-load-balancer-attributes \
--load-balancer-arn <arn> \
--attributes Key=idle_timeout.timeout_seconds,Value=3600Point the target group at container port 6420 and terminate TLS on the listener. See
Set the target group health check path to /health on port 6421, with a five second timeout.
aws ecs describe-services --cluster <cluster> --services rivet-engine \
--query 'services[0].deployments[0].rolloutState'Expect COMPLETED. Then open /ui on the load balancer hostname and log in with the admin token.
A runner config declares a pool that workers connect to. Without one the control plane refuses every worker, so create it before deploying any:
curl -X PUT "http://<load-balancer-host>/runner-configs/default?namespace=default" \
-H "Authorization: Bearer $RIVET_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"datacenters":{"default":{"normal":{}}}}'Use normal for long-lived workers. See
Scaling past one task
EFS-backed file system storage is single-node: RocksDB cannot be shared between tasks. Before raising the desired count above one, move to RDS PostgreSQL and add NATS for pub/sub. See
Once on RDS, ECS Service Auto Scaling can drive the desired count. Use target tracking on average CPU at 60%, matching the
Next steps
Production checklist Deploy workers on AWS ECS Configuration reference
File: src/content/self-host/control-plane/backups.mdx
title: "Backup & Restore"
Everything the control plane persists lives in its storage backend, so backing up the control plane means backing up that backend. The engine itself is stateless between restarts and needs no separate backup.
What you must be able to restore:
- The storage backend. Actor state, namespaces, and runner configuration.
- Your configuration. The config file or environment variables, including the admin token. Losing the admin token locks you out of the dashboard and the API.
By backend
Use your provider's automated backups, or pg_dump on a schedule. Point-in-time recovery is worth enabling if your provider offers it.
pg_dump "postgresql://user:password@host:5432/rivet" --format=custom --file=rivet-$(date +%F).dumpRestore into an empty database, then start the control plane against it:
pg_restore --dbname="postgresql://user:password@host:5432/rivet" --clean --if-exists rivet-2026-01-01.dumpManaged providers generally do this better than you will. Prefer their automated backups plus a standby replica over a cron job.
Stop the control plane before copying the data directory. RocksDB is not safe to copy while a process holds it open, and a copy taken from a running node can restore into a corrupt state.
# Stop the control plane first
tar czf rivet-data-$(date +%F).tar.gz -C /var/lib/rivet dataRestore by extracting into the same path and starting the control plane again. If you cannot tolerate the downtime this implies, that is a signal to move to PostgreSQL.
FoundationDB has its own backup agent and continuous backup support. Backup topology is covered during enterprise onboarding. Contact enterprise support.
Test the restore
A backup you have never restored is not a backup. Restore into a scratch environment on a schedule and confirm:
- The control plane starts and reports healthy on
/health. - The dashboard loads and your namespaces are present.
- A worker connects and appears under Runners.
- An actor created before the backup still resolves and reads its state.
Next steps
Storage backends Upgrades Production checklist
File: src/content/self-host/control-plane/configuration.mdx
title: "Configuration"
import EngineConfigSchema from "@/components/docs/EngineConfigSchemaClient.astro";
The control plane is the Rivet Engine. It reads configuration from files, from environment variables, or from both.
Configuration sources
The engine accepts JSON, JSON5, JSONC, YAML, and YML, plus environment variables.
Environment variables
Prefix a setting with RIVET__ and separate each level of nesting with __. Names are case-insensitive. To set postgres.url:
RIVET__POSTGRES__URL="postgresql://user:password@host:5432/database"Configuration files
Files are discovered automatically in a platform-specific directory:
| Platform | Path |
|---|---|
| Linux | /etc/rivet/config.json |
| macOS | /Library/Application Support/rivet/config.json |
| Windows | C:\ProgramData\rivet\config.json |
Multiple files in the same directory are merged. /etc/rivet/config.json and /etc/rivet/database.json are loaded together.
Override the search path with --config:
# Load from a specific file
rivet-engine --config /path/to/config.json
# Load from a directory
rivet-engine --config /etc/rivet
# Load multiple paths, merged in order
rivet-engine --config /etc/rivet/base.json --config /etc/rivet/override.jsonReference
Envoy load balancing
pegboard.envoy_load_balancer selects how actors are assigned to envoys. The hash strategy uses a hash ring:
{
"pegboard": {
"envoy_load_balancer": {
"hash": {
"virtual_nodes": 8,
"samples": 2,
"max_scan": 16,
"use_snapshot_read": true
}
}
}
}Use samples: 1 for a uniform random pick that skips slot reads, or samples: 2 or higher for power-of-K choices over envoy slot counts. Treat virtual_nodes as an operational invariant once envoys have registered: changing it reshuffles the ring.
Telemetry
The engine exports traces and metrics over OpenTelemetry.
| Variable | Purpose | Default |
|---|---|---|
RIVET_OTEL_ENABLED |
Set to 1 to enable export |
off |
RIVET_OTEL_GRPC_ENDPOINT |
Collector endpoint | http://localhost:4317 |
RIVET_OTEL_SAMPLER_RATIO |
Trace sampling ratio | 0.001 |
Next steps
Storage backends Ports Production checklist
File: src/content/self-host/control-plane/custom.mdx
title: "Custom Platform"
The control plane is a single container image, rivetdev/engine. Any platform that can run it with a persistent volume and a stable address can host it.
Requirements
Your platform must provide:
- A container runtime, or a Linux host you can run the binary on.
- A persistent volume. The control plane is stateful. Storage that resets on redeploy will lose actor state.
- A stable network identity, so workers keep reaching the same place.
- Long-lived connections. Platforms that cap request duration or idle time below an hour will sever WebSockets. This rules out serverless platforms entirely.
SIGTERMplus a grace period, so the control plane can drain and flush state before it is killed.
Steps
openssl rand -hex 32Store it wherever your platform keeps secrets. Without it, the API is unauthenticated.
Pin the tag. Never run latest in production.
docker run -d \
--restart unless-stopped \
-p 6420:6420 \
-p 6421:6421 \
-v rivet-data:/data \
-e RIVET__FILE_SYSTEM__PATH="/data" \
-e RIVET__AUTH__ADMIN_TOKEN="<your-token>" \
rivetdev/engine:2.3.3For multi-node, drop the file system variable, set RIVET__POSTGRES__URL instead, and add NATS for pub/sub. Do not replicate or autoscale a node that is still on the file system backend: RocksDB is single-node. See
6420 carries API, dashboard, and WebSocket traffic and should sit behind TLS. 6421 serves health checks and should stay internal. See
Set idle, read, and send timeouts to at least 3600 seconds on every proxy in the path. The 30 to 60 second defaults sever live WebSockets and cause reconnect storms.
curl -i http://<host>:6421/healthExpect 200. The dashboard is at /ui on port 6420.
A runner config declares a pool that workers connect to. Without one the control plane refuses every worker, so create it before deploying any:
curl -X PUT "http://<host>:6420/runner-configs/default?namespace=default" \
-H "Authorization: Bearer $RIVET_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"datacenters":{"default":{"normal":{}}}}'Use normal for long-lived workers. See
Point a worker at the control plane and confirm it appears under Runners:
RIVET_ENDPOINT="https://default:<admin-token>@your-control-plane.example.com"Troubleshooting
Workers connect, then drop every 30 to 60 seconds. The load balancer idle timeout is still at its default.
State disappears after a deploy. The volume is not persistent, or the data path does not point at it.
The dashboard rejects your token. RIVET__AUTH__ADMIN_TOKEN is not reaching the container. Confirm the variable name, including the double underscores.
Next steps
Configuration reference Production checklist Deploy your workers
File: src/content/self-host/control-plane/docker-compose.mdx
title: "Docker Compose"
Requirements
- Docker with the Compose plugin
- A host with a persistent volume
Steps
This is a single-node deployment on the file system backend. The named volume is what makes the data survive a restart.
services:
rivet-engine:
image: rivetdev/engine:latest
ports:
- "6420:6420"
volumes:
- rivet-data:/data
environment:
RIVET__FILE_SYSTEM__PATH: "/data"
RIVET__AUTH__ADMIN_TOKEN: "${RIVET_ADMIN_TOKEN}"
restart: unless-stopped
volumes:
rivet-data:echo "RIVET_ADMIN_TOKEN=$(openssl rand -hex 32)" >> .envWithout a token the API is unauthenticated. Keep .env out of version control.
docker compose up -dcurl -i http://localhost:6420/healthExpect 200. The dashboard is at http://localhost:6420/ui; log in with the admin token.
A runner config declares a pool that workers connect to. Without one the control plane refuses every worker, so create it before adding your app:
curl -X PUT "http://localhost:6420/runner-configs/default?namespace=default" \
-H "Authorization: Bearer $RIVET_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"datacenters":{"default":{"normal":{}}}}'Use normal for the long-lived workers this file runs. See
Add your app to the same Compose file. Inside the Compose network it reaches the control plane at rivet-engine:6420.
my-app:
build: .
environment:
RIVET_ENDPOINT: "http://default:${RIVET_ADMIN_TOKEN}@rivet-engine:6420"
depends_on:
- rivet-engine
restart: unless-stoppeddocker compose up -dConfirm the worker appears under Runners in the dashboard.
Using PostgreSQL
Swap the file system backend for PostgreSQL when you outgrow one node.
services:
postgres:
image: postgres:15
environment:
POSTGRES_DB: rivet
POSTGRES_USER: rivet
POSTGRES_PASSWORD: rivet_password
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U rivet -d rivet"]
interval: 5s
timeout: 5s
retries: 12
restart: unless-stopped
rivet-engine:
image: rivetdev/engine:latest
ports:
- "6420:6420"
environment:
RIVET__POSTGRES__URL: postgresql://rivet:rivet_password@postgres:5432/rivet
RIVET__AUTH__ADMIN_TOKEN: "${RIVET_ADMIN_TOKEN}"
depends_on:
postgres:
condition: service_healthy
restart: unless-stopped
volumes:
postgres-data:This file still runs a single engine container, so it is not yet a multi-node deployment. It is the prerequisite for one: the file system backend is single-node RocksDB and cannot be shared, while PostgreSQL can. Multi-node deployments also need NATS. See
Using a config file
Mount JSON instead of setting environment variables:
volumes:
- ./rivet-config.json:/etc/rivet/config.json:ro
- rivet-data:/dataSee
Next steps
Production checklist Deploy your workers Configuration reference