Cloud Parts

icepickExperimental

A small, experimental Rust CLI and library that commits Parquet files to Apache Iceberg tables and runs compaction and snapshot cleanup through a REST catalog, aimed at Cloudflare’s R2 Data Catalog (now Basin Catalog) and Amazon S3 Tables, with no JVM.

Type
Open source
Made by
Clay Smith
License
Apache 2.0
Status
Experimental. It describes itself as an experimental, append-only client.
Facts checked
11 October 2026

What it is

icepick is one binary (cargo install icepick --features cli) that talks to an Iceberg REST catalog with just two inputs, a catalog URL and a bearer token. It reads the catalog’s /v1/config for the prefix, then asks the catalog’s /credentials endpoint for short-lived storage keys for each table. icepick commit takes a glob of Parquet files, checks that they all match the first file’s schema, uploads local files to the table’s location and registers them in one snapshot, skipping files already in the table. icepick compact bin-packs small files into larger ones (by default files under 128 MB into 256 MB outputs, in groups of at least 3), icepick snapshot cleanup expires snapshots older than N days while keeping the last N and anything a branch or tag points to, and icepick table scan --filter shows how many files partition pruning would skip. commit, compact and snapshot cleanup each take --dry-run to print the plan first.

Clay Smith started it in November 2025 because the official iceberg-rust library didn’t compile to WebAssembly and most Iceberg tooling needs a JVM. Four days in, it replaced iceberg-rust with its own implementation of the Iceberg REST protocol; it now writes manifests itself with apache-avro and reaches storage through opendal. The README says its R2 catalog code is WebAssembly-compatible, for use in Cloudflare Workers, while S3 Tables needs the AWS SDK and runs only on native platforms; in 0.4.1 the CLI itself only takes a URL and token, so S3 Tables is reachable only from the Rust library. It describes itself as an experimental, append-only client. The latest release is 0.4.1 (19 January 2026), and the repository has had no commits since that day.

Why teams pick it

  • No JVM, Spark or Python: one native binary commits files, compacts and expires snapshots, which suits cron jobs and CI
  • Registers Parquet files that already exist, without rewriting them, and skips files already in the table, so reruns are safe
  • Needs only a catalog URL and token; in a test for this page the same binary worked against a local Lakekeeper 0.14 catalog with MinIO, because it relies only on the standard config and credentials endpoints
  • Snapshot cleanup never expires the current snapshot or one a branch or tag points to, and only removes snapshots that are both older than the age limit and outside the last N

Watch out for

  • A one-person experiment: version 0.4.1, a few hundred downloads, no commits since January 2026, and docs that have drifted from the code (the README’s --limit flag and ICEPICK_CATALOG_ARN setting don’t exist in the 0.4.1 CLI, and the changelog describes a 0.5.0 that was never published)
  • In a test for this page, 0.4.1’s compact couldn’t read Snappy-compressed Parquet, because its parquet dependency is built without compression codecs, and on uncompressed files it left the six original files live next to the merged one, so readers saw 120 rows instead of 60
  • Append-only, and strict about inputs: no deletes or updates, and commit rejects Parquet files whose columns lack Iceberg field ids, which a plain PyArrow write doesn’t add
  • In a test for this page, commit --create --partition created a partitioned table but registered the files with no partition values, so filters pruned nothing

Alternatives

What all table formats have in common →

How it fits with other technologies

Register local Parquet files as a new Iceberg table, then plan a compaction · bash

cargo install icepick --version 0.4.1 --features cli --locked

# For Basin Catalog: https://catalog.cloudflarestorage.com/<account-id>/<bucket>
# Run here against a local Lakekeeper 0.14 catalog (warehouse "catalog") on MinIO
export ICEPICK_CATALOG_URL=http://localhost:28181/catalog
export ICEPICK_TOKEN=dummy                  # a Cloudflare API token on Basin

icepick namespace create web
# Namespace 'web' created successfully.

# Six uncompressed files written by PyArrow, with PARQUET:field_id on each column
icepick commit 'raw/*.parquet' --namespace web --table clicks --create
# Found 6 Parquet files
# Detected local files - will upload to table storage
# Schema from: raw/part-0.parquet
# Created table: web.clicks
# Uploading 6 local files...
#   part-0.parquet -> s3://lake/01a12e09-.../data/part-0_b5acfe29-....parquet
#   ...
# Upload complete
#   Files: 6 committed, 0 skipped
#   Rows: 60

icepick compact web.clicks --dry-run
# Partition: (unpartitioned)
#   Input:  6 files, 5.7 kiB (avg 974 B /file)
#   Output: ~1 files (target 5.7 kiB)
# Dry run complete. Remove --dry-run to execute.

icepick snapshot list web.clicks           # one append snapshot, current, on main

See it in a real stack

No architecture uses icepick yet. Drop it into the playground and wire it up yourself.Open playground →
Where it came from2025–2026

By 2025 teams could get a managed Iceberg catalog without running servers, such as Amazon S3 Tables or Cloudflare’s R2 Data Catalog, which entered public beta in April 2025. Most Iceberg tools, icepick’s README notes, are built for JVM environments, and the official Rust library, iceberg-rust, couldn’t be compiled to WebAssembly, so it couldn’t run inside a Cloudflare Worker.

Clay Smith began the project on 15 November 2025 as hello-world-iceberg, a test of iceberg-rust against S3 Tables, and renamed it icepick. That first day the commit history records an S3 Tables incompatibility finding and a switch from iceberg-catalog-rest to a minimal hand-written client; on 19 November “Standalone implementation of Iceberg REST” removed iceberg-rust altogether. 0.1.0 went to crates.io on 17 November 2025.

December’s 0.3.0 added registration of existing Parquet files with Hive-style partition values read from their paths. In January 2026 a reworked CLI arrived with partition pruning, bin-pack compaction, snapshot cleanup and the commit command, and 0.4.1 shipped on 19 January 2026.

Why it’s built this way

Its own REST client instead of iceberg-rust
The 0.4.0 changelog notes that iceberg-rust 0.7.0 couldn’t build for WebAssembly because of its Tokio dependency, which blocked the main goal of running in Cloudflare Workers.
Only a catalog URL and a token
The CLI rework made everything else, the prefix and the storage credentials, come from the catalog’s own config and credentials endpoints, so pointing it at R2 or another REST catalog takes two settings.
Register files rather than write rows
The developer guide pitches it for Parquet files that already sit in object storage: they become an Iceberg table without being rewritten, and files already registered are skipped.
Bearer tokens for R2, SigV4 only on native builds
R2’s catalog takes a Cloudflare API token, which works from WebAssembly. S3 Tables needs SigV4 signing and the AWS SDK, which doesn’t compile to WebAssembly, so that path is native-only.

Timeline

  1. 2025

    Clay Smith starts hello-world-iceberg on 15 November and renames it icepick

  2. 2025

    Replaces iceberg-rust with a standalone REST client on 19 November

  3. 2025

    0.3.0 adds registration of existing Parquet files in December

  4. 2026

    0.4.1 brings the CLI with commit, compaction and snapshot cleanup on 19 January

Sources10 · facts checked 11 October 2026

Improve this page on GitHub