---
image: true
author: nathan-flurry
published: "2025-12-03"
category: changelog
keywords: ["ai", "backend", "generation", "freestyle", "actors", "realtime", "database"]
title: "AI & User Generated Backends with Rivet"
description: "**Rivet now supports programmatically deploying AI-generated and user-generated actor code to sandboxed namespaces, enabling use cases like AI code execution, user sandbox environments, preview deployments, and multi-tenant applications.**"
---

**Rivet now supports programmatically deploying AI-generated and user-generated actor code to sandboxed namespaces, enabling use cases like AI code execution, user sandbox environments, preview deployments, and multi-tenant applications.**

## The Problem With AI-Generated Backend Code

When AI agents generate backend code, they typically need to coordinate across multiple disconnected systems:

- **Database schemas**: Define tables, columns, and relationships
- **API logic**: Write endpoints that query and mutate data
- **Schema synchronization**: Keep database and API in sync as requirements change

Each system requires separate context, increasing token usage and cognitive load for the AI. More importantly, state and behavior can drift apart when defined separately, leading to bugs and inconsistencies.

## How We Solved This

### Rivet Actors: AI-Friendly Code Generation With Less Context & Fragmentation

Rivet Actors solve this by unifying state and logic in a single actor definition. Instead of coordinating between databases and APIs, **state and behavior live together**:

<Tabs>
<Tab title="With Rivet">

```typescript actors.ts
export const user = actor({
  // State is defined alongside behavior
  createState: (c, input) => ({
    name: input.name,
    email: input.email,
    createdAt: Date.now(),
  }),

  // Actions can read and mutate state
  actions: {
    updateEmail: (c, email: string) => {
      c.state.email = email;
    },
    getProfile: (c) => c.state,
  },
});
```

</Tab>
<Tab title="With HTTP + SQL">

```sql migrations/001_create_users.sql
CREATE TABLE users (
  id UUID PRIMARY KEY,
  name TEXT NOT NULL,
  created_at BIGINT NOT NULL
);
```

```sql migrations/002_add_email.sql
ALTER TABLE users ADD COLUMN email TEXT NOT NULL DEFAULT '';
CREATE INDEX idx_users_email ON users(email);
```

```typescript api/users.ts
import { Hono } from "hono";
import { db } from "./db";

const app = new Hono();

app.post("/users/:id", async (c) => {
  const { id } = c.req.param();
  const { name, email } = await c.req.json();

  await db.query(
    "INSERT INTO users (id, name, email, created_at) VALUES ($1, $2, $3, $4)",
    [id, name, email, Date.now()]
  );

  return c.json({ success: true });
});

app.patch("/users/:id/email", async (c) => {
  const { id } = c.req.param();
  const { email } = await c.req.json();

  await db.query(
    "UPDATE users SET email = $1 WHERE id = $2",
    [email, id]
  );

  return c.json({ success: true });
});

app.get("/users/:id", async (c) => {
  const { id } = c.req.param();
  const result = await db.query(
    "SELECT name, email, created_at FROM users WHERE id = $1",
    [id]
  );

  return c.json(result.rows[0]);
});
```

</Tab>
</Tabs>

This consolidation eliminates fragmentation:

- **Single source of truth**: No need to keep migrations, schemas, and APIs in sync
- **Less LLM context required**: Generate one file instead of coordinating multiple systems
- **Fewer errors**: State and behavior can't drift apart when they're defined together
- **More powerful generation**: AI agents can focus on business logic instead of infrastructure plumbing

### Rivet Namespaces: Fully Sandboxed Environments

Sandboxed namespaces provide isolated environments where **each AI-generated or user-generated deployment runs independently** with its own resources, tokens, and configuration. This enables safe multi-tenant deployments and user-generated code execution.

## Use Cases

Sandboxed namespaces enable a variety of isolated deployment scenarios:

- **AI-generated code**: Deploy LLM-generated backends safely in isolated environments
- **User sandbox environments**: Give users their own sandboxed Rivet namespace to experiment
- **Preview deployments**: Create ephemeral environments for testing pull requests
- **Multi-tenant applications**: Isolate each customer in their own sandboxed namespace

## How It Works

The deployment process involves four key steps:

1. **Create sandboxed namespace**: Programmatically create an isolated Rivet namespace using the Cloud API or self-hosted Rivet API

2. **Generate tokens**: Create the necessary authentication tokens:
   - **Runner token**: Authenticates the serverless runner to execute actors
   - **Publishable token**: Used by frontend clients to connect to actors
   - **Access token**: Provides API access for configuring the namespace

3. **Deploy code**: Deploy the actor code and frontend programmatically to your serverless platform of choice (Vercel, Netlify, AWS Lambda, Freestyle, etc.)

4. **Connect Rivet**: Configure Rivet to run actors on your deployment in your sandboxed namespace

## Show Me The Code

Here's a simplified example of the deployment flow using [Freestyle](https://freestyle.sh) (built specifically for this use case):

```typescript
import { RivetClient } from "@rivetkit/engine-api-full";
import { FreestyleSandboxes } from "freestyle-sandboxes";

async function deploy(projectDir: string) {
  // Step 1: Create sandboxed namespace
  const { project, organization } = await cloudRequest("GET", "/tokens/api/inspect");
  const { namespace } = await cloudRequest(
    "POST",
    `/projects/${project}/namespaces?org=${organization}`,
    { displayName: `ns-${Date.now()}` }
  );

  // Step 2: Generate tokens
  // ...omitted...

  // Step 3: Deploy to Freestyle
  const freestyle = new FreestyleSandboxes({ apiKey: FREESTYLE_API_KEY });
  const deploymentSource = prepareDirForDeploymentSync(projectDir);
  await freestyle.deployWeb(deploymentSource, {
    envVars: {
      RIVET_ENDPOINT: "https://api.rivet.dev",
      RIVET_NAMESPACE: namespace.access.engineNamespaceName,
      RIVET_TOKEN: runnerToken,
    },
    entrypoint: "src/backend/server.ts",
    domains: [FREESTYLE_DOMAIN],
  });

  // Step 4: Configure Rivet to run actors on the deployment
  const rivet = new RivetClient({
    environment: "https://api.rivet.dev",
    token: accessToken,
  });
  await rivet.runnerConfigsUpsert("default", {
    datacenters: {
      "us-west-1": {
        serverless: {
          url: `https://${FREESTYLE_DOMAIN}/api/rivet`,
          headers: {},
          maxRunners: 1000,
        },
      },
    },
    namespace: namespace.access.engineNamespaceName,
  });
}
```

Call this deployment function whenever your AI agent generates new actor code or a user requests their own sandbox environment. The entire process takes seconds and creates a fully isolated, production-ready deployment.

## Getting Started

To try deploying AI-generated or user-generated Rivet Actors:

- Check out the [complete example on GitHub](https://github.com/rivet-dev/rivet/tree/main/examples/ai-and-user-generated-actors-freestyle)
- Read the [full documentation guide](/docs/actors/ai-and-user-generated-actors)
- Sign up for [Rivet Cloud](https://dashboard.rivet.dev) or [self-host Rivet](/docs/self-hosting)


