Fix.

Migrate a Lovable app from Vite to Next.js and Supabase

How to extract a Lovable web app from client-side Vite into Next.js App Router, migrate Supabase auth to server cookies, and deploy standalone.

8 min read

AI app builders like Lovable get prototypes running remarkably fast. Within a few hours of natural language prompting, you have an interactive interface with styled tables, working login forms, and mock workflows.

The friction begins when real paying users arrive. Lovable code exports as a client-side Single Page Application (SPA) powered by Vite and react-router-dom. When you need server-side rendering for search engine discovery, cryptographic webhook validation for Stripe, or secure cookie-based session management, a client-only bundle hits a wall.

Migrating your prototype from client-side Vite to Next.js App Router with an independent Supabase project gives you complete code ownership, zero vendor lock-in, and an architecture ready for production traffic.

Here is the technical migration sequence our studio uses to decouple Lovable prototypes into maintainable standalone repositories.

Step 1: Export the codebase and database backup

Before modifying any source files, separate your code from the managed cloud instance:

  1. GitHub synchronization: Inside Lovable, connect your GitHub account and synchronize the project to a private repository. Clone this repository locally.
  2. Export the database: In the Lovable dashboard, open your project stack settings, navigate to Lovable Cloud, and initiate a database export. You will receive a PostgreSQL custom-format archive (.backup file) containing your table schemas, triggers, Row-Level Security policies, and user auth records.
  3. Provision an independent Supabase project: Create a new project in your own Supabase account. Restore the .backup file using pg_restore via the Supabase CLI:
supabase db restore --db-url "postgresql://postgres:[YOUR-PASSWORD]@[YOUR-HOST]:5432/postgres" < export.backup

Restoring the full dump preserves hashed user passwords, ensuring existing customers do not experience broken login sessions.

Step 2: Transition from Vite to Next.js App Router

Lovable exports rely on client-side routing packages like react-router-dom. In Next.js App Router, routing is determined by the filesystem structure under app/:

  1. Initialize the Next.js shell: Create a Next.js project with TypeScript and Tailwind CSS (npx create-next-app@latest). Copy over your custom components from src/components/ and utility functions from src/lib/.
  2. Restructure client views: Replace <Routes> and <Route path="/dashboard" element={<Dashboard />} /> declarations with page files:
    • src/pages/Index.tsx becomes app/page.tsx
    • src/pages/Dashboard.tsx becomes app/dashboard/page.tsx
    • src/pages/Auth.tsx becomes app/(auth)/login/page.tsx
  3. Replace client links: Change all import { Link } from "react-router-dom" references to import Link from "next/link".
  4. Environment variables: Update variable prefixes. Vite uses import.meta.env.VITE_*, which exposes values to the browser. In Next.js, rename public keys to NEXT_PUBLIC_* and keep sensitive backend keys strictly server-side:
# Public keys (browser accessible)
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key

# Private secrets (server route handlers only)
SUPABASE_SERVICE_ROLE_KEY=your-secret-service-role-key
STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...

Step 3: Replace client-only auth with server cookies

Lovable prototypes typically initialize Supabase in the browser using @supabase/supabase-js and store JWT session tokens in browser localStorage.

localStorage has two critical vulnerabilities in production:

  • It is readable by any client-side JavaScript, leaving sessions exposed to cross-site scripting (XSS).
  • It cannot be read by Next.js Server Components, middleware, or edge functions before page rendering, causing layout shifts and auth redirects.

Migrate to @supabase/ssr, which manages authentication through HttpOnly server cookies:

// lib/supabase/server.ts
import { createServerClient } from '@supabase/ssr';
import { cookies } from 'next/headers';

export async function createClient() {
  const cookieStore = await cookies();

  return createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        getAll() {
          return cookieStore.getAll();
        },
        setAll(cookiesToSet) {
          try {
            cookiesToSet.forEach(({ name, value, options }) =>
              cookieStore.set(name, value, options)
            );
          } catch {
            // Handled in middleware for Server Components
          }
        },
      },
    }
  );
}

With cookie-based auth in place, you can enforce route protection directly in middleware.ts, preventing unauthenticated visitors from downloading dashboard assets.

Step 4: Secure payment webhooks and API routes

In Lovable apps, payment flows frequently rely on redirect parameters (e.g. checking ?success=true in the URL) to grant credits or upgraded user roles. A visitor who inspects the frontend code can navigate directly to the success URL and bypass billing.

Move all subscription mutations into a Next.js API route handler that verifies cryptographic signatures directly with Stripe:

// app/api/webhooks/stripe/route.ts
import { headers } from 'next/headers';
import { NextResponse } from 'next/server';
import Stripe from 'stripe';
import { createClient } from '@supabase/supabase-js';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
const supabaseAdmin = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL!,
  process.env.SUPABASE_SERVICE_ROLE_KEY!
);

export async function POST(req: Request) {
  const body = await req.text();
  const signature = (await headers()).get('stripe-signature');

  let event: Stripe.Event;
  try {
    event = stripe.webhooks.constructEvent(
      body,
      signature!,
      process.env.STRIPE_WEBHOOK_SECRET!
    );
  } catch (err) {
    return NextResponse.json({ error: 'Webhook signature verification failed' }, { status: 400 });
  }

  if (event.type === 'checkout.session.completed') {
    const session = event.data.object as Stripe.Checkout.Session;
    const userId = session.metadata?.userId;

    // Mutate subscription records using server credentials only
    await supabaseAdmin
      .from('profiles')
      .update({ subscription_tier: 'pro', updated_at: new Date().toISOString() })
      .eq('id', userId);
  }

  return NextResponse.json({ received: true });
}

Notice that SUPABASE_SERVICE_ROLE_KEY is loaded only inside this server-side route handler. It never ships to the browser bundle.

Step 5: Preparing for native mobile packaging

Once your web application runs on a clean Next.js architecture with dedicated database tables and server-side authentication, converting it to a native mobile app becomes straightforward.

Using Capacitor, you can wrap your production web views into native iOS and Android packages that share the same backend, database, and auth cookies. Because the underlying code is clean and modular, passing Apple App Store review (and satisfying Guideline 4.2 Minimum Functionality) is predictable. Our studio successfully used this exact path to ship SlabMath: Predict & Profit to the iOS App Store.

Summary

Migrating from a visual AI builder to a standalone codebase requires five clear steps:

  1. Export your source code and extract your PostgreSQL database dump.
  2. Port client-side react-router views into Next.js App Router.
  3. Replace browser localStorage auth with @supabase/ssr server cookies.
  4. Move sensitive mutations and Stripe webhooks into verified backend route handlers.
  5. Deploy to independent infrastructure you control.

If your prototype has paying customers and you want an experienced engineer to handle the migration, explore our vibe coded to standalone migration service or request our free production diagnosis for written findings on your live app within 48 hours.

About the author

Adeola Ilori founded Adeola Forge and leads its engineering work. The studio builds and fixes web apps, AI-built apps and automations.

More guides on fix

Have a project in mind?
Let's build it.

Whether you are building a new SaaS platform from scratch, launching a mobile product, designing a high-conversion interface, or need an urgent rescue for an AI-built app, we are ready to help. You will receive a clear scoped plan and milestone timeline within 1 to 2 business days.

100% code ownershipDirect founder accessFixed milestones
WhatsApp us