Skip to main content

MySQL / PostgreSQL / SQLite and Redis

The metadata store is MySQL, PostgreSQL or SQLite (testing only); the process creates the schema on first start, and Redis holds runtime state such as heartbeats.

Nightingale connects to two stores: a metadata database (users, business groups, alert rules, dashboards, notification config) and Redis. Metrics are not in either — those belong to the time-series store.

Which one​

Use it whenCost
SQLiteTrying it alone, writing docs, CINo second copy, no sharing between instances, and two processes on one file corrupt it
MySQL 8The default choice, and what most of the community runsYou provide the high availability
PostgreSQL 12+Your team already runs PGSame, and a few tables use different column types under PG

MySQL and PostgreSQL are both first-class in production; pick the one your team can operate. SQLite is for testing — that is its purpose, not a tuning problem.

MySQL​

[DB]
DBType = "mysql"
DSN = "n9e:<password>@tcp(mysql:3306)/n9e_v6?charset=utf8mb4&parseTime=True&loc=Local"
MaxOpenConns = 150
MaxIdleConns = 50

parseTime=True is not optional. Use utf8mb4, or emoji in notification templates fail to write.

The database is conventionally called n9e_v6; the name has been carried since v6 and the bundled schema scripts still use it. Another name works fine — change the DSN.

PostgreSQL​

[DB]
DBType = "postgres"
DSN = "host=postgres port=5432 user=n9e dbname=n9e_v6 password=<password> sslmode=disable"

The DSN is key=value form, not a URL. In production set sslmode to require or stricter.

SQLite​

The default, with nothing to configure:

[DB]
DBType = "sqlite"
DSN = "n9e.db"

The file lands next to the binary. To reset it, delete n9e.db, n9e.db-wal and n9e.db-shm together — removing only the main file leaves a fresh database paired with a stale WAL.

Where the schema comes from​

n9e runs AutoMigrate on every start: it creates missing tables and adds missing columns and indexes. Bootstrapping therefore needs only an empty database and an account that may create and alter tables.

The SQL files in the repository are conveniences for specific situations, and none of them is a complete schema:

FilePurposeCaveat
docker/initsql/a-n9e.sqlCreates the MySQL database and tables; run by compose on first startMissing notify_channel_config, ai_llm_config and others — AutoMigrate fills them in
docker/compose-postgres/initsql_for_postgres/The PostgreSQL equivalentSame
docker/migratesql/migrate.sqlCumulative DDL deltas, for people who bootstrapped from SQL and want to align by handNot a required upgrade step
docker/sqlite.sqlAn early SQLite schemaStale — none of the v9 tables are in it; SQLite relies on AutoMigrate

A failed migration is logged and does not stop startup, so after an upgrade search the log for failed to migrate table. The two large tables, alert_his_event and alert_cur_event, migrate asynchronously; building indexes on a large one can take tens of minutes.

What Redis is for​

Redis is not an optional cache layer, it is required:

  • Login sessions — JWT issuing and revocation, under [HTTP.JWTAuth] RedisKeyPrefix (/jwt/ by default);
  • Host metadata — CPU, memory and OS reported by heartbeats, written to Redis in batches every second; the host list reads from there;
  • Captchas, when [HTTP.ShowCaptcha] is on;
  • AI conversation state and locks, plus the pub/sub channel that cancels a conversation across instances.
[Redis]
RedisType = "standalone"
Address = "redis:6379"
# Password = ""
# DB = 0

RedisType accepts standalone, cluster, sentinel and miniredis. The default miniredis is a fake Redis running inside the Nightingale process — its data goes when the process does, so it is for testing only. For cluster and sentinel, put several comma-separated addresses in Address.

n9e-edge cannot reuse the central Redis. Deploy a separate one at the edge site, otherwise the edge dies with the link it was supposed to survive.

Next​