Same auth (Supabase) — users stay
Same UI (shadcn/ui + Tailwind)
Same framework (Next.js App Router)
Zero forced sign-outs

Why migrate?

Lovable is excellent at getting you to a working prototype fast. The moment you need to add billing that doesn't break on edge cases, isolate data between customers, or hand a codebase to a team without months of archaeology — you need a proper foundation.

Already is that foundation. It's not a different stack. It's the same Supabase + Next.js setup Lovable uses, with everything your production app actually needs already wired together.

What carries over without changes

  • Your users and sessions. Lovable uses Supabase Auth. Already uses Supabase Auth. Point Already at your existing Supabase project and your users are never touched.
  • Your UI components. Both use shadcn/ui and Tailwind CSS. Copy-paste your buttons, forms, and layouts directly into Already's component directory.
  • Your database schema. Your Supabase tables stay exactly where they are. You'll add Drizzle schema files that mirror them, but the data doesn't move.

What needs migration work

  • Routing. Lovable uses Next.js App Router but tends to use a flat app/ structure. Remap to Already's (app) / (auth) / (public) route groups.
  • Data fetching. Lovable generates useEffect-based data fetching in client components. Already uses Server Components. See the before/after below.
  • Env vars. Lovable uses VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY. Already uses NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY.
  • Auth calls. Lovable calls supabase.auth.getUser() in components. Already centralizes this with await requireAuth() in layout.tsx.
  • Lovable-specific packages. Remove lovable-tagger and any @lovable-dev/* packages from package.json — these are editor tooling, not application code.

Env var mapping

Rename these in your .env.local — the values stay the same, only the key names change:

# Lovable (remove these)
VITE_SUPABASE_URL=https://xxxx.supabase.co
VITE_SUPABASE_ANON_KEY=eyJhbGci...

# Already (add these)
NEXT_PUBLIC_SUPABASE_URL=https://xxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGci...

Data fetching pattern: before / after

Lovable generates client components with useEffect for data fetching. In Already, prefer Server Components — the data arrives at render time with no loading state, no client bundle weight.

// Lovable pattern — client component with useEffect
'use client'
export default function ProjectList() {
  const [projects, setProjects] = useState([])
  useEffect(() => {
    supabase.from('projects').select('*').then(({ data }) => setProjects(data))
  }, [])
  return <ul>{projects.map(p => <li key={p.id}>{p.name}</li>)}</ul>
}

// Already pattern — Server Component, no useEffect needed
import { db } from '@/lib/db'
import { projects } from '@/db/schema'
import { withOrgScope } from '@/lib/org'

export default async function ProjectList() {
  const rows = await withOrgScope(db.select().from(projects))
  return <ul>{rows.map(p => <li key={p.id}>{p.name}</li>)}</ul>
}

Auth pattern: before / after

// Lovable pattern — getUser() called per component
'use client'
export default function Dashboard() {
  const [user, setUser] = useState(null)
  useEffect(() => {
    supabase.auth.getUser().then(({ data }) => setUser(data.user))
  }, [])
  if (!user) return <Redirect to="/login" />
  return <div>Hello {user.email}</div>
}

// Already pattern — requireAuth() in layout, user passed as prop
// app/(app)/layout.tsx
import { requireAuth } from '@/lib/auth'
export default async function AppLayout({ children }) {
  const user = await requireAuth() // redirects to /login if not authed
  return <AppShell user={user}>{children}</AppShell>
}

Step-by-step migration

01
Copy your Supabase project credentials

Go to your Supabase dashboard → Project Settings → API. Copy the project URL and anon key. Add them to Already's .env.local using the NEXT_PUBLIC_ prefix (not VITE_). Already will connect to your existing database and users.

02
Remove Lovable-specific packages

Open your Lovable project's package.json and remove lovable-tagger and any @lovable-dev/* packages. These are Lovable editor tooling — they serve no purpose outside the Lovable environment and will cause confusion in your new codebase.

03
Copy your UI components

Both use shadcn/ui and Tailwind. Copy your components/ directory contents to Already's components/. Your design tokens and variants paste across without modification.

# From your Lovable project root:
cp -r components/ ../your-already-project/components/
04
Recreate your routes in Already's group structure

Map your Lovable routes to Already's route groups:

Lovable: app/dashboard/page.tsx
Already: app/(app)/dashboard/page.tsx

Lovable: app/projects/page.tsx
Already: app/(app)/projects/page.tsx

Lovable: app/login/page.tsx
Already: app/(auth)/login/page.tsx  (usually already done)

Lovable: app/page.tsx  (marketing)
Already: app/(public)/page.tsx
05
Convert useEffect data fetching to Server Components

Search your Lovable codebase for useEffect calls that fetch from Supabase. Replace each with a Server Component using Already's Drizzle helpers. The before/after pattern above applies universally. Components that handle user events (clicks, form input) stay as client components with "use client" — only the data-fetching shell moves to the server.

06
Add Drizzle schema for your tables

Already uses Drizzle ORM. Add schema definitions in db/schema/ that mirror your existing Supabase tables. Run pnpm db:push to sync — no data migration, just schema declaration.

07
Wire up billing

Already's billing is pre-built. Add your Stripe keys, run pnpm setup:stripe to create products, then wrap any paid route with await requirePlan('pro'). That's it.

08
already migrate lovable

The included CLI command automates 70% of this process — env var mapping, route inventory, schema introspection, and a structured TODO report for what needs manual review.

already migrate lovable --source ../my-lovable-app

Common questions

Will my users get logged out?

No. Already connects to your existing Supabase project. Sessions, tokens, and RLS policies are unchanged. Your users will never know anything happened on the backend.

My Lovable app has a src/integrations/supabase/ folder — what do I do?

That folder contains Lovable's auto-generated Supabase client initialization. Copy the credentials out of it (project URL and anon key), but do not copy the client setup code itself. Already's Supabase client lives in lib/supabase/ and is pre-configured for SSR with cookie-based session handling. Using Lovable's client in an SSR context will break auth on server renders.

What if my Lovable app uses Supabase Storage?

Already includes a file upload helper wrapping Supabase Storage. Your existing buckets and files stay intact — just update the upload calls to use Already's lib/storage helper.

How long does a migration take?

A simple Lovable app (5–10 routes, basic auth) typically migrates in 2–4 hours. A more complex app (custom RLS policies, multiple orgs, payment flows) takes a day. The CLI command cuts that in half.