Guides / Brain

Choosing a database engine

The built-in local engine, Supabase and your own Postgres, and when to switch.

The brain stores everything in a Postgres database with the pgvector extension. You can run that database three ways: the built-in local engine (PGLite), a hosted Supabase project, or your own Postgres server. This guide compares them, shows how to set up each one, how to move an existing brain between them, and how to recover when the local engine will not open.

Start on the local engine unless you already know you need a server. Switch when your brain grows large, when several processes need the database at once, or when nexusbrain doctor keeps reporting repairs.

Time
15 minutes, plus copy time when migrating a large brain
For
Anyone deciding where their brain's data lives, or recovering a local brain that fails to open

Before you start

  • The nexusbrain command works in your terminal.
  • For Supabase: a Supabase project and its Transaction pooler connection string.
  • For your own Postgres: a connection string for a database where the vector extension is available.

01Compare the three engines

All three run the same schema, so every brain feature works on each. The differences are where the data lives and how many processes can use it at once.

  • Running init in a folder with 1000 or more .md files prints a suggestion to use Supabase for faster search at that size.
  • If auto-repair has run twice or more in a week, nexusbrain doctor says the corruption keeps regenerating and suggests switching engines. That is the signal to move off the local engine rather than repair again.
  • The one process limit applies to the local engine only. On the local engine, stop nexusbrain serve before running other commands. See Running serve and sync together.
Local (PGLite)SupabaseYour own Postgres
Set up withnexusbrain init --pglitenexusbrain init --supabasenexusbrain init --url <connection string>
Where data livesA folder on this machine, ~/.nexusbrain/brain.pglite by defaultA hosted Postgres databaseAny Postgres server you run, with pgvector
Server neededNoNo, Supabase runs itYes
Processes at onceOne. A running nexusbrain serve blocks other commands.ManyMany
Database reachable from other machinesNo. Other machines can still use it through nexusbrain serve --http.YesYes
Good forGetting started, one person, brains under about 1000 .md filesLarge brains, remote access, always-on agentsTeams that already run Postgres
Recovery toolspglite-repair, reinit-pgliteYour provider's backupsYour own backups

02Set up the local engine

  1. Create a local brain.

    Add --path <DIR> to keep the database somewhere other than ~/.nexusbrain/brain.pglite.

    nexusbrain init --pglite

    You should seeSetting up local brain with PGLite (no server needed)..., then Brain ready at with the path and Engine: PGLite (local Postgres).

  2. Check its health.

    nexusbrain doctor

    You should seeOverall health score: N/100. with All checks passed. or All checks OK (some warnings).

03Set up Supabase or your own Postgres

The brain connects straight to Postgres using a connection string that starts with postgresql://. It does not use the Supabase project URL or anon key.

For Supabase, use the Transaction pooler string on port 6543. Find it in the Supabase dashboard under Connect in the top bar, then Connection String, then Transaction pooler. The direct connection on port 5432 only works over IPv6, which many networks cannot reach.

  1. Start the Supabase wizard.

    It asks for the connection string. To skip the prompt, use nexusbrain init --non-interactive --url "<connection string>", or set NEXUS_BRAIN_DATABASE_URL and pass --non-interactive. The same --url form works for your own Postgres server.

    nexusbrain init --supabase

    You should seeA Connection URL: prompt. After you paste the string: Connecting to database..., Running schema migration..., Config saved to ~/.nexusbrain/config.json, and Brain ready. 0 pages. Engine: Postgres (Supabase).

  2. Confirm pgvector is enabled.

    Init creates the extension if it is missing. If it cannot, it prints Could not auto-create pgvector extension. Run CREATE EXTENSION vector; in your database's SQL editor, then run init again.

    nexusbrain doctor

    You should seeThe connection and pgvector checks pass.

Environment variableWhat it does
NEXUS_BRAIN_DATABASE_URLThe connection string to use with --non-interactive.
NEXUS_BRAIN_DIRECT_DATABASE_URLWith a pooler string, the brain works out a direct connection for schema changes. This overrides that address. On an IPv4 only network, set it to the Supabase Session pooler string.
NEXUS_BRAIN_DISABLE_DIRECT_POOL=1Turn the separate direct connection off completely.
Warning

nexusbrain init --supabase points your config at a new, empty database. It does not copy an existing local brain. To bring your pages with you, use the migration steps below instead.

04Move an existing brain to another engine

nexusbrain migrate copies every source, page, link, tag and timeline entry from your current engine to a new one, then switches your config to it. Your old local database is left in place as a backup.

  1. Stop any running nexusbrain serve, such as an open agent session.

    You should seeNo agent session is using the brain.

  2. Copy the brain to Supabase or your own Postgres.

    Use an empty target database. The copy can be run again: if it stops part way, running the same command resumes where it left off.

    nexusbrain migrate --to supabase --url "postgresql://postgres.[ref]:[password]@aws-0-[region].pooler.supabase.com:6543/postgres"

    You should seeMigrating N pages, then Migration complete. N pages transferred., Config updated to engine: postgres, and Original PGLite brain preserved at with the old path.

  3. Read the verification lines printed after the copy.

    You should seeok pages: N (matches source), an embeddings: line, and ok schema: version N. If embeddings show WARN, run nexusbrain embed --stale.

  4. Run a full health check on the new engine.

    nexusbrain doctor

    You should seeAll checks pass against the Postgres database.

