Iceberg is not "implemented in the top 10 languages" — it is implemented for real in five languages under the Apache umbrella, plus one deliberately narrow community client in TypeScript. Nothing real exists for .NET, Ruby, PHP, etc. (C# usage goes through engines or hand-rolled metadata writing). The implementations are at radically different maturity levels, and the official status page tracks them poorly in both directions.
| Library | Language | Version @ HEAD | Scale (approx.) | Scope | Maturity verdict (from code) |
|---|---|---|---|---|---|
| apache/iceberg | Java | 1.11.0-SNAPSHOT (latest release 1.10.2) | ~110k LOC core + ~40k API | Full table format + engines (Spark, Flink, Hive, Kafka Connect) | Reference. Only complete implementation: v1–v3 fully, v4 underway, views, encryption, 11 catalogs, full maintenance suite. |
| apache/iceberg-python | Python (PyIceberg) | 0.11.0 | ~38k LOC | Full client: read + write, catalogs, CLI | Mature for v1/v2 Parquet read/write; v3 write hard-blocked; no equality deletes, no merge-on-read, no compaction. |
| apache/iceberg-rust | Rust | 0.10.0 | ~248 source files, 12 crates | Core lib + catalogs + DataFusion integration | Strong metadata/scan layer; write side is append-only — no overwrite/delete/upsert transaction actions yet. |
| apache/iceberg-go | Go | untagged pre-1.0 | ~69k LOC (+104k test) | Full client + CLI | Deepest non-Java implementation: v3 deletion vectors read+write, merge-on-read deletes, compaction, orphan cleanup. |
| apache/iceberg-cpp | C++ (C++23) | 0.4.0-dev (released: 0.3.0) | ~380 source files | Core lib on Arrow; REST/SQL catalogs | Young but real and moving fast: transactions, DV read/write, branching. Hive catalog is a 100% stub; no views/ORC. |
| supabase/iceberg-js | TypeScript | 1.0.0 | ~1k LOC src | REST Catalog HTTP client only | Polished for its narrow scope (catalog CRUD, spec-pinned 1.11.0-rc1). Not a table-format engine: zero Parquet/Avro/manifest I/O. |
Every cell below is derived from source inspection, not from any project's own claims. Where a cell disagrees with the official status matrix or the project's docs, it appears again in section 4.
| Capability | Java | PyIceberg | Rust | Go | C++ | iceberg-js |
|---|---|---|---|---|---|---|
| Spec format versions | ||||||
| v1 read + write | Yes | Yes | Yes | Yes | Yes | n/acatalog client; DTOs only |
| v2 read + write | Yesdefault | Yesdefault | Yes | Yes | Yesdefault | n/a |
| v3 read | Yes | Partialparses metadata; eq-deletes unread | Partialmetadata + row lineage; no DV | Yes | Partialtypes + row-lineage read | n/a |
| v3 write | Yes | Noraises NotImplementedError (metadata.py:578) | Partialupgrade + lineage on append | Yesincl. v2→v3 upgrade | Partial | n/a |
| v4 (in development) | PartialV4Metadata, Parquet manifests | No | No | No | No | n/a |
| v3 marker features | ||||||
| Deletion vectors — read | Yes | Yes | Noexplicit TODO; Puffin primitives idle | Yes | Yes | n/a |
| Deletion vectors — write | Yes | No | No | Yes | Yes | n/a |
| Row lineage | Yes | Partialfields modeled only | Partialassigned on fast-append | Yes | Partialread only | n/a |
| Variant type | Yesincl. Parquet shredding | Nono VariantType class exists | Partialtype defined; Parquet write rejects it | Yesincl. shredded variant | No | n/a |
| Geometry / geography | Yesnot in ORC | Partialtypes only; WKB/WKT conv raises | Noabsent from type enum | Yesgeoarrow WKB + bounds; nested TODO | No | n/a |
| timestamp_ns / unknown / defaults | Yes | Partialns downcast to µs on write | Partialns + defaults; no unknown type | Yes | Yesns + unknown + defaults gated | n/a |
| Read path | ||||||
| Scan planning + predicate pushdown | Yesmetrics, dict, bloom, distributed | Yes+ REST server-side planning | Yesrow-group, page index, row selection | Yesrow-group stats; decimal bloom TODO | Partialfile-level only; row-group TODO | n/a |
| Positional delete reads | Yes | Yes | Yes | Yes | Yes | n/a |
| Equality delete reads | Yes | Noraises on eq-delete files | Yes | Yes | Yes | n/a |
| Incremental / changelog scans | Yesappend + CDC changelog | Partialappend-only | No | Noexplicitly deferred | Partialboth, changelog w/o deletes | n/a |
| Write path | ||||||
| Append | Yes | Yes | Yesfast-append only | Yes | Yesfast + merge append | n/a |
| Overwrite / rewrite | Yes | Yes | Nono transaction action | Yes | Yes | n/a |
| Row-level delete | Yescopy-on-write + merge-on-read | PartialCOW only; MoR silently falls back | No | YesCOW + MoR | Yesrow-delta + delete-files actions | n/a |
| Upsert / merge | Yes | YesCOW | No | Norow-delta exists, no upsert API | Partialvia row-delta | n/a |
| Position / equality delete writes | Yes | No | Partialeq-writer exists, no commit action | Yes | Yes | n/a |
| Transactions, commit + retry | Yes | Yes | Yes | Yes+ multi-table txns | Yes | Partialcommit endpoint + idempotency keys |
| Evolution & snapshots | ||||||
| Schema evolution | Yes | Yes | Yes | Yes | Yesunion-by-name NotImplemented | n/a |
| Partition evolution | Yes | Yes | Nospec builder only, no txn action | Yes | Yes | n/a |
| All partition transforms | Yes | Yes | Yes | Yes | Yes | n/a |
| Time travel | Yesid + timestamp + ref | Yesid + ref | Partialsnapshot-id only | Yes | Yesid + timestamp + ref | n/a |
| Branching & tagging | Yes | Yes | Nomodel only; writes pin main | Yes | Yesincl. fast-forward | n/a |
| File formats | ||||||
| Parquet (data) | Yes+ vectorized | Yes | Yes | Yes | Yes | n/a |
| Avro (data) | Yes | Nomanifests only | Nomanifests only | Nomanifests only | Yes | n/a |
| ORC (data) | Yes | Partialread only | No | No | No | n/a |
| Puffin (stats / DV blobs) | Yes | Partialread only | Yesr/w; DV blobs not wired | Yes | Yes | n/a |
| Catalogs, storage, views, ops | ||||||
| Catalogs (working) | 11REST, Hive, Glue, JDBC, Nessie, DynamoDB, Hadoop, InMem, Snowflake, BigQuery, ECS | 7REST, SQL, Hive, Glue, DynamoDB, BigQuery, InMem | 4 + 2 partialREST, Glue, SQL, Mem; HMS can't commit, S3Tables partial | 5REST, SQL, Glue, Hive, Hadoop | 3 + stubREST, SQL, InMem; Hive = 100% stub | REST onlyby design |
| FileIO backends | YesS3, GCS, ADLS, HDFS, OSS, ECS, local | YesS3, GCS, ADLS, HDFS, OSS, HF, local | PartialS3, GCS, ADLS, OSS, HF, local — no HDFS | PartialS3, GCS, ADLS, local — no HDFS | Partiallocal + S3 only | n/a |
| Views | Yes5 view catalogs | PartialREST catalog only | Partialspec model only | YesREST, SQL, Hive (not Glue) | No | Nodeclared non-goal |
| Maintenance (expire, compact, orphans) | Yesfull action suite | Partialexpire only; no compaction | Partialexpire only | Yesexpire + compaction + orphan + rewrite manifests | Partialexpire + rewrite; no orphan removal | n/a |
| Table encryption | YesAES-GCM + KMS, v3-gated | No | Partialscaffolding + memory KMS | No | Noheader only | Partialencryption-key DTOs only |
Strengths and hard limits per library, with code evidence. "Hard limit" means the code raises, stubs, or simply lacks the path — not a style judgment.
BaseDVFileWriter), variant with Parquet shredding, geospatial types, row lineage, CDC changelog scans.SUPPORTED_TABLE_FORMAT_VERSION = 4, V4Metadata.java, Parquet manifests (v4-only; v3 manifests hard-assert Avro).StandardEncryptionManager, v3-gated), 11 working catalogs.PartitionField holds a single sourceId (spec reserves them).UnsupportedOperationException)._read_deletes PUFFIN branch).model_dump_json → NotImplementedError("Writing V3 is not yet supported") (metadata.py:578, #1551).table/__init__.py:2635); no delete-file writes of any kind; merge-on-read silently falls back to copy-on-write with a warning.sort_order_id=None hardcoded, #271); no compaction/orphan removal; views only via REST catalog.transaction/mod.rs:135-170).caching_delete_file_loader.rs:54) despite DELETION_VECTOR_V1 constants and a working Puffin writer — primitives imply a capability the pipeline doesn't deliver.MAIN_BRANCH), time travel by snapshot-id only, no geometry/geography, HMS catalog cannot commit (update_table → FeatureUnsupported).ErrNotImplemented, #1178).NotImplemented (hive_catalog.cc:31-129) despite being an advertised build option.UnionByNameWith NotImplemented, changelog scans can't handle deletes, encryption is a lone header.apache-iceberg-1.11.0-rc1 with an automated OpenAPI conformance suite — namespaces, tables, commit/requirements, register/rename, vended-credential headers, UUIDv7 idempotency keys, conditional GETs.The cross-check's main finding: the official implementation-status matrix at iceberg.apache.org/status is stale in both directions, and several projects' own docs disagree with their code. Every row below was verified against source at HEAD.
| Claim on iceberg.apache.org/status | Direction | What the code says |
|---|---|---|
PyIceberg supports variant — Y | Overstated | No VariantType exists anywhere in pyiceberg; the only reference is a TODO comment (transforms.py:722). |
PyIceberg supports timestamp_ns — Y | Overstated | Type classes exist, but writes downcast ns→µs with a warning (io/pyarrow.py:1466) and v3 persistence is blocked entirely. |
| Rust + Go support Hadoop Filesystem — Y | Overstated | Neither has an HDFS backend: Rust's opendal storage crate ships s3/gcs/azdls/oss/hf/fs/memory only; Go's io + gocloud layer has no hdfs scheme. |
| Rust writes equality deletes — Y | Overstated | An EqualityDeleteWriter exists, but no transaction action can commit delete files — the only data-committing action is fast_append. |
| PyIceberg "Read data file" (spec v1) — N | Understated | PyIceberg reads v1 tables fine — v1 metadata is parsed and normalized in-memory (TableMetadataV1.to_v2). |
C++ column: append/write ops N, S3 N, SQL catalog N, Puffin N, timestamp_ns/unknown N | Understated | All exist at HEAD: full update-action suite + data writer, Arrow S3 FileIO, SQL catalog (SQLite/Postgres/MySQL), Puffin r/w, TimestampNsType and kUnknown. The column reflects ~0.1.0-era status. |
| Puffin: PyIceberg N, Rust N, Go N | Understated | PyIceberg reads Puffin DVs; Rust has Puffin read and write (theta-sketch stats); Go has a full Puffin reader/writer and writes deletion vectors with it. |
| Expire snapshots: PyIceberg N, Rust N | Understated | Both implemented: MaintenanceTable.expire_snapshots (py), transaction/expire_snapshots.rs (rust). |
| Replace sort order / manage snapshots: PyIceberg N | Understated | UpdateSortOrder (table/update/sorting.py) and ManageSnapshots (create/remove branch & tag) both exist. |
REST createView: PyIceberg N | Understated | Real implementation in catalog/rest/__init__.py:972 (verified: builds schema, POSTs view). The N is stale. |
| ORC: PyIceberg N | Understated | ORC read works for data and positional-delete files; only the write side is missing. A binary Y/N cell can't express it — the truth is "read-only". |
| Geometry/geography: Go N | Understated | Go reads and writes geo columns via geoarrow WKB with bounds statistics (arrow_utils.go:382,684). |
| Project | Doc claim | Direction | Reality in code |
|---|---|---|---|
| PyIceberg | geospatial.md shows creating a v3 table with geometry columns as a working example | Doc bug | The example fails at commit: v3 serialization raises NotImplementedError (metadata.py:578). Geo WKB↔WKT conversions also raise (conversions.py:515-690). |
| PyIceberg | Accepts write.delete.mode=merge-on-read as a table property | Doc bug | Property accepted, then silently ignored — delete falls back to copy-on-write with only a warning (table/__init__.py:730). |
| C++ | index.md: "Full table spec support today" | Overstated | v3 is partial (row-lineage read-only, no variant/geo), no views/UDF, no ORC, union-by-name schema merge NotImplemented. |
| C++ | index.md: Puffin "on the roadmap" | Understated | Puffin reader and writer shipped in 0.3.0 — the roadmap line is stale in the opposite direction. |
| C++ | README advertises ICEBERG_BUILD_HIVE / Hive catalog client | Overstated | Every HiveCatalog method returns NotImplemented (hive_catalog.cc:31-129); the generated Thrift client is unused. Buildable, non-functional. |
| Go | README matrix: REST "Load View" unsupported; "Rewrite manifests" blank | Understated | Both implemented: LoadView (rest.go:2188), rewrite_manifests.go + CLI subcommand. README lags the code. |
| Go | transforms.go:84 comment: transforms "do not yet provide transformation functions" | Understated | Stale comment — all transforms ship working Apply/Transformer functions. |
| Rust | README lists HMS and S3Tables as peer catalog crates | Overstated | HMS update_table → FeatureUnsupported (can't commit writes); S3Tables lacks drop_table/register/update_namespace. Neither caveat appears in docs. |
| Rust | Public API exposes Type::Variant and Puffin DELETION_VECTOR_V1 | Overstated | API surface implies capability the pipelines lack: Parquet writer rejects variant columns; DV blobs are neither read (TODO) nor written by the delete path. |
| iceberg-js | README: "1:1 mapping to the Iceberg REST Catalog API" | Overstated | Views, multi-table transactions, OAuth token, scan-planning, and metrics endpoints are absent (some declared non-goals — but then it isn't 1:1). |
| iceberg-js | README: createNamespace(): Promise<void>; types table shows fixed(length) | Doc bug | Code returns CreateNamespaceResponse, not void; the parser accepts only Iceberg-canonical fixed[length] — the parenthesized form in the docs wouldn't parse. |
| Java | — | Aligned | No material mismatch found. format/spec.md is candid that v4 is "under active development and not formally adopted," which matches the code (ceiling = 4, default = 2, V4Metadata partial). |
Measured against the adopted spec (v1–v3), the practical picture as of July 2026:
| If you need… | Use | Why |
|---|---|---|
| Full spec, v3 features, views, encryption, v4 lead time | Java | Only complete implementation; everything else is a subset of it. |
| Python data engineering on v1/v2 tables | PyIceberg | Mature read/write + catalogs — as long as you don't need v3, equality deletes, or merge-on-read. |
| Non-JVM writes with v3 (DVs, MoR deletes) + table ops | Go | The only non-Java library with DV write, MoR, compaction, and orphan cleanup today. |
| Embedding reads in a native engine | Rust (or C++) | Rust: best scan pipeline + DataFusion, but append-only writes. C++: Arrow-native, fuller write path, younger overall. |
| Browser/Node catalog control-plane only | iceberg-js | Clean spec-pinned REST client; pair with an engine for data access. |
| .NET, Ruby, PHP, … | — | No real implementation exists; use the REST catalog + an engine, or the C FFI of one of the native libraries. |