---
title: "Deploying to Rivet Compute"
description: "Run your backend on Rivet Compute."
skill: true
---

<Note>
Rivet Compute is currently in beta.
</Note>

<Note>
Using an AI coding agent? Open **Connect** on the [Rivet dashboard](https://dashboard.rivet.dev), select **Rivet Cloud**, and paste the one-shot prompt into your agent and have it connect with Rivet Compute for you.
</Note>

## Steps

<Steps>
<Step title="Prerequisites">

- Your RivetKit app in a GitHub repository
  - If you don't have one, see the [Quickstart](/docs/actors/quickstart) page or our [Examples](https://github.com/rivet-dev/rivet/tree/main/examples)
- A [Rivet Cloud](https://dashboard.rivet.dev) account and project

</Step>
<Step title="Configure Serverless Mode">

Rivet Compute runs your app as a short-lived, serverless container. Make sure your server `serve()` or uses `handler()` instead of `startRunner()`:

```typescript src/server.js @nocheck
import { registry } from "./actors.js";
import { Hono } from "hono";
import { serve } from "@hono/node-server";

const app = new Hono();

// Mount Rivet handler
app.all("/api/rivet/*", (c) => registry.handler(c.req.raw));

const PORT = parseInt(process.env.PORT);

serve({ fetch: app.fetch, port: PORT });
```

See [Runtime Modes](/docs/general/runtime-modes) for details on when to use each mode.

</Step>
<Step title="Containerize Your App">

Create a `Dockerfile` in your project root:

```dockerfile @nocheck
FROM node:24-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
CMD ["node", "src/server.js"]
```

</Step>
<Step title="Get Your Cloud Token">

1. Open the [Rivet dashboard](https://dashboard.rivet.dev) and navigate to your project
2. Click **Connect** and select **Rivet Cloud**
3. Copy the **`RIVET_CLOUD_TOKEN`** value shown — this is all you need for deployment

</Step>
<Step title="Set Up GitHub Actions">

Add `RIVET_CLOUD_TOKEN` as a secret in your GitHub repository (**Settings → Secrets and variables → Actions**), then create `.github/workflows/deploy.yml`:

```yaml @nocheck
name: Rivet Deploy

on:
  pull_request:
    types: [opened, synchronize, reopened, closed]
  push:
    branches: [main]
  workflow_dispatch:

concurrency:
  group: rivet-deploy-${{ github.event.pull_request.number || github.ref }}
  cancel-in-progress: true

jobs:
  rivet-deploy:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write
    steps:
      - uses: actions/checkout@v4
      - uses: rivet-dev/deploy-action@v1.1.1
        with:
          rivet-token: ${{ secrets.RIVET_CLOUD_TOKEN }}
```

The `deploy-action` handles everything automatically:

- Builds your Docker image and pushes it to Rivet's built-in container registry
- Creates a `production` namespace on pushes to `main`
- Creates an isolated `pr-{number}` namespace for each pull request
- Posts a comment on the PR with a link to the Rivet dashboard
- Cleans up the PR namespace when the pull request is closed

</Step>
<Step title="Monitor Deployment">

The dashboard shows live status as Rivet Compute provisions your backend:

| Status | Description |
| --- | --- |
| Provisioning | Allocating compute resources |
| Initializing | Starting the runtime environment |
| Allocating | Assigning the runner to your pool |
| Deploying | Pulling and launching your container |
| Binding | Connecting the runner to the network |
| Ready | Deployment complete |

Once the status reaches **Ready**, your backend is live and actors are available for connections.

<LLMOnly>

If you are an agent monitoring the deployment via API rather than the dashboard, poll the managed-pool endpoint on the Cloud API.

The `RIVET_CLOUD_TOKEN` secret is a `cloud_api_*` management token scoped to the Cloud API at `cloud-api.rivet.dev`. Use it for `Authorization: Bearer ...` against the Cloud API. Do not confuse it with a `pk_*` publishable key, which is scoped to the Rivet Engine API at `api.rivet.dev` and will 401 against this endpoint.

Substitute `$CLOUD_API_URL` (typically `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`.

```bash
curl -s "$CLOUD_API_URL/projects/$PROJECT/namespaces/$CLOUD_NAMESPACE/managed-pools/default?org=$ORG" -H "Authorization: Bearer $CLOUD_TOKEN"
```

</LLMOnly>

</Step>
</Steps>

## Troubleshooting

<AccordionGroup>
<Accordion title="Deployment stuck in Provisioning">

If the status stays in **Provisioning** for more than a few minutes, verify that:

- The `RIVET_CLOUD_TOKEN` secret is correctly set in your GitHub repository
- The GitHub Actions workflow completed without errors — check the run logs

</Accordion>
<Accordion title="Deployment error">

If the status shows **Error**, check that your container starts successfully and does not exit immediately. Common causes:

- The server file is not calling `registry.startRunner()`
- A runtime crash on startup — test the image locally with `docker run`
- The Dockerfile is not listening on the `PORT` environmental variable

</Accordion>

</AccordionGroup>