Flag for `migrate`What it does
--to supabaseCopy to a Postgres database. Works for Supabase and your own server.
--to pgliteCopy back to a local brain.
--url <url>The target connection string. Falls back to NEXUS_BRAIN_DATABASE_URL.
--path <path>The target folder when moving to the local engine.
--forceWipe every page in a target that already has data, then copy.
Note

If some pages fail to copy, the command lists them and prints Config NOT switched, so you keep using the old engine. Run the same command again to retry only the failed pages.

05Recover a local brain that will not open

The local engine can fail to open after an unclean shutdown, such as a reboot while the brain was writing. The usual error is PGLite failed to initialize its WASM runtime. with Aborted() in the original error. The cause is a half-written log of recent changes (the WAL), not your notes. Work through these options in order.

  1. Diagnose the database folder without changing anything.

    nexusbrain pglite-repair --dry-run

    You should seePGLite data dir: with the path, a Verdict: line, the lock state, and Repairable: yes or Repairable: NO with a reason.

  2. If it says repairable, repair the log in place.

    Your data files are kept. Changes that had not been saved to them yet may be lost. The old log files are copied to a backup folder next to the brain first. Without a terminal, --yes is required.

    nexusbrain pglite-repair --yes

    You should seeWAL reset complete. with the data folder and backup path, and a reminder to run any brain command to reopen it, then nexusbrain doctor.

  3. If repair is not possible, rebuild the brain from your notes.

    This moves the database to <path>.bak, creates a fresh one with the embedding model and size from your config file, and runs a sync. Anything that only existed in the database, such as registered sources, has to be added again. Pass --embedding-model and --embedding-dimensions to change the model at the same time, or --no-sync to skip the sync.

    If the sync cannot run, you see The brain is initialized but empty. That is expected when your notes were registered as sources. Continue with the next step.

    nexusbrain reinit-pglite --yes

    You should seeBacked up brain to the .bak path, the normal init output, Re-syncing brain repo..., and Reinit complete. To roll back: with an mv command.

  4. Add your sources back and sync them.

    nexusbrain sources add notes --path ~/notes && nexusbrain sync --all

    You should seeEach source is created and synced. See Brains and sources.

  5. Fill in any missing embeddings.

    nexusbrain embed --stale

    You should seeProgress while the remaining chunks are embedded.

  • To rebuild by hand instead: back up ~/.nexusbrain, move brain.pglite aside, run nexusbrain init --pglite, add your sources again, then run nexusbrain sync and nexusbrain embed --stale.
  • Auto-repair runs on ordinary commands by default. Set NEXUS_BRAIN_PGLITE_WAL_REPAIR=off to turn it off and run nexusbrain pglite-repair yourself.
  • Deleting .nexusbrain-lock or postmaster.pid does not fix a damaged database.
What doctor or dry-run reportsWhat to do
Lock held by a live processAnother nexusbrain process, often nexusbrain serve, has the brain open. Stop it and try again.
No data folder foundRun nexusbrain init --pglite to create one.
Unclean shutdown state (WAL corruption likely)Run nexusbrain pglite-repair --yes.
Layout looks healthy but it still failsOnly repair if the error mentions Aborted(). For errors mentioning 58P01 or pgvector failing to load, use nexusbrain reinit-pglite.
Not repairable in place, or the store looks corruptedRestore a backup of the brain.pglite folder, or run nexusbrain reinit-pglite.
Auto-repair has run several times this weekSwitch to Supabase or your own Postgres using the migration steps above.
Warning

There is no way to force a repair while another process holds the lock. That is deliberate: two processes writing the same local database is what causes the damage in the first place.

06Troubleshooting

Connection failed. Supabase direct connections (db.*.supabase.co:5432) are IPv6 only.

You used the direct connection string. Copy the Transaction pooler string (port 6543) from the Supabase dashboard and run init again.

Sync reports far fewer pages than the repo has, on Supabase from an IPv4 only network

Reads go through the pooler, but schema changes and sync use a derived direct connection that is IPv6 only. Set NEXUS_BRAIN_DIRECT_DATABASE_URL to the Session pooler string, or enable Supabase's IPv4 add-on.

Target brain is not empty (N pages).

Migrate into an empty database, or add --force to wipe the target first.

Already using postgres engine. Nothing to migrate.

Your config already points at Postgres. Check with nexusbrain config show.

Target is Supabase but no connection string provided. Use: --url <connection_string>

Add --url "<connection string>" or set NEXUS_BRAIN_DATABASE_URL.

pglite-repair or reinit-pglite says it is for PGLite brains only

Your config uses Postgres, so these tools do not apply. Use your database provider's backups. To repair a local data folder anyway, pass --path <dir> to pglite-repair.

Non-TTY environment requires --yes to confirm the WAL reset.

You ran the repair from a script or agent. Add --yes once you have read the dry-run output.

Backup already exists at a .bak path when running reinit-pglite

A previous rebuild left its backup. Move or delete that .bak folder, then run the command again.