---
title: Build a v0-style app builder with OpenAI Agents API and Vercel Sandbox
description: Build a chat-to-app workspace with live Next.js previews, follow-up edits, and saved projects using the OpenAI Agents API preview, Vercel Sandbox, and Queues.
url: /kb/guide/v0-clone-openai-agents-vercel-sandbox
canonical_url: "https://vercel.com/kb/guide/v0-clone-openai-agents-vercel-sandbox"
published: 2026-09-11
last_updated: 2026-09-11
authors: Anshuman Bhardwaj
related:
  - /docs/sandbox
  - /docs/agent-resources/vercel-plugin
  - /docs/cli
  - /docs/sandbox/sdk-reference
  - /docs/queues/quickstart
  - /docs/postgres
  - /kb/guide/fastapi-openai-agents-api-vercel-sandbox
  - /docs/sandbox/concepts/persistent-sandboxes
install_vercel_plugin: npx plugins add vercel/vercel-plugin
---

Build an app that turns a prompt into a working Next.js application, then lets you refine the result through chat. Forma is a single-user app builder with saved projects, a conversation history, and a live preview you can pause and reopen later.

The OpenAI Agents API manages the coding agent's session and streams updates as it works. In this project, the agent connects to an executor in your own compute environment to edit files, install packages, and run commands.

