Self-hosted
You own the runtime, data, and keys. No vendor control plane sits in the request path.
LakeHold is self-hostable, tenant-aware, and built on open Parquet — governed data infrastructure that stays on your infrastructure.
You own the runtime, data, and keys. No vendor control plane sits in the request path.
Open format for tables and metadata, with a verified exit path any Parquet reader can use.
First-party source SDKs share one versioned API, with first-class EF Core integration for .NET applications.
Compaction, snapshots, backups, and catalog operations stay on schedules you control.
LakeHold now has its first governed source-to-table path. It is a focused EDP direction, not a claim that the full enterprise platform is finished.
PostgreSQL control and metadata, DuckDB compute, open Parquet, tenant identity, audit, time travel, maintenance, backup, and verified eject.
Bounded REST and gRPC full snapshots with schedules, quality contracts, target ownership, fenced publication, telemetry, and retained run evidence.
HTTP, SQL, EF Core, MCP, owner metadata, and audit exist. Search, classification, lineage graphs, semantic metrics, Power BI, and open multi-engine access remain planned.
Every number below came from running the stack, not from a datasheet.
August 2026 — optional isolated C# LINQ and a governed source-to-table path, with SQL remaining built in and every product boundary explicit and testable.
Choose SQL or C# LINQ in the same CodeMirror editor, with catalog-aware completion, line diagnostics, generated parameterized SQL, separate language buffers, history, and language-preserving saved queries. The compiler receives source and schema only; the credential-owning API validates and executes its plan through the same catalog, authorization, limit, telemetry, and audit path as SQL.
Caveat: The Compose linq profile is opt-in. It accepts one side-effect-free expression and supports queryables plus Count, LongCount, Any, Min, Max, Sum, and Average — not arbitrary LINQPad scripts. Native types without an EF property mapping remain available through SQL.
REST/gRPC snapshots plus PostgreSQL, HubSpot, and Kafka Avro adapters share durable schedules, checkpoints, retry/dead-letter lifecycle, mappings, schema policy, external secret references, quality gates, bounded scratch space, safe egress, target ownership, and atomic DuckLake publication.
Caveat: Five built-in adapters are not a broad production-certified connector ecosystem. Kafka Avro uses a Confluent-compatible Registry and deployment-owned egress gateways; it is at-least-once, not generic CDC or exactly-once.
Authentication cannot be switched off. API tokens are scoped to a tenant and optionally a single catalog, carrying an owner, editor, or reader role, and people sign in through your identity provider. The sole credential-less HTTP path is an explicitly configured reader for one demo catalog; MCP never accepts it. LakeHold federates authentication and owns authorization: what a signed-in person reaches comes from a membership record you administer in the product, so a provider re-asserting a stale role cannot undo a decision made here. The credential or demo identity names the tenant and the URL segment is validated against it rather than trusted. A reader’s selected catalog is attached read-only, and revoking a token closes the HTTP API and PostgreSQL wire endpoint together because both resolve against the same store.
Caveat: Authorization stops at the catalog: a role, and optionally one catalog. There are no row or column policies, so anyone who can read a table reads all of it. A read-only selected-catalog attachment does not contain arbitrary SQL from process-visible files, URLs, secrets, or new attachments. Leaving Lakehold:Oidc:Audience empty disables audience validation and accepts every token that issuer minted — LakeHold warns at start-up, and you should treat it as an error.
Ejects a verified bundle of your data as ordinary Parquet, plus the metadata catalog when you want history. It re-materialises every table through the catalog rather than copying files, so merge-on-read deletes are applied, superseded update rows are gone, inlined commits are included, and none of DuckLake’s internal columns leak. Every file is counted back through a plain Parquet reader and compared to the catalog before the manifest is written, and the manifest carries per-table row counts, SHA-256 digests, and an HMAC signature when you configure a key.
Caveat: A copy of the data path is not an eject. Deletes are merge-on-read sidecars only DuckLake understands, so copying files resurrects deleted rows and duplicates updated ones — which is exactly why this exists.
LakeHold speaks the PostgreSQL wire protocol, so a client that already speaks Postgres connects to a catalog with no .mez file, driver, or plugin. The user is the tenant and the database is the catalog, and every statement resolves through the same tenant check, session gate, and query history as an HTTP query, so client traffic is visible in the history for the first time. The 10,000-row ceiling does not apply: rows are encoded straight to the socket rather than materialised, so a result streams instead of being silently truncated.
Caveat: psql, DBeaver, and Npgsql work today. Power BI does not yet: it reads the server’s type catalogue when connecting, and DuckDB leaves pg_type.typreceive empty, so the driver’s own join comes back with nothing. That is fixable in our compatibility shim rather than in DuckDB, and it is measured rather than guessed — see docs/POSTGRES-WIRE.md. Off by default, with TLS and per-tenant credentials.
DuckLake already records what each snapshot changed, so LakeHold exposes it directly: a typed pull API for change pages, and outbound webhooks fired per new snapshot and signed with HMAC-SHA256 over a timestamped base. Updates arrive as a paired pre-image and post-image sharing a row id, so you can take net effect or diff them. No Debezium, no Kafka, no second pipeline.
Caveat: Delivery is at-least-once. The cursor advances one snapshot at a time and only after a 2xx, so a failing consumer replays rather than skips — make your handler idempotent on (snapshot, row, change type).
The metadata catalog is exported to Parquet hourly and can rebuild a working catalog from that export — row counts, deletions, updated values, views, and AT (VERSION => n) time travel all intact. Restore writes a new catalog and refuses to overwrite an existing one, because recovery happens under pressure.
Caveat: An export with no completion manifest is refused outright. If it died partway and the missing table is ducklake_delete_file, deleted rows would silently come back.
A catalog whose metadata lives in PostgreSQL exports the same 30 tables and restores into a plain DuckDB file — verified against PostgreSQL 17. That makes it an exit path from the catalog database, not just a copy of it. pg_dump restores into PostgreSQL; this restores into a file you can open with the duckdb CLI and nothing else.
The backup root can be an s3:// prefix. Listing generations, reading manifests, and restoring from a bucket are all verified against a live S3 endpoint.
Caveat: Retention cannot prune a bucket — DuckDB has no delete for object stores. Set a lifecycle rule on the prefix. LakeHold reports "retention deferred" rather than a "0 pruned" that would read as though it had run.
Flush, backup, and compact run on cron schedules you control, with recent runs and their timings readable over the API. Where a catalog can genuinely be shared between nodes, a lease stops every node running the same sweep.
Caveat: Snapshot expiry and orphan cleanup are deliberately not scheduled. They are irreversible, so they stay manual and dry-run by default.
Tenants, tokens, catalog definitions, subscriptions, and audit history now live in a migrated PostgreSQL control plane. New DuckLake catalogs receive isolated PostgreSQL metadata schemas, while Parquet independently targets local files, S3/S3-compatible storage, GCS, or Azure Blob/ADLS. Credentials remain deployment secrets and are injected only into a worker’s temporary DuckDB session.
Caveat: DuckDB is still the in-process query engine. Nodes scale tenant and request concurrency; one query is not distributed across a cluster, and local Parquet remains a single-node/shared-filesystem choice.
Stated as plainly as the shipped list, caveats and all.
The versioned source SDK, resumable reads, retry/dead-letter lifecycle, mappings, schema policy, external secrets, PostgreSQL, and HubSpot Contacts are implemented. The next connector milestone is a separately distributed and production-certified catalogue driven by demand.
Honestly: The current SDK lives in the API assembly and the built-in catalogue contains five adapters; no partner ecosystem or broad SaaS coverage is claimed.
Eject proves the data is portable, but it is a batch artifact. Serving the Iceberg REST Catalog protocol would let Spark, Trino, Snowflake, or DuckDB attach to a LakeHold catalog directly and read it live, with no export step and the same credential-bound tenant/catalog routing as the query path. That would still require its own containment and authorization review.
Honestly: DuckLake’s Iceberg support is a copy between formats, not this — the translation is ours to write, and whether merge-on-read delete sidecars map cleanly onto Iceberg deletes is unverified. That test comes before the promise.
The EF Core model already describes both your application and your lake. A LakeHold client would make that installable: migrations that define lake tables, results deserialised into your own entity types, and the change feed surfaced as ChangeEvent<T> with pre-image and post-image already paired into Before and After.
Honestly: Today there is no client package — the .NET story is a property of the architecture and the provider, not something you can add to a csproj yet.
Eject proves the exit path when someone calls it. On a schedule, it would prove it continuously: as of this snapshot, every table re-materialised, row counts verified against the catalog, read back with no DuckLake extension loaded — kept as a signed, dated artifact instead of an on-demand call.
Honestly: The value is in it failing loudly. An attestation that has gone stale relative to the newest snapshot has to read as a warning, or silence stops meaning verified.
A comparison that only listed our strengths would be marketing, not engineering.
Full comparison — MotherDuck, ClickHouse, and the cloud warehouses →