Freestyle
Run Rivet workers on Freestyle.
Freestyle runs untrusted code in a sandboxed Deno runtime, which makes it a natural host for AI-generated backends. Workers run in serverless mode: the control plane calls your deployment to start actors.
Requirements
- A Freestyle account
- A control plane, either Rivet Cloud or your own
Steps
Add a Deno entrypoint
Freestyle serves web deployments with Deno, so the entrypoint hands requests to the registry handler.
import { registry } from "./index";
// Deno is provided by Freestyle's runtime.
// @ts-ignore
Deno.serve((request: Request) => registry.handler(request));
Deploy
const FREESTYLE_DOMAIN = "my-domain.style.dev";
const res = await freestyle.deployWeb(buildDir, {
envVars: {
FREESTYLE_ENDPOINT: `https://${FREESTYLE_DOMAIN}`,
RIVETKIT_RUNTIME_MODE: "serverless",
RIVET_ENDPOINT: "https://your-namespace:sk_...@api.rivet.dev",
},
timeout: 60 * 5,
entrypoint: "server.ts",
domains: [FREESTYLE_DOMAIN],
build: false,
});
| Setting | Why |
|---|---|
timeout | Maximum request lifetime. Actors live inside a request, so keep this high. Five minutes is a reasonable floor. |
entrypoint | The file that starts the serverless handler |
domains | Your Freestyle domain |
build: false | Skip Freestyle’s build if you pre-build your assets |
RIVETKIT_RUNTIME_MODE=serverless is required. Without it the app defaults to runner mode, which does not fit Freestyle’s request-driven model. See Freestyle’s web docs for buildDir and the other options.
Register the runner
Point the control plane at the deployment. requestLifespan must be shorter than Freestyle’s timeout, or the platform kills the request before actors migrate.
import { RivetClient } from "@rivetkit/engine-api-full";
const rivet = new RivetClient({
environment: "https://api.rivet.dev",
token: process.env.RIVET_API_TOKEN,
});
await rivet.runnerConfigsUpsert("freestyle-runner", {
namespace: "my-rivet-namespace",
datacenters: {
default: {
serverless: {
url: `https://${FREESTYLE_DOMAIN}/api/rivet`,
requestLifespan: 60 * 5 - 5,
drainGracePeriod: 30,
maxConcurrentActors: 1000,
},
},
},
});
| Field | Meaning |
|---|---|
url | The deployment’s /api/rivet base path. The control plane appends /start itself. |
requestLifespan | Request lifetime, kept just under Freestyle’s timeout |
drainGracePeriod | Time reserved at the end of each request for actors to stop gracefully. Must be less than requestLifespan, and it defaults to 1800, so a short lifespan has to set it explicitly or the config is rejected. |
maxConcurrentActors | Ceiling on concurrent actors across the pool. Freestyle scales the deployment itself, so this is the only scaling bound to set. |
Do not pin minRunners, maxRunners, slotsPerRunner, or runnersMargin. They are deprecated, and maxRunners still has a live effect: when maxConcurrentActors is omitted it becomes the concurrency ceiling, so maxRunners: 1 caps the whole deployment at one actor.
Verify
Once the runner config is applied, the deployment appears as connected in the dashboard.