[Vercel Sandbox](https://vercel.com/docs/sandbox) provides that environment: an isolated Linux workspace for each generated app. Its persistent file system lets you return to a project and continue editing the same code after its compute has stopped. It also provides a stable preview URL for the running app.

In this guide, you’ll learn how to make your own app builder like v0, understand its architecture, and deploy it to Vercel for everyone to use.

Deploy the template now, or follow the steps below to build it.

## Quick start with an AI coding agent

### Agent prompt

```txt
Help me set up and deploy Forma, a v0-style app builder, from https://github.com/vercel-labs/openai-agents-api-v0-clone. Read README.md, ARCHITECTURE.md, AGENTS.md, and .env.example before making changes.

Use Node.js 24 and pnpm. Help me configure OpenAI Agents API preview access, an application key and a separate restricted executor key, a saved agent, Vercel Sandbox, and Neon Postgres. Explain how to obtain any missing credentials without putting secrets into chat or source files.

Run the app locally with pnpm dev, which starts Next.js and the database worker. For deployment, configure both Vercel Queue consumers, the five-minute Cron job, pnpm vercel-build, and the signed OpenAI webhook. Use separate production credentials and a production database or Neon branch.

Explain how a prompt becomes a background job, how the agent edits the sandbox workspace, and how the browser receives progress and displays the preview. Preserve each project's session and sandbox across follow-up edits. Help me verify generation, a follow-up edit, and Save & pause, followed by reopening the project.
```

The [template repository](https://github.com/vercel-labs/openai-agents-api-v0-clone) contains the complete implementation. This guide focuses on the main integration points and the steps to run your own instance.

### Vercel Plugin

Give your coding agent Vercel-specific guidance with the optional [Vercel Plugin](https://vercel.com/docs/agent-resources/vercel-plugin). It provides product context, skills, and commands for working with Vercel, including Next.js and deployment tasks. Install it in your coding agent's development environment. The plugin is optional.

```bash
npx plugins add vercel/vercel-plugin
```

## Prerequisites

Before you begin, make sure you have:

- Node.js v24 and pnpm 10.34.5.
  
- A [Vercel account](https://vercel.com/signup) and a project with access to Vercel Sandbox, Queues, and Integrations.
  
- [Vercel CLI](https://vercel.com/docs/cli) installed (`npm i -g vercel`).
  
- An OpenAI project with **Agents API preview access** and permission to create API keys and register webhooks.
  

## How it works

- **Next.js serves the UI and backend.** The builder's App Router application contains the project picker, chat, preview panel, authentication, and API routes. A prompt is saved as a background job before the server acknowledges it.
  
- **The OpenAI Agents API performs the coding work.** A saved agent defines the model and instructions. Each Forma project gets its own hosted session, which is reused for follow-up prompts.
  
- **Vercel Sandbox holds the persistent workspace.** The executor, generated source, installed dependencies, and Next.js development server live in the project's named sandbox. Stopping it saves the file system; reopening it restarts the required processes.
  
- **Neon Postgres stores application state.** Projects, session and sandbox identifiers, messages, and jobs live in the database. That saved state allows the browser to recover its view after a refresh.
  
- **Vercel Queues delivers background work.** One consumer processes edits, pauses, and resumes. Another handles OpenAI session lifecycle notifications that need executor reconciliation.
  
- **Vercel Cron recovers pending work and stops idle compute.** It periodically republishes eligible unfinished jobs and schedules idle sandboxes to stop.
  
- **The browser observes progress and loads the preview.** Server-sent events (SSE) deliver saved project and chat updates. An iframe displays the generated app from its sandbox URL.
  

The builder and each generated app are separate Next.js applications. The builder is deployed on Vercel; the generated apps run inside Sandbox.

## Integration walkthrough

### 1\. Set up the Next.js app

Start with an App Router project using TypeScript and Tailwind CSS:

```bash
pnpm create next-app@16.3.4 forma --ts --tailwind --eslint --app --use-pnpm --no-src-dir --import-alias '@/*'
cd forma
pnpm add @vercel/sandbox@3.2.1 @vercel/queue@0.5.1 openai@7.15.0 undici@7.29.1 pg zod lucide-react react-markdown
pnpm add -D @types/pg tsx
```

The template implements the builder interface as a Client Component with a prompt composer, saved project list, conversation, and preview panel. Route Handlers under `app/api` handle sign-in, project reads, and requests to edit, pause, or resume a project.

Keep the handlers small: validate the request and ownership, save a job, and return its identifier. Put database operations in `lib/projects.ts`, background execution in `lib/worker.ts`, and external service calls in their own modules. This lets the deployed Queue consumer and the local worker use the same execution logic.

The template also includes shared-password authentication and same-origin checks for browser mutations. Everyone who signs in shares the same workspace. For production workflows, you should set up sign-up and sign-in flows for individual users.

### 2\. Configure the OpenAI Agents API

Create a saved agent with instructions to build Next.js apps in `/workspace`, preserve the managed preview server, and check its changes before finishing. The template's creation script selects `gpt-5.6` and saves the returned identifier as `OPENAI_AGENT_ID`.

The application uses `client.beta.agents` from the [OpenAI TypeScript SDK](https://github.com/openai/openai-agents-js), which adds the `OpenAI-Beta: agents=v1` header automatically. For a new project, `client.beta.agents.sessions.create()` sends the following body to `POST https://api.openai.com/v1/agents/sessions`:

```json
{
  "agent_id": "<OPENAI_AGENT_ID>",
  "environment": {
    "type": "self_hosted",
    "workspace_directory": "/workspace"
  }
}
```

Save the returned session ID against the project. Start the Codex executor in that project's sandbox with `--environment-id` set to `session.environment.id` and `--remote` set to `session.environment.remote_url`. Save both values and reuse the returned URL unchanged when reconnecting. Subsequent prompts go to the same session, so the agent can continue working on the existing app.

Subscribe to the session's event stream before submitting a prompt, then save assistant text and progress as events arrive. Give each submission a stable job ID as its idempotency key so a retried request can refer to the same input.

### 3\. Give each project a persistent sandbox

The agent needs a place to write source files, install dependencies, and run the generated app. Create a named Vercel Sandbox for each project so that those operations happen in an isolated workspace, and later edits can retrieve the same files.

For a project without an existing agent session, `lib/sandbox.ts` uses the following sandbox configuration:

```typescript
const sandbox = await Sandbox.getOrCreate({
  name: project.sandbox_name,
  image: "vercel/sandbox/node:24",
  ports: [3000],
  persistent: true,
  timeout: 30 * 60_000,
  snapshotExpiration: 0,
  keepLastSnapshots: { count: 2, expiration: 0, deleteEvicted: true },
  networkPolicy: {
    allow: [
      "api.openai.com",
      "codex-cloud-environments.chatgpt.com",
      "registry.npmjs.org",
    ],
  },
});
```

On first use, prepare `/workspace`, install the executor, write the starter Next.js app, and install its packages. For a project with an existing agent session, use `Sandbox.get({ name })`. A missing saved workspace must surface an error instead of silently creating an empty replacement.

[Persistent sandboxes](https://vercel.com/docs/sandbox/sdk-reference#sandbox-class) snapshot their file system on stop and restore it on resume. Forma retains two snapshots without automatic expiration, so **Save & pause** stops compute while retained storage can still incur charges. Running processes are restarted when the project reopens.

Only the restricted executor key is passed into the sandbox. The application's OpenAI key, database connection string, and authentication secrets stay in the builder backend.

### 4\. Store projects and jobs with Postgres

Connect a Neon Postgres database and use its pooled connection string as `DATABASE_URL`. The template uses `pg` for database access and keeps its repeatable schema in `db/schema.sql`.

The following four tables cover the application's state:

| Table            | What it stores                                                                 |
| ---------------- | ------------------------------------------------------------------------------ |
| `projects`       | Ownership, sandbox name, OpenAI session, preview URL, and current status.      |
| `jobs`           | Edit, resume, and stop operations, including execution phase and worker lease. |
| `messages`       | User prompts, assistant responses, progress, and errors.                       |
| `login_attempts` | Counters for shared-password login throttling.                                 |

When accepting an edit, lock the project and create its job, user message, and active-job pointer in one transaction. A repeated request ID returns the existing job. So, a new edit is rejected while another operation is active.

The worker claims a job with a time-limited lease. This gives duplicate queue deliveries a way to detect work already in progress. The database also preserves unfinished jobs if publishing to the queue fails.

### 5\. Process background work with Vercel Queues

Configure two topics using [Vercel Queues](https://vercel.com/docs/queues/quickstart): `studio-jobs` for project operations and `studio-provision` for session reconciliation. The private consumers are declared in `vercel.json`:

```json
{
  "functions": {
    "app/api/queues/jobs/route.ts": {
      "experimentalTriggers": [{ "type": "queue/v2beta", "topic": "studio-jobs" }]
    },
    "app/api/queues/provision/route.ts": {
      "experimentalTriggers": [{ "type": "queue/v2beta", "topic": "studio-provision" }]
    }
  }
}
```

After committing a job, publish its ID. The jobs consumer loads its state and calls the worker:

```typescript
import { queue } from "@/lib/queue";
import { runJob } from "@/lib/worker";

export const maxDuration = 800;
export const POST = queue.handleCallback<{ jobId: string }>(
  async ({ jobId }) => runJob(jobId),
  { visibilityTimeoutSeconds: 900, retry: () => ({ afterSeconds: 30 }) },
);
```

OpenAI lifecycle notifications enter through `/api/webhook`. Verify the signature against the raw request body, then send the relevant session ID to `studio-provision`. Its consumer checks that the session belongs to a saved project before reconnecting an executor or handling a failed session.

### 6\. Add recovery and idle cleanup with Vercel Cron

Add the Cron schedule alongside the Queue configuration in `vercel.json`:

```json
{
  "crons": [{ "path": "/api/cron", "schedule": "*/5 * * * *" }]
}
```

Every five minutes, `/api/cron` republishes unfinished jobs whose leases are absent or expired. It also enqueues stop operations for inactive projects with no active job and removes expired login-throttling records. The route checks the bearer token supplied through `CRON_SECRET`.

Projects become eligible for an idle shutdown after 10 minutes of inactivity. Shutdown happens after the next cron run and queue delivery. An active sandbox also has its own compute timeout.

### 7\. Connect progress and previews to the UI

Start the generated Next.js development server on `0.0.0.0:3000` inside the sandbox. Wait for a successful HTTP response before saving `sandbox.domain(3000)` as the project's preview URL. The studio loads that URL in an iframe, and the development server updates the preview as source files change.

After the agent finishes, the worker runs a separate production build. The starter uses `BUILD_CHECK=1` to write verification output to `.next-build`, leaving the live server's `.next` directory separate. A successful build and preview readiness check mark the project ready; a failed build appears in chat so the user can request a fix.

The browser connects to an SSE endpoint that reads saved project state and messages from Neon. Refreshing or closing the page leaves the background job running. Reconnecting restores the saved conversation and status.

The iframe restricts navigation and runs on a separate origin. Its URL is accessible to anyone who has it; the builder's password does not protect generated previews.

### 8\. Journey of a request

The complete request flow is:

1. A signed-in user submits a prompt. The app saves the edit job and publishes its ID for workers.
   
2. The worker claims the job, prepares the sandbox, and creates or retrieves the project's agent session.
   
3. The executor connects to OpenAI, and the worker submits the prompt while recording streamed progress.
   
4. The agent edits the app. The preview updates, and the browser receives saved chat and status changes.
   
5. The worker checks the build and marks the operation complete. A follow-up prompt repeats the flow with the same session and files.
   

**Save & pause** is available when no operation is active and creates a stop job. Reopening the project creates a resume job that restores the workspace and restarts its preview without sending a new coding prompt.

## Set up locally

Clone the template and link it to your Vercel project:

```bash
git clone https://github.com/vercel-labs/openai-agents-api-v0-clone.git
cd openai-agents-api-v0-clone
pnpm install
vercel link
```

### Configure credentials

In the Vercel project's **Storage** tab, connect Neon through the [Marketplace](https://vercel.com/docs/postgres). Select a database or branch for development and connect it to the Development environment. Pull the environment variables and local Vercel authentication:

```bash
vercel env pull .env.local
```

Use `.env.example` as the checklist for the remaining settings:

| Variable                  | How to obtain it                                                                                                                                                                                 |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `DATABASE_URL`            | Use the Neon integration's pooled Postgres connection string for development.                                                                                                                    |
| `OPENAI_API_KEY`          | Create an application key in your OpenAI project with Agents API preview access.                                                                                                                 |
| `OPENAI_EXECUTOR_API_KEY` | Create an [environment key](https://developers.openai.com/api/docs/guides/agents-api/environments/self-hosted#authentication) from the OpenAI dashboard’s Agents tab, under Environments → Keys. |
| `OPENAI_AGENT_ID`         | Run `pnpm agent:create` after setting the application key. The script saves the ID in `.env.local`.                                                                                              |
| `OPENAI_WEBHOOK_SECRET`   | Register a reachable `/api/webhook` endpoint in the OpenAI project's webhook settings and save the signing secret. The deployment steps below explain how to establish that endpoint.            |
| `APP_PASSWORD`            | Choose a strong password for signing in to the shared workspace.                                                                                                                                 |
| `AUTH_SECRET`             | Generate an independent random value for signing cookies and deriving workspace ownership.                                                                                                       |
| `CRON_SECRET`             | Generate another independent random value for authenticating Cron requests.                                                                                                                      |
| `VERCEL_OIDC_TOKEN`       | Obtain it through `vercel env pull`; the Sandbox SDK uses it for local authentication.                                                                                                           |

You can generate a random secret with `openssl rand -hex 32`; run it separately for each secret. Keep `.env.local` out of version control. Leave `APP_URL` unset locally so requests use the local origin.

For the webhook, subscribe to `agent.session.action_required` and `agent.session.failed`. OpenAI provides the signing secret when you [register the endpoint](https://developers.openai.com/api/docs/guides/webhooks). If you don't have a deployed URL yet, complete the initial deployment below, then save the returned secret locally before starting generation.

The local worker can establish executor connections directly. A production webhook only reconciles sessions present in its own database; it does not process projects stored exclusively in a development branch.

### Run the app

Once the environment is configured, create the saved agent, apply the schema, and start development:

```bash
pnpm agent:create
pnpm db:migrate
pnpm dev
```

The agent script keeps an existing `OPENAI_AGENT_ID`. The development command starts both Next.js and the database worker; running Next.js by itself leaves local jobs unprocessed.

Open `localhost:3000`, sign in with `APP_PASSWORD`, and try:

```plaintext
Build a reading list app with book cards, a form to add a book, and filters for books I want to read and books I've finished.
```

Wait for the build check, then request a change such as adding a rating control. Refresh to confirm the conversation returns. Use **Save & pause**, reopen the project, and check that the generated code is still there. Data entered into the generated app needs its own storage if it should survive reloads.

If local Sandbox authentication expires, pull fresh variables into a separate temporary file and copy the new `VERCEL_OIDC_TOKEN` into `.env.local`, preserving your other settings. Restart `pnpm dev` after changing credentials.

## Deploy the app

Before proceeding with production deployment, create a production database or Neon branch and a separate set of production credentials. Within each environment, the OpenAI application and executor keys must belong to the same organization and project. Use an agent accessible to that production OpenAI project and a webhook registered for the production endpoint.

In the Vercel project settings:

1. Select **Next.js** as the framework and **Node.js 24** as the runtime.
   
2. Set the Build Command to `pnpm vercel-build`. It applies `db/schema.sql` to the deployment’s `DATABASE_URL` before building Next.js.
   
3. Add the application settings from `.env.example` to the Production environment, using the production database and keys. Create the production agent with `pnpm agent:create` in a checkout configured with the API credentials, then copy the returned ID into Vercel.
   

Make the initial deployment to establish its URL:

```bash
vercel deploy --prod
```

Generation remains unconfigured until the webhook secret is installed. In the production OpenAI project's webhook settings, register `https://your-domain.example/api/webhook` for `agent.session.action_required` and `agent.session.failed`. Add the returned `OPENAI_WEBHOOK_SECRET` to the Vercel project’s environment variables and redeploy.

Finally, sign in and verify a new project, a follow-up edit, and pause/resume. Inspect OpenAI's webhook delivery history and the provision consumer logs to confirm actual lifecycle events arrive.

## Next steps

- **Add per-user signup and login.** Replace the shared password with individual identities, associate projects with those users, and enforce ownership throughout the API and background worker.
  
- **Expand the background workflows.** Add bounded retries, cancellation, recovery for failed agent sessions, and browser checks for generated apps. For longer tasks, save intermediate progress and require approval before publishing.
  
- **Protect against abuse.** Extend the existing login throttling with per-user generation limits, concurrency quotas, and usage budgets. Add role-based access control (RBAC) for actions such as deleting and publishing projects.
  
- **Deploy generated apps to Vercel projects.** Add a publishing flow that connects a user's Vercel account, exports the generated source, and creates a deployment after validation.
  

## Related resources

- Learn how to [Build an agentic app in FastAPI with OpenAI Agents API and Vercel Sandbox.](https://vercel.com/kb/guide/fastapi-openai-agents-api-vercel-sandbox)
  
- Read the [OpenAI Agents API docs.](https://developers.openai.com/api/docs/guides/agents-api/overview)
  
- Clone and review the [template repository.](https://github.com/vercel-labs/openai-agents-api-v0-clone)
  
- Read about [Vercel Sandbox persistence.](https://vercel.com/docs/sandbox/concepts/persistent-sandboxes)
  
- Learn more about the Vercel Sandbox APIs with the [JavaScript SDK Reference](https://vercel.com/docs/sandbox/sdk-reference).
  
- Learn how to [Build an agentic app in FastAPI with OpenAI Agents API and Vercel Sandbox.](https://vercel.com/kb/guide/fastapi-openai-agents-api-vercel-sandbox)