What changed on April 20, 2026
Lovable switched new projects from client-side React SPAs to TanStack Start, a full-stack React meta-framework built on TanStack Router. Existing projects remain as SPAs with no announced migration path.
Architecture proposal
Lovable's shift to TanStack Start SSR introduces a new deployment type that xCloud does not yet handle. With Bolt and Replit on the roadmap, the question is not just how to support Lovable SSR — it's how to build an architecture where adding any new AI builder is trivial.
xCloud already supports static Lovable deployments end-to-end. The build pipeline
runs npm install and npm run build,
Nginx serves the output with proper SPA fallback, and PM2 is correctly skipped for static sites. This works well.
The challenge is what comes next. On April 20, 2026, Lovable began generating TanStack Start SSR applications for new projects — a fundamentally different deployment model that requires a running Node.js process instead of static file serving. And with Bolt and Replit planned for future integration, we need an architecture that scales beyond one-off type checks.
Industry context
Lovable switched new projects from client-side React SPAs to TanStack Start, a full-stack React meta-framework built on TanStack Router. Existing projects remain as SPAs with no announced migration path.
Server-side rendering on every request, server functions via createServerFn() for secure backend logic, file-based type-safe routing, and built-in data fetching with TanStack Query (caching, deduplication, background refetching).
SSR apps need a running Node.js process — there is no index.html to serve statically. The server renders HTML per request, handles server function RPCs, and manages secrets via process.env instead of build-time VITE_* variables.
Pre-SSR Lovable apps sent an empty HTML shell to crawlers. With TanStack Start, Googlebot receives fully rendered HTML with meta tags, canonical links, and structured data on first request. This was the primary motivation for the transition.
The transition appears gradual — some users reported new projects still lacking SSR as of April 23. This may indicate A/B testing or a phased rollout. Both output types will coexist for the foreseeable future.
Deployment landscape
Lovable projects now produce one of three deployment archetypes depending on when the project was created and what template was used.
All projects before April 20, 2026 — and some after
| Stack | React 19, Vite 7, React Router, Tailwind CSS, shadcn/ui, Supabase client SDK |
| Build output | dist/index.html + dist/assets/* |
| Runtime | None — static files served by Nginx |
| Nginx strategy | try_files $uri $uri/ /index.html (SPA fallback) |
| Env vars | VITE_* prefix, embedded at build time — rebuild required on change |
| Detection | react-router-dom in package.json, src/App.tsx exists, dist/index.html after build |
New projects after April 20, 2026 — gradual rollout
| Stack | React 19, TanStack Start 1.x, TanStack Router, Nitro server engine, Vite 7 |
| Build output | .output/server/index.mjs + .output/public/* |
| Runtime | Node.js process managed by PM2 |
| Nginx strategy | Reverse proxy to localhost:PORT |
| Env vars | process.env.* read at runtime — restart suffices on change |
| Detection | @tanstack/react-start in package.json, src/router.tsx exists, .output/server/index.mjs after build |
Niche variant — depends on project template or user prompt
| Stack | Same as SSR + @cloudflare/vite-plugin, wrangler.jsonc |
| Build output | Worker bundle — no .output/server/index.mjs |
| Runtime | Cloudflare V8 isolates (not Node.js) |
| Nginx strategy | N/A — runs on Cloudflare edge network |
| Env vars | Worker secrets set via Cloudflare dashboard |
| Detection | wrangler.jsonc or wrangler.toml in project root |
Current state
Lovable site type is properly registered. Correct icon, no database provisioning, Node runtime installed.
npm install and npm run build run correctly during deployment via the Node app deploy path.
Nginx config detects isStaticSite() and applies try_files $uri $uri/ /index.html — SPA routing works.
PM2 startup is correctly skipped for static Lovable sites — no unnecessary process running.
Git pull, deploy script execution, and file serving chain work end-to-end for static builds.
Gaps
New Lovable projects using TanStack Start produce .output/server/index.mjs instead of dist/index.html. The platform has no path to run these as PM2 processes with reverse proxy.
No post-build validation. If a TanStack Start project builds but produces no dist/index.html, the deployment silently fails with no guidance to the user.
Projects targeting Cloudflare Workers (wrangler.jsonc present) will build but produce no usable output. Should detect and fail with an explanation instead of deploying broken.
Adding a new AI builder (Bolt, Replit) requires touching 14+ files across backend, frontend, scripts, and config. Type-specific checks are scattered throughout the codebase.
Current default web root is dist/. Newer Lovable projects may output to dist/client/. Need flexible web root handling per deployment type.
Architecture concern
The current architecture ties site identity (who built it) to deployment behavior (how to deploy it) through scattered type checks across the codebase. Adding a single new AI builder today means touching 14 files across backend, frontend, scripts, and configuration:
Every AI builder produces the same 2-3 output types (static SPA, Node SSR, or edge runtime). The deployment logic should care about what was built, not who built it.
Proposed solution
The SiteType enum already declares capabilities like
filesBackupSupported() and
databaseBackupSupported().
We extend this pattern so that every downstream system — deploy scripts, Nginx config, frontend UI — reads
capabilities from the enum instead of checking type identity.
| Method | Purpose | Replaces |
|---|---|---|
| isAiBuilder() | Identifies AI app builder platforms (Lovable, Bolt, Replit) | Scattered isLovable() || isBolt() checks across the codebase |
| supportsSSR() | Whether this type can run as a Node.js SSR application | isNodejs() || isLovable() checks and growing if-chains |
| defaultDeployMode() | Default mode when site is created (static_spa or node_ssr) | Hardcoded if-chains in isStaticSite() |
| defaultWebRoot() | Default web root per type (dist/client, dist, null) | Hardcoded web_root assignments in SiteMigrationController |
| defaultStartCommand() | Default PM2 start command for SSR mode | Hardcoded start_command logic in Vue components |
| unsupportedTargetSignals() | Files that indicate an unsupported deployment target | Nothing — this is new capability for detecting CF Workers, Vercel, Netlify targets |
New enum case, new model methods, update type arrays in 4 Vue files, new deploy script block, new Nginx conditional, new sidebar section, migration defaults, language files.
New enum case with match arms in SiteType.php, one line in Site manager(), app type definition in frontend, translations. All deploy logic inherits from capabilities.
Deploy safety
Instead of assuming what the build will produce based on site type, validate the actual output after
npm run build completes. This catches edge targets,
misconfigurations, and framework changes automatically.
Implementation
No big-bang rewrite. Each phase is a standalone PR that can be reviewed, tested, and shipped independently.
New methods only, no behavior change. Follows existing pattern of filesBackupSupported() and databaseBackupSupported().
Risk: None
Replace isStaticSite() logic and scattered type checks with $this->type->supportsSSR() calls. Same behavior, cleaner code.
Risk: Low
Gate PM2 startup and Nginx reverse proxy on supportsSSR() + meta->is_ssr_app. Add post-build output detection.
Risk: Medium
Detect wrangler.jsonc, vercel.json, netlify.toml in deploy script. Fail with actionable guidance instead of silent broken deploy.
Risk: Low
Pass capabilities via SiteResource. Replace hardcoded type arrays in Vue with capability-driven checks.
Risk: Medium
References
Recommendation
Static Lovable deployments work. The existing pipeline handles them correctly — build, serve, SPA fallback, no PM2. This is the majority of Lovable projects today and will remain so for a while.
SSR support is the immediate gap. New Lovable projects using TanStack Start need a Node.js process, reverse proxy, and runtime environment variables. This is the most impactful feature to add next.
The capability-driven architecture is the long-term investment. Five incremental PRs transform "adding a new AI builder" from a 14-file integration project into a 4-file configuration change. This pays for itself the moment Bolt or Replit are added.
Post-build detection prevents silent failures. Validating actual build output instead of assuming structure catches edge targets, framework changes, and misconfiguration — regardless of which AI builder produced the project.