# immudb: a tamper-evident database with client-side verification

> immudb is a Go database that keeps every version of a record and lets clients prove the history has not been altered. It ships as a server, a Docker image, a Helm chart and an embeddable library, and the trade-off is that nothing is ever deleted.

**codenotary/immudb** — immudb - immutable database based on zero trust, SQL/Key-Value/Document model, tamperproof, data change history

- Repository: https://github.com/codenotary/immudb
- Website: https://immudb.io
- Stars: 9,041 · Forks: 379
- Language: Go
- License: NOASSERTION
- Published: 2026-09-21 · Updated: 2026-09-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/codenotary-immudb

## The problem immudb addresses: mutable logs cannot prove their own history

A conventional database lets an administrator rewrite a row and the application has no way to notice. The README frames this directly: traditional transactions and logs are mutable, so there is no way to know for sure whether data has been compromised. immudb's answer is to make the store append-only at the storage layer and to push verification to the client, so the database operator does not have to be trusted. That threat model is the whole point of the project. It is aimed at teams that must demonstrate integrity to someone else: auditors, regulators, downstream consumers of a build artifact, or a customer reading a compliance report. The README lists sensitive data, transactions, software build recipes, rule-based data, artifacts and video streams among current uses, and the topics include GDPR and PCI-DSS, which tells you the intended buyer is a compliance-adjacent engineer rather than someone optimizing query throughput. If nobody will ever ask you to prove that a past record is unchanged, immudb costs you more than it returns.

## How the cryptographic proof works, and where the client sits in the data flow

The mechanism is a Merkle tree over appended entries plus a client-held state. The README states that data is cryptographically coherent and verifiable and that the integrity of the history is protected by the clients, without the need to trust the database. In practice the client keeps a small piece of state from the last verification and, on each read, checks the returned proof against it, so a server that silently rewrites an earlier entry fails the check. That design decision has a consequence the README does not dwell on: verification is only as strong as the client's stored state. A client that starts fresh has nothing to compare against, and a client whose state file is lost or reset loses the ability to detect a rewrite before that point. The repository layout reflects the split. The top level contains cmd/, pkg/, embedded/ and examples/embedded/, and the README points to a separate embedding guide for running immudb fully in-process as a Go library with no server and no container. The go.mod confirms the server side is Go 1.25.0 and pulls in grpc, grpc-gateway, a Prometheus client, and a PostgreSQL parser, which is the dependency trail of a service that speaks gRPC with an HTTP gateway and offers a SQL dialect.

## Installing immudb with Docker and running a first verification

The README gives three install paths: a downloaded binary, a Docker image, and a Helm chart. The Docker route is the shortest. The published command runs the container with host networking, and the README notes that if you skip host networking you must expose ports 3322 and 9497 yourself.

```bash
docker run -d --net host -it --rm --name immudb codenotary/immudb:latest
```

For Kubernetes, the README adds the project's Helm repository and installs with a generated name.

```bash
helm repo add immudb https://packages.codenotary.org/helm
helm repo update
helm install immudb/immudb --generate-name
```

One detail in that chart is worth knowing before you upgrade an existing cluster. The README explains that the chart now places database files in a subdirectory (by default immudb) because volumes from providers such as EBS and DigitalOcean contain a /lost+found directory at the root, and immudb would otherwise treat it as a database. If you already have data written by a chart at version 1.3.1 or earlier, the README says you can set volumeSubPath.enabled=false during the upgrade to keep the old layout, or migrate the files into an immudb subdirectory. The README supplies a busybox pod manifest for that migration that creates /data/immudb and moves everything except immudb and lost+found into it. There is no rollback documented for that move, so treat it as one-way and take a copy of the volume first. The same README section documents the environment variables for storing data in S3 or a compatible service, including IMMUDB_S3_STORAGE, IMMUDB_S3_BUCKET_NAME, IMMUDB_S3_LOCATION and IMMUDB_S3_PATH_PREFIX, set before starting the ./immudb binary.

## The immutability is real, which means your delete and update paths are not

