Backup and restore
One file matters. Everything else under instance.dataDir is a clone or a
derived index, and will be rebuilt from your code hosts and your configuration.
/var/lib/searchcode/
subjects.db <- back this up
repos/ <- clones. Rebuildable.
analysis/ <- derived. Rebuildable.
audit/ <- if audit.output: file. See below.
subjects.db
One SQLite file holding five tables, and it is the enterprise binary's only durable state:
| Table | What is lost if it goes |
|---|---|
subjects |
Every principal this instance has authenticated, in every auth mode, with first-seen and last-seen. This is what the seat meter reads. |
local_accounts |
Password records for auth.mode: local. Everybody has to be recreated. |
api_keys |
Personal API keys. Every agent integration that uses one breaks until it is reissued. |
oauth_refresh_tokens |
The refresh tokens OAuth-connected agents hold, as digests. Every such agent has to sign in through the browser again. |
connections |
Code-host connections created on the connect screen, with their tokens sealed under the connection key. Back up that key with this file: restoring one without the other leaves connections that cannot be decrypted (see connections). |
In auth.mode: open no store is opened at all, so an open instance has no
database under dataDir. That is deliberate rather than an oversight.
Backing it up
SQLite in WAL mode, so do not copy the file with cp while the process is
running — you will get a torn read. Use the online backup:
sqlite3 /var/lib/searchcode/subjects.db ".backup '/backup/subjects-$(date +%F).db'"
Or stop the service and copy it. It is a few megabytes for a few thousand users; a nightly job is ample.
In Kubernetes, a volume snapshot of the PVC is the simplest correct answer. The file is consistent from a snapshot in the same way it is consistent after a power cut, which SQLite is designed for.
Configuration
Your searchcode.yaml and conf.d/ fragments are the other thing you cannot
regenerate — and they belong in git rather than in a backup, which is what the
no-inline-secrets rule buys you. There is no field anywhere in the file that
takes a secret value, so the whole configuration directory is safe to commit,
review and diff.
What is not in git: the files those *File references point at — SSH keys,
proxy shared secrets, the licence. Those come from your secret manager and
should already be in whatever backup covers it.
Restoring
- Install the same product version, or a newer one. State is forward-compatible.
- Restore
searchcode.yamlandconf.d/from git. - Restore the secret files your config references.
- Restore
subjects.dbintoinstance.dataDir. - Start it.
Clones and analysis rebuild on their own. The instance serves while that is happening — it binds and answers before ingestion finishes, and a repository that is not ready yet is reported as a coverage gap rather than as an empty result. Depending on estate size, expect full coverage in minutes to hours; see Sizing.
Restoring without subjects.db
Recoverable, but not silently:
- Local accounts are gone. Recreate an administrator on the box:
searchcode user add --admin alice. - Every personal API key and OAuth token is invalid. Every agent integration fails with a 401 until reissued. Tell people before you cut over, not after.
- Service accounts are unaffected — they are declared in config, not in the database, which is one more reason to use one for an unattended integration. See Which credential do I use?.
- Seat history restarts. In proxy mode, subjects are re-recorded as people sign in.
Audit records
If audit.output is file, those files are your compliance artefact and your
retention policy applies to them, not ours. They are written one file per UTC
day, which is what makes retention a whole-file delete rather than a rewrite of a
file being appended to.
If audit.output is stdout (the default), stderr or syslog, the records
are already in whatever collects them and nothing under dataDir needs backing
up.
Disaster recovery drill
Worth doing once, and it takes an afternoon:
- Snapshot
subjects.db. - Stand up a second instance with the same config and the restored file.
- Sign in, issue a search, call one MCP tool with an existing key.
- Watch the estate rebuild and time it. That number is your recovery time objective, and it is dominated by clone throughput rather than by anything this product does.
What is deliberately not here
There is no backup command, no snapshot subcommand and no restore wizard. One SQLite file and a directory of configuration is a backup story your existing tooling already covers, and a bespoke one would be a second thing to test.