Deploy a v0 app without Vercel
It comes down to one question: does your v0 project use Server Actions? If it does, there's no static export and no honest workaround - leave it on Vercel. If it doesn't, adding output: 'export' to next.config.mjs makes next build write a folder of plain HTML any web server can serve. What nobody tells you is that this folder does not work on an Apache host until you change one more setting - you'll get a 404 on every page except the homepage. That fix is at the bottom.
One correction first, because it changes the decision. Attaching your own domain to a v0 app costs nothing: Vercel's free Hobby plan allows 50 domains per project, and v0 inherits whatever domains the connected Vercel project has (checked August 2026). If you're leaving because you assumed the domain was the paid part, don't - Publish → Customize Domain, or Project Menu ... → Domains, and you're done in an afternoon. The real reason to leave is further down, and it isn't price either.
Your v0 preview cannot tell you whether the app is static
This trips people up because it used to be reliable. Since the 4 February 2026 update, v0 previews run in Vercel Sandbox, an actual Node.js virtual machine, and v0's docs say server-side code, API routes, database connections and environment variables all work there. Better preview, worse diagnostic: a hopelessly server-dependent project looks perfect right up until you try to export it.
So read the code instead. Search the editor for each of these; every hit is a feature a static export does not support (checked August 2026, Next.js 16):
'use server'- Server Actions. The blocker. Any form that mutates data, anyaction={...}on a<form>. v0 reaches for these constantly, because it defaults to Next.js specifically for the server-action ergonomics.cookies()orheaders()fromnext/headers- reading the request. Common in any v0 app that added auth.proxy.tsat the project root - in Next.js 16 this is whatmiddleware.tswas renamed to (v16.0.0, now defaulting to the Node.js runtime). If you ran the codemodnpx @next/codemod@canary middleware-to-proxy .and forgot you had a redirect in there, this is where it hides.generateStaticParamsmissing from a[slug]route - a dynamic route with no build-time list of params can't be exported. Same fordynamicParams: true.redirects,rewritesorheadersinnext.config- server features, silently ignored by an export.revalidate- Incremental Static Regeneration needs a server to regenerate on.
Route Handlers are the one everybody gets wrong. They do survive a static export, on two conditions: the GET verb only, and the handler must not read anything from the incoming Request. An app/data.json/route.ts returning Response.json({ name: 'Lee' }) is rendered at build time into a real data.json file in your output. A read-only JSON endpoint is fine; POST /api/contact is not.
The config change, and what it costs you
// next.config.mjs
const nextConfig = {
output: 'export',
trailingSlash: true,
images: { unoptimized: true },
}
export default nextConfignext build now writes to out/ instead of .next/. Three things to know about those last two lines.
images: { unoptimized: true } is the blunt fix. next/image with the default loader needs Vercel's Image Optimization service at request time, so it cannot be exported. unoptimized serves your source files as-is: you keep the layout behaviour and lazy loading, you lose automatic WebP conversion and resizing. The alternative is a custom loader pointed at Cloudinary or similar, documented in Next's static export guide. For most v0 landing pages, compressing the images once by hand beats both.
trailingSlash: true is not optional if you're going anywhere near Apache. Explained below; it's the whole reason this article exists.
The unsupported features at least fail loudly - next dev errors on them rather than letting you find out in production.
Getting the code out of v0
v0's Git model is unusually well behaved - the opposite of Bolt's, where the builder overwrites your repository on a conflict. In the sidebar, click Git → Connect and pick a scope and repository name. v0 then creates a working branch per chat - something like v0/username-abc123 - auto-commits every message that changes code, and never pushes directly to `main`. Changes reach your default branch through a pull request you open with Publish → Open PR.
Two consequences. Once connected, v0's docs are explicit that the repository "becomes the source of truth for your project. v0 does not store a separate copy of your code" - delete it on GitHub and your code may be unrecoverable. And because merges are gated behind a PR, wiring a build to main is safe here in a way it isn't with other builders: CI runs on merge, not on every half-finished thought.
The actual reason to leave: Hobby is non-commercial
Here's the rule almost nobody reads. Vercel's fair use guidelines state that Hobby teams are "restricted to non-commercial personal use only," and the definition of commercial catches nearly every site people build in v0 (checked August 2026):
- any method of requesting or processing payment from visitors
- advertising the sale of a product or service
- receiving payment to create, update, or host the site
- affiliate linking as the primary purpose
- ads, including AdSense
- asking for donations
Read that second one again. A landing page for your SaaS is commercial. A freelancer's portfolio listing rates is commercial. Anything you were paid to build is commercial, explicitly including where a "paid employee or consultant" wrote the code. Pro is $20 per developer seat per month - $240 a year - and the trigger is the nature of your site, not its traffic. That's the honest fork in the road, and it has nothing to do with domains.
Separately: free-plan deploys carry a "Built with v0" badge bottom-right. Paid plans switch it off at Project Menu ... → Vercel Project. Visitors can dismiss it per page, which is not the same as it being gone.
Serving a Next.js export on WordPress hosting
If you already pay for WordPress hosting, that server is already handing back files without WordPress being involved - every image in wp-content/uploads proves it. A Next.js export suits it better than a Vite SPA does, because next build has already written one HTML file per route. Nothing has to pre-render for you; the content is in the files.
Except for the trap. By default Next emits out/about.html for the route /about. Now look at what WordPress writes into your .htaccess:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]trailingSlash: true removes the problem rather than patching around it. With it set, Next emits out/about/index.html. Now /about is an existing directory, !-d fails, no rewrite happens, and Apache serves the index file inside it. Set it before your first deploy - changing it later changes every URL on your site.
From there it's a GitHub Action. Parkstatic builds the repo v0 syncs to and publishes the output to your WordPress site, keeping each deploy as a version you can roll back to. The only v0-specific line is the output directory, since Next exports to out/ rather than the dist/ most builders produce:
name: Build and Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: ParkStatic/action@main
with:
parkstatic-secret: ${{ secrets.PARKSTATIC_SECRET }}
output-dir: outGitHub Actions is free on public repositories and includes 2,000 minutes a month on GitHub Free for private ones (checked August 2026); a Next export spends two or three. The React and Vite guide covers the general build setup, and the deploy hub has the other builders.
When you should not do this
Your app uses Server Actions
I said it first and I'll say it last, because it's the clearest "don't buy this" case on the whole site. No configuration makes a Server Action run on a folder of static files - not mine, not anyone's. Keep it on Vercel, or move it to a host that runs Node.
It's a personal site and it isn't commercial
Vercel Hobby is free, your domain is free, and deploying is one button you already have. Adding a build pipeline to save $0 is a bad trade.
You don't already pay for WordPress hosting
This only works when the bill exists anyway. Cloudflare Pages and GitHub Pages will serve a Next export for nothing.
You need preview deployments per pull request
v0's PR-based workflow pairs naturally with Vercel previews, and losing them is a real downgrade once more than one person touches the repo. I don't do previews, edge functions or team seats.
If your v0 app is a marketing site or portfolio that happens to count as commercial, exports cleanly, and you already pay a WordPress host for something else, the arithmetic is easy: $240 a year for a Vercel Pro seat against $29.99 a year, or $89.99 once, for one WordPress site (checked August 2026). The full case for static hosting on WordPress is the longer version of that argument.