The core server component of Apache Iggy: a persistent, append-only log for message streaming. It runs thread-per-core and shared-nothing on io_uring (through compio), and commits every write through Viewstamped Replication (VSR), so the same binary serves a standalone node and a multi-node cluster.
Clients connect over TCP (custom binary protocol), QUIC, WebSocket, or the HTTP REST API.
cargo run --bin iggy-server --release
Missing or empty storage is initialized automatically. Existing incompatible storage is refused without modification. --fresh deletes existing data in the configured system path and must be an explicit reset, never a restart default. A new cluster starts automatically when its metadata WAL and superblock are absent. A node with retained metadata rejoins through recovery. Loss of a replica's entire metadata directory is outside the automatic recovery guarantee, including loss on every replica. Empty metadata cannot distinguish a new cluster from a previously used one. Restore a verified consistent backup through a validated recovery procedure before restarting erased metadata disks.
The Docker image apache/iggy:latest ships the server together with the CLI; the edge tag tracks the latest development build.
The image binds every listener to 0.0.0.0 so the container is reachable from outside it. A wildcard bind says which interfaces accept connections, not where a client reaches the server, so the address to publish in cluster metadata has to be supplied and the server refuses to start without it. On a single host with published ports that address is localhost:
docker run -p 3000:3000 -p 8090:8090 \ -e IGGY_NODE_ADVERTISED_ADDRESS=localhost apache/iggy:latest
Use the hostname or load balancer address clients actually dial when they are not on the same host. The Helm chart derives it from the Service DNS name.
To run one node of a cluster, pass its replica ID from the cluster.nodes roster:
cargo run --bin iggy-server --release -- --replica-id 0
Command-line arguments include --replica-id, --fresh (-f), --with-default-root-credentials, and --list-config-env-vars. Other settings come from configuration.
Deploy matching server and SDK releases together. Rolling upgrades and mixed server versions are unsupported. Partition control frames from older servers carry incarnation zero and are rejected, so a mixed-version cluster cannot complete partition view changes. The IGGY-OWNERSHIP-HISTORY-5 storage gate also rejects older data directories without modifying them. Existing data requires a separately validated offline migration or restore procedure before this release can use it.
Cluster metadata includes replica_id. Java‘s ClusterNode record adds a leading replicaId component, changing constructor calls and record patterns. C# callers must initialize the required ReplicaId property. The CLI’s cluster metadata list appends a replica ID column. Swift‘s ClusterNode initializer now requires replicaID. C++‘s FFI ClusterNode, Rust’s iggy_common::ClusterNode and iggy_binary_protocol::responses::system::ClusterNodeResponse add the public replica_id field; update aggregate and struct initializers. Go, Java, Node.js and C# clients use command 105’s new partition routes and refresh on NotPrimary (89); use their matching releases.
Settings are read from config.toml, resolved relative to the working directory. Set IGGY_CONFIG_PATH to load a different file.
Any single value can be overridden with an IGGY_-prefixed environment variable that mirrors the TOML path:
IGGY_TCP_ADDRESS=127.0.0.1:8090 IGGY_HTTP_ENABLED=false cargo run --bin iggy-server
Cluster membership, quorum and replica addressing live under [cluster].
Protocol 0.11.1 uses client-owned registration proofs and BindSession (15) to share a logical session across connections. Command 14 is retired. Primary polling uses commands 103 and 104; offset routing uses 123. Disconnecting a connection does not log out its logical session. Server-observed activity renews the session lease, and expiry or explicit logout retires it before capacity is reused.
External group offsets belong to groups managed outside Iggy, such as a Kafka gateway. They require no Iggy group membership and can exceed the partition's message-offset range.
The bind proof is an independent session credential. Password changes and PAT revocation or expiry do not end an established session. Binding checks that the owner still exists and is active; current permissions still govern each request. Explicit logout, lease expiry and user deactivation end session access.
clients_table_max and dedup_clients_max nominate immutable limits when the first operation commits in each metadata or partition group. Recovery and state transfer preserve those committed limits. Configuration changes affect groups that have not committed a limit yet; existing groups log a mismatch and retain their committed capacity. At capacity, new sessions or writers are refused until ordered retirement releases slots. Live retry protection is never evicted.
HTTP writes using one session and partition serialize through the previous write‘s reply or bounded deadline. With ack=none, a request returns 202 after its dispatch, while the next request to that partition waits for the previous write to settle. Waiters acquire the in-flight permit after the partition gate, so they do not consume the session’s budget for other partitions.
Durability defaults remain Replicated, and ordinary SDK sends and explicit offset writes support the configured policy. Crash-safe send retries require Persisted; crash-safe explicit offset retries require Persisted and Quorum. Weaker policies can lose data and receipts on a crash. A retained receipt still replays its original result, but a lost receipt cannot prevent another execution. NoAck and internal auto-commit polls retain their weaker completion contracts.
Topics have an immutable partition_resize_policy creation option. The default, mutable, permits partition addition and deletion without a bounded cutover or per-key ordering across partition layouts. fixed rejects both operations with PartitionResizeDisabled (2023). Existing messages stay in their original partitions. Neither policy prevents retention or deletion of the topic. Set the option through TopicCreateOptions::partition_resize_policy, HTTP‘s options map, or the CLI’s --set partition_resize_policy=fixed.
This release changes protocol and storage formats. Servers and compatible clients deploy together; mixed versions and rolling upgrades are unsupported. Peers verify protocol, release and storage-format identity before admission. Executable packaging does not affect that identity, so stripping or rebuilding the same compatible release does not by itself prevent a replica from joining.
This checkout uses development protocol 0.11.1. Finalize its version and minimum before the next stable release. Released server-0.9.0 uses protocol 0.11.0 and accepts every 0.11.x patch. An incompatible release therefore needs a new minor protocol version, such as 0.12.0, for that released server to reject new clients before decoding their login.
The protocol number is independent of server and SDK package versions. Its current and minimum values are maintained manually for stable releases. The client login gate checks the full inclusive range, including patch versions. Both bounds stay equal unless compatibility with older released protocols is explicitly supported. Edge builds require matching clients and servers, even when their protocol numbers match.
An unsupported data directory is refused before WAL scanning or file changes. Replacing the binary does not migrate old data. Restore or migrate retained data only through a separately verified procedure; copying a format marker is not a migration.
Partition recovery refuses a superblock whose nonzero log_view is below the partition's committed created_view. It also refuses a WAL certificate with a nonzero log_view below that floor. The log names the superblock directory or the prepares-{revision} WAL directory and the recorded views. The affected partition is tombstoned locally and is not served; its durable files are preserved.
For a superblock with log_view zero, recovery raises view to at least created_view without changing log_view. The raised view must be persisted before any view-scoped send, just as when no superblock record exists.
Such state can have been written by older servers, including server-0.9.0, after restarting before the partition's first superblock write. The creation view was not restored on that path. Raising a nonzero log_view during an upgrade would certify history that the replica may not hold, so the server does not repair those records automatically.
Partition directories hold a created.revision file with the revision that created the partition. Recovery deletes a directory whose file names an older revision. The partition then starts empty, as if it had no directory, and in a cluster the replica copies its data from the other replicas.
A directory that an older server made has no such file. A delete that did not finish before a restart leaves such a directory on disk, and a later create with the same stream, topic and partition ids finds it. Recovery then loads the leftover directory as the new partition. Only a leftover superblock with a nonzero log_view below created_view trips the superblock refusal. The WAL refusal does not apply, because each partition has its own prepares-{revision} WAL directory. Recovery logs adopting a nonempty partition directory without created.revision before adopting such a directory, since it cannot distinguish a live legacy incarnation from a deleted one.
If recovery logs falls below committed creation view or the adoption warning above, look at the history of the affected topic or partition first. If it was deleted and created again with the same ids, delete it again, and then create it again. The delete removes the leftover directory on every replica. It also removes every message in that topic or partition, so do this only if you can lose them.
In every other case:
There is no automatic in-place migration for below-floor log certificates. Do not edit view numbers or delete superblocks or WAL directories to bypass the refusal: an empty history could then replace committed data during a view change.
Before a partition can serve, initialization publishes its incarnation in partition-initialization/<namespace>/created.revision under the system data directory. This atomic record remains outside the partition directory, including after that directory is lost. Preserve it with metadata and partition backups. Storage format IGGY-OWNERSHIP-HISTORY-5 requires this initialization contract; older data directories are refused before mutation.
Retirement also writes retirement.fence in that external namespace directory before counting a permanently failed partition as retired. The fence names the failed incarnation and keeps it offline on subsequent boots, even if its partition directory is replaced. Healthy partitions and new logins can continue. If the fence cannot be persisted, the session remains retained and retirement retries. Temporary teardown tombstones and state transfer do not qualify as permanent failures.
Partition retirement barriers batch up to 128 ended sessions per commit. Each session still requires retirement reports covering every allocated partition from a common replica quorum before metadata releases its registry slot. Segment deletion does not invalidate those reports; changes to partition incarnations do. Metadata snapshot format 10 persists that separate revision.
A committed partition that has never initialized on this replica can finish initialization after a crash, including when all replicas stopped before their first WAL frontiers were published. An initialized partition with no durable prepare-WAL frontier remains fenced as missing history. A singleton refuses to serve it; a replicated partition requires history from a healthy peer. If every replica lost initialized history, restarting does not clear the fence.
Preserve the files and restore a verified consistent backup or use a validated recovery procedure. If the partition is independently known to be empty, or its data may be discarded, delete and recreate it through the metadata API. This creates a new partition incarnation and removes the old data. Missing files alone are not evidence that discarding that data is safe. Do not create a WAL frontier or remove initialization records or recovery fences manually.
Build with the systemd feature to enable readiness and watchdog notifications:
cargo build --bin iggy-server --release --features systemd
The server sends READY=1 only after every enabled transport is bound and accepting, so a unit ordered after it can dial as soon as it is notified. When the unit sets WatchdogSec=, the server pings WATCHDOG=1 at half that interval. On shutdown it sends STOPPING=1, which stops a long drain from counting against the watchdog.