Bubble to Next.js Migration: How to Move a Live App Without Downtime

A Bubble to Next.js migration is a rebuild with the working app as the specification, run in parallel with the live app, finished with a short read-only window instead of downtime. That is the whole method. The rest of this post is the seven steps, with what went right and wrong when I did it on a live clinic scheduling product.

Can you export a Bubble app? What actually transfers

You cannot export a Bubble app as code. What transfers is the data (export per data type), the uploaded files, and the knowledge of how the app behaves, which is worth more than people expect. Discovery on a normal software project is weeks of workshops. On a migration, the app already answers every "what should happen when" question; you click through it and write down the answer.

Three ways to migrate a Bubble app to code

Approach How it works Choose it when
Backend first Keep the Bubble front end, move the data and logic to a coded backend the Bubble app calls through its API connector The screens are fine and the pain is rules, integrations or cost
Full rebuild in parallel Build the whole new app beside the live one, move the data, cut over once The screens and the logic both need to change, or isolation and ownership are the goal
Phased Move one feature area at a time, with users on both apps for a period Large apps where a single cutover is too risky

Clinical Stack was a full rebuild in parallel. The rules engine, the messaging and per-practice isolation all needed the new foundation, so a half-move would have meant maintaining two systems for longer than the rebuild itself took.

Step 1: inventory the app

List every data type with its fields, every option set, every workflow that changes data, every scheduled or recurring workflow, every API connector call, every plugin, and every place a privacy rule applies. Then mark each item: keep, change, or drop. Most apps carry fields and workflows nobody has used in a year; a migration is the one chance to leave them behind.

Also export a sample of real records from each type now. You will need them in steps 4 and 5.

Step 2: design the schema (Bubble to Supabase)

Bubble stores data in a way that is convenient for a visual builder: lists inside records, references by unique ID, option sets as text. A relational database wants the opposite. The schema work is where the migration is won:

  • Every list field in Bubble becomes a join table or a foreign key.
  • Option sets become enums or small lookup tables.
  • Bubble's unique IDs are kept as a legacy_id column on every migrated table, so any record can be traced back during testing.
  • Decide who may read and write each table, then enforce it with row-level security so a practice, a company or a team can only ever reach its own rows.

On Clinical Stack this came to roughly 30 tables and 49 migrations, with row-level security per practice (/work/clinical-stack). Those migrations are versioned files in the repository, which is the first thing a buyer or auditor asks to see.

Step 3: build in parallel, demo weekly

The new app is built on its own domain while the Bubble app keeps serving customers. Every week the client sees a staging link with the parity list ticked off. The parity list is the inventory from step 1 rewritten as "a user can..." statements. It is also the acceptance criteria for the fixed-price milestones, so there is no argument later about what "done" means.

Rules move into code with tests. If the Bubble app said a staff member cannot exceed their weekly hours, there is now a test that tries to exceed them and expects a refusal.

Step 4: rehearse the data move

Write the import once, run it many times. Each rehearsal exports fresh data from Bubble, maps unique IDs to new keys through the legacy_id columns, converts option-set text to enums, re-links uploaded files, and reports counts per table against the source. When two rehearsals in a row produce the same counts and no mapping errors, the import is ready. The final run is the same script with the clock set to cutover day.

Step 5: test for parity on real records

Testing on sample data is how migrations ship with surprises. Take ten real customers, or practices, or accounts, and walk their actual records through the new app: log in as them, open their last month, run their reports, trigger their notifications to a test number. Compare against the Bubble app side by side. Fix, then repeat with ten more.

Step 6: cut over without downtime

The cutover is a sequence, announced in advance:

  1. Put the Bubble app into a short read-only state (a banner and disabled write workflows) at a quiet hour.
  2. Run the final data move; it has been rehearsed, so it is minutes to an hour.
  3. Point the domain at the new app.
  4. Log in as two or three real accounts and run the smoke checks from step 5.
  5. Lift the banner.

Users saw a read-only notice for a short window and then a new app with their data in it. Logins were re-created through the new auth system with a reset link, which is the one part users must be told about in advance.

Step 7: the month after

Keep the Bubble app running read-only for a month so anything missed can be looked up. Watch error logs and the support inbox daily for the first week. Move the integrations that could not run in parallel (payment webhooks, messaging numbers) on cutover day and confirm each with a live transaction. Then, and only then, cancel the Bubble plan.

How long does a Bubble migration take, and what does it cost

Three things set both: the number of data types and the mess inside them, the number of workflows that encode rules, and the integrations that must not drop a message. A small app with a few types and no billing is weeks. A product with billing, messaging, several user roles and multi-tenant isolation is months. I will not put a number on yours without the step 1 inventory, but I will give you a fixed price per milestone once we have it, with the parity list as the acceptance criteria.

If you run a Bubble agency and need migration capacity under your own brand, that is covered at /for/bubble-agencies. If you are not sure the migration is needed at all, read the signs in post 03 first.

Want a migration estimate?

Send me view access to the app or a short description of its data types, workflows and integrations. I will reply with the approach I would take, the risks I see, and a milestone outline. Use the form at /contact, or read more at /services/bubble-to-nextjs-migration.

Questions people ask

Can a Bubble app be migrated to Next.js without downtime?

Yes. Build the new app in parallel, rehearse the data move until the counts match, then cut over inside a short read-only window at a quiet hour. Users see a notice, not an outage.

Do I have to migrate everything at once?

No. Backend-first and phased approaches keep the Bubble front end or move one feature area at a time. A full rebuild in parallel is the cleanest when both the screens and the logic need to change.

What happens to my data?

It exports from Bubble, is mapped through a legacy ID column to the new schema, and is imported in rehearsed runs. Counts are reconciled per table on every run.

Can users keep their logins?

Accounts are re-created in the new authentication system and users set a new password through a reset link. Tell them before cutover day.

How long does a Bubble to Next.js migration take?

Weeks for a small app, months for a product with billing, messaging and several roles. The inventory in step 1 is what makes an honest estimate possible.

What about plugins?

Each plugin maps to a library, an API call or custom code in the new app. List them in the inventory; a plugin that no longer has an equivalent is a scope decision, not a blocker.

Have a project like this in mind?

Tell me what you're building