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.
nexusbrain command works in your terminal.vector extension is available.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.
.md files prints a suggestion to use Supabase for faster search at that size.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.nexusbrain serve before running other commands. See Running serve and sync together.| Local (PGLite) | Supabase | Your own Postgres | |
|---|---|---|---|
| Set up with | nexusbrain init --pglite | nexusbrain init --supabase | nexusbrain init --url <connection string> |
| Where data lives | A folder on this machine, ~/.nexusbrain/brain.pglite by default | A hosted Postgres database | Any Postgres server you run, with pgvector |
| Server needed | No | No, Supabase runs it | Yes |
| Processes at once | One. A running nexusbrain serve blocks other commands. | Many | Many |
| Database reachable from other machines | No. Other machines can still use it through nexusbrain serve --http. | Yes | Yes |
| Good for | Getting started, one person, brains under about 1000 .md files | Large brains, remote access, always-on agents | Teams that already run Postgres |
| Recovery tools | pglite-repair, reinit-pglite | Your provider's backups | Your own backups |
Add --path <DIR> to keep the database somewhere other than ~/.nexusbrain/brain.pglite.
nexusbrain init --pgliteYou should seeSetting up local brain with PGLite (no server needed)..., then Brain ready at with the path and Engine: PGLite (local Postgres).
nexusbrain doctorYou should seeOverall health score: N/100. with All checks passed. or All checks OK (some warnings).
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.
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 --supabaseYou 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).
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 doctorYou should seeThe connection and pgvector checks pass.
| Environment variable | What it does |
|---|---|
NEXUS_BRAIN_DATABASE_URL | The connection string to use with --non-interactive. |
NEXUS_BRAIN_DIRECT_DATABASE_URL | With 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=1 | Turn the separate direct connection off completely. |
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.
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.
nexusbrain serve, such as an open agent session.You should seeNo agent session is using the brain.
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.
You should seeok pages: N (matches source), an embeddings: line, and ok schema: version N. If embeddings show WARN, run nexusbrain embed --stale.
nexusbrain doctorYou should seeAll checks pass against the Postgres database.
| Flag for `migrate` | What it does |
|---|---|
--to supabase | Copy to a Postgres database. Works for Supabase and your own server. |
--to pglite | Copy 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. |
--force | Wipe every page in a target that already has data, then copy. |
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.
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.
nexusbrain pglite-repair --dry-runYou should seePGLite data dir: with the path, a Verdict: line, the lock state, and Repairable: yes or Repairable: NO with a reason.
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 --yesYou 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.
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 --yesYou 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.
nexusbrain sources add notes --path ~/notes && nexusbrain sync --allYou should seeEach source is created and synced. See Brains and sources.
nexusbrain embed --staleYou should seeProgress while the remaining chunks are embedded.
~/.nexusbrain, move brain.pglite aside, run nexusbrain init --pglite, add your sources again, then run nexusbrain sync and nexusbrain embed --stale.NEXUS_BRAIN_PGLITE_WAL_REPAIR=off to turn it off and run nexusbrain pglite-repair yourself..nexusbrain-lock or postmaster.pid does not fix a damaged database.| What doctor or dry-run reports | What to do |
|---|---|
| Lock held by a live process | Another nexusbrain process, often nexusbrain serve, has the brain open. Stop it and try again. |
| No data folder found | Run nexusbrain init --pglite to create one. |
| Unclean shutdown state (WAL corruption likely) | Run nexusbrain pglite-repair --yes. |
| Layout looks healthy but it still fails | Only 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 corrupted | Restore a backup of the brain.pglite folder, or run nexusbrain reinit-pglite. |
| Auto-repair has run several times this week | Switch to Supabase or your own Postgres using the migration steps above. |
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.
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.
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 onlyYour 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-pgliteA previous rebuild left its backup. Move or delete that .bak folder, then run the command again.