Skip to content

Lovable apps on TanStack Start

Lovable creates new projects with TanStack Start. Pages render on a server, and server functions run your backend code. Lovable publishes these apps to Cloudflare Workers. ScaleBop builds the same code as a Node.js server and runs it in your AWS account on ECS Fargate behind a load balancer and CloudFront.

Older Lovable projects (React and Vite, without server rendering) still deploy as a static site on S3 and CloudFront. If you upgrade one of them to TanStack Start in Lovable, see When your app changes shape.

You don’t need a Dockerfile. When your repository has none, ScaleBop adds .scalebop-deploy/Dockerfile in its setup pull request. It:

  1. installs your dependencies with the tool that wrote your lockfile (Lovable uses bun.lock)
  2. runs your build script with NITRO_PRESET=node-server, so the build writes a Node.js server to .output/ instead of a Cloudflare Workers bundle
  3. runs node .output/server/index.mjs on port 3000

Your vite.config.ts and the rest of your code stay as they are, so Lovable keeps working on the same files.

If your repository has its own Dockerfile, ScaleBop builds that instead. See Bring your own Dockerfile.

A server runs all the time, so a TanStack Start app costs more each month than a static site. See Compute and cost. If you upgrade a static Lovable app, the notice that pauses Ship changes shows the monthly estimate before and after.

If your app turns on SPA mode (tanstackStart: { spa: { enabled: true } } in vite.config.ts) and has no server functions (createServerFn) or server routes, nothing needs a server. ScaleBop then deploys it as a static site on S3 and CloudFront, which costs less. CloudFront serves the _shell.html page SPA mode writes for every route.

As soon as the app gains a server function, it needs a server again. ScaleBop notices on the next push and asks you to update the setup.

  • VITE_ variables are public: they’re built into the JavaScript your visitors download. Add them under Configuration so they reach the build. The Supabase URL and publishable (anon) key belong here.
  • Variables without the prefix are server-only. Server functions read them from process.env while the app runs. Add them as secrets under Configuration, for example SUPABASE_SERVICE_ROLE_KEY.

Never put a secret behind the VITE_ prefix: anyone who opens your site can read it.

Lovable’s template is written for Cloudflare, so its AI may reach for Cloudflare-only features. The rules under Deployment files → Rules for your AI tool on your project hub include TanStack Start lines that steer it away from them: read secrets with process.env, don’t use Cloudflare bindings, and don’t change the Nitro settings in vite.config.ts. Paste them into your project’s knowledge in Lovable.

Message What to do
The app doesn’t build with Nitro, or has no nitro dependency Lovable’s current template includes both. Ask Lovable to “upgrade the Vite TanStack config to the latest version and add the nitro package”.
@lovable.dev/vite-tanstack-config version 1 only builds for Cloudflare Workers Upgrade it to version 2 or later, with the same prompt.
vite.config pins a Nitro preset Remove the preset option, so the build target is chosen when the app deploys.
The app imports Cloudflare Workers modules (cloudflare:*) Ask Lovable to “read server secrets from process.env, not Cloudflare bindings”. Those modules only exist on Cloudflare.
The Wrangler config declares Cloudflare bindings (KV, D1, R2, …) Move that data to a service your app reaches over the network, such as Supabase, then remove the bindings.

Each of these also goes away if you commit a Dockerfile that runs the server.