Leaving Lovable
Lovable to Next.js: Auth, RLS, and Cutover Guide
Engineering guide to a Lovable-to-Next.js migration: Supabase SSR sessions, RLS-safe data access, route parity, SEO continuity, and cutover risks.

Engineering guide for older React and Vite exports: This article covers Supabase SSR sessions, RLS-safe data access, SEO continuity, and production cutover when a legacy Lovable app genuinely needs a Next.js port. New Lovable projects use TanStack Start with SSR, and Lovable hosting prerenders older apps for verified crawlers. Inspect the actual exported framework and served HTML before deciding to migrate. For a route-by-route procedure, use the conversion playbook; for copy-paste agent instructions, use the Cursor conversion prompts.
Migrating a Lovable app to Next.js is a six-phase engineering project, not a button click. If you are a founder or PM who has hit Lovable's ceiling and is wondering whether the effort is worth it, this post explains what changes, which boundaries are risky, and where the work tends to grow. The phases below are a planning framework, not a record of one verified migration.
Older Lovable exports are React single-page applications built on Vite and React Router. Lovable says new projects created since May 13, 2026 use TanStack Start, with SSR and server functions; they are outside this guide's direct-port scope. For an older export, Next.js changes routing, data fetching, authentication patterns, and environment variable conventions. This guide walks through those engineering decisions, especially where auth, data boundaries, and cutover can regress.
Six-phase migration audit
A production Lovable to Next.js migration should pass six checkpoints: inventory the exported app, scaffold the App Router shell, port routes for visual parity, move auth and data boundaries, rebuild the SEO layer, and cut over with redirects and rollback prepared. If any checkpoint is skipped, the project usually fails later as broken sessions, leaked env vars, missing metadata, or split-host indexing.
- Inventory: routes, Supabase calls, env vars, callbacks, webhooks, and SEO URLs.
- Shell: Next.js layout, deployment, lint/test/build, and Supabase SSR clients.
- Route parity: public and protected routes mapped from React Router to App Router.
- Data boundaries: RLS-safe server reads, client writes where appropriate, and server-only secrets.
- SEO layer: metadata, canonicals, sitemap, robots, JSON-LD, and Googlebot fetch checks.
- Cutover: OAuth allowlists, Stripe endpoints, 301s, smoke tests, monitoring, and rollback.
When staying on Lovable is the right call
Before you plan a migration, be honest about whether you actually need one. There are at least three situations where staying on Lovable is the correct engineering decision.
You are still iterating on the product
If your product direction is still changing week to week, migrating to Next.js will slow you down significantly. Lovable lets a non-engineer make product changes without engineering involvement. That speed is worth real money in the early stage. Wait until the core flows are stable before spending engineering capital on infrastructure.
Current rendering meets your search needs
SEO alone no longer makes a Lovable-to-Next.js migration automatic. New TanStack Start projects can server-render, while Lovable hosting prerenders older Vite apps for verified crawlers. A generic third-party fetch may still see the SPA shell. Check the published URL, crawler-visible HTML, metadata, index coverage, and the routes that matter before attributing a search problem to rendering.
Your team has no Next.js experience
A Next.js codebase adds operating work that an older Vite SPA may not require. If the engineer doing the migration has not shipped a production Next.js app before, include a learning and review allowance in the estimate. If nobody on the team has that experience, get an architecture review before committing to a port.
Signals it is time to migrate to Next.js
With that caveat in place, here are the five concrete signals that a migration is genuinely warranted.
SEO is a priority and pages are not indexing
If organic search matters, first inspect the HTML Lovable serves for the affected published routes and check Search Console's page-level indexing evidence. Older Vite exports are client-rendered for human visitors, but Lovable hosting prerenders verified crawler requests. New TanStack Start projects already support SSR. A Next.js port becomes an SEO option when a measured rendering, metadata, URL, or content problem remains and cannot be solved within the current stack; an indexing warning by itself does not establish that cause.
Core Web Vitals and Largest Contentful Paint are failing
Older client-rendered Vite exports can accumulate browser JavaScript as they grow. New TanStack Start projects have a different rendering model, so inspect the actual bundle and LCP trace before blaming Lovable's framework. Next.js offers route splitting and server components, but a framework move is justified only if a measured bottleneck remains after narrower fixes.
You need custom backend logic that Supabase Edge Functions cannot cleanly handle
An older Vite export may put backend logic in separate Supabase Edge Functions. A new TanStack Start project can use integrated server functions, so this is no longer a blanket reason to migrate. Compare the specific webhook, job, auth, or provider boundary you need with what your current project supports. Next.js Route Handlers may fit when those requirements and operational ownership favor a separate Next.js app.
You are hiring engineers who push back on the codebase
This is a team-specific signal. If an older Vite export lacks the review, test, or data boundaries the incoming team needs, estimate the cost of adding them where the app is before planning a port. Do not assume a newer TanStack Start project has the same gaps.
Vendor lock-in is becoming a board-level concern
Lovable is a small company. Its product direction, pricing, and continued operation are outside your control. Most of its output is standard code you can export, but your development workflow, AI-assisted iteration, and deployment pipeline are all tied to the platform. For early-stage companies this tradeoff is fine. For companies with investors, revenue, and a long-term roadmap, owning a standard codebase on a commodity hosting platform is a lower-risk position.
What Lovable gives you (and what it does not)
Before planning the migration, do an honest inventory of what you are keeping, what you are replacing, and what Lovable never gave you in the first place. The table below covers the main areas.
| Area | Older Lovable React/Vite export | Next.js (App Router) | Migration effort |
|---|---|---|---|
| UI components | React + shadcn/ui + Tailwind | Same - copy across | Low |
| Client-side routing | react-router-dom | File-system (App Router) | Medium - manual port |
| Data fetching | Browser reads in some older exports | Server or client reads with a user-scoped client where appropriate | Depends on boundaries |
| Authentication | Supabase Auth (client-side) | Supabase SSR (cookie-based sessions) | Medium |
| Database | Supabase (Postgres) | Same Supabase project | None - you keep it |
| SEO / metadata | SPA for people; verified-crawler prerendering on Lovable hosting | Metadata API, sitemap.ts, structured data | Depends on measured gaps |
| Image optimisation | None built in | next/image with automatic WebP/AVIF | Low - swap tags |
| API routes / backend | Supabase Edge Functions | Route Handlers co-located in /app | Low to medium |
| Payments | Stripe (if added) | Same Stripe integration, webhook handler moves to Route Handler | Low |
| CI/CD | Lovable deploy pipeline | Vercel, Fly.io, or custom GitHub Actions | Medium - new pipeline |
| Team collaboration | Lovable AI editor | Standard git workflow | Process change, not technical |
| Caching / ISR | None | Full - fetch cache, revalidatePath, ISR | Low - additive only |
For an older Vite export, the UI layer often moves more directly than routing, data, and auth. Verify each component and dependency before copying it. See our guide to rescuing a Lovable app for issues to assess before committing to a port.
The migration plan - phase by phase
This is the sequence we use. Do not skip phases or run them in parallel. Each phase de-risks the next.
Phase 0: Inventory
Before writing a single line of Next.js code, document what you are migrating. This sounds obvious but most failed migrations skip it.
- Routes: List every page in your react-router-dom config. Note which are public, which require auth, which are dynamic (e.g.
/project/:id). - API calls: Search your codebase for every
supabase.from(andsupabase.functions.invoke(call. Note the table, the operation (select/insert/update/delete), and whether it runs inside a component or in an event handler. - Environment variables: List every
VITE_prefixed variable. Only values safe for the browser should becomeNEXT_PUBLIC_in Next.js. Move secrets to server-only configuration and rotate any secret already exposed. - Supabase schema: Export your schema DDL from Supabase's SQL editor. You will not migrate the database, but you need to know which tables have RLS enabled and what the policies are, because server components bypass RLS if you use the service-role key carelessly.
- Third-party integrations: Stripe webhooks, email providers, OAuth redirect URIs. Each has a config change when your domain structure changes.
The output of Phase 0 is a spreadsheet or doc you will check off as you work through Phases 1-5. Without it you will miss routes and ship a broken redirect on launch day.
Phase 1: Scaffold Next.js with App Router and Supabase SSR
Create the Next.js project alongside your existing repo (not replacing it). Keep the Lovable app running in production throughout the migration.
bun create next-app my-app --typescript --tailwind --app
cd my-app
bun add @supabase/supabase-js @supabase/ssr
The critical setup is a user-scoped Supabase SSR client for server requests and a browser client for interactions. Follow Supabase's current Next.js SSR guide for cookie handling and session refresh. In Next.js 16, its refresh entry point is proxy.ts. Protect pages and user data with verified claims (getClaims()), not the user object returned by getSession() from an unverified cookie. Prove signed-in, signed-out, expired-session, and refresh behavior on a deployed preview before porting protected routes.
Install shadcn/ui into the new project using its CLI. Your existing component code will be compatible, but shadcn components are not copy-paste portable as files - reinstall them fresh so the config and dependencies are correct for your Next.js version.
Phase 2: Port the UI route by route
Work through your Phase 0 route inventory one route at a time. Create the corresponding app/ directory structure. For a Lovable route like /dashboard you create app/dashboard/page.tsx. For /project/:id you create app/project/[id]/page.tsx.
Copy the JSX from your Lovable components into the new files. At this stage, keep components as client components ('use client') so you do not have to change data fetching patterns yet. The goal of this phase is visual parity, not architectural improvement. You can refactor to server components in Phase 3.
Replace all react-router-dom imports: Link comes from next/link, useNavigate becomes useRouter from next/navigation, and useParams stays useParams but imports from next/navigation instead. The useSearchParams hook requires a Suspense boundary in App Router - wrap any component that uses it.
Phase 3: Convert data fetching to server components
This is the most time-consuming phase and the one most likely to introduce bugs. Take it slowly.
The pattern shift in some older Lovable exports is from a client-side useEffect query to a user-scoped server read where it helps. Before a protected server read, verify identity with the current Supabase SSR pattern and ensure the query still runs under the intended user's RLS policies. An empty result must not stand in for an authorization check. Keep interactive components client-side and test cross-user isolation, expired sessions, and failure states.
Not everything belongs in a server component. Any component that uses browser APIs, React hooks, event handlers, or state must remain a client component. The practical split: fetch data in a server component, pass it as props to client components that handle interactivity.
Move Supabase Edge Functions to Route Handlers where it makes sense. A webhook handler at app/api/stripe/webhook/route.ts replaces an Edge Function and is easier to test locally and deploy.
Phase 4: SEO layer
Next.js gives you the Metadata API, sitemap.ts, robots.ts, and structured data. Rebuild this layer if the inventory found a real SEO or URL gap; Lovable's SSR and crawler prerendering may already cover the rendering requirement.
Add a generateMetadata export to every page that needs unique title and description tags. For dynamic pages, fetch the data inside generateMetadata - Next.js deduplicates the fetch so you are not hitting the database twice.
Add app/sitemap.ts to generate a dynamic XML sitemap from your database. Add app/robots.ts to set crawl rules. If your content warrants structured data (articles, products, FAQs), add JSON-LD as a server-rendered script tag in each page's layout.
For a deeper look at SEO patterns specific to apps that started on Lovable, see our post on SEO for Lovable apps.
Phase 5: Deploy and DNS cutover
Deploy the Next.js app before you cut DNS. Run both apps in parallel against the same Supabase project for a QA period based on your auth, billing, callback, and rollback risks.
Vercel is the path of least resistance for Next.js deployment - zero config, automatic preview deployments, built-in image optimisation, and Edge Network for static assets. If you need more control or are self-hosting, we use Fly.io for containerised Next.js deployments and Cloudflare Workers with Next-on-Pages for edge-rendered apps. Each has tradeoffs: Vercel is fast to ship, Fly.io is more flexible for background jobs and WebSockets, Cloudflare Workers require careful attention to the Node.js API subset available at the edge.
Update OAuth redirect URIs in Supabase (and any third-party providers like Google or GitHub) before switching DNS. Update Stripe webhook endpoints. Run your full test suite against the new domain on a staging environment before the cutover. Set up 301 redirects for any URLs that change structure.
Gotchas the tutorials do not mention
These are the issues that show up in real migrations that are not covered in the official Next.js or Supabase docs.
Supabase RLS behaves differently under SSR
In an older Lovable Vite export, a browser Supabase call may use a browser-stored session. In a Next.js Server Component, the request uses cookies. Verify claims before returning protected data and use a user-scoped client so RLS still applies. A missing or expired cookie can otherwise look like an empty result. Test expired and missing sessions, cross-user access, and refresh behavior before release; follow the current Supabase SSR guidance for Proxy and cookie handling.
If you use the service-role key (for admin operations), RLS is bypassed entirely. This is intentional and sometimes necessary, but if you accidentally use the service-role key in a route that serves user-facing data, you expose data across users. Keep the service-role key strictly server-side and only in contexts where you have validated the user's identity via a separate check.
Hooks that break in server components
React hooks (useState, useEffect, useContext, useRef) are not available in server components. The compiler error is clear, but the fix is not always obvious. Components that use hooks must be marked 'use client'. If a third-party library you are using internally calls hooks without exporting client components, you need to wrap it in a client boundary. Check every component you copy from Lovable for hook usage before assuming it can become a server component.
Environment variable prefix changes
In an older Vite export, VITE_ variables are browser-exposed. Next.js uses NEXT_PUBLIC_ for browser values; unprefixed values belong in server-only code. Inventory import.meta.env.VITE_ references and classify each value before replacing it. If a service-role key, webhook secret, or other secret was exposed through a browser prefix, rotate it and move the integration behind a server boundary.
Image loader configuration
If you reference images from external domains (Supabase Storage, Cloudinary, a CDN), you must whitelist those domains in next.config.ts under images.remotePatterns. Next.js will refuse to optimise images from unlisted domains and will throw a build error. Pull your image domains from your Phase 0 inventory and add them before you start swapping img tags for next/image.
shadcn/ui version drift
If your Lovable app is six months old, the shadcn/ui components inside it may be multiple versions behind the current CLI output. When you reinstall shadcn components fresh into your Next.js project, the generated code may differ from what Lovable generated. The differences are usually minor (import paths, variant names) but if you have customised the component internals in Lovable, those changes will not survive the reinstall. Take a diff of each component before copying any customisations across.
How to estimate the work
Start from the Phase 0 inventory rather than a route-count-to-weeks formula. Size the route and component port, then estimate auth and RLS verification, each integration and callback, SEO URL parity, deployment setup, QA, and a reversible cutover. Separate pre-existing repairs such as RLS gaps or missing tests from the framework move so a decision-maker can see both costs. If the project already uses TanStack Start, treat this legacy Vite procedure as inapplicable and assess the current server functions and routing first.
What AppHandoff adds to the process
AppHandoff is useful when the Lovable interface is moving faster than the production backend or when multiple people need to coordinate the migration. It tracks route expectations, backend contracts, handoff tickets, and drift between the app that Lovable generated and the system engineers need to maintain.
You do not need AppHandoff for a simple landing page. You do need a handoff layer when the app has roles, billing, integrations, admin workflows, or an external backend team. The cost of migration is not just moving files - it is preserving product intent while the framework changes underneath.
Related conversion resources
If you need to execute a direct migration, follow the step-by-step conversion playbook. If you need agent instructions for a specific slice, use the copy-paste Cursor prompts. If your current app is breaking but not ready for a rewrite, start with Rescue Your Lovable App.
Related paths
Questions we get
- What is AppHandoff for Lovable teams?
- AppHandoff is a Lovable MCP server and coordination layer that tracks API contracts, backend readiness, handoff tickets, and drift between a fast-moving Lovable frontend and the team responsible for production systems.
- How does AppHandoff help a Lovable to Next.js migration?
- It preserves the expected routes, data contracts, auth assumptions, and backend work while the UI moves from Lovable-generated React into a Next.js App Router structure. The point is fewer lost requirements and fewer backend surprises.
- Do I need MCP for every Lovable project?
- No. Simple landing pages do not need MCP. Use MCP when AI agents or backend teams need a safe, typed way to inspect, update, or coordinate real product state from the Lovable workflow.