v0
Three distinct surfaces share the name. Do not conflate them.
| Surface |
What it is |
Entry point |
| v0 web app |
The hosted builder: chats, previews, projects, GitHub sync, one-click deploy |
v0.app |
| v0 Platform API |
REST API that drives that same agent headlessly — v2, https://api.v0.dev/v2, bearer auth |
npm i v0 |
| v0 Model API |
Separate OpenAI-compatible /chat/completions endpoint under api.v0.dev/v1 |
see Models, below |
Getting v0 output into a repo
Four routes. Pick by how much you intend to keep.
| Route |
Mechanism |
Use when |
| shadcn registry |
npx shadcn@latest add "<v0 chat URL>", or a v0 entry under registries in components.json then @v0/<name> |
One screen or component. The default "Add to Codebase" path. |
| GitHub integration |
v0 cuts a working branch off a base branch; you review and merge a PR |
The chat is an ongoing contributor to the repo |
| Platform API files |
v0.chats.getFiles({ chatId }) → { files: [{ path, content, encoding }] }, or downloadFiles for a ZIP |
Scripted/bulk import, or you want the file set under your own diffing |
| Copy/paste |
— |
Throwaway spike only. It loses provenance; prefer any of the above. |
@v0 is not a built-in shadcn namespace — it only resolves if components.json declares it. Registry mechanics, components.json, and namespace auth belong to shadcn; do not restate them here.
The Platform API also runs the seam backwards: chats.createFromRepo (GitHub URL + branch), createFromFiles (≤20 UTF-8 files), and createFromZip seed a chat from your code, so an iteration starts from what you actually shipped instead of from v0's last memory of it.
Import review checklist
v0 optimizes for a working preview, not for your repo's invariants. Walk this before the first commit; everything here is routine in generated output and cheap to fix at import time, expensive later.
| Check |
What you will find |
Fix |
| Hardcoded data |
Inline arrays of fake rows, const user = { name: "Jane" }, placeholder counts |
Replace with the real fetch; keep the array as a fixture only if a test uses it |
| Client/server boundary |
"use client" at the top of files that never touch state or an effect; data fetched in useEffect |
Strip the directive where nothing needs it; move fetching to the server component. Boundary rules → nextjs |
| Loading / error / empty |
Only the happy path exists |
Add loading.tsx / error.tsx or Suspense + a real empty state |
| Accessibility |
Icon-only buttons with no accessible name, div click handlers, unlabeled inputs, decorative-only focus rings, contrast from ad-hoc colors |
Name every control, use real button/label, keep the token-based focus ring |
| Dependencies |
Packages added at whatever version resolved during generation; occasionally a package the repo already solves another way |
Reconcile against the existing lockfile before installing; delete duplicates rather than adding a second date/icon/chart library |
| Theme drift |
Literal hex/bg-slate-900 instead of bg-background / text-muted-foreground / border-border |
Re-map onto the project's tokens |
components/ui/** overwrite |
The add command silently replaces primitives you have already customized |
--dry-run first, then --diff; never --overwrite blind |
| Secrets & env |
Keys inlined, or NEXT_PUBLIC_ on something that must stay server-side |
Move to server env; add the name (never the value) to .env.example |
| Images / fonts |
Remote placeholder image hosts, a second font family |
Point at your own assets; drop the extra font |
Render-performance findings (waterfalls, needless re-renders, bundle weight) are react-best-practices' territory — run it after the checklist, don't duplicate it.
Keeping generated code maintainable
- Land the import as its own commit, unmodified, then fix in a second commit. The two-commit shape is what makes "what did v0 actually write" answerable later.
- Treat generated files as normal owned source the moment they merge. There is no supported re-sync of an edited file back from a chat;
chats.updateFiles pushes edits into the chat, it does not pull.
- Re-generating? Feed the current repo back in with
createFromRepo / createFromFiles first. Prompting a stale chat produces a diff against code you no longer have.
- Keep one chat per surface. A chat that has accumulated five unrelated screens re-emits all five.
Platform API (v2)
Verified against packages/v0-sdk/openapi.json at vercel/v0-sdk@276e1c2 (OpenAPI 3.1.2, info.version 2.0.0, server https://api.v0.dev/v2).
| Package |
npm latest (2026-08-25) |
Purpose |
v0 |
3.0.4 |
The v2 SDK. import { v0 } from 'v0' |
v0-sdk |
0.16.7 |
The v1 SDK — defaults to https://api.v0.dev/v1. Legacy name; new work uses v0 |
@v0-sdk/react |
— |
Hooks + AI SDK transport for a browser client calling your proxy routes |
@v0-sdk/ai-tools |
— |
Every OpenAPI operation as an AI SDK tool (v0Tools, v0ToolsByCategory) |
Auth: the default client uses V0_API_KEY, and falls back to Vercel OIDC for server-side code deployed on Vercel. createV0Client({ auth, baseUrl }) overrides both. Every call returns { data, error } — check error rather than relying on a throw.
import { v0 } from 'v0'
const res = await v0.chats.create({ message: 'Build a pricing page' })
if (res.error) throw new Error(res.error.message)
const preview = await v0.chats.getPreview({ chatId: res.data.chat.id })
// preview.data is null while the preview is still starting — poll.
const { data } = await v0.chats.getFiles({ chatId: res.data.chat.id })
// data.files: { path: 'app/page.tsx', content: string, encoding: 'utf8' | 'base64' }[]
| Group |
Operations |
chats |
list create createFromFiles createFromZip createFromRepo createStream createAsync get update delete duplicate getPreview getFiles updateFiles downloadFiles getConnectStatus restoreMessage resume deploy createVercelProject |
messages |
list get send sendStream sendAsync resolve resolveStream resolveAsync stop |
mcpServers, settings, usage, webhooks |
CRUD; settings.{get,set}PreviewHosts; usage.{getSummary,listEvents,getActivity} |
- Streaming:
createStream / sendStream return a server result — readV0Stream(result.toResponse()) yields { stream, final }.
chats.deploy returns a deploymentId; the build runs asynchronously on Vercel — track it with the Vercel API, not by polling v0. Deploy/CI mechanics → deployments-cicd, vercel-cli.
- Webhook events:
chat.created chat.updated chat.deleted message.created message.updated message.deleted message.finished.
chats.create accepts skills (≤3) drawn from skills.sh (remote), user/team memory, or project scope.
- Never ship
V0_API_KEY to a browser. @v0-sdk/react is deliberately built around app-owned proxy routes that call the server-side SDK and re-expose only what you authorize.
Models
modelConfiguration.modelId on chat/message creation, from the checked-in v2 spec: v0-mini, v0-pro (default), v0-max, v0-max-fast. Pair with imageGenerations (default false). The v1 SDK's typings also list v0-auto; it is absent from the v2 enum — read the enum in openapi.json for the version you install rather than hardcoding from here.
The Model API is a different product from the Platform API despite sharing the api.v0.dev host: an OpenAI-compatible POST /v1/chat/completions with v0-1.x-series model ids, supporting only messages, model, stream, tools, tool_choice. Reach for it when you want v0's frontend-tuned generation inside your own chat app; reach for the Platform API when you want chats, files, previews, and deploys. Routing either through AI Gateway (vercel/… provider prefix) is ai-gateway's topic — resolve ids with gateway.getAvailableModels() before hardcoding.
Verified vs not
Verified here by reading the artifact: the v2 OpenAPI document, SDK method surface, model enum, file/webhook schemas, auth model, and npm package lineage and dates. @v0 being a configured — not built-in — shadcn namespace was verified against shadcn@4.19.0's own error strings.
Not verified — v0.app, v0.dev, vercel.com, ai-sdk.dev, and api.v0.dev were all unreachable from this environment (egress policy), so the following come from secondary evidence and should be re-checked against the docs before you rely on them: the exact registry URL for the @v0 namespace; the exact "Add to Codebase" command string; the GitHub integration's branch/PR mechanics; the Model API's current model ids and whether it is still offered; and which v0 models AI Gateway carries.
References
1---2name: v03description: Vercel's v0 app builder — taking v0 output into a production repo, and driving the v0 Platform API (v2, api.v0.dev/v2) from code with the `v0` npm SDK. Use when the user names v0, v0.dev, v0.app, the v0 Platform API, a v0 chat/preview/deploy URL, `V0_API_KEY`, `@v0-sdk/*`, or is reviewing/merging code described as generated by v0. Scope boundary: this skill owns the v0-specific workflow — the import seam, the Platform API surface, and v0-vs-repo drift. It does not own the topics of the code v0 emits: shadcn/ui and registries → shadcn, App Router and Server Components → nextjs, render performance → react-best-practices, model routing → ai-gateway, repo/env provisioning → bootstrap. Do not claim a request merely because the project is Next.js, uses shadcn/ui, or is deployed on Vercel.4---5# v067Three distinct surfaces share the name. Do not conflate them.89| Surface | What it is | Entry point |10|---|---|---|11| v0 web app | The hosted builder: chats, previews, projects, GitHub sync, one-click deploy | `v0.app` |12| v0 Platform API | REST API that drives that same agent headlessly — v2, `https://api.v0.dev/v2`, bearer auth | `npm i v0` |13| v0 Model API | Separate OpenAI-compatible `/chat/completions` endpoint under `api.v0.dev/v1` | see *Models*, below |1415## Getting v0 output into a repo1617Four routes. Pick by how much you intend to keep.1819| Route | Mechanism | Use when |20|---|---|---|21| shadcn registry | `npx shadcn@latest add "<v0 chat URL>"`, or a `v0` entry under `registries` in `components.json` then `@v0/<name>` | One screen or component. The default "Add to Codebase" path. |22| GitHub integration | v0 cuts a working branch off a base branch; you review and merge a PR | The chat is an ongoing contributor to the repo |23| Platform API files | `v0.chats.getFiles({ chatId })` → `{ files: [{ path, content, encoding }] }`, or `downloadFiles` for a ZIP | Scripted/bulk import, or you want the file set under your own diffing |24| Copy/paste | — | Throwaway spike only. It loses provenance; prefer any of the above. |2526`@v0` is **not** a built-in shadcn namespace — it only resolves if `components.json` declares it. Registry mechanics, `components.json`, and namespace auth belong to **shadcn**; do not restate them here.2728The Platform API also runs the seam backwards: `chats.createFromRepo` (GitHub URL + branch), `createFromFiles` (≤20 UTF-8 files), and `createFromZip` seed a chat *from your code*, so an iteration starts from what you actually shipped instead of from v0's last memory of it.2930### Import review checklist3132v0 optimizes for a working preview, not for your repo's invariants. Walk this before the first commit; everything here is routine in generated output and cheap to fix at import time, expensive later.3334| Check | What you will find | Fix |35|---|---|---|36| Hardcoded data | Inline arrays of fake rows, `const user = { name: "Jane" }`, placeholder counts | Replace with the real fetch; keep the array as a fixture only if a test uses it |37| Client/server boundary | `"use client"` at the top of files that never touch state or an effect; data fetched in `useEffect` | Strip the directive where nothing needs it; move fetching to the server component. Boundary rules → **nextjs** |38| Loading / error / empty | Only the happy path exists | Add `loading.tsx` / `error.tsx` or `Suspense` + a real empty state |39| Accessibility | Icon-only buttons with no accessible name, `div` click handlers, unlabeled inputs, decorative-only focus rings, contrast from ad-hoc colors | Name every control, use real `button`/`label`, keep the token-based focus ring |40| Dependencies | Packages added at whatever version resolved during generation; occasionally a package the repo already solves another way | Reconcile against the existing lockfile before installing; delete duplicates rather than adding a second date/icon/chart library |41| Theme drift | Literal hex/`bg-slate-900` instead of `bg-background` / `text-muted-foreground` / `border-border` | Re-map onto the project's tokens |42| `components/ui/**` overwrite | The add command silently replaces primitives you have already customized | `--dry-run` first, then `--diff`; never `--overwrite` blind |43| Secrets & env | Keys inlined, or `NEXT_PUBLIC_` on something that must stay server-side | Move to server env; add the name (never the value) to `.env.example` |44| Images / fonts | Remote placeholder image hosts, a second font family | Point at your own assets; drop the extra font |4546Render-performance findings (waterfalls, needless re-renders, bundle weight) are **react-best-practices**' territory — run it after the checklist, don't duplicate it.4748### Keeping generated code maintainable4950- Land the import as its own commit, unmodified, then fix in a second commit. The two-commit shape is what makes "what did v0 actually write" answerable later.51- Treat generated files as normal owned source the moment they merge. There is no supported re-sync of an edited file back from a chat; `chats.updateFiles` pushes edits *into* the chat, it does not pull.52- Re-generating? Feed the current repo back in with `createFromRepo` / `createFromFiles` first. Prompting a stale chat produces a diff against code you no longer have.53- Keep one chat per surface. A chat that has accumulated five unrelated screens re-emits all five.5455## Platform API (v2)5657Verified against `packages/v0-sdk/openapi.json` at `vercel/v0-sdk@276e1c2` (OpenAPI 3.1.2, `info.version` 2.0.0, server `https://api.v0.dev/v2`).5859| Package | npm latest (2026-08-25) | Purpose |60|---|---|---|61| `v0` | 3.0.4 | The v2 SDK. `import { v0 } from 'v0'` |62| `v0-sdk` | 0.16.7 | The **v1** SDK — defaults to `https://api.v0.dev/v1`. Legacy name; new work uses `v0` |63| `@v0-sdk/react` | — | Hooks + AI SDK transport for a browser client calling *your* proxy routes |64| `@v0-sdk/ai-tools` | — | Every OpenAPI operation as an AI SDK tool (`v0Tools`, `v0ToolsByCategory`) |6566Auth: the default client uses `V0_API_KEY`, and falls back to Vercel OIDC for server-side code deployed on Vercel. `createV0Client({ auth, baseUrl })` overrides both. Every call returns `{ data, error }` — check `error` rather than relying on a throw.6768```ts69import { v0 } from 'v0'7071const res = await v0.chats.create({ message: 'Build a pricing page' })72if (res.error) throw new Error(res.error.message)7374const preview = await v0.chats.getPreview({ chatId: res.data.chat.id })75// preview.data is null while the preview is still starting — poll.7677const { data } = await v0.chats.getFiles({ chatId: res.data.chat.id })78// data.files: { path: 'app/page.tsx', content: string, encoding: 'utf8' | 'base64' }[]79```8081| Group | Operations |82|---|---|83| `chats` | `list` `create` `createFromFiles` `createFromZip` `createFromRepo` `createStream` `createAsync` `get` `update` `delete` `duplicate` `getPreview` `getFiles` `updateFiles` `downloadFiles` `getConnectStatus` `restoreMessage` `resume` `deploy` `createVercelProject` |84| `messages` | `list` `get` `send` `sendStream` `sendAsync` `resolve` `resolveStream` `resolveAsync` `stop` |85| `mcpServers`, `settings`, `usage`, `webhooks` | CRUD; `settings.{get,set}PreviewHosts`; `usage.{getSummary,listEvents,getActivity}` |8687- Streaming: `createStream` / `sendStream` return a server result — `readV0Stream(result.toResponse())` yields `{ stream, final }`.88- `chats.deploy` returns a `deploymentId`; the build runs asynchronously on Vercel — track it with the Vercel API, not by polling v0. Deploy/CI mechanics → **deployments-cicd**, **vercel-cli**.89- Webhook events: `chat.created` `chat.updated` `chat.deleted` `message.created` `message.updated` `message.deleted` `message.finished`.90- `chats.create` accepts `skills` (≤3) drawn from skills.sh (`remote`), user/team `memory`, or `project` scope.91- **Never ship `V0_API_KEY` to a browser.** `@v0-sdk/react` is deliberately built around app-owned proxy routes that call the server-side SDK and re-expose only what you authorize.9293## Models9495`modelConfiguration.modelId` on chat/message creation, from the checked-in v2 spec: `v0-mini`, `v0-pro` (default), `v0-max`, `v0-max-fast`. Pair with `imageGenerations` (default `false`). The v1 SDK's typings also list `v0-auto`; it is absent from the v2 enum — read the enum in `openapi.json` for the version you install rather than hardcoding from here.9697The **Model API** is a different product from the Platform API despite sharing the `api.v0.dev` host: an OpenAI-compatible `POST /v1/chat/completions` with `v0-1.x`-series model ids, supporting only `messages`, `model`, `stream`, `tools`, `tool_choice`. Reach for it when you want v0's frontend-tuned generation inside your own chat app; reach for the Platform API when you want chats, files, previews, and deploys. Routing either through AI Gateway (`vercel/…` provider prefix) is **ai-gateway**'s topic — resolve ids with `gateway.getAvailableModels()` before hardcoding.9899## Verified vs not100101Verified here by reading the artifact: the v2 OpenAPI document, SDK method surface, model enum, file/webhook schemas, auth model, and npm package lineage and dates. `@v0` being a configured — not built-in — shadcn namespace was verified against `shadcn@4.19.0`'s own error strings.102103Not verified — `v0.app`, `v0.dev`, `vercel.com`, `ai-sdk.dev`, and `api.v0.dev` were all unreachable from this environment (egress policy), so the following come from secondary evidence and should be re-checked against the docs before you rely on them: the exact registry URL for the `@v0` namespace; the exact "Add to Codebase" command string; the GitHub integration's branch/PR mechanics; the Model API's current model ids and whether it is still offered; and which v0 models AI Gateway carries.104105## References106107- v0 docs — https://v0.app/docs · Platform API v2 — https://v0.app/docs/api/v2 · v1→v2 migration and AI models pages under the same tree108- `vercel/v0-sdk` — https://github.com/vercel/v0-sdk (read at `276e1c2`; `packages/v0-sdk/openapi.json` is the generated SDK's copy of the upstream v2 spec)109- npm: [`v0`](https://www.npmjs.com/package/v0) · [`v0-sdk`](https://www.npmjs.com/package/v0-sdk) · [`@v0-sdk/react`](https://www.npmjs.com/package/@v0-sdk/react)110- Model API request body — https://v0.dev/docs/v0-model-api#request-body (cited by third-party clients; not fetched)111- In-repo: `skills/vercel/shadcn` (registries, `components.json`, theming) · `skills/vercel/nextjs` · `skills/vercel/react-best-practices` · `skills/vercel/ai-gateway`