scribase
Migrate from InstantDB

Keep your app, your users, and their ids.

Export the app with its admin token, and Scribase moves every namespace, every user, and every file into Postgres with the same ids, so links keep resolving and users sign in by email code like before.

Four steps in the console: connect the source, review a dry run that writes nothing, run it, and read the verification report. Your place is saved if you close the tab; credentials never are.

What moves

Everything a InstantDB app runs on

Namespaces
Each namespace becomes a table with a uuid primary key and a jsonb data column holding every attribute.
Links
Exported as arrays of linked ids inside data, so data->'owner' joins back to the linked table.
$users
Every user with the same id and email, marked confirmed, ready for email-code and magic-link sign-in.
$files
Every file at the same path in a private files bucket, checked with SHA-256.

What stays the same

  • Entity ids, so every link and every stored reference still resolves
  • User ids, so rows that point at a user still point at the same person
  • Email sign-in: users get a code or a magic link, as on Instant

What you do by hand

  • Instant permission rules are not SQL. Tables start with row level security on and no policies; port each rule to an RLS policy.
  • If you used Instant OAuth, enable the same providers on Scribase. Users are linked by email on their first OAuth sign-in.
  • Realtime queries become Postgres changes over Scribase Realtime; subscribe with the JavaScript client.
How it works

Plan, run, prove

  1. Step 1

    Export with the admin token

    The scribase package calls the same admin query endpoint the Instant admin SDK uses, flattens links to id arrays, and downloads every $files object.

    import { writeInstantExport } from 'scribase/importers';
    
    await writeInstantExport({
      appId: process.env.INSTANT_APP_ID!,
      adminToken: process.env.INSTANT_ADMIN_TOKEN!,
      namespaces: ['todos', 'projects'],
      links: { todos: ['owner'], projects: ['members'] },
      directory: './instant-my-app',
    });
  2. Step 2

    Plan, then run

    Upload instant-export.json in the console wizard, or place the folder in the server exports directory to include files.

    await scribase.imports.createFrom({
      source: 'instantdb',
      sourceInstantAppId: process.env.INSTANT_APP_ID!,
      sourceExportDir: 'instant-my-app',
      destination: { organizationId: 'acme', projectId: 'app', environmentId: 'production' },
    });
  3. Step 3

    Read the report

    Every namespace compared by row count and checksum, plus user and file counts. The verdict is fail-closed.

The verification report

Old versus new, table by table

Every import ends with this. The verdict is VERIFIED only when every row count and checksum matches, every policy is present, and the sign-in proof passes. The numbers below are an example of the format.

TableInstantDB rowsScribase rowsChecksum
public.profiles12,40812,408 match
public.orders88,21488,214 match
public.order_items240,977240,977 match
Also checked: RLS policy parity, auth user count, storage object count, and a sign-in with an account you control. Verdict: VERIFIED
Hosted migration

Want us to host it? Join the InstantDB waitlist.

The importer runs today on any Scribase you operate. Hosted Scribase opens by source, in waitlist order. Tell us your size and we will reach out when your slot opens.

FAQ

Migrating from InstantDB

Do users need new accounts?

No. Each user keeps the same id and email and signs in with an email code or magic link. Instant never stored passwords, so there is nothing to reset.

Is the data still queryable like InstaQL?

It is Postgres: query with SQL or the JavaScript client, and subscribe to changes with Scribase Realtime. Links become id arrays you can join on, and you can normalize hot paths into real columns with ordinary migrations.