Inventory what the browser currently owns

MDN documents localStorage as origin-partitioned browser storage that persists after the browser closes. That means two users, browsers, devices, or origins may hold different records. Before exporting anything, answer:

  • Which origin and application version created the records?
  • Which record types, keys, and relationships exist?
  • Are identifiers stable or generated only in the browser?
  • Which defaults or derived values are not stored?
  • Can multiple tabs or users create duplicates?
  • Which browser copy is authoritative, and who may decide that?

Freeze writes while taking the control export, or record exactly how changes during the migration will be reconciled. A successful export from one browser does not prove every expected record was captured.

Define the target and rollback boundary

Name the target database, environment, owner, import procedure, and account used for the exercise. Define what “durable” means for this application: backups, restore ownership, access control, retention, and operational support matter alongside the storage engine.

Write the rollback boundary before importing. It should answer:

  • Can the target be cleaned without affecting another application?
  • Will the old browser data remain read-only during acceptance?
  • Who decides whether to retry, repair, or abandon the import?
  • When may old local copies be removed?

Do not use a destructive database command copied from a generic guide. For example, PostgreSQL's current pg_restore documentation covers archives created by pg_dump, warns that restore executes source SQL, and offers --single-transaction for all-or-nothing behavior. Those details apply only when that archive and procedure are actually selected.

Freeze records, transforms, and rejection rules

Create a small migration specification before running the import:

Source item Target item Transform Reject when
Record identifier Primary key Preserve or map once Missing or duplicate
Required text Required column Trim only if approved Empty after transform
Status Constrained value Map from frozen table Unknown value
Timestamp Timestamp with zone Parse with named assumption Ambiguous or invalid

Count each source record type and retain safe sample identifiers or checksums. Decide whether invalid and duplicate records stop the whole import or enter a review queue. Never silently discard them.

Import into an isolated target

Use the selected provider's current first-party procedure and retain the command, migration identifier, or provider receipt without credentials. Give the migration account only the permissions the procedure needs.

Lovable's current Supabase integration documentation describes connecting a customer-owned Supabase project and explicitly says there is no automatic migration between Lovable's built-in backend and a customer Supabase project. If that is your path, freeze the manual schema and data movement instead of assuming the connection moves existing records.

Capture both success and failure evidence. An import completion message shows that a tool finished; it does not establish record completeness, meaning, authorization, or application behavior.

Verify data and the critical workflow

Compare the target count with the accepted source count plus documented rejections. Then inspect samples chosen before the import, including edge cases such as the oldest record, newest record, missing optional value, and duplicate candidate.

Start a clean browser profile with local storage empty. Verify that:

  1. the expected records load from the target;
  2. a least-privileged test user sees only the intended scope;
  3. creating or editing one synthetic record writes to the target;
  4. refreshing or opening another clean session shows the change;
  5. the browser does not silently fall back to old local data; and
  6. a controlled dependency failure does not report false success.

Retain the observed result and evidence location for each check.

Accept, repair, or roll back

The data owner—not the migration script—decides whether the result is acceptable. Keep the old local data until that decision and the rollback window are explicit.

If verification fails, stop new writes, preserve the evidence, classify the gap as export, transform, import, authorization, or application behavior, and follow the prewritten cleanup path. Do not repeatedly import into an unknown partial state.

Evidence boundary for this draft

The accompanying dependency-free fixture ran five tests on August 4, 2026. It preserved control totals, applied one frozen title transform, rejected invalid and duplicate records, forced a clean-session reader to use only the target, and left the target unchanged after an interrupted migration.

That fixture used two synthetic records and no browser, provider account, cloud database, or approved dataset. This review version reports only those local results; a completed provider worksheet and data-owner decision are required before claiming that a real migration worked.

Migration worksheet

Verification Expected Observed Evidence
Target control count
Samples preserve meaning
Invalid and duplicate handling
Clean session uses target
Critical read/write workflow
Failure and cleanup path

Record the old-data retention decision, rollback owner, and acceptance date beside this table.

Frequently asked questions

Can I just copy the localStorage JSON into a table?

Only after inventorying identifiers, types, relationships, invalid values, and authorization. A JSON import can complete while changing the meaning of data.

When should the browser copy be deleted?

After the data owner accepts target totals, samples, and clean-session behavior, and after the agreed rollback window. Until then, keep it protected from accidental writes.

Does a managed database make the application durable?

Not by itself. Durability also depends on owners, access, backups, restore testing, migrations, monitoring, and how the application handles failure.