DuckDB alternative — DuckDB vs Skippr
DuckDB is MIT embedded analytics. Latest LTS is 2.0.0 "Cinnamon Teal" (21 Oct 2026), supported through 22 Oct 2027. 1.4 LTS ends 17 Nov 2026; 1.5 is supported through March 2027. Iceberg is the iceberg core extension (secondary, best-effort). iceberg_scan on a metadata path is read-only. Writes need an Iceberg REST catalog ATTACH: CREATE/DROP schema and table, INSERT, UPDATE, DELETE, MERGE INTO, ALTER TABLE. DELETE/UPDATE write positional deletes; copy-on-write is not supported. DML on partitioned or sorted tables errors. CDC is not DuckDB. Hosted: MotherDuck Lite is free (10 GB, 10 Pulse hours); Business is 250 USD/month plus usage (Pulse 0.60 USD per CU-hour). This is not Iceberg ∪ WAL you query in one binary.
Skippr is an open Streamhouse you run as one Rust binary. Write skippr.yml (or the same thing in Python), discover, sync. You query live state over Iceberg ∪ WAL, and the history is ordinary Iceberg in your bucket. DuckDB remains exquisite for a one-shot SELECT on files you already have. ELT into a warehouse is one path, not the product.
| Feature | Skippr | DuckDB |
|---|---|---|
| Deploy | Single Rust binary, your VPC or on-prem | In-process library, CLI, or MotherDuck |
| Schema | In-stream evolution, sibling columns | SQL DDL. Iceberg schema after REST ATTACH |
| Storage | Open Iceberg on Parquet you own | .duckdb file, or Iceberg via the extension |
| CDC | Log-based; fails closed if the dest cannot honour | Not a CDC product. You load a snapshot |
| Query | skipprd query on Iceberg ∪ WAL; history in any Iceberg engine | DuckDB SQL in-process, or MotherDuck |
| Pricing | Free self-hosted engine | MIT. MotherDuck Lite free; Business from 250 USD/month. |
What DuckDB is good at
SQL on a laptop, in a notebook, or in a sidecar, without standing up a warehouse. That is the product. The Iceberg REST ATTACH (and MotherDuck persisted catalogs) is why some lakes get a DuckDB session on files Spark already wrote. If the job is "this SELECT on these Parquet files," DuckDB is the narrower tool, and it is a good one.
Where the job is wider
DuckDB is an embedded SQL engine. It is not a Streamhouse. There is no Iceberg ∪ WAL. There is no skipprd query on in-flight lake rows. Iceberg writes need a REST catalog; a metadata-path scan will not take INSERT. CDC still starts in Debezium or skipprd. Skippr will not replace DuckDB for ad-hoc SQL.
The process (or MotherDuck CUs) is the ops. Skippr will not run the DuckDB CLI. skipprd can land a Duckdb dest; that is still Skippr doing ingest.
If the job is "DuckDB we already staff," DuckDB is the narrower tool. If the job is live SQL on Iceberg you run, the embedded engine was never that.
Getting started
Install skipprd from the install guide, or pip install skippr. The three tabs write the same skippr.yml. Then discover, sync, and query.
skippr:
workspace: analytics
skipprd_el_storage_mode: local
pipelines:
orders:
data_source: data_sources.app_db
data_sink: data_sinks.lake
data_sources:
app_db:
Postgres:
host: db.internal
user: skippr_reader
password: ${APP_DB_PASSWORD}
database: app
tables: [orders, customers]
cdc_mode: snapshot_then_cdc
data_sinks:
lake:
AthenaIceberg:
warehouse: s3://my-iceberg-warehouse/
glue_database_name: analytics
athena_workgroup_name: primary
athena_results_s3_bucket: my-athena-results
region: us-east-1
schema_sink: schema_sinks.lake_schema
schema_sinks:
lake_schema:
AthenaIceberg:
warehouse: s3://my-iceberg-warehouse/
glue_database_name: analytics
athena_workgroup_name: primary
athena_results_s3_bucket: my-athena-results
region: us-east-1skipprd --workspace analytics --storage-mode local connect data-source postgres \
--pipeline orders \
--name app_db \
--host db.internal \
--user skippr_reader \
--password '${APP_DB_PASSWORD}' \
--database app \
--tables orders \
--tables customers \
--cdc-mode snapshot_then_cdc
skipprd connect data-sink athenaiceberg \
--pipeline orders \
--name lake \
--warehouse s3://my-iceberg-warehouse/ \
--glue-database-name analytics \
--athena-workgroup-name primary \
--athena-results-s3-bucket my-athena-results \
--region us-east-1
skipprd connect schema-sink athenaiceberg \
--pipeline orders \
--name lake_schemafrom skippr import (
Config,
DataSinkAthenaIceberg,
DataSourcePostgres,
DataSourcePostgresSourceCdcMode,
EnvRef,
LocalStorage,
Pipeline,
)
cfg = Config().workspace("analytics").storage(LocalStorage())
app_db = cfg.data_source(
"app_db",
DataSourcePostgres(
host="db.internal",
user="skippr_reader",
password=EnvRef("APP_DB_PASSWORD"),
database="app",
tables=["orders", "customers"],
cdc_mode=DataSourcePostgresSourceCdcMode.SNAPSHOTTHENCDC,
),
)
lake = cfg.data_sink(
"lake",
DataSinkAthenaIceberg(
warehouse="s3://my-iceberg-warehouse/",
glue_database_name="analytics",
athena_workgroup_name="primary",
athena_results_s3_bucket="my-athena-results",
region="us-east-1",
),
schema_sink="lake_schema",
)
cfg.pipeline("orders", Pipeline(data_source=app_db, data_sink=lake))
cfg.save("skippr.yml")export APP_DB_PASSWORD='your-postgres-password'
skipprd discover --pipeline orders
skipprd sync --pipeline orders --once
skipprd query "SELECT count(*) FROM analytics.orders"Which to choose
Choose DuckDB if you want in-process SQL, and Iceberg as a REST-catalog ATTACH (or a read-only scan) is enough.
Choose Skippr if you want one binary, live SQL on Iceberg ∪ WAL, and files that stay yours. Skippr will not replace DuckDB.
Install from Install. Connector and query reference live in Developer Docs. For optional onboarding in your VPC, Enterprise Jumpstart or Contact.
