Starting the Database
Start the NukeBase server with configuration options by calling startDB() once at the end of your configuration:
// Basic setup - pass the domain object to startDB
const nukebase = addDomain({
authPath: ["users"],
host: "127.0.0.1", // optional
port: 3000 // optional
});
startDB(nukebase);
addDomain Configuration Options:
- authPath: Array - path to user authentication data (e.g.,
["users"]) - host: String (optional) - the IP address to bind to
- Use "127.0.0.1" to accept connections only from the local machine (default)
- Use a specific IP address like "126.23.45.1" to bind to that server address
- Use "0.0.0.0" to accept connections from any IP
- port: Number (optional) - the port to listen on (default: 3000)
Environment Variables
The server reads these from the environment. Every one has a working default — you normally set none of them.
Deployment
| Variable | Default | Effect |
|---|---|---|
DOMAIN | — | Public origin used to build magic-link URLs and console output (e.g. https://your-app.nukebase.com). |
SOCKET | — | If set, the server listens on this Unix domain socket instead of host/port (useful behind nginx/Caddy). The socket file is created, chmoded to 777, and replaced if it already exists. |
TRUST_PROXY | auto | Peer-only override. See the note below — you almost certainly do not need this. |
DB_ALLOW_MISSING_SPLITS | 0 | Set to "1" to downgrade a missing or corrupt $split subdirectory from a fatal startup error to a logged warning, treating the subtree as empty. Default is fail-fast so a bad disk state can't silently produce data loss on the next flush. |
The client IP is worked out from where the connection came from — there is nothing to configure. A forwarding header (x-real-ip, then x-forwarded-for) is honored only when the peer could plausibly be a proxy you put there:
- Unix socket — no peer address exists, so the header is the only source of a client IP. This is how the managed platform runs.
- Loopback or private address (127.0.0.0/8, ::1, RFC1918, fc00::/7, fe80::/10) — a local proxy. The header is used if present, otherwise the peer.
- Public address — the open internet. The peer address wins and the header is ignored, because a caller on a public port can set and rotate that header themselves.
This replaced an earlier TRUST_PROXY flag that had exactly one correct value per deployment and no way for anyone to know which. Setting TRUST_PROXY="false" or "0" still forces the peer address unconditionally — useful only for a topology that answers the question wrongly, such as a reverse proxy on another host reaching the engine over a public address. Any other value, including "true", has no effect.
Files
| Variable | Default | Effect |
|---|---|---|
FILES_DIR | server/files | Root of the file store. Nothing outside it is reachable. |
FILE_MAX_BYTES | 67108864 (64 MB) | Hard ceiling on a single file, enforced on the bytes that actually arrive. |
FILE_MAX_DIR_ENTRIES | 10000 | Entries returned by one directory listing before it is truncated. |
FILE_WRITE_RATE_MAX | 120 | Uploads + deletes per IP per minute. |
Limits and capacity
| Variable | Default | Effect |
|---|---|---|
WS_RATE_LIMIT_MAX | 500000 | WebSocket messages per second per connection. Exceeding it sends a rateLimit notice and closes the socket. |
HTTP_MAX_BODY_BYTES | 1048576 (1 MB) | Default body cap for postWithBody handlers. Override per route with { maxBytes }. |
QUERY_MAX_RESULTS | 1000000 | Maximum records one query may return before it is truncated. |
QUERYSUB_MAX_RESULTS | 1000 | Matching records above which a querySub is refused or dropped. |
WINDOW_SUB_SCAN_MAX | 1000 | Collection size above which a windowed subscription requires an index-order plan. |
MAX_QUERY_BUCKETS_PER_PATH | 64 | Distinct query-subscription windows allowed on one path/event/action. |
MAX_TOTAL_INDEX_ENTRIES | 8000000 | Total index entries held across the whole process. |
KEY_INDEX_MIN_RECORDS | 1000 | Collection size at which an automatic $key index becomes worth building. |
Graceful shutdown is automatic. On SIGTERM or SIGINT the server clears its flush timer, writes every dirty subtree to disk, and exits — so a normal restart never loses the last few seconds of writes.