SSG & SSR on Lovable
What works, what doesn't, and the gotchas you'll hit when building statically-rendered apps in Lovable.
Visit /about pageRendering modes
CSR (default)
Client-side rendering
The Lovable default. Ships an empty HTML shell, hydrates in the browser.
SSG
Static Site Generation
Routes are pre-rendered at build time into static HTML. Best SEO, fastest TTFB.
SSR
Server-Side Rendering
Renders HTML on every request. Requires a Node server runtime.
Lovable limitations
Lovable's preview & hosting infrastructure serves static assets only. Here's what that means in practice.
No Node.js runtime in production
Lovable hosting serves static files only — there's no server process to handle SSR requests at runtime.
No request-time data fetching
Loaders run at build time only. Per-user or per-request HTML cannot be generated server-side.
No server actions
Form actions and mutations must run client-side or via Lovable Cloud edge functions.
Routes must be enumerable at build
Dynamic routes need an explicit prerender list. You can't lazily generate /post/:slug for unknown slugs.
No middleware on the edge
Auth gates, redirects, and rewrites must happen client-side after hydration.
Environment variables are baked in
All env vars are inlined at build time. Rotating a secret requires a fresh build & deploy.
What works in SSG mode
Fully pre-rendered HTML
Every listed route ships as static HTML — great for SEO and crawlers.
Client-side routing & state
After hydration, the app behaves like a standard SPA with React Router.
Lovable Cloud integrations
Database, auth, storage, and edge functions all work — called from the client.
Build-time data loaders
Fetch from CMSs or APIs during build to embed content in the static output.
Gotchas we hit
Hydration flash with browser extensions
<body> before React hydrates, causing a brief flash of unstyled content. Fix: add suppressHydrationWarning to <body>.lovable-tagger expects a src/ folder
app/ (React Router 7 convention) crash the dev server if componentTagger is enabled. Remove it from vite.config.ts.Preview server needs SPA fallback for nested routes
/about → /about/index.html. Add middleware or pre-render every route.Every route must be in prerender
react-router.config.ts means it won't exist as static HTML in production.Deploy SSG output to Cloudflare Pages
Lovable hosting can't serve nested static routes like /about. We bypass that by building, copying build/client into dist, and pushing dist straight to Cloudflare Pages — which serves every index.html natively.
One-time setup
Install Wrangler and authenticate with Cloudflare.
npm install -D wrangler
npx wrangler login
npx wrangler pages project create my-app --production-branch mainBuild, copy & deploy
Run after every change you want pushed live. Pulls latest from Lovable, pre-renders all routes, copies them into dist, and uploads.
# 1. Pull latest changes from Lovable (via GitHub sync)
git pull origin main
# 2. Build the static site (outputs to build/client)
npm run build
# 3. Copy build/client → dist (our deployable folder)
node scripts/copy-build.js
# or manually: rm -rf dist && cp -r build/client dist
# 4. Deploy dist to Cloudflare Pages
npx wrangler pages deploy dist --project-name=my-appOptional: one-line npm script
Add to package.json so a single command rebuilds, copies, and deploys.
"scripts": {
"deploy": "npm run build && node scripts/copy-build.js && wrangler pages deploy dist --project-name=my-app"
}Then just run npm run deploy after each Lovable edit. Cloudflare's CDN serves /, /about, and any future pre-rendered routes with proper static HTML — no SPA fallback hacks needed.