Reference
novad reference
Every novad flag, its NOVAD_* environment variable and default, grouped by concern, plus the YAML config file
novad is the serving process (a running one is a star) and, unless told otherwise, also the background auditor. Every setting is a flag with a NOVAD_* environment variable and a YAML key of the same name; this page lists them all, grouped by concern, with defaults copied from novad --help. A default of 0 or 0s means "use the built-in value" named in the meaning column.
novad [global options]Resolution order for every setting: a command-line flag beats its environment variable, which beats the config file, which beats the built-in default. Secret material (S3 secret key, HMAC secrets, passwords, peer tokens, the root secret) should come from the environment or the config file, never from argv, where it is visible in process listings; two of them (--admin-password and --peer-service-token) print no help text for exactly that reason.
Config file and dev mode
| Flag | Env | Default | Meaning |
|---|---|---|---|
--config | NOVAD_CONFIG | — | YAML config file; flags and NOVAD_* env override it |
--dev | NOVAD_DEV | false | Single-process playground: in-memory backends, data vanishes on exit |
--version, -v | — | — | Print the version |
Outside --dev, the process refuses to start without --oxia, --oxia-naming, --s3-bucket, and an identity: --node-id, or --dir to read or mint one.
Serving and limits
The client-plane caps. A request asking for more than a cap is clamped to it; an append exceeding one is refused.
| Flag | Env | Default | Meaning |
|---|---|---|---|
--max-read-bytes | NOVAD_MAX_READ_BYTES | 0 | Bytes cap on one read response's payload; a request's max_bytes clamps to it; zero uses 8 MiB |
--max-read-records | NOVAD_MAX_READ_RECORDS | 0 | Record cap on one read response; a request's limit clamps to it; zero uses 8192 |
--max-record-bytes | NOVAD_MAX_RECORD_BYTES | 0 | Bytes cap on one appended record; zero uses 1 MiB |
--max-batch-bytes | NOVAD_MAX_BATCH_BYTES | 0 | Bytes cap on one append batch's payload total; zero uses 100 MiB |
--max-batch-records | NOVAD_MAX_BATCH_RECORDS | 0 | Record cap on one append batch; zero uses 65536 |
--max-producer-sessions | NOVAD_MAX_PRODUCER_SESSIONS | 0 | Cap on concurrent producer sessions per star; opens past it shed with ResourceExhausted; zero uses 4096 |
--grpc-stream-window-kib | NOVAD_GRPC_STREAM_WINDOW_KIB | 0 | Pin the server's HTTP/2 flow-control windows: KiB per stream (64 minimum, 65536 maximum), 4× per connection. Inbound bytes buffered ahead of the handlers are bounded per stream, so sessions × window is the transport's memory plane; zero pins the 64 KiB protocol floor |
--net-capacity | NOVAD_NET_CAPACITY | 0 | Sustained network capacity in bytes/sec, stamped by the operator: the network saturation axis's denominator; zero leaves the axis off |
--memory-ceiling | NOVAD_MEMORY_CEILING | 0 | Retained-memory budget in bytes, stamped by the operator from the pod limit with margin: the memory saturation axis's denominator; zero leaves the axis off |
Identity and placement
| Flag | Env | Default | Meaning |
|---|---|---|---|
--dir | NOVAD_DIR | — | Directory holding the star's identity file; optional when --node-id pins it |
--node-id | NOVAD_NODE_ID | — | Pin the star's StarID (UUID); default: read or mint <dir>/node-id |
--location | NOVAD_LOCATION | — | Where this star runs (an availability zone in cloud terms): the placement spread label, and the express zone its reads prefer |
--advertise | NOVAD_ADVERTISE | — | Address announced to the fleet; default: the listen address (hostname when unspecified). Clients and the Gateway dial redirect targets verbatim, so it must resolve from their network position |
Listeners and TLS
One gRPC listener serves every plane (data, admin, and peer traffic) under one auth mode and one TLS identity.
| Flag | Env | Default | Meaning |
|---|---|---|---|
--listen | NOVAD_LISTEN | :7780 | gRPC listen address for all services (the advertised address) |
--http-listen | NOVAD_HTTP_LISTEN | — | HTTP address for the data bridge; empty disables it |
--metrics-listen | NOVAD_METRICS_LISTEN | — | HTTP address to serve Prometheus /metrics (also /healthz, /readyz, and the admin UI); empty disables metrics |
--admin-ui | NOVAD_ADMIN_UI | true | Serve the admin dashboard and its read-only JSON bridge at /admin/ on the metrics listener; the whole surface vanishes without --metrics-listen |
--admin-ui-reader | NOVAD_ADMIN_UI_READER | true | Mirror the admin reader's record read on the bridge, the dashboard's one endpoint that returns record bodies; off keeps the metadata dashboard while the authenticated gRPC plane alone serves records |
--tls-cert | NOVAD_TLS_CERT | — | TLS serving certificate; empty serves plaintext |
--tls-key | NOVAD_TLS_KEY | — | TLS private key; required with --tls-cert |
--tls-ca | NOVAD_TLS_CA | — | CA bundle for verifying peers on outbound dials; empty uses the system roots |
--tls-client-ca | NOVAD_TLS_CLIENT_CA | — | CA bundle for verifying client certificates; required by auth mode mtls |
Auth
One mechanism applies to every caller, clients and peers alike. Modes jwt and basic carry credentials on the wire, so they require TLS or an explicit --insecure-auth.
| Flag | Env | Default | Meaning |
|---|---|---|---|
--auth | NOVAD_AUTH | off | Auth for every caller: off, mtls, jwt, or basic |
--insecure-auth | NOVAD_INSECURE_AUTH | false | Explicitly accept credentials over plaintext (TLS terminated elsewhere) |
--jwt-hmac-secret-file | NOVAD_JWT_HMAC_SECRET_FILE | — | Verify tokens against this shared secret (HS256 only); one jwt source exactly |
--jwt-hmac-secret | NOVAD_JWT_HMAC_SECRET | — | The shared secret itself, inline, the diskless variant; secret material, prefer the env |
--jwt-hmac-keys | NOVAD_JWT_HMAC_KEYS | — | Named key set, id:secret comma-separated: the first signs, all verify, minted tokens stamp their kid; rotation is prepend-and-roll; secret material, prefer the env |
--jwt-jwks-url | NOVAD_JWT_JWKS_URL | — | Verify tokens against this JWKS endpoint (asymmetric algorithms only) |
--jwt-oidc-issuer | NOVAD_JWT_OIDC_ISSUER | — | Discover the JWKS from this OIDC issuer (asymmetric algorithms only) |
--jwt-audience | NOVAD_JWT_AUDIENCE | — | Expected aud claim; empty skips the audience check |
--admin-username | NOVAD_ADMIN_USERNAME | — | Basic-auth username; the password comes from NOVAD_ADMIN_PASSWORD or the config file |
--admin-password | NOVAD_ADMIN_PASSWORD | — | Basic-auth password; env or config file only |
--peer-service-token-file | NOVAD_PEER_SERVICE_TOKEN_FILE | — | File holding the token this star presents on peer dials (jwt with a JWKS/OIDC source only) |
--peer-service-token | NOVAD_PEER_SERVICE_TOKEN | — | The token itself; env or config file only |
--root-credential-file | NOVAD_ROOT_CREDENTIAL_FILE | — | nova-generated seed converged into the credential registry at boot |
--root-credential | NOVAD_ROOT_CREDENTIAL | — | The seed's JSON passed inline (holds only the hash), the diskless variant |
--root-key-id | NOVAD_ROOT_KEY_ID | — | The pair form of the root seed: the key id; comes with NOVAD_ROOT_SECRET, the plainest bootstrap for compose runs |
--root-secret | NOVAD_ROOT_SECRET | — | The pair's secret, hashed at boot; secret material, prefer the env |
Validation at startup:
mtlsneeds--tls-client-caand the server pair.jwtneeds exactly one source among--jwt-hmac-secret-file,NOVAD_JWT_HMAC_SECRET,NOVAD_JWT_HMAC_KEYS,--jwt-jwks-url,--jwt-oidc-issuer. With a JWKS or OIDC source the star cannot self-mint its peer credential, so--peer-service-token-file(orNOVAD_PEER_SERVICE_TOKEN) is required.basicneeds--admin-usernameandNOVAD_ADMIN_PASSWORD.- The root credential is one seed: set at most one of
--root-credential-file,--root-credential, or theNOVAD_ROOT_KEY_ID/NOVAD_ROOT_SECRETpair (which come together).
How the modes fit clients and the Gateway is the authentication guide's subject.
Metastore (oxia)
| Flag | Env | Default | Meaning |
|---|---|---|---|
--oxia | NOVAD_OXIA | — | oxia service address (required) |
--oxia-naming | NOVAD_OXIA_NAMING | — | NATURAL-sorted oxia service address for the naming keyspace (required) |
--oxia-session-timeout | NOVAD_OXIA_SESSION_TIMEOUT | 0s | oxia session timeout, the fleet's failure-detection floor: a dead star's leases and liveness survive this long, and failover waits it out; zero uses the client default (15s); keep it above worst-case process stalls |
--oxia-write-window | NOVAD_OXIA_WRITE_WINDOW | 0 | Write batches in flight per oxia shard, pipelined, ordered even across failovers; zero uses the client default (4), one disables pipelining |
--oxia-max-batch-kib | NOVAD_OXIA_MAX_BATCH_KIB | 0 | Byte cap on one oxia write batch in KiB; with one batch in flight per shard this bounds per-star row throughput; zero uses the client default (128) |
--oxia-records-namespace | NOVAD_OXIA_RECORDS_NAMESPACE | — | Namespace for durable records; default: the client default |
--oxia-work-namespace | NOVAD_OXIA_WORK_NAMESPACE | — | Namespace for work queues |
--oxia-ephemeral-namespace | NOVAD_OXIA_EPHEMERAL_NAMESPACE | — | Namespace for ephemerals (liveness, leases) |
Object storage and the Standard write path
| Flag | Env | Default | Meaning |
|---|---|---|---|
--s3-bucket | NOVAD_S3_BUCKET | — | Object storage bucket (required) |
--s3-endpoint | NOVAD_S3_ENDPOINT | — | Custom S3 endpoint (e.g. MinIO); empty uses AWS S3 |
--s3-region | NOVAD_S3_REGION | — | S3 region |
--s3-access-key | NOVAD_S3_ACCESS_KEY | — | S3 access key; leave both keys empty to use the SDK default chain (env, shared config, IAM role/IRSA) |
--s3-secret-key | NOVAD_S3_SECRET_KEY | — | S3 secret key (prefer the env or the config file over argv) |
--s3-path-style | NOVAD_S3_PATH_STYLE | false | Use path-style addressing (MinIO and most non-AWS endpoints) |
--s3-attempt-timeout | NOVAD_S3_ATTEMPT_TIMEOUT | 0s | Cap on one S3 request attempt (e.g. 2s): a straggling attempt is cut at the deadline and transparently retried, sequential hedging for the PUT tail; size it well above the largest routine PUT's p50; zero leaves attempts unbounded |
--s3-bundle-size-mib | NOVAD_S3_BUNDLE_SIZE_MIB | 0 | Pooled payload MiB at or above which a Standard bundle flushes immediately; zero uses 8; bigger bundles amortize PUT cost, smaller ones cut time-to-durable |
--s3-bundle-batch-interval | NOVAD_S3_BUNDLE_BATCH_INTERVAL | 0s | Deadline no pooled Standard byte waits past before its bundle flushes regardless of size; zero uses 200ms, the ack-latency bound at low traffic |
--s3-parallel-uploads | NOVAD_S3_PARALLEL_UPLOADS | 0 | Pipelined Standard slot PUTs per star; acknowledgements stay ordered regardless; zero uses 128 |
--s3-memory-buffer-mib | NOVAD_S3_MEMORY_BUFFER_MIB | 0 | MiB of appends pooled but not yet flushed on the Standard write path before producers block; zero uses 256, the admission buffer that absorbs bursts between flushes |
--s3-chain-backlog-flights | NOVAD_S3_CHAIN_BACKLOG_FLIGHTS | 0 | Flights the Standard chain may hold un-absorbed (the backlog budget); appends block at the bound until the absorb's checkpoint catches up. Bounds leader tail memory, takeover settlement time, and chain storage together; zero uses 1024 |
Express
A non-empty bucket set enables the Express class on this star. Zone labels match the stars' --location spelling; when a label is an AZ id (use1-az4) it must match the id embedded in its directory bucket's name, and directory buckets refuse path-style addressing.
| Flag | Env | Default | Meaning |
|---|---|---|---|
--s3-express-buckets | NOVAD_S3_EXPRESS_BUCKETS | — | Express bucket set as comma-separated zone=bucket pairs (one per AZ); non-empty enables Express, whose reads prefer the zone serving this star's --location |
--s3-express-ack-quorum | NOVAD_S3_EXPRESS_ACK_QUORUM | 0 | Express bucket copies that must confirm before an append acks; zero uses 2 |
--s3-express-publish-deadline | NOVAD_S3_EXPRESS_PUBLISH_DEADLINE | 0s | Deadline for an express flight to confirm its copy quorum; past it appends fail fast and producers retry; zero uses 2s |
--s3-express-parallel-uploads | NOVAD_S3_EXPRESS_PARALLEL_UPLOADS | 0 | Concurrent express bundle PUTs (at most 256); each fans to every bucket in the set; zero uses 16 |
--s3-express-memory-buffer-mib | NOVAD_S3_EXPRESS_MEMORY_BUFFER_MIB | 0 | MiB of bundle bytes buffered for express fanout before admission blocks (at most 16384); zero uses 32 |
Absorb and the tail window
| Flag | Env | Default | Meaning |
|---|---|---|---|
--absorb-fanout | NOVAD_ABSORB_FANOUT | 0 | Concurrent per-stream metadata commits the absorb fans across a batch (refs, covering segments, liveness); the absorb's drain rate at high stream density scales with it, bounded so one star's bursts cannot monopolize the shared metastore; zero uses 4096 |
--absorb-pass-interval | NOVAD_ABSORB_PASS_INTERVAL | 0s | Pacing floor on the absorb pass cadence (e.g. 5s): released flights pool behind it and one paced pass commits the window, amortizing each stream's metastore ops to one per interval, at the cost of that much absorb lag (non-leader read visibility, failover settlement). A publish stalling on the backlog budget breaks the floor. Zero absorbs on every release |
--tail-window-cache-mib | NOVAD_TAIL_WINDOW_CACHE_MIB | 0 | MiB of acked flight payloads the leader retains in memory (the tail window cache), serving hot reads without object storage until the absorb's checkpoint retires them; one budget shared across every class; zero uses 128 |
Auditor and reclamation
The auditor runs embedded in every star by default. --audit-only runs the same image as a reclamation pod with no serving plane and no star registration; --no-audit turns it off on a serving star. Setting both is a configuration error. Sizing guidance is in auditor tuning.
| Flag | Env | Default | Meaning |
|---|---|---|---|
--no-audit | NOVAD_NO_AUDIT | false | Disable the background auditor on this star |
--audit-only | NOVAD_AUDIT_ONLY | false | Run only the background auditor: no engine, no serving plane, no star registration |
--auditor-s3-budget | NOVAD_AUDITOR_S3_BUDGET | 0 | Background object-store requests per second the auditor may issue; the settle rewrite moves every transit byte the write path commits, so size this to sustain ingest or the rewrite backlog ages; zero uses 50 |
--auditor-rewrite-mib | NOVAD_AUDITOR_REWRITE_MIB | 0 | MiB per second the auditor's rewrites may move through this star: bytes assembled by ranged GETs and re-PUT (server-side copies are free of it); size it with the S3 budget to sustain ingest; zero uses 64 |
--auditor-workers | NOVAD_AUDITOR_WORKERS | 0 | Concurrent background reclamation jobs (rewrites, teardown walks, GC): the throughput dial for metastore-latency-bound work; zero uses 2 |
--auditor-markers-per-era | NOVAD_AUDITOR_MARKERS_PER_ERA | 0 | Ripe batch markers one dispatched settle job gathers as an era: a contiguous run of one chain's slots whose bundles each download once for every stream they carry; zero or one settles one marker per job |
--auditor-member-parallel | NOVAD_AUDITOR_MEMBER_PARALLEL | 0 | Concurrent member settles inside one batch walk; a chain's era runs as one job, so serial member latency would cap its settle rate below the chain's production rate; zero uses 8 |
--auditor-fetch-cache-dir | NOVAD_AUDITOR_FETCH_CACHE_DIR | — | Scratch directory enabling the settle's whole-object fetch cache: each transit bundle downloads once and every consumer reads the file, replacing per-extent ranged GETs. Startup wipes the directory's contents: point it at dedicated scratch (a Kubernetes emptyDir), never at data; empty keeps the per-range strategy |
--auditor-fetch-cache-mib | NOVAD_AUDITOR_FETCH_CACHE_MIB | 0 | MiB of scratch the fetch cache may keep resident; a read the budget cannot admit falls back to a ranged GET; zero uses 40960 |
--auditor-fetch-parallel | NOVAD_AUDITOR_FETCH_PARALLEL | 0 | Concurrent background downloads warming the fetch cache; zero uses 64 |
--auditor-orphan-grace | NOVAD_AUDITOR_ORPHAN_GRACE | 0s | Age before an unresolved write intent is judged, and the bound the teardown's final walk waits out; zero uses 1h; keep it above the slowest legitimate commit |
--auditor-read-grace | NOVAD_AUDITOR_READ_GRACE | 0s | Reader-safety window between an object's last tombstone and its physical delete; zero uses 10m; keep it above twice any reader's cached-footer lifetime |
Object cache
A non-empty instance list routes the serving lane's cold reads and the audit lane's deletes through the shared object cache; every failure falls back to the direct client. A contradictory cache config refuses to boot rather than silently serving zero hits.
| Flag | Env | Default | Meaning |
|---|---|---|---|
--object-cache-instances | NOVAD_OBJECT_CACHE_INSTANCES | — | Comma-separated object-cache instance base URLs (http://host:port; cached traffic is plain HTTP); empty keeps all requests direct |
--object-cache-load-factor | NOVAD_OBJECT_CACHE_LOAD_FACTOR | 1.25 | Bounded-load ceiling over the mean in-flight claims per instance; a hot key spills its overflow to the next instance at the ceiling; must exceed 1 |
--object-cache-connect-budget | NOVAD_OBJECT_CACHE_CONNECT_BUDGET | 1s | Dial budget for one cache attempt; a breach charges the instance and the request goes direct |
--object-cache-first-byte-budget | NOVAD_OBJECT_CACHE_FIRST_BYTE_BUDGET | 5s | Request-to-first-byte budget for one cache attempt, sized above direct-S3 p99 so S3's own slowness is not misread as a sick instance; a breach charges the instance and the request goes direct |
Read plans
| Flag | Env | Default | Meaning |
|---|---|---|---|
--readplan-vending | NOVAD_READPLAN_VENDING | — | How read plans vend settled-object locations: presigned (short-lived URLs; needs the store's presign capability; the default when empty) or raw (bucket + key for trust-domain consumers fetching under their own storage identity) |
--readplan-ttl | NOVAD_READPLAN_TTL | 0s | Read-plan validity: presigned URL expiry, and the advisory fetch bound for raw consumers; zero uses 5m; must be at most half the auditor read grace |
Settle timing
The two timers that bound how long a committed byte stays in transit form before it settles into a per-stream object: the linger after a stream crosses the size trigger, and the per-class age cap.
| Flag | Env | Default | Meaning |
|---|---|---|---|
--denorm-output-cap-mib | NOVAD_DENORM_OUTPUT_CAP_MIB | 0 | MiB cap on one settle output object; an over-cap transit window splits at row boundaries; zero uses 256 |
--denorm-linger | NOVAD_DENORM_LINGER | 0s | Delay from a Standard stream crossing the size trigger to its settle round; it batches crossings so outputs grow past the trigger; zero uses 5m |
--denorm-age-cap | NOVAD_DENORM_AGE_CAP | 0s | Hard bound on a Standard-class byte's transit residency before its batch settles; zero uses 24h |
--express-denorm-linger | NOVAD_EXPRESS_DENORM_LINGER | 0s | The size-trigger linger for Express streams; zero uses 5m |
--express-denorm-age-cap | NOVAD_EXPRESS_DENORM_AGE_CAP | 0s | Hard bound on an Express-class byte's transit residency; express storage bills for the transit window, so keep this short; zero uses 1h |
Drain and shutdown
The first SIGTERM or SIGINT starts the exit drain (leadership handed off within the budget), then close. A second signal cuts the drain and goes straight to close; a third is the OS default and kills the process. Size the supervisor's kill deadline above the exit-drain budget plus the close guard (the compose stack allows 75 s).
| Flag | Env | Default | Meaning |
|---|---|---|---|
--drain-session-grace | NOVAD_DRAIN_SESSION_GRACE | 30s | How long in-flight work gets to finish after a drain starts: producer sessions before leadership hands off, background jobs before they are cut |
--exit-drain-budget | NOVAD_EXIT_DRAIN_BUDGET | 30s | Hard bound on the exit drain: the leadership shed a stop signal runs before close |
--shutdown-on-stdin-close | NOVAD_SHUTDOWN_ON_STDIN_CLOSE | false | Shut down when stdin reaches EOF; a supervisor closes the pipe on its own death, so the daemon never outlives its parent |
Logging
Logs are JSON on stderr. Levels follow one rule: Info is lifecycle edges and the periodic star summary, Debug is per-connection and per-job lines, Warn and Error are failures. See observability.
| Flag | Env | Default | Meaning |
|---|---|---|---|
--log-level | NOVAD_LOG_LEVEL | info | debug, info, warn, or error; an unparseable level falls back to info |
--log-summary-interval | NOVAD_LOG_SUMMARY_INTERVAL | 1m0s | How often the star summary line (leaders, sessions, append/read MiB/s, backlog age, state flags) is logged; zero disables it |
The YAML config file
--config (or NOVAD_CONFIG) names a YAML file whose keys are the flag names without the leading dashes: listen, s3-secret-key, no-audit, auditor-markers-per-era. Durations are Go duration strings (2m, 1h30m), booleans are true/false. A key the file leaves out takes the env or the built-in default; a flag or NOVAD_* variable always overrides the file, which is how one shared file serves a whole fleet while each star sets its own --advertise and --location, and an audit pod overrides the file's no-audit: true with --audit-only --no-audit=false on its own command line.
dir: /data
listen: ":7780"
http-listen: ":7788"
metrics-listen: ":9090"
oxia: oxia:6648
oxia-naming: oxia-naming:6648
s3-bucket: nova
s3-endpoint: http://minio:9000
s3-region: us-east-1
s3-path-style: true
s3-access-key: nova
s3-secret-key: novatest # or NOVAD_S3_SECRET_KEY in the environment
s3-express-buckets: az-1=nova-exp-az1,az-2=nova-exp-az2,az-3=nova-exp-az3
auth: jwt
jwt-hmac-secret-file: /etc/nova/hmac.key
root-credential-file: /etc/nova/root-seed.json
auditor-orphan-grace: 2m
auditor-read-grace: 2m
readplan-ttl: 1m # at most half the read grace
auditor-markers-per-era: 256
object-cache-instances: http://objectcache-0:3128,http://objectcache-1:3128
log-level: infoThen per star, on the command line or in its environment:
NOVAD_CONFIG=/etc/nova/nova.yaml NOVAD_LOCATION=az-1 NOVAD_ADVERTISE=novad-1:7780 novadNote the file above puts the S3 secret in YAML for illustration; the file is a secret-bearing artifact then and needs the permissions to match. Prefer NOVAD_S3_SECRET_KEY, NOVAD_JWT_HMAC_SECRET, NOVAD_ADMIN_PASSWORD, NOVAD_PEER_SERVICE_TOKEN, and NOVAD_ROOT_SECRET from a secret store when the platform offers one.
Source documents
cmd/novad/main.go: flag binding and the signal ladderinternal/daemon/config.go:Config, defaults, and validationdeploy/docker/docker-compose.yml: the compose stack's real flag set