The README is unusually blunt: you can add new versions of existing records, but never change or delete records. That is not a retention policy you can configure away, it is the property that makes the proofs meaningful. The practical fallout is larger than it first appears. A GDPR erasure request against a field that was written in error cannot be satisfied by a DELETE, because the earlier version remains in the history. A schema migration that would normally backfill a column has to be expressed as new versions. Your storage grows monotonically, and the only lever is the cost of the medium, which is presumably why S3-backed storage exists as an option. The README does not document a compaction or pruning mechanism, and it does not document rollback of a migration, so plan the volume accordingly. There is also a security default worth flagging: the Dockerfile sets IMMUDB_DEVMODE="true" and IMMUDB_ADMIN_PASSWORD="immudb" in the image environment. Those are image defaults, and a deployment that leaves them in place is running with a known admin password in development mode. Change them before the container reaches anything that matters.

## immudb versus PostgreSQL, and what the PostgreSQL compatibility claim actually covers

The obvious question is why not just use PostgreSQL, and the honest answer is that they solve different problems. PostgreSQL is mutable by design, and its audit story is triggers, write-ahead log archiving, or an external append-only sink. immudb makes the append-only property native and adds client-verifiable proofs on top, so an auditor does not have to trust the DBA. The cost is that you give up UPDATE and DELETE as first-class operations, and you inherit a much younger query engine. The repository vendors github.com/auxten/postgresql-parser v1.0.1 and depends on jackc/pgx/v5 and lib/pq, and the Dockerfile enables IMMUDB_PGSQL_SERVER="true" and the README lists PostgreSQL SQL compatibility among recent changes. That is a compatibility effort, not a claim of parity. If your workload leans on PostgreSQL-specific features such as extensions, advanced window functions or stored procedures, the parser dependency is not evidence that they are supported. Test your actual statements against immudb before you plan a migration. For teams that need immutability but already run PostgreSQL, an append-only table plus periodic hash anchoring is the cheaper alternative and requires no new database.

## Maintenance, licensing and the cost of staying current

The last push to the default branch was on 2026-09-10, and the most recent release is v1.11.2 from 2026-09-03, following v1.11.1 in June and v1.11.0 in April. The repository is not archived. Upgrades are not just a binary swap, because the Helm chart changed its on-disk layout and the README treats the volume migration as a manual job. Budget for a maintenance window per cluster upgrade, and pin the chart version so an upgrade does not silently move your data directory. The Makefile pins VERSION=1.11.0 and builds for linux/amd64, windows/amd64, darwin/amd64, linux/arm64, freebsd/amd64 and darwin/arm64, so the release matrix is broad. On licensing, the repository metadata reports NOASSERTION rather than a recognized SPDX identifier, while the Dockerfile and Makefile headers carry an Apache License 2.0 notice and state that the software is distributed on an AS IS BASIS without warranties. Two sources disagreeing is exactly the situation where you read the LICENSE file at the repository root yourself rather than trusting a badge or a header comment. This is not legal advice; if the distinction matters to your organization, have counsel read the file.

## Conclusion

Adopt immudb when your problem is proving that a record was not altered after the fact, for example audit logs, build recipes or sensor readings, and you can accept append-only storage. Do not adopt it as a drop-in replacement for a mutable application database, because the README is explicit that records can never be changed or deleted. Before committing, verify two things on your own hardware: how the client-side proof check behaves under your latency budget, and how the SQL surface you depend on is handled, since the repository vendors a PostgreSQL parser rather than claiming full compatibility.

## FAQ

### What is an immutable database and how does immudb work?

An immutable database keeps every version of a record instead of overwriting it, so the history itself is the durable artifact. immudb stores data with built-in cryptographic proof and lets the clients, not the server, verify that the history has not been altered.

### What does immutable data mean in immudb?

The README states that you can add new versions of existing records, but never change or delete records. Writes append; they do not overwrite, which is what allows the verification proofs to mean something.

### Is immudb an immutable ledger?

The README describes immudb as a database with built-in cryptographic proof and verification that protects the integrity of the history, and it contrasts this with blockchains by noting that immudb can handle millions of transactions per second. It does not use the word ledger for itself.

### immudb vs postgres: which should I choose?

PostgreSQL is mutable by design and its audit trail comes from triggers or log archiving, while immudb makes the append-only property native and adds client-side proofs. The repository vendors a PostgreSQL parser and the container enables IMMUDB_PGSQL_SERVER, but the README presents this as SQL compatibility, not as full PostgreSQL parity.

## Sources

- [codenotary/immudb on GitHub](https://github.com/codenotary/immudb)
- [Issues](https://github.com/codenotary/immudb/issues)
- [Project website](https://immudb.io)
- [README](https://github.com/codenotary/immudb/blob/master/README.md)
- [Releases](https://github.com/codenotary/immudb/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/codenotary-immudb
