Why Lovable + TanStack Start 404s on Vercel
Lovable's TanStack Start uses Nitro with Cloudflare preset by default. Fix 404 errors on Vercel by reconfiguring to Vercel preset. Step-by-step guide.
- Lovable's April 2026 switch to TanStack Start uses Nitro with Cloudflare preset by default, which is incompatible with Vercel Functions
- Reconfigure Nitro by adding
preset: "vercel"to yourvite.config.tsto fix 404 errors on every route - Test server-side rendering works by refreshing pages and checking browser source code for actual content, not just JavaScript placeholders
Your Lovable app works perfectly when running locally. But when you deploy to Vercel, every route returns 404. Refreshing pages fails. This started happening after Lovable's April 2026 update. The root cause: Lovable moved new projects to TanStack Start, a full-stack framework that bundles Nitro, a universal server adapter. Nitro defaults to Cloudflare Workers output format, which Vercel Functions cannot execute. The fix requires one configuration change: telling Nitro to output for Vercel instead.
The Error and Why It Happens
When you refresh a page on your deployed Lovable app, you see a 404 error. This is not a routing bug in your code. Your code routes work fine locally and in Lovable's preview. The issue is at the server level.
Here is what changed: In April 2026, Lovable rolled out TanStack Start to all new projects as a replacement for the older Vite + React stack. TanStack Start is a full-stack framework that generates server-side rendered output. Unlike the old stack, which built a static SPA (single-page app), TanStack Start creates a hybrid: static files for assets, plus a server component that handles dynamic routes.
This server component is built with Nitro, an open-source universal deployment adapter. Nitro supports 25+ hosting platforms, from Cloudflare Workers to AWS Lambda to Vercel Functions. Each platform has a different output format. Cloudflare Workers expects code in a specific ESM module format. Vercel Functions expect Node.js entry points. They are incompatible.
Lovable's default configuration for new TanStack Start projects includes Nitro with the Cloudflare Workers preset activated by default. This is a reasonable choice for many users. But when you deploy to Vercel, the Cloudflare-formatted bundle does not work. Vercel's platform cannot execute Cloudflare Workers code. The result: every request hits a 404 because Vercel has no function to call.
The old workaround, adding a vercel.json rewrite config to force all routes to index.html, does not work here. That technique was for single-page apps where the frontend router handles everything. TanStack Start has a real server, so it needs a real adapter, not a static rewrite.
Understanding Nitro and Presets
Nitro is a server runtime engine that compiles your full-stack code into a format compatible with any hosting platform. Think of it as a translation layer. You write your code once. Nitro translates it to Cloudflare's format, or Vercel's format, or Deno Deploy's format, depending on which "preset" you choose.
A preset is a build configuration that specifies the target platform. Nitro includes presets for Cloudflare Workers (ESM modules), Vercel Functions (Node.js handler), Netlify Functions (Node.js handler), AWS Lambda, Deno Deploy, and 19 others.
When Lovable configured Nitro in the default vite.config.ts for new projects, they chose the Cloudflare preset. This works great if you deploy to Cloudflare Pages. It also works great if you move to Netlify. But Vercel is not Cloudflare. Vercel's serverless platform runs Node.js functions, not ESM modules.
The fix is not to remove Nitro or rebuild everything. The fix is to change one line: preset: "vercel" instead of preset: "cloudflare".
Why did Lovable default to Cloudflare? Because Cloudflare and Lovable share technology foundations. Cloudflare also offers competitive pricing and global edge performance. But this default catches Vercel users by surprise.
The Fix: Reconfigure Nitro for Vercel
Here is the step-by-step fix to deploy your Lovable + TanStack Start app to Vercel without 404 errors.
Step 1: Update vite.config.ts
Open your vite.config.ts file. Add the Nitro import at the top (if not already present) and register the Nitro Vite plugin:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { nitro } from 'nitropack/dist/vite'
export default defineConfig({
plugins: [react(), nitro()],
})
Step 2: Add Nitro Configuration
In the same vite.config.ts, add a Nitro configuration block. You can do this at the root level or nested under the plugins array. Here is the minimal approach:
export default defineConfig({
plugins: [react(), nitro()],
nitro: {
preset: 'vercel'
}
})
This tells Nitro to compile for Vercel's serverless Functions instead of Cloudflare Workers.
Step 3: Remove vercel.json (If Present)
If you have a vercel.json file in your project root, delete it. The old static-rewrite technique will conflict with Nitro's server adapter. Nitro handles routing natively.
Step 4: Verify Vercel Project Settings
Log into your Vercel dashboard. Navigate to your project settings:
- Build output directory:
dist - Install command:
npm install - Build command:
npm run build - Node.js version: 22 (or newer)
These should be detected automatically if Vercel sees the vite.config.ts with Nitro, but if you had a vercel.json override, you might need to manually reset them.
Step 5: Set Environment Variables
Lovable stores API keys and secrets in its .env file during development. These do not automatically transfer to Vercel.
You need two types of variables:
- Client-side: Prefix with
VITE_. For example, setVITE_API_URLto your production API endpoint. These are baked into your build artifact and visible in the browser. - Server-side: No prefix. For example,
DATABASE_URL=postgres://.... These stay on the server and are never sent to the browser.
Open your .env file. For each variable:
- If it is safe to expose (API endpoints, public IDs), add it to Vercel with the
VITE_prefix - If it is secret (API keys, database passwords), add it to Vercel without the prefix
In Vercel dashboard: Settings > Environment Variables. Paste each variable and its value.
Step 6: Redeploy
Commit your changes to Git:
git add vite.config.ts
git commit -m "Configure Nitro for Vercel deployment"
git push
Vercel will automatically trigger a new deployment. Monitor the build logs. The build should complete without errors. If build logs show stale artifacts, redeploy with cache cleared:
In Vercel dashboard: Deployments > Recent Deployment > Redeploy (with "Use existing Build Cache" unchecked).
Once deployed, test a live URL. Refresh pages. All routes should load.
Conditional Nitro: Keep Lovable Preview Working
A common mistake: adding Nitro unconditionally can break your Lovable preview environment. Lovable's preview runs your code locally without deploying to Vercel. If Nitro is configured to always use Vercel's preset, Lovable's local server might not start correctly.
The solution: conditionally enable Nitro only when deploying to Vercel. Use an environment variable to switch:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { nitro } from 'nitropack/dist/vite'
export default defineConfig({
plugins: [
react(),
process.env.VERCEL ? nitro() : null
].filter(Boolean),
nitro: process.env.VERCEL ? { preset: 'vercel' } : undefined
})
When you run Lovable locally or in preview, process.env.VERCEL is not set, so Nitro is skipped. When Vercel deploys, it automatically sets VERCEL=1, and Nitro activates.
This approach is non-breaking. Your Lovable workflow stays unchanged, and only the Vercel deployment gets the Nitro adapter.
Troubleshooting: When the Fix Doesn't Work
Still getting 404s after reconfiguring Nitro?
Check that nitro() is actually registered in your vite.config.ts. The plugin must be in the plugins array, not just imported. Run npm run build locally and look at the build output. If you see "Built with Nitro" or "Vercel functions generated", you are on the right track.
"Cannot find module '@rollup/rollup-linux-x64-gnu' during build"
This is a Node.js version mismatch. Vercel might be using Node 18, but your vite.config.ts assumes Node 22. In Vercel dashboard, set Node.js version to 22 in Project Settings > Environment > Node.js Version. Redeploy.
Blank white screen on deployed URL
This usually means environment variables are missing. Open browser DevTools console (F12). Look for errors about undefined variables or failed API calls. Check your Vercel environment variables list. Make sure all VITE_* prefixed variables are set. If a client-side variable is missing, Lovable's frontend will not initialize.
"Build succeeds but app crashes on first request"
Check your server-side code for missing environment variables. If your Nitro server tries to access process.env.DATABASE_URL but you forgot to set it in Vercel, the function crashes. Add the variable to Vercel without the VITE_ prefix and redeploy.
"Error: Vercel Functions folder not detected"
This means Vercel is not recognizing your Nitro build output. Delete dist/ and node_modules/. Run npm install && npm run build locally. Verify that a .vercel/output folder or dist folder contains a functions subdirectory. If it does not, your Nitro plugin is not configured correctly. Re-read the vite.config.ts setup above.
Platform Comparison: Vercel vs. Alternatives
Vercel is not your only option. After fixing the 404 error, you might choose to stay on Vercel, or you might evaluate alternatives.
Cloudflare Pages
Cloudflare has a Nitro preset built in. If you deploy to Cloudflare Pages, Nitro works out of the box without preset reconfiguration. Cloudflare is often faster for global latency because it runs on Cloudflare's edge network. Free tier includes unlimited static sites. Workers (the compute layer) cost per request. For most indie Lovable projects, Cloudflare Pages is cheaper than Vercel's usage-based pricing. However, Cloudflare's API is less familiar to most developers. See our guide on Lovable to Cloudflare Pages migration.
Netlify
Netlify has a similar stack to Vercel: serverless functions, git-based deployments, analytics. Nitro supports Netlify with a preset, so the configuration is nearly identical to Vercel. Netlify's free tier is comparable to Vercel's. Performance is similar. The main difference is UI. Some teams prefer Netlify's interface. Deploy Lovable to Netlify with the same Nitro configuration.
Managed Hosting: Opsily Ship
If you want predictable costs and no platform lock-in, consider managed hosting. Opsily's Ship platform runs your Lovable app on your own isolated server or Kubernetes cluster. You pay a flat monthly rate, not per request or per user. This scales better once your traffic grows. You also own your deployment. No learning Vercel's or Cloudflare's ecosystem. Ship handles updates, backups, and security. Learn about Ship hosting options.
The tradeoff: managed hosting requires you to trust your provider's infrastructure. It also removes the "pay for nothing" free tier. But if you are running a production app with predictable traffic, flat pricing often beats per-request billing.
Next Steps: Production Readiness
Once your Vercel deployment is live and stable, verify a few more things before calling it production-ready.
Dynamic Routes: Test nested routes. If your app has /blog/[slug] routes, navigate to a few post URLs and refresh the page. Verify server-side rendering works (content is in the HTML, not just rendered by JavaScript). Open page source (Ctrl+U) and look for actual text, not just <div id="root"></div>.
Environment Variables: Double-check that all secrets are in Vercel and not committed to Git. Run git log --all -S "API_KEY" to search your repo for leaked secrets. If you find any, rotate them immediately.
Custom Domain: If you have a custom domain, add it to Vercel project settings. Point your DNS records to Vercel (NS records or CNAME, depending on your registrar). Verify HTTPS works automatically.
Keep Editing in Lovable: You can keep using Lovable's web editor while your code is deployed to Vercel. Lovable's preview syncs with your GitHub repo, and your Vercel deployments read from the same repo. Push from Lovable, and Vercel redeploys automatically. This is the same workflow as before. Nothing changes on the Lovable side.
Monitoring: Set up error tracking. Use Sentry or Vercel's built-in error logging to catch runtime errors in production. Monitor your Vercel Function execution time. If functions are slow, consider upgrading your database or moving to managed hosting.
Use Opsily's migration checklist to validate all steps before going live.
Frequently Asked Questions
Does this affect existing Lovable projects already deployed to Vercel?
No. If your project was created before April 2026, you are using the old Vite + React stack. It deploys to Vercel without Nitro. Only new projects starting from May 13, 2026 use TanStack Start by default. If your old project is working, do not change it.
Can I roll back from TanStack Start to the old Vite stack?
Technically yes. You can delete vite.config.ts changes and rewrite your code for the old stack. But this is painful. TanStack Start is the future of Lovable. The better path is to fix the Nitro configuration (one line change) and stay on TanStack Start.
Why did Lovable make this change?
TanStack Start enables server-side rendering. This improves SEO, initial page load, and data fetching. The old React SPA pattern had limitations: every page required JavaScript to render, and API calls happened in the browser. TanStack Start moves rendering to the server, which is faster and more secure.
Do I need to manually configure environment variables, or do they sync from Lovable?
Manual configuration. Lovable's .env file is local to your machine and repo. Vercel has its own environment variable system. You must copy variables from .env to Vercel dashboard. This is intentional. It prevents secrets from leaking accidentally.
What is the difference between the Cloudflare preset and Vercel preset?
Cloudflare preset outputs ESM modules for Cloudflare Workers. Vercel preset outputs Node.js handler functions. They are incompatible. Choose one based on where you deploy. If you stay on Vercel, use preset: "vercel". If you switch to Cloudflare, use preset: "cloudflare".
Why does Lovable default to Cloudflare if Vercel is more popular?
Cloudflare and Lovable have shared technology foundations. Cloudflare also offers competitive pricing and global edge performance. But the default catches Vercel users off guard. Future versions of Lovable may detect your Vercel project and auto-configure the preset.
Will this setup break if I switch hosting providers later?
No. Nitro is portable. If you move to Netlify, change preset: "netlify" and redeploy. If you move to Cloudflare, change preset: "cloudflare". Your code stays the same. Only the build target changes.
The Bottom Line
Your Lovable + TanStack Start app returns 404 on Vercel because Nitro's Cloudflare preset is incompatible with Vercel's Node.js runtime. One configuration change fixes it: set preset: "vercel" in your vite.config.ts. This takes 30 seconds.
Once your app is deployed and working on Vercel, you have a choice. Stay on Vercel and ride the platform's ecosystem. Or evaluate alternatives: Cloudflare Pages (no Nitro reconfiguration needed, often cheaper), Netlify (similar to Vercel, familiar interface), or managed hosting like Opsily Ship (flat-rate, vendor-neutral, better long-term scaling). Most indie Lovable projects thrive on Vercel. But if your traffic grows or costs matter, managed hosting eliminates surprise bills and platform lock-in.