Skip to content

Configuration ​

A node is configured entirely through pico serve flags. There is no server config file. Every flag has a PICO_* environment variable, so container deployments can configure everything through the environment, and a flag always wins over its variable.

bash
pico serve \
    --node-id 2 \
    --listen 0.0.0.0:4437 --http-address http://node2.internal:4437 \
    --meta-url postgres://user:pass@pg:5432/picomq \
    --storage=-2@s3://bucket?region=us-east-1

Identity ​

FlagDefaultPurpose
--node-id1Stable identity in the cluster. Must be unique per node.
--node-epochcurrent time in msFencing token for this process. Leave unset so every restart gets a higher one.
--cluster-idpicomqReported in the admin API, useful when running several clusters.
--slots1Placement weight registered at startup. A node with 4 slots takes four times the streams of a node with 1.

The node id is the one value worth care. Reusing an id for a different machine is safe only after the old one is gone, since the epoch of the new process fences the old.

Listeners ​

FlagDefaultPurpose
--listen127.0.0.1:4437The HTTP stream protocol listener.
--admin-listen127.0.0.1:9090The admin API and dashboard.
--no-adminoffDisables the admin listener entirely.
--http-addresshttp://{listen}The public URL other nodes redirect clients to.
--kafka-listen127.0.0.1:9092The Kafka listener.
--no-kafkaoffDisables the Kafka listener.
--kafka-advertise{kafka-listen}The Kafka address registered in metadata and returned to clients.
--backlog1024Listener accept queue depth.
--shutdown-drain-sec0How long to fail readiness before closing listeners on shutdown.

--protocol is a global flag rather than a serve flag. It selects the HTTP protocol the stream listener speaks, pico or ds. Kafka is a separate listener and is covered on the Kafka protocol page.

--http-address and --kafka-advertise matter in any multi-node deployment. Both are registered in the metadata state and handed to clients verbatim, in redirects for HTTP and in metadata responses for Kafka, so they must be addresses clients can actually reach, not bind addresses. The defaults only work single-node on localhost.

Binding an unauthenticated listener to anything but loopback fails startup unless --insecure-allow-remote deliberately opts out for deployments that bring their own network boundary. For the HTTP listeners, --auth required is the authenticated alternative. The Kafka listener has no authentication, so exposing it always takes the explicit opt-out.

Metadata ​

--meta-url points at the SQL database holding the metadata log. Three forms are accepted.

bash
--meta-url sqlite::memory:                        # tests, throwaway
--meta-url sqlite:./data/meta.db                  # single node
--meta-url postgres://user:pass@host:5432/picomq  # cluster

SQLite is a file, so it works for exactly one node. Every multi-node cluster needs Postgres, and all nodes must point at the same database, which is what makes them one cluster.

Storage ​

--storage is the data bucket in the form bucket-id@uri. The bucket id is the engine's internal identifier and any stable value works, and the URI selects the backend.

bash
--storage=-2@file://./objects                # local filesystem
--storage=-2@s3://bucket?region=us-east-1    # S3 and compatible stores

S3 credentials come from the standard AWS_* environment variables. Compatible stores such as MinIO or RustFS take endpoint and pathStyle parameters on the URI:

bash
--storage=-2@s3://picomq?region=us-east-1&endpoint=http://rustfs:9000&pathStyle=true

--wal selects where the write-ahead log lives.

--walWAL location
absentThe data bucket, under the next bucket id
id@s3://...Its own bucket, for a different storage class or lifecycle rules
postgres://...Tables in a Postgres database

--schema-registry points at a store of named schemas that streams bind and optionally validate against. Unset by default, covered in Schemas.

Postgres WAL ​

bash
--wal=postgres://user:pass@pg:5432/picomq?sslmode=require&batchInterval=1

Query parameters below are consumed by pico. Any other parameter, such as sslmode, is passed to the connection. The Write-ahead log page covers the layout and what each parameter does.

ParameterDefaultPurpose
batchInterval1Milliseconds records accumulate before a batch is inserted.
maxBytesInBatch1048576Batch size that triggers an insert before the interval lapses.
maxInflight4Concurrent batch inserts.
maxUnflushedBytes134217728Acknowledged bytes not yet uploaded to data objects before appends wait.
segments8Slot tables in the ring. At least 2.
segmentBytes67108864Bytes per slot. (segments - 1) * segmentBytes must exceed maxUnflushedBytes.
synchronousCommitonon, remote_write, remote_apply, or local.
allowUnsafefalseStart even when Postgres has fsync = off.

Startup checks: the database must be a primary, fsync must be on unless allowUnsafe=true, and a warning is logged when synchronous_standby_names is empty. The same database can hold both the metadata log and the WAL, which is the layout the Postgres extension uses.

S3 Express One Zone for the WAL ​

The WAL bucket can be an S3 Express One Zone directory bucket while the data bucket stays on standard S3. Express PUTs complete in single-digit milliseconds, so this cuts append acknowledgment latency without changing the data bucket's economics.

A directory bucket is detected automatically from AWS's reserved name suffix ({base}--{zone-id}--x-s3), which switches the client to Express session authentication. The s3Express=true URI parameter forces it explicitly.

bash
--storage=-2@s3://picomq-data?region=us-east-1 \
--wal=-4@s3://picomq-wal--use1-az4--x-s3?region=us-east-1&batchInterval=15

Three things make this setup effective:

  • Lower batchInterval. The default 250 ms batch window exists to amortize standard S3 request costs. Express PUTs are faster and cheaper, so a 10 to 25 ms window turns the latency gain into client-visible acknowledgment latency.
  • Run the node in the bucket's availability zone. The zone is encoded in the bucket name. Cross-zone access works but gives most of the latency win back.
  • Keep the Express residency short. --wal-upload-threshold and --wal-upload-interval-ms control how quickly WAL data compacts out to the data bucket. Express is single-zone storage, so acknowledged records carry that exposure until they land in the standard bucket.

Auth ​

FlagDefaultPurpose
--authoffrequired gates every request on both listeners. off allows loopback binds only.
--insecure-allow-remoteoffPermit non-loopback binds with auth off.
--auth-bootstrap-tokennoneRoot token in wire form, seeded at startup. Idempotent across restarts.
--auth-bootstrap-token-filenoneRead the bootstrap token from a file instead, keeping it out of process listings.

A different token under an already-stored bootstrap id fails startup rather than silently rotating a live credential. Bootstrap, token issuance, and client credentials are covered in Authentication.

Behavior ​

FlagDefaultPurpose
--routingredirectredirect sends clients to the owner with 307. local serves everything locally, for single-node setups or a routing proxy in front.
--long-poll-timeout-sec25How long a waiting read parks before returning empty.
--sse-max-duration-sec55Connection cap for SSE, after which the client reconnects.
--max-chunk-size65536Response chunk size for streamed reads.
--max-request-size33554432Cap on a single request body. Oversized bodies get 413.

The two timeouts default below common proxy idle limits. Raise them only if every intermediary between clients and nodes is known to allow longer idle connections.

Engine ​

Four flags override the storage engine defaults: --wal-cache-size, --block-cache-size, --wal-upload-threshold, and --wal-upload-interval-ms. What they trade against each other is covered in Tuning.