June 28, 2026 · 9 min read
The Ejection Trap: Surviving the Export from Lovable to Local
Hit Export Project and discover broken env vars, monolithic files, missing pieces, and a build that won't build. Here's the survival path.
By Launched team
You outgrew the platform. You hit Export Project. A zip lands on your desktop. You unzip it, run npm install, run npm run dev, and the screen goes white. Console error: SUPABASE_URL is undefined. You add it to a .env file. New error: a route imports a file that isn't in the export. You fix that. New error: the auth callback redirects to a preview URL that no longer exists. By midnight you're wondering if you should just go back.
The export is not the running app
What runs in the cloud preview is the export plus a stack of platform magic: env injection, route patching, callback rewriting, runtime polyfills. The zip you downloaded is the export. The magic stayed behind.
The failure modes, in order of appearance
- Missing env vars: the platform injected them; your
.envdoesn't exist yet. - Hardcoded project IDs and URLs: scattered across files, pointing at preview infrastructure.
- OAuth callbacks pointing at the old preview domain: sign-in works once, never again.
- Monolithic route or component files: 2,000-line files that no human (or AI) wants to touch.
- Missing exports / dangling imports: the route tree references files the zip didn't include.
- Lockfile drift: the preview ran a patched version of a Vite plugin; you don't have it.
The survival path
Step 1: Get it to boot, ugly
Don't refactor yet. Stub the missing env vars with placeholders, comment out the broken imports, get npm run dev to render something. You need a baseline.
Step 2: Stand up your own Supabase project
Don't try to reuse the platform's. Create a new Supabase project, port the schema (a clean migration is easier than reverse-engineering), repoint the env vars, rewrite the OAuth callback URLs.
Step 3: Port feature-by-feature, not file-by-file
The exported file structure is optimized for the platform's runtime, not for human maintenance. Take the business logic, leave the platform glue, rewrite the wiring on a normal React meta-framework (Next.js or TanStack Start).
Step 4: Wire integrations one at a time
Stripe webhook URLs, Resend domains, OAuth providers, storage CORS. Make a checklist. Cross each one off only after a real end-to-end test.
Step 5: Cut over behind a feature flag
Run both deployments in parallel. Diff behavior. Flip the DNS only when nothing is on fire.
Where Launched comes in
We do this migration weekly. Flat fee. Days, not weeks. You keep the code and you keep the database. Book a 20-minute call. Related: Escape vendor lock-in, Own your build.
