Skip to content

Instantly share code, notes, and snippets.

@johnlindquist
Created February 28, 2026 01:03
Show Gist options
  • Select an option

  • Save johnlindquist/737205ec67d84c4a6e03ff84556dcc80 to your computer and use it in GitHub Desktop.

Select an option

Save johnlindquist/737205ec67d84c4a6e03ff84556dcc80 to your computer and use it in GitHub Desktop.
v0 Platform API: File uploads don't get full-stack sandbox previews

v0 Platform API: File uploads don't get full-stack sandbox previews

The Problem

When publishing Next.js apps via the v0 Platform API using chats.init({ type: "files" }), the preview (demo-*.vusercontent.net) does not execute API routes, Server Actions, or any server-side code. Every request — including POST /api/my-route — returns the page HTML instead.

This makes it impossible to build interactive demos that use workflow, database connections, or any backend logic when publishing via the Platform API.

The same app connected via chats.init({ type: "repo" }) gets a real Vercel Sandbox where API routes work, workflows execute, and server-side code runs as expected.

What We Tested

Approach API Routes Work? Preview URL Pattern
type: "files" (inline content) No demo-*.vusercontent.net
type: "zip" (data URI) No demo-*.vusercontent.net
type: "files" + sendMessage() No demo-*.vusercontent.net
type: "files" + deployments.create() Deployment works (separate URL), but preview unchanged demo-*.vusercontent.net
Extra fields (sandbox: true, fullStack: true, deploy: true) Silently ignored (additionalProperties: false) demo-*.vusercontent.net
type: "repo" (GitHub URL) Yes Real Vercel deployment URL

Evidence

File upload preview — API route returns HTML

curl -s -D - "https://demo-XXXX.vusercontent.net/api/fan-out" \
  -X POST -H "Content-Type: application/json" \
  -d '{"incidentId":"T","message":"t","failChannels":[]}'

# Response:
# HTTP/2 200
# content-type: text/html; charset=utf-8
# x-matched-path: /render/next    <-- all routes hit the page renderer

Git-connected preview — API route returns JSON

The same app connected via type: "repo" pointing to vercel-labs/workflow-fan-out returns proper JSON from /api/fan-out and the Workflow DevKit runtime executes.

OpenAPI spec confirms no sandbox controls

curl -H "Authorization: Bearer $V0_API_KEY" https://api.v0.dev/v1/openapi.json

The /chats/init schema uses additionalProperties: false on all type variants — no hidden fields can be passed. No sandbox/preview/fullStack parameters exist anywhere in the spec.

deployments.create() creates a separate deployment

// After chats.init with type: "files":
const deployment = await client.deployments.create({
  projectId: project.id,
  chatId: chat.id,
  versionId: chat.latestVersion.id,
});
// deployment.webUrl = "https://xxx.labs.vercel.dev" (real Vercel, behind SSO)
// But the v0 chat preview still shows demo-*.vusercontent.net
// Re-fetching the chat shows demoUrl is UNCHANGED

The Gap

The v0 docs state:

"Previews now run your full application exactly as it would in production. This means server-side code, API routes, database connections, and environment variables all work in the preview."

This is true for the interactive v0 UI (when you chat with v0 and it builds/modifies your app) and for repo-connected projects. But it is not true for Platform API file uploads.

The demo-*.vusercontent.net preview appears to be a lightweight static renderer that:

  • Renders React server components (page.tsx)
  • Serves static assets
  • Does NOT execute API Route Handlers
  • Does NOT run serverless functions
  • Does NOT have access to the Vercel Workflow runtime

Impact

This blocks the use case of programmatically publishing interactive full-stack demos. We're building 56 standalone Workflow DevKit examples for a campaign, each needs:

  • Working API routes (to call start(), getRun(), getReadable() from workflow/api)
  • Real workflow execution (fan-out, retry, saga patterns)
  • SSE streaming from getWritable() in workflow steps

Currently the only path that works requires creating a GitHub repo per example and using type: "repo", which doesn't scale.

Feature Request

Allow type: "files" (and type: "zip") uploads to run in the full Vercel Sandbox with API route support — the same way type: "repo" does.

Alternatively, expose a parameter like sandbox: "full" or buildMode: "deploy" on chats.init to opt into the real sandbox for file uploads.

How to Reproduce

import { createClient } from "v0-sdk";

const client = createClient({ apiKey: process.env.V0_API_KEY });

const project = await client.projects.create({ name: "Test" });

// This gets a preview WITHOUT API route support:
const chat = await client.chats.init({
  type: "files",
  projectId: project.id,
  files: [
    { name: "app/page.tsx", content: "export default function Home() { return <div>Hello</div> }" },
    { name: "app/api/test/route.ts", content: "export async function GET() { return Response.json({ ok: true }) }" },
    { name: "package.json", content: '{"dependencies":{"next":"16.0.10","react":"19.2.3","react-dom":"19.2.3"}}' },
    { name: "next.config.ts", content: "export default {}" },
    { name: "tsconfig.json", content: '{"compilerOptions":{"jsx":"react-jsx"}}' },
  ],
});

// This URL does NOT serve /api/test — returns page HTML instead:
console.log(chat.latestVersion?.demoUrl);

// Compare with type: "repo" which DOES serve /api/test:
const repoChat = await client.chats.init({
  type: "repo",
  projectId: project.id,
  repo: { url: "https://github.com/your-org/your-repo" },
});

Further Research

Check if the Feb 2026 sandbox update broke file-upload previews

Compare the preview URL patterns

  • demo-*.vusercontent.net — Platform API file uploads (no API routes)
  • preview-*.vusercontent.net — Older pattern, also no API routes
  • Git-connected projects get a real .vercel.app or .labs.vercel.dev URL

Monitor the v0-sdk repo for changes

  • https://github.com/vercel/v0-sdk
  • Watch for new type options or sandbox parameters in the OpenAPI spec
  • The spec is at https://api.v0.dev/v1/openapi.json — diff it periodically

Test the v0 web UI pipeline

  • Manually create a v0 project via the web UI (not the API)
  • Upload files via the chat interface ("Start from these files")
  • Check if that preview has working API routes
  • If yes, the web UI uses a different build pipeline than the Platform API

Check Vercel Sandbox docs

Try the integrations.vercel.projects endpoint

// This links a v0 project to an existing Vercel project
await client.integrations.vercel.projects.create({
  projectId: v0ProjectId,
  name: "my-project",
});
  • If the v0 project is linked to a Vercel project that has a deployment, the preview might switch to using that deployment

OpenAPI spec reference

Save and diff the spec over time:

curl -s -H "Authorization: Bearer $V0_API_KEY" \
  https://api.v0.dev/v1/openapi.json | python3 -m json.tool > v0-openapi-$(date +%Y%m%d).json
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment