KDB knowledge

kdb serve

Start the KDB server - web console, HTTP API, line protocol and PostgreSQL port - on one database or on the whole data folder.

kdb serve starts the server. It keeps running until you press Ctrl+C. While it runs, programs use the databases through it: the web console in a browser, the HTTP API, the line protocol (POST /write) and PostgreSQL tools on the PostgreSQL port.

The server has the database files open. So kdb sql, kdb shell, kdb backup and kdb check on the same database fail while it runs. Use the server instead: the console, POST /exec, BACKUP DATABASE, POST /api/check.

kdb serve

Syntax:

kdb serve [<db>] [--data-dir <folder>] [--config <file>] [--db <name>] [--port 9900] [--bind 127.0.0.1]
          [--backups <dir>] [--token <secret>] [--memory <MB>] [--memory-limit <size>] [--threads N] [--cache-mb <MB>]
          [--sync-commits always|batch] [--pg-port 8832] [--pg-timestamptz] [--pg-int-division on|off]
          [--warm-indexes on|off] [--reader-yield on|off] [--per-table-reads on|off] [--read-only-calls on|off]
          [--scoped-ddl on|off] [--ddl-beside-writers on|off] [--skip-locked-beside on|off]
          [--log-lock-waits on|off] [--deadlock-timeout 1s]
          [--snapshot-reads on|off] [--snapshot-index-rows N] [--txn-spill-mb 64] [--tail-files on|off]
          [--table-writers one|many]
          [--timezone <zone>] [--drain-timeout 30s] [--pin-threads auto|on|off]
          [--http-threads N] [--max-connections N] [--timer-workers N] [--lock-timeout 5s] [--idle-in-transaction-timeout 30s]
          [--trigger-retries N] [--max-trigger-jobs N] [--alert-webhook <url>] [--slow-query-ms N] [--token-name <name>]
          [--trash-max-mb N] [--tls-cert <file> --tls-key <file>] [--tls-required on|off]
          [--lanes on|off] [--heavy-ms 100] [--heavy-slots N] [--heavy-queue N] [--read-slots auto|off|N]
          [protection and backup options: see protection and backup-schedule]
OptionMeaningDefault
<db>Without it: every database in the data folder. A name from the data folder: every database, and this one is the default. A folder path: only that folder.all databases in the data folder
--data-dir <folder>The data folder (see the data folder). Always wins over kdb.conf.kdb.conf, else KDB_DATA_DIR, else data next to kdb
--config <file>Settings the console's Settings page may change: the data folder, and wal_archive_mb (old log kept per database; it wins over the KDB_WAL_ARCHIVE_MB environment variable, default 1024).kdb.conf next to kdb
--db <name>The default database: the one a request uses when it names no database. With a folder path: the name the folder is served under.default (with a path: the folder's name)
--port NThe HTTP port for the console and the API (1 to 65535)9900
--bind <address>The network address to listen on. 127.0.0.1 = only this computer. 0.0.0.0 = every network.127.0.0.1
--backups <dir>Backup folder for BACKUP DATABASE, the console's Backup now, POST /api/backup and the schedule. A database of the data folder backs up into <dir>/<name>. Damaged files are also repaired from here when a database opens. off = no backups. Also KDB_BACKUP_DIR or backup_dir in kdb.conf._backups in the data folder; for one folder served by its path, _backups/<folder name> next to that folder
--token <secret>A secret every request must send (Authorization: Bearer <secret>). It works like an admin user. kdb serve reads no environment variable for it; the Docker image passes its KDB_TOKEN as --token.no token
--memory <MB>Memory for table data kept loaded, for all open databases together. Data over it is read from disk again when needed. No environment variable in the program; the Docker image passes its KDB_MEMORY as --memory.512, but without the flag at most 40% of the memory limit
--memory-limit <size>One limit for everything the server holds: table data, unsaved changes, indexes, results and caches (see memory limit). 3GB, 512MB, or a plain number of megabytes. 0 or off = no limit. Also KDB_MEMORY_LIMIT.85% of a container's memory limit, else of the machine's memory
--threads NThreads for big queries and writes, shared by all databases. From 1 to half of the machine's CPU threads. A number set here stays; without it the count follows the CPU limit (self-tuning).half of the CPUs the process may use
--cache-mb <MB>Memory for results of repeated queries, for all open databases together. 0 = no result cache. Else cache_mb in kdb.conf, else KDB_CACHE_MB. One result may use a quarter of it, a pinned one three quarters.256, but at most a tenth of the memory limit
--warm-indexes on|offBuild every index of a database on a background thread right after it opens, so the first query finds it ready (see indexes). off = build on first use. Also KDB_WARM_INDEXES.on
--read-only-calls on|offon: a CALL of a procedure that changes nothing runs like a SELECT: no table locks, no transaction (a CALL that only reads). off: every CALL is a transaction. Also KDB_READ_ONLY_CALLS.on
--scoped-ddl on|offon: CREATE, ALTER and DROP TABLE, CREATE and DROP INDEX and CREATE, ALTER and DROP TRIGGER, TRUNCATE, CREATE TABLE ... AS and materialized views lock only their tables, and views, procedures and functions lock none, so they do not wait for a long writer of other tables (schema changes). off: every schema change locks every table. Also KDB_SCOPED_DDL.on
--ddl-beside-writers on|offWith --scoped-ddl on: CREATE TABLE, ALTER TABLE, RENAME TABLE and CREATE / DROP INDEX run beside writers of other tables, also beside one long statement that never pauses (a big INSERT ... SELECT or COPY), instead of failing with 55P03 after the lock timeout (schema changes). off: they wait until such a writer pauses between two statements, as before 2026-09-25. Also KDB_DDL_BESIDE_WRITERS.on
--skip-locked-beside on|offon: SELECT ... FOR UPDATE SKIP LOCKED inside BEGIN returns the rows another open transaction did not lock or change, although that transaction holds the table. Your UPDATE of such a row then waits for its COMMIT and fails with 40001 after the lock timeout (FOR UPDATE). off: no rows there, as before; without BEGIN the free rows are returned either way. Also KDB_SKIP_LOCKED_BESIDE.off
--reader-yield on|offon: a reader of a table a long trigger, CALL or transaction is writing does not wait for it. The writer steps aside between its statements and the reader sees the last committed rows. off: such readers wait for the writer's whole request. Also KDB_READER_YIELD. The start-up line readers says which is in use.on
--pin-threads auto|on|offLinux. auto: inside a CPU quota (docker --cpus, cgroup cpu.max) smaller than the CPUs the process may run on, every thread is pinned to the quota's worth of CPUs, one per core, and moved back when the quota goes (pinning threads). on: each HTTP worker, PostgreSQL connection and query thread runs on one CPU of its own, so its CPU cache stays warm. off: nothing is pinned. Windows: ignored (on with a warning). Also KDB_PIN_THREADS.auto
--per-table-reads on|offon: a reader waits only for writers of the tables it reads, and not while a checkpoint writes its files (see transactions). off: every reader waits for every writer. Also KDB_PER_TABLE_READS.on
--snapshot-reads on|offon: a reader of a table a long CALL, trigger job or big statement is writing does not wait at all: it reads a snapshot of the committed rows (see transactions). Tables with an index too, while a writer is busy on them: such a read still uses a plain or expression index, on the snapshot. Also KDB_SNAPSHOT_READS. The start-up line readers says so.off
--table-writers one|manymany: several users change one table at the same time when each of their statements on it touches single rows by the primary key - a one-row INSERT, UPDATE ... WHERE id = x, DELETE ... WHERE id = x, a CALL or trigger made of such statements. The same row is waited for, as in PostgreSQL; two writers that wait for each other's rows get deadlock (40P01). Anything else on the table (a range UPDATE, INSERT ... SELECT, a SELECT statement, BEGIN ... COMMIT across requests, a table with foreign keys or other UNIQUE columns) takes the whole table, as before (several writers of one table). one: one writer per table at a time. Also KDB_TABLE_WRITERS.one
--snapshot-index-rows NWith snapshot reads on: a plain or expression index is used on a snapshot at any table size. A table with a full-text or JSON index, or an index not built in memory yet, has its snapshot scanned instead, and only while it has at most this many rows; a bigger one is waited for, as before, so a lookup does not turn into a scan of millions of rows. 0: indexed tables are always waited for. Also KDB_SNAPSHOT_INDEX_ROWS.1000000
--tail-files on|offon: a save (checkpoint) puts rows appended after the end of a partition in a small tail file next to it, instead of writing the whole partition again. A database with tail files needs KDB 2026-10-02 or newer. Also KDB_TAIL_FILES.off
--txn-spill-mb NA transaction's log records past this many MB (or 1/16 of --memory-limit, if less) go to a temporary file in the database's _tmp folder until COMMIT, so a long CALL or trigger job does not hold them all in memory (see transactions). 0: they all stay in memory. Also KDB_TXN_SPILL_MB.64
--sync-commits alwaysEvery write is on disk before KDB confirms it.always
--sync-commits batchWrites are confirmed at once and put on disk every 10 ms.
--pg-port NPort for the PostgreSQL protocol. 0 = off.8832
--pg-timestamptzSend TIMESTAMP columns to PostgreSQL clients as timestamptz (with time zone).off
--timezone <zone>The server's time zone, like Asia/Kathmandu: the clock of CURRENT_DATE, ::date, date_trunc and EXTRACT for sessions that set none, and of timer and backup schedules. Times are still stored in UTC. Env KDB_TIMEZONE, kdb.conf "timezone". See time zones.UTC (schedules: the machine's clock)
--pg-int-division on|offon: on the Postgres port, whole number / whole number gives a whole number (7 / 2 is 3), as in PostgreSQL. A connection can still choose with SET int_division = integer | float. Also KDB_PG_INT_DIVISION. See integer division.off
--pg-compat on|offon: PostgreSQL 14's answers (exact decimal literals, RANGE window frames, locale text order, ...) for every database without its own ALTER DATABASE ... SET pg_compat. A session can still choose with SET kdb.pg_compat. Also KDB_PG_COMPAT. Waiting for the owner's decision: keep it off. See PostgreSQL-compatible results.off
--drain-timeout <time>On a stop, how long running requests may still finish while new ones get 503 (see stopping). 0 = do not wait.30s, or KDB_DRAIN_TIMEOUT
--http-threads NHTTP requests handled at the same time (1 to 1024). A slow query holds its thread until it ends, so more threads keep fast lookups from waiting behind slow ones. Also KDB_HTTP_THREADS or http_threads in kdb.conf.the CPUs the process may use, at least 8, at most 64; without a number set it follows the CPU limit while the server runs (docker update --cpus)
--http-gzip remote|on|offAnswers of 2 KB or more (JSON, CSV, the console's files) go out compressed (Content-Encoding: gzip, about a fifth of the bytes) to a client that sends Accept-Encoding: gzip, as browsers, Go and Python do by themselves. remote: only clients beyond this computer and its private networks; one on this computer (127.x), on the same LAN (10.x, 172.16-31.x, 192.168.x) or in another container on this computer (Docker's bridge, 172.17.x) gets plain answers, as there the bytes arrive faster than they can be compressed. Also KDB_HTTP_GZIP. See compressed answers.remote
--lanes on|offPriority lanes: a read that used --heavy-ms of CPU or more the last three times runs only when a heavy slot is free, so charts stay fast while reports run. off: every statement starts at once. Also KDB_LANES.on
--heavy-ms NHow much CPU time (in ms) a read must use, three times in a row, to count as heavy. Also KDB_HEAVY_MS.100
--heavy-slots NHeavy statements that run at the same time. Also KDB_HEAVY_SLOTS.half of the CPUs the process may use, at least 1
--heavy-queue NHeavy HTTP requests that may wait for a slot at the same time. Past it a request sent with priority low is refused with 503; a read heavy by its history runs at once. PostgreSQL statements are not counted. Also KDB_HEAVY_QUEUE.half of --http-threads, at least 4
--read-slots auto|off|NRead slots: reads that run at the same time; the rest wait in line, and a read holds its slot for at most 10 ms. off: every read starts at once. Also KDB_READ_SLOTS.auto: the CPUs the process may use, at least 2
--max-connections NPostgreSQL logins at the same time, for all databases together. 0 = no limit. Also KDB_MAX_CONNECTIONS or max_connections in kdb.conf.500
--timer-workers NTimers that may run at the same time (1 to 64). Each running timer is one more writer at the database. Also KDB_TIMER_WORKERS or timer_workers in kdb.conf.3
--tcp-keepalives-idle S, --tcp-keepalives-interval S, --tcp-keepalives-count NTCP keepalive of every HTTP and PostgreSQL connection: seconds without traffic before the first probe (0 to 32767), seconds between probes, probes before a vanished client is dropped (0 to 127). Keepalive is always on; 0 = the system's timings. A Postgres connection can set its own with SET tcp_keepalives_idle (idle and vanished clients). Also KDB_TCP_KEEPALIVES_IDLE, KDB_TCP_KEEPALIVES_INTERVAL, KDB_TCP_KEEPALIVES_COUNT or tcp_keepalives_idle, tcp_keepalives_interval, tcp_keepalives_count in kdb.conf.0 (the system's)
--trigger-retries <N>A failed deferred trigger job runs again this many times, 1 s, 2 s, 4 s ... apart, before its queue stops. 0 = never. Also KDB_TRIGGER_RETRIES.3
--max-trigger-jobs <N>Deferred trigger jobs that may wait in one database. A write past it is refused with 503 and the reason. 0 = no limit. Also KDB_MAX_TRIGGER_JOBS.10000
--alert-webhook <url>Failed deferred trigger jobs are sent as JSON to this http://<IPv4>:<port>/<path> (alerts). Also KDB_ALERT_WEBHOOK or alert_webhook in kdb.conf.none
--lock-timeout <time>How long a writer waits for a table another writer holds, then table 'x' is busy. 0 = no limit. A session can set its own with SET lock_timeout (lock timeout). Also KDB_LOCK_TIMEOUT or lock_timeout_ms in kdb.conf.5s
--idle-in-transaction-timeout <time>An open BEGIN ... COMMIT that sends nothing this long is rolled back, so a client that died cannot keep its tables locked. 0 = never. A session can set its own with SET idle_in_transaction_session_timeout (idle transactions). Also KDB_IDLE_IN_TRANSACTION_TIMEOUT or idle_in_transaction_timeout_ms in kdb.conf.30s

kdb.conf

kdb.conf is a small JSON file of settings, next to kdb (or --config <file>). The console's Settings page writes it. A server on one folder path (kdb serve ./market) reads only the three folder keys from it.

KeyMeaningElse
data_dirthe data folderKDB_DATA_DIR, then data next to kdb. --data-dir always wins over it.
wal_archive_mbold log each database keeps for repairs (0 = none)KDB_WAL_ARCHIVE_MB, then 1024
cache_mbthe result cache of all databases together, in MB (0 = off)KDB_CACHE_MB, then 256. --cache-mb wins.
keep_versionsolder file versions kept for repairs (0 to 10)KDB_KEEP_VERSIONS, then 2
trash_keep_hourshow long replaced files stay in the trashKDB_TRASH_KEEP_HOURS, then 1
trash_max_mbthe most a database's trash may hold; beyond it the oldest folders go at once, whatever their age (0 = no limit)KDB_TRASH_MAX_MB, then a quarter of the database's data (at least 256 MB). --trash-max-mb wins.
slow_query_msstatements taking this many milliseconds or more go to the slow-query log (0 = off)KDB_SLOW_QUERY_MS, then 1000. --slow-query-ms wins.
http_threadsHTTP requests handled at once (1 to 1024)KDB_HTTP_THREADS, then the CPU threads (at least 8, at most 64). --http-threads wins.
max_connectionsPostgreSQL logins at once (0 = no limit)KDB_MAX_CONNECTIONS, then 500. --max-connections wins.
lock_timeout_msmilliseconds a writer waits for a busy table (0 = no limit)KDB_LOCK_TIMEOUT, then 5000. --lock-timeout wins.
idle_in_transaction_timeout_msmilliseconds an open transaction may send nothing before it is rolled back (0 = never)KDB_IDLE_IN_TRANSACTION_TIMEOUT, then 30000. --idle-in-transaction-timeout wins.
timer_workerstimers that may run at the same time (1 to 64)KDB_TIMER_WORKERS, then 3. --timer-workers wins.
tcp_keepalives_idle, tcp_keepalives_interval, tcp_keepalives_countTCP keepalive timings of every connection: seconds, seconds, probes (0 = the system's)KDB_TCP_KEEPALIVES_IDLE, KDB_TCP_KEEPALIVES_INTERVAL, KDB_TCP_KEEPALIVES_COUNT, then 0. The --tcp-keepalives-* flags win.
rate_limit_ip, rate_limit_userrequests per second per client address / per user (0 = no limit; rate limits)KDB_RATE_LIMIT_IP, KDB_RATE_LIMIT_USER, then 0. --rate-limit-ip, --rate-limit-user win.
timezonethe server's time zone, like "Asia/Kathmandu" or "America/New_York" (summer time)KDB_TIMEZONE, then the computer's own zone (UTC in a container without one). --timezone wins.
alert_webhookwhere failed deferred trigger jobs are POSTed (alerts)KDB_ALERT_WEBHOOK, then none. --alert-webhook wins.
tls_cert, tls_keyPEM files for TLS on both ports; tls_cert "auto" = a self-signed pairKDB_TLS_CERT, KDB_TLS_KEY, then off. --tls-cert, --tls-key win.
http_functions, http_timeout_msthe hosts http_get / http_post may call ("off" or a list), and the milliseconds one call may takeKDB_HTTP_FUNCTIONS, KDB_HTTP_TIMEOUT_MS, then off and 10000. No flag.
web_dir, help_dir, skill_dirthe folders of the console, the help and the Claude skillKDB_WEB_DIR ..., then the folders next to kdb (folders)
backup_dir, backup_schedule, backup_keep_daily, backup_keep_weekly, backup_commandthe backup settings (backup_dir "off" = none)KDB_BACKUP_DIR, KDB_BACKUP_SCHEDULE, ..., then _backups in the data folder, off, 7, 4, none. The flags win.
{
  "data_dir": "E:/kdb-data",
  "wal_archive_mb": 512
}

Command line: Every database of the data folder

kdb serve

Output:

KDB 0.2.0-dev
  console   http://127.0.0.1:9900
  data      ./kdb-data (from KDB_DATA_DIR; one folder per database)
  default   default (used when a request names no database)
  backups   ./kdb-data/_backups/<database name> (from default)
  access    no token
  capacity  32 HTTP threads (default), 500 PostgreSQL connections (default), lock wait 5 s (default)
  lanes     reads using 100 ms of CPU (three times in a row) wait for one of 16 heavy slots, at most 16 HTTP in line (--lanes on)
  reads     32 reads run at once (the CPUs, at least 2; follows the CPU limit), the rest wait in line (--read-slots)
  commits   synced to disk before they are confirmed (--sync-commits always)
  time zone Asia/Katmandu (the computer's); also timers and backup schedules
  readers   read while a long trigger or CALL writes (--reader-yield on); idle open transaction rolled back after 30 s (default)
  memory    26.95 GB for the whole process (85% of the machine's memory); table data 512.0 MB of it (--memory)
  cpu       32 CPUs (the machine's); 16 query threads (half of the CPUs, follows the limit), limits checked every 10 s
  limits    statement timeout 1 min, result memory 1.00 GB, 5000000 groups, 32 statements per user
  safety    writes allowed; DROP TABLE kept 7 days (UNDROP TABLE); audit log on (SHOW AUDIT)
  logs      slow queries >= 1000 ms to ./kdb-data/_logs/slow_queries.jsonl; pg_stat_statements on; metrics at /metrics
  recovery  the default database is created when it is first used

Press Ctrl+C to stop.

Command line: Only one database folder, given by its path (sample data: sample)

kdb serve ./market

Output:

KDB 0.2.0-dev
  console   http://127.0.0.1:9900
  data      ./market
  backups   ./_backups/market (from default)
  access    no token
  capacity  32 HTTP threads (default), 500 PostgreSQL connections (default), lock wait 5 s (default)
  lanes     reads using 100 ms of CPU (three times in a row) wait for one of 16 heavy slots, at most 16 HTTP in line (--lanes on)
  reads     32 reads run at once (the CPUs, at least 2; follows the CPU limit), the rest wait in line (--read-slots)
  commits   synced to disk before they are confirmed (--sync-commits always)
  time zone Asia/Katmandu (the computer's); also timers and backup schedules
  readers   read while a long trigger or CALL writes (--reader-yield on); idle open transaction rolled back after 30 s (default)
  memory    26.95 GB for the whole process (85% of the machine's memory); table data 512.0 MB of it (--memory)
  cpu       32 CPUs (the machine's); 16 query threads (half of the CPUs, follows the limit), limits checked every 10 s
  limits    statement timeout 1 min, result memory 1.00 GB, 5000000 groups, 32 statements per user
  safety    writes allowed; DROP TABLE kept 7 days (UNDROP TABLE); audit log off
  logs      slow queries >= 1000 ms to ./market/_logs/slow_queries.jsonl; pg_stat_statements on; metrics at /metrics
  recovery  manifest copy: a, last shutdown: clean
  open      opened in 2 ms: manifest 1 ms, 1 files read 0 ms (8 table files left for their first use), log check 1 ms, replay 0 ms (0 transactions), clean-up 0 ms

Press Ctrl+C to stop.

Command line: More memory, batch commits, backups and a token (sample data: sample)

kdb serve ./market --backups backups --memory 2048 --threads 1 --sync-commits batch --token a-long-random-secret

Output:

KDB 0.2.0-dev
  console   http://127.0.0.1:9900
  data      ./market
  backups   backups (from --backups)
  access    token required
  capacity  32 HTTP threads (default), 500 PostgreSQL connections (default), lock wait 5 s (default)
  lanes     reads using 100 ms of CPU (three times in a row) wait for one of 16 heavy slots, at most 16 HTTP in line (--lanes on)
  reads     32 reads run at once (the CPUs, at least 2; follows the CPU limit), the rest wait in line (--read-slots)
  commits   synced every 10 ms (--sync-commits batch)
  time zone Asia/Katmandu (the computer's); also timers and backup schedules
  readers   read while a long trigger or CALL writes (--reader-yield on); idle open transaction rolled back after 30 s (default)
  memory    26.95 GB for the whole process (85% of the machine's memory); table data 2.00 GB of it (--memory)
  cpu       32 CPUs (the machine's); 1 query thread (--threads), limits checked every 10 s
  limits    statement timeout 1 min, result memory 1.00 GB, 5000000 groups, 32 statements per user
  safety    writes allowed; DROP TABLE kept 7 days (UNDROP TABLE); audit log off
  logs      slow queries >= 1000 ms to ./market/_logs/slow_queries.jsonl; pg_stat_statements on; metrics at /metrics
  recovery  manifest copy: a, last shutdown: clean
  open      opened in 3 ms: manifest 0 ms, 1 files read 0 ms (8 table files left for their first use), log check 1 ms, replay 1 ms (0 transactions), clean-up 1 ms

Press Ctrl+C to stop.

Command line: PostgreSQL port and result cache (sample data: sample)

kdb serve ./market --pg-port 18832 --pg-timestamptz --cache-mb 256

Output:

KDB 0.2.0-dev
  console   http://127.0.0.1:9900
  postgres  127.0.0.1:18832 (PostgreSQL protocol, no TLS; no password on this computer only)
  data      ./market
  backups   ./_backups/market (from default)
  access    no token
  capacity  32 HTTP threads (default), 500 PostgreSQL connections (default), lock wait 5 s (default)
  lanes     reads using 100 ms of CPU (three times in a row) wait for one of 16 heavy slots, at most 16 HTTP in line (--lanes on)
  reads     32 reads run at once (the CPUs, at least 2; follows the CPU limit), the rest wait in line (--read-slots)
  commits   synced to disk before they are confirmed (--sync-commits always)
  time zone Asia/Katmandu (the computer's); also timers and backup schedules
  readers   read while a long trigger or CALL writes (--reader-yield on); idle open transaction rolled back after 30 s (default)
  memory    26.95 GB for the whole process (85% of the machine's memory); table data 512.0 MB of it (--memory)
  cpu       32 CPUs (the machine's); 16 query threads (half of the CPUs, follows the limit), limits checked every 10 s
  limits    statement timeout 1 min, result memory 1.00 GB, 5000000 groups, 32 statements per user
  safety    writes allowed; DROP TABLE kept 7 days (UNDROP TABLE); audit log off
  logs      slow queries >= 1000 ms to ./market/_logs/slow_queries.jsonl; pg_stat_statements on; metrics at /metrics
  recovery  manifest copy: a, last shutdown: clean
  open      opened in 2 ms: manifest 0 ms, 1 files read 1 ms (8 table files left for their first use), log check 0 ms, replay 0 ms (0 transactions), clean-up 1 ms

Press Ctrl+C to stop.

The help build runs every example on a free port, so the banner always shows port 9900. --pg-port 18832 is used here only so the example does not meet a real server on 8832.

Command line: --bind 0.0.0.0 without a token or users is refused

kdb serve --bind 0.0.0.0

Output:

error: --bind 0.0.0.0 without --token and without users would let anyone who can reach this computer
read, change and delete every database. Do one of these first:
  1. create an admin user:   kdb user add <name> --role admin
  2. or start with a secret:  --token <long random text>
  3. or keep --bind 127.0.0.1 and put a web server with HTTPS in front of KDB
See docs/tutorial/16-users-passwords-security.md

exit code 1

Command line: A wrong value stops the start

kdb serve --sync-commits fast

Output:

error: --sync-commits must be 'always' or 'batch'

exit code 1

Every option at a glance

Every setting of kdb serve in one table: the flag, the environment variable, the kdb.conf key and the default. - means there is none. When one setting has more than one of them, the flag wins, then kdb.conf, then the environment, then the default.

FlagEnvironmentkdb.confDefaultMore
--data-dirKDB_DATA_DIRdata_dirdata next to kdbdata folder
--config- (Docker: KDB_CONFIG)-kdb.conf next to kdbkdb.conf
--db--defaultmany databases
--port, --bind--9900, 127.0.0.1kdb serve
--pg-port--8832 (0 = off)PostgreSQL port
--token- (Docker: KDB_TOKEN)-noneserver security
--token-nameKDB_TOKEN_NAME-tokenaudit log
--memory- (Docker: KDB_MEMORY)-512, at most 40% of the memory limitkdb serve
--memory-limitKDB_MEMORY_LIMIT-85% of the container's or machine's memorymemory limit
--threads--half of the CPUs, follows the CPU limitself-tuning
--cache-mbKDB_CACHE_MBcache_mb256, at most a tenth of the memory limitresult cache
--sync-commits--alwaysperformance tips
--http-threadsKDB_HTTP_THREADShttp_threadsthe CPUs, 8 to 64kdb serve
--http-gzipKDB_HTTP_GZIP-remotecompressed answers
--max-connectionsKDB_MAX_CONNECTIONSmax_connections500kdb serve
--lanesKDB_LANES-onpriority lanes
--heavy-ms, --heavy-slots, --heavy-queueKDB_HEAVY_MS, KDB_HEAVY_SLOTS, KDB_HEAVY_QUEUE-100, half of the CPUs, half of the HTTP threads (at least 4)priority lanes
--read-slotsKDB_READ_SLOTS-auto (the CPUs, at least 2)read slots
--timer-workersKDB_TIMER_WORKERStimer_workers3timers
--tcp-keepalives-idle, --tcp-keepalives-interval, --tcp-keepalives-countKDB_TCP_KEEPALIVES_IDLE, KDB_TCP_KEEPALIVES_INTERVAL, KDB_TCP_KEEPALIVES_COUNTtcp_keepalives_idle, tcp_keepalives_interval, tcp_keepalives_count0 (the system's)idle and vanished clients
--lock-timeoutKDB_LOCK_TIMEOUTlock_timeout_ms5slock timeout
--idle-in-transaction-timeoutKDB_IDLE_IN_TRANSACTION_TIMEOUTidle_in_transaction_timeout_ms30sidle transactions
--reader-yieldKDB_READER_YIELD-onreader yield
--pin-threadsKDB_PIN_THREADS-autopinning threads
--per-table-readsKDB_PER_TABLE_READS-onper-table reads
--snapshot-readsKDB_SNAPSHOT_READS-offsnapshot reads
--snapshot-index-rowsKDB_SNAPSHOT_INDEX_ROWS-1000000kdb serve
--table-writersKDB_TABLE_WRITERS-oneseveral writers of one table
--tail-filesKDB_TAIL_FILES-offtail files
--read-only-callsKDB_READ_ONLY_CALLS-onprocedures
--scoped-ddlKDB_SCOPED_DDL-onschema changes
--ddl-beside-writersKDB_DDL_BESIDE_WRITERS-onschema changes
--skip-locked-besideKDB_SKIP_LOCKED_BESIDE-offFOR UPDATE
--log-lock-waitsKDB_LOG_LOCK_WAITS-offlock waits
--deadlock-timeoutKDB_DEADLOCK_TIMEOUT-1slock waits
--warm-indexesKDB_WARM_INDEXES-onindexes
--timezoneKDB_TIMEZONEtimezoneUTCtime zones
--pg-timestamptz--offPostgreSQL port
--pg-int-divisionKDB_PG_INT_DIVISION-offinteger division
--pg-compatKDB_PG_COMPAT-offPostgreSQL-compatible results
--trigger-retriesKDB_TRIGGER_RETRIES-3deferred triggers
--max-trigger-jobsKDB_MAX_TRIGGER_JOBS-10000deferred triggers
--alert-webhookKDB_ALERT_WEBHOOKalert_webhooknonealerts
--statement-timeout--60sprotection
--max-result-memory, --max-groups--1GB, 5000000protection
--max-queries-per-user--32protection
--rate-limit-ip, --rate-limit-userKDB_RATE_LIMIT_IP, KDB_RATE_LIMIT_USERrate_limit_ip, rate_limit_user0 (no limit)rate limits
--safe-updates--offprotection
--read-only--offprotection
--standby-of, --standby-tokenKDB_STANDBY_OF, KDB_STANDBY_TOKEN-offstandby (kdb promote makes it a primary)
--drain-timeoutKDB_DRAIN_TIMEOUT-30s (Docker image: 5s)stopping
--tls-cert, --tls-keyKDB_TLS_CERT, KDB_TLS_KEYtls_cert, tls_keyoffTLS
--tls-requiredKDB_TLS_REQUIRED-onTLS
--audit, --audit-keep-days--on, 0 (keep for ever)audit log
--activity-log-size--5000monitor
--slow-query-msKDB_SLOW_QUERY_MSslow_query_ms1000slow queries
--trash-days--7trash
--trash-max-mbKDB_TRASH_MAX_MBtrash_max_mba quarter of the data, at least 256 MBkdb.conf
-KDB_TRASH_KEEP_HOURStrash_keep_hours1kdb.conf
-KDB_KEEP_VERSIONSkeep_versions2kdb.conf
-KDB_WAL_ARCHIVE_MBwal_archive_mb1024Settings page
-KDB_HTTP_FUNCTIONS, KDB_HTTP_TIMEOUT_MShttp_functions, http_timeout_msoff, 10000calls from SQL
-KDB_WEB_DIR, KDB_HELP_DIR, KDB_SKILL_DIRweb_dir, help_dir, skill_dirnext to kdbfolders
--backupsKDB_BACKUP_DIRbackup_dir_backups in the data folderbackup schedule
--backup-scheduleKDB_BACKUP_SCHEDULEbackup_scheduleoffbackup schedule
--keep-daily, --keep-weeklyKDB_BACKUP_KEEP_DAILY, KDB_BACKUP_KEEP_WEEKLYbackup_keep_daily, backup_keep_weekly7, 4backup schedule
--backup-commandKDB_BACKUP_COMMANDbackup_commandnonebackup command
--backup-copy--nonebackup schedule
--backup-warn-hours--26backup schedule
-KDB_LAZY_OPEN-onkdb serve (start-up)
-KDB_SELF_TUNING_SECONDS-10 (0 = only at start)self-tuning
-KDB_TTL_CHECK_MS-60000how often partitions past their TTL are dropped (100 to 86400000 ms)
-KDB_LEVEL_FROM_HEAP-offmemory limit

Switches for tests and comparisons

These environment variables turn one engine feature off, so its gain can be measured and a wrong answer can be traced to it. The answers stay the same, only slower. Do not set them on a server people use.

VariableTurns off
KDB_CHECKPOINT_BESIDE_WRITERS=offloads (POST /write) going on while a save (checkpoint) writes its files: with it off, every writer waits for the files again
KDB_NO_ZONE_MAPSskipping partitions and blocks by their saved min and max (EXPLAIN)
KDB_NO_COLUMN_MASKbuilding only the columns a query names
KDB_NO_SYMBOL_PRUNINGskipping partitions that do not hold the symbol asked for
KDB_NO_TIME_SPANScutting a scan to the time range asked for
KDB_NO_PARTITION_ANSWERSanswering count, min, max, sum from saved partition stats
KDB_NO_LATEST_PARTITIONSLATEST ON read from the newest partition of each symbol
KDB_NO_NEWEST_FIRSTORDER BY time DESC LIMIT n reading the newest partitions first
KDB_NO_TEXT_KEYSGROUP BY a STRING column in the column engine
KDB_NO_VECTOR_EXPR, KDB_NO_VECTOR_CASE, KDB_NO_VECTOR_DISTINCTa + b between columns, sum(CASE WHEN ...) and count(DISTINCT col) in the column engine
KDB_NO_UNION_PUSHDOWNgrouping each part of a UNION ALL on its own (limits)
KDB_NO_VIEW_PUSHDOWNmoving a WHERE into a view
KDB_NO_SUBQUERY_STREAMstreaming the rows of a subquery into the grouping
KDB_NO_JOIN_LOOKUPa join done by key lookups
KDB_NO_JOIN_PLACESa hash join that points at the joined table's rows instead of copying them
KDB_NO_KEY_STRETCHnarrowing a scan to the keys an index found
KDB_NO_POST_WINDOW_FILTER, KDB_NO_WINDOW_TOP_PER_KEY, KDB_WINDOW_NO_FAST, KDB_WINDOW_NO_VECTOR_SCANthe fast paths of window functions
KDB_NO_INSERT_STREAM, KDB_NO_INSERT_RUNS, KDB_NO_INSERT_APPLYINSERT ... SELECT writing while it reads, keeping rows as columns, and applying batches before the commit (memory limit)
KDB_NO_BATCH_DEDUPthe batch key check of loads into a DEDUP KEY table (dedup)
KDB_NO_FOREIGN_PUSHrunning a SELECT of another database's tables in that database (cross-database queries)
KDB_NO_VECTOR_PRESELECTthe column engine finding the rows of a row-engine read of a small table (a SELECT or INSERT ... SELECT that works out values per row)
KDB_NO_PREFETCHreading a partition file's columns several at once from a slow disk (a Windows folder mounted into Docker)
KDB_MV_NO_DEFERwaiting with the refresh of a materialized view while its table takes a bulk load (views)

Syntax:

KDB <version>
  console   http://127.0.0.1:9900
  help      not installed (...)          (only when the help pages are missing)
  postgres  127.0.0.1:8832 (...)
  data      <folder> (from --data-dir | kdb.conf | KDB_DATA_DIR | program folder; one folder per database)
  default   <name> (used when a request names no database)
  backups   <dir>/<database name> (from --backups | kdb.conf | KDB_BACKUP_DIR | default) | off (...)
  copy      after each backup: <command> (from ...)   (only with a backup command)
  access    no token | token required | login required (N users)
  commits   synced to disk before they are confirmed | synced every 10 ms
  readers   read while a long trigger or CALL writes (--reader-yield on); idle open transaction rolled back after 30 s (default)
  memory    3.00 GB for the whole process (--memory-limit); table data 1.00 GB of it (--memory)
  cpu       2 CPUs of the machine's 16 (cgroup v2 cpu.max 2.00); 1 query thread (half of the CPUs, follows the limit), limits checked every 10 s
  limits    statement timeout 60s, result memory 1.00 GB, 5000000 groups, 32 statements per user
  safety    writes allowed; DROP TABLE kept 7 days (UNDROP TABLE); audit log on (SHOW AUDIT)
  schedule  backups daily 16:00, next ...        (only with --backup-schedule)
  recovery  manifest copy: a, last shutdown: clean
Press Ctrl+C to stop.
LineMeaning
consoleOpen this address in a browser for the web console. The help is at /help. When the console files are missing, a second line says so; the page at this address lists the folders KDB looked in (folders).
helpOnly when the help pages are not installed: build them with node tools/help/build_help.mjs and put them next to the program as help/
postgresThe PostgreSQL port and how to log in there. Not shown with --pg-port 0.
dataThe data folder and where its name came from, or the one folder served
defaultThe database used when a request names no database
backupsWhere BACKUP DATABASE writes and where that came from, or off
copyOnly with a backup command: what runs after each backup
accessno token, token required, or login required (N users)
commits--sync-commits always or batch
readersWhether a SELECT waits for a long trigger or CALL (reader yield), and after how long an idle open transaction is rolled back (idle transactions)
memoryThe memory limit and where it came from, and the table data share (--memory). Without a limit: no limit for the whole process. A warning line follows when --memory is more than 60% of the limit.
cpuThe CPUs the process may use and what decided it (the machine's, a container's cgroup v2 cpu.max, cgroup v1 cpu.cfs_quota_us, affinity, or a Windows job object CPU rate), and the query threads chosen from it (self-tuning)
pinningWith --pin-threads on, or with auto inside a CPU quota: the CPUs the threads are pinned to, out of the CPUs the process may run on, or why nothing was pinned (pinning threads)
limits, safetyThe protection settings in force
scheduleOnly with --backup-schedule: the schedule and the next run (backup schedule)
recoveryWhat happened when the default database opened: last shutdown: clean, or not clean (crash or kill) and how many log records were replayed. Repaired or damaged files are listed here too.

Command line: A data folder with users

kdb user add admin --role admin
> Long-Admin-Passw0rd
kdb serve

Output:

> kdb user add admin --role admin

user 'admin' added with role admin in ./kdb-data

> kdb serve

KDB 0.2.0-dev
  console   http://127.0.0.1:9900
  data      ./kdb-data (from KDB_DATA_DIR; one folder per database)
  default   default (used when a request names no database)
  backups   ./kdb-data/_backups/<database name> (from default)
  access    login required (1 user)
  capacity  32 HTTP threads (default), 500 PostgreSQL connections (default), lock wait 5 s (default)
  lanes     reads using 100 ms of CPU (three times in a row) wait for one of 16 heavy slots, at most 16 HTTP in line (--lanes on)
  reads     32 reads run at once (the CPUs, at least 2; follows the CPU limit), the rest wait in line (--read-slots)
  commits   synced to disk before they are confirmed (--sync-commits always)
  time zone Asia/Katmandu (the computer's); also timers and backup schedules
  readers   read while a long trigger or CALL writes (--reader-yield on); idle open transaction rolled back after 30 s (default)
  memory    26.95 GB for the whole process (85% of the machine's memory); table data 512.0 MB of it (--memory)
  cpu       32 CPUs (the machine's); 16 query threads (half of the CPUs, follows the limit), limits checked every 10 s
  limits    statement timeout 1 min, result memory 1.00 GB, 5000000 groups, 32 statements per user
  safety    writes allowed; DROP TABLE kept 7 days (UNDROP TABLE); audit log on (SHOW AUDIT)
  logs      slow queries >= 1000 ms to ./kdb-data/_logs/slow_queries.jsonl; pg_stat_statements on; metrics at /metrics
  recovery  the default database is created when it is first used

Press Ctrl+C to stop.

Self-tuning to the CPU and memory limits

Inside docker run --cpus=1 a program still sees every core of the host. KDB reads the real limits instead, and sizes itself from them:

LimitWhere KDB reads itWhat follows it
CPUsLinux: cgroup v2 cpu.max (also a parent cgroup's), else cgroup v1 cpu.cfs_quota_us; the CPUs the process may run on (--cpuset-cpus). Windows: the affinity mask and a job's CPU rate cap. --cpus=1.5 counts as 2.query threads (half of the CPUs, at least 1), and so every parallel scan, sort, load and index build; HTTP threads at start
Memorycgroup v2 memory.max, cgroup v1 memory.limit_in_bytes, a Windows job's memory limitthe memory limit (85%), and with it the unsaved-changes share that forces a checkpoint (a quarter). At start also the result cache (at most a tenth of the limit) and, without --memory, the table data (at most 40%).

Pinning threads to CPUs

auto (the default, Linux): a container started with docker run --cpus=2 on a 32-core host gets two cores' worth of time in every period, but its threads may run on all 32 cores. KDB has a thread per PostgreSQL connection, 8 HTTP workers and the query threads, so 32 clients ran 32 threads at once on 32 cores: they spent the two cores' time in a fraction of the period, then every thread stood still for the rest of it, and while they ran they met on every shared lock. Measured (2026-10-04, a 0.1 ms key lookup over the PostgreSQL port from 32 connections): 5,965 requests a second that way, 39,000 when the same server was kept on two cores with taskset. So inside a CPU quota smaller than the CPUs the process may run on, KDB pins all its threads to the quota's worth of CPUs:

on: the kernel moves a busy thread from core to core, and each move leaves the CPU cache it had warmed behind. --pin-threads on (or KDB_PIN_THREADS=on) keeps KDB's threads in place:

ThreadsWhere they run
HTTP workers, PostgreSQL connections, query threadsone CPU each, taken in turn
the checkpoint thread, timer jobs, the backup scheduleany of the pinned CPUs

Both:

Priority lanes

On a server with one or two CPUs, a few heavy reports (a big GROUP BY over all rows) take the whole processor, and a chart that answers in 2 ms alone takes 30 to 60 ms. Priority lanes stop that. Every statement goes into one lane before it runs:

LaneWhich statementsWhat happens
fasta statement whose shape ran in under 20 ms last time; anything with priority highruns at once
normala shape not seen yet, writes, BEGIN, SET, SHOW, and everything betweenruns at once
heavya read (SELECT, WITH, VALUES, EXPLAIN) whose shape used --heavy-ms of CPU or more the last three times it ran; anything but BEGIN, COMMIT, SET and SHOW with priority lowwaits for a heavy slot, first come first served, then runs at a lower CPU priority

Choose a lane by hand:

HowWhere
SET kdb.priority = high | normal | lowa PostgreSQL connection or an HTTP session; RESET kdb.priority goes back; SHOW kdb.priority shows the one in use
X-KDB-Priority: high | normal | lowone HTTP request
ALTER USER reports SET kdb.priority = lowevery statement of that user (admin only; RESET kdb.priority takes it away)

Measured (2026-09-25, Windows, the process pinned to 2 CPUs and then 1, bench/lanes.mjs): a candle page of 300 bars every 10 ms while 4 clients ran a GROUP BY over 4 million rows back to back (about 0.5 s each alone). Times of the candle page:

CPUsp50p95p99reports finished in 20 s
2alone1 ms2 ms4.3 ms-
2with the reports, before lanes1.5 ms34.7 ms64 ms100
2with the reports, lanes on0.9 ms2.1 ms5.8 ms57
1alone3.6 ms13.6 ms18.6 ms-
1with the reports, before lanes24 ms109 ms170 ms44
1with the reports, lanes on3.9 ms13.1 ms14.5 ms43

Judged by CPU time over three runs (the default since 2026-09-25, --heavy-ms 100), the same test gave a candle p95 of 2.0 to 2.4 ms on 2 CPUs (63 to 65 reports) and 1.8 ms on 1 CPU (53 reports), with 1.7 to 2.1 ms alone. The charts stay as fast as alone. On 2 CPUs the reports take turns on one of them, so fewer finish while charts are served; --heavy-slots 2 let 69 through, but the chart p99 went to 10 ms. The 1-CPU run was on a busier machine, so its "alone" numbers are higher.

See it: lanes in GET /api/stats (slots in use, how many wait, the waits since start per lane), the Lanes card of the Monitor, and lane / waiting on each running statement. A waiting statement shows Lane / heavy queue in pg_stat_activity.wait_event_type / wait_event.

Read slots

Since 2026-10-02, reads run at most --read-slots at a time (by default as many as the CPUs the process may use, at least 2). The rest wait in line, first come first served, and each read that ends lets the next one in.

Why: a container limited with docker update --cpus 2 still sees every core of the machine. With 30 clients, 30 reads ran at once on 30 cores until the 2-CPU budget was spent, and they spent most of that budget waking each other up on shared locks instead of reading. Taking turns does the same work with a quarter of the CPU.

StatementTakes a read slot?
a read (SELECT, WITH, VALUES, EXPLAIN) in the fast or normal laneyes
a read inside BEGIN ... COMMITno: it may hold tables a running read needs
a write, CALL, DDL, BEGIN, SET, SHOWno
a read sent with priority highno
a heavy readno: it has its own heavy slots

Measured (2026-10-02, Linux build in WSL, the process limited to 2 CPUs with a CPU quota as docker --cpus 2 does, 32 HTTP threads as the container has; 523,233 day candles of 544 symbols; 006's day-candle mix: last 500 bars, SAMPLE BY 7d last 300, SAMPLE BY 1M last 200, the whole history; result cache off). Requests a second:

Clients1102550100200
before1,0851,303592464469500
read slots1,7343,0352,6302,6852,2852,526

The CPU per request fell from 4.4 ms to 0.75 ms at 50 clients. Over the PostgreSQL port at 50 clients: simple queries 1,042 -> 2,682 a second, prepared statements 514 -> 2,253.

Memory limit for the whole process

Syntax:

kdb serve --memory-limit 3GB        (or 3072 = megabytes; 0 or off = no limit)
KDB_MEMORY_LIMIT=3GB                (the environment; the flag wins)

--memory limits only the table data kept loaded. Unsaved changes, indexes, the rows of running queries and what the allocator keeps come on top. --memory-limit is one limit for all of it, so the server slows down or refuses work instead of being killed.

KDB looks ten times a second at two numbers: the bytes its objects hold (the heap) and what the system says the process holds (resident). The larger one is in use, so memory the allocator keeps after a free counts too:

LevelWhenWhat happens
greenunder 80% of the limitnothing
yellow80% to 95%memory is given back: on Linux freed memory goes back to the system first, then loaded partitions are unloaded (idle databases first), then kept query results (the result cache) when that was not enough
red95% and overalso: a quick statement runs at once in a small reserve; any other new statement waits up to 2 s for memory, then fails with memory full: ...

Command line: A 3 GB limit for everything, 1 GB of it for table data (sample data: sample)

kdb serve ./market --memory 1024 --memory-limit 3GB

Output:

KDB 0.2.0-dev
  console   http://127.0.0.1:9900
  data      ./market
  backups   ./_backups/market (from default)
  access    no token
  capacity  32 HTTP threads (default), 500 PostgreSQL connections (default), lock wait 5 s (default)
  lanes     reads using 100 ms of CPU (three times in a row) wait for one of 16 heavy slots, at most 16 HTTP in line (--lanes on)
  reads     32 reads run at once (the CPUs, at least 2; follows the CPU limit), the rest wait in line (--read-slots)
  commits   synced to disk before they are confirmed (--sync-commits always)
  time zone Asia/Katmandu (the computer's); also timers and backup schedules
  readers   read while a long trigger or CALL writes (--reader-yield on); idle open transaction rolled back after 30 s (default)
  memory    3.00 GB for the whole process (--memory-limit); table data 1.00 GB of it (--memory)
  cpu       32 CPUs (the machine's); 16 query threads (half of the CPUs, follows the limit), limits checked every 10 s
  limits    statement timeout 1 min, result memory 1.00 GB, 5000000 groups, 32 statements per user
  safety    writes allowed; DROP TABLE kept 7 days (UNDROP TABLE); audit log off
  logs      slow queries >= 1000 ms to ./market/_logs/slow_queries.jsonl; pg_stat_statements on; metrics at /metrics
  recovery  manifest copy: a, last shutdown: clean
  open      opened in 3 ms: manifest 1 ms, 1 files read 0 ms (8 table files left for their first use), log check 1 ms, replay 0 ms (0 transactions), clean-up 1 ms

Press Ctrl+C to stop.

Command line: Too small a limit stops the start

kdb serve --memory-limit 10MB

Output:

error: --memory-limit (or KDB_MEMORY_LIMIT) needs a size of at least 64MB, like 3GB or 3072 (megabytes), or off; not '10MB'

exit code 1

A database far bigger than --memory

A database whose table files are more than 8 times --memory still works, but slowly in ways that look like a fault: a query over much of it, or a write into old partitions, reads the same files again and again. So when such a database opens, KDB says so once:

warning: /data/market: database market is 12.0 GB on disk and --memory is 1.5 GB (8x, shared by all open databases):
expect loads and evictions - queries over much of it, and writes into old partitions, read files again and again
and take seconds. Give KDB more memory: --memory 6144 or more (KDB_MEMORY in Docker); ...

Many databases

Syntax:

kdb serve                         -- every database in the data folder, default 'default'
kdb serve market                   -- every database, default 'market' (a name in the data folder)
kdb serve --db market              -- the same
kdb serve ./market                 -- only this folder

Without a folder path, one server serves every database in the data folder.

Command line: The default database is 'reports'

kdb shell
> CREATE DATABASE reports;
kdb serve --db reports --backups backups

Output:

> kdb shell

KDB 0.2.0-dev shell on default (data folder ./kdb-data)
End statements with ';'. Type .help for commands, .exit to quit.
kdb> database 'reports' created
kdb>

> kdb serve --db reports --backups backups

KDB 0.2.0-dev
  console   http://127.0.0.1:9900
  data      ./kdb-data (from KDB_DATA_DIR; one folder per database)
  default   reports (used when a request names no database)
  backups   backups/<database name> (from --backups)
  access    no token
  capacity  32 HTTP threads (default), 500 PostgreSQL connections (default), lock wait 5 s (default)
  lanes     reads using 100 ms of CPU (three times in a row) wait for one of 16 heavy slots, at most 16 HTTP in line (--lanes on)
  reads     32 reads run at once (the CPUs, at least 2; follows the CPU limit), the rest wait in line (--read-slots)
  commits   synced to disk before they are confirmed (--sync-commits always)
  time zone Asia/Katmandu (the computer's); also timers and backup schedules
  readers   read while a long trigger or CALL writes (--reader-yield on); idle open transaction rolled back after 30 s (default)
  memory    26.95 GB for the whole process (85% of the machine's memory); table data 512.0 MB of it (--memory)
  cpu       32 CPUs (the machine's); 16 query threads (half of the CPUs, follows the limit), limits checked every 10 s
  limits    statement timeout 1 min, result memory 1.00 GB, 5000000 groups, 32 statements per user
  safety    writes allowed; DROP TABLE kept 7 days (UNDROP TABLE); audit log on (SHOW AUDIT)
  logs      slow queries >= 1000 ms to ./kdb-data/_logs/slow_queries.jsonl; pg_stat_statements on; metrics at /metrics
  recovery  manifest copy: a, last shutdown: clean
  open      opened in 1 ms: manifest 0 ms, 0 files read 0 ms, log check 0 ms, replay 1 ms (0 transactions), clean-up 0 ms

Press Ctrl+C to stop.

Stopping the server

Syntax:

Ctrl+C                 -- in the server's window (Windows, Linux, macOS)
kill -TERM <pid>       -- Linux, macOS (systemd: KillSignal=SIGINT or SIGTERM)

Press Ctrl+C in the server's window. The server prints stopping..., finishes its work, closes every database cleanly and prints databases closed cleanly (N ms) (or database closed cleanly for one folder). Then it ends with exit code 0.

# /etc/systemd/system/kdb.service on Linux (not run here)
[Service]
User=kdb
ExecStart=/usr/local/bin/kdb serve --data-dir /srv/kdb/data --backups /srv/kdb/backups
Restart=on-failure
KillSignal=SIGINT
TimeoutStopSec=60

Port in use, database in use

Syntax:

error: Already exists: port 9900 on 127.0.0.1 is already in use
error: the database is open in another program. Stop it first.

kdb serve stops at once when it cannot use the port or the database.

MessageWhyFix
port 9900 on 127.0.0.1 is already in useAnother program (often another kdb serve) listens on that port--port 9901, or stop the other program
Postgres protocol port: ...Port 8832 is in use--pg-port 8833, or --pg-port 0 to turn it off
the database is open in another programA kdb shell, kdb sql or another server has the database openClose it (look for kdb in Task Manager)
--threads needs a number from 1 to NMore threads than half of the CPU threadsA smaller number
--memory needs a number of megabytesNot a number--memory 2048
--memory-limit (or KDB_MEMORY_LIMIT) needs a size of at least 64MBNot a size, or under 64 MB--memory-limit 3GB, or off

Command line: Too many threads

kdb serve --threads 100000

Output:

error: --threads needs a number from 1 to 32 (this computer's CPU threads)

exit code 1