Public catalogs: let anyone read a catalog

An admin can make a catalog public. From then on anyone can read its tables, with DuckDB and no account and no credentials, and any LakehouseBox account can attach the whole catalog read-only by name. Writes stay with your organisation: publishing changes who can read, never who can write. Making the catalog private again stops anonymous reads at once.

Public is all or nothing for the tables of a catalog: there is no per-table publishing yet. If only some tables should be public, put them in a catalog of their own.

Publish and unpublish

lhbox catalog publish <name> --confirm                     # admin; --confirm (or --yes) acknowledges
lhbox catalog publish <name> --confirm <name>              # the same, with the name typed out
lhbox catalog publish <name> --confirm --files public/     # also publish one folder of the file bucket
lhbox catalog publish <name> --confirm --no-files          # stop publishing the folder; the tables stay public
lhbox catalog unpublish <name>                             # private again: tables, folder and AGENTS.md
lhbox catalog public-url <name> [--table <ns>.<table>]     # the public URL and the no-credentials DuckDB recipe

Only an admin of the organisation can publish or unpublish. The account page has the same control in the catalog's Settings. In the API it is POST /v1/catalogs/{id}/public with {"confirm": "<catalog name>"} (and optionally "files": "<prefix>/" or "files": null), and DELETE /v1/catalogs/{id}/public; see the API.

Publishing again without --files keeps whatever folder is already published. A new --files folder replaces the old one; only one folder can be public at a time.

What becomes public

part of the catalog public?
every table: every data file and every retained metadata.json, including the table's history yes, read-only
the list of object names in the catalog's table storage yes
the catalog's AGENTS.md (at the root of its file bucket), when it has one yes, that one file
one folder of the file bucket, named with --files <prefix>/ only if you name it
the rest of the file bucket no
writes and deletes, by anyone outside your organisation no, refused
your other catalogs no, unchanged

In the published folder, anyone can download a file, make HTTP range requests (a Cloud-Optimized GeoTIFF read with GDAL fetches only the ranges it needs) and list the files under the folder. Nothing outside the folder can be read or listed, and nothing inside it can be written or deleted anonymously. The folder is one relative prefix ending in /; a prefix with *, ?, $ or .., or a top-level folder starting with _, is refused with 400 invalid_files_prefix before anything changes.

lhbox catalog get and lhbox catalog list show public_files_prefix; the catalog's API row carries public_url, public_files_url and public_agents_md_url while it is public (null while private).

The public page

A public catalog has a page at https://lakehousebox.com/app/<handle>/<catalog>, where <handle> is your organisation's handle. It needs no account. It lists the tables with their columns, shows the catalog's AGENTS.md under "Written by the catalog owner", and gives two recipes: one to read every table with no account, and the lhbox duckdb command to attach it by name. The same content is JSON at GET /v1/public/<handle>/<catalog>, which answers 404 public_catalog_not_found for any catalog that is not public, whether it is private or does not exist.

Reading without an account

DuckDB reads a public table over plain HTTPS. The requests go unsigned; do not put a made-up key pair in the secret, because the store refuses keys it does not know, even on a public catalog.

INSTALL iceberg; LOAD iceberg; INSTALL httpfs; LOAD httpfs;
CREATE SECRET lhbox_public (TYPE S3, ENDPOINT 's3.lakehousebox.com', URL_STYLE 'path', USE_SSL true);
-- a table by its root (reads <ns>/<table>/metadata/version-hint.text)
SELECT count(*) FROM iceberg_scan('s3://<handle>--<catalog>/<ns>/<table>');
-- or by its current metadata file, with no secret at all
SELECT count(*) FROM iceberg_scan('https://s3.lakehousebox.com/<handle>--<catalog>/<ns>/<table>/metadata/v<N>.metadata.json');

The bucket name is the catalog's own (bucket in lhbox catalog get); catalogs created before 2026-09-21 have a w-<uuid> bucket instead. lhbox catalog public-url <name> --table <ns>.<table> prints a table's current metadata URL, which changes on every commit. The table-root form follows version-hint.text: it is current at once after a change made through LakehouseBox, and within about two minutes after a commit an engine makes directly. Until then it reads the previous version.

A reader with no account gets no catalog access: the REST catalog stays closed to anonymous callers.

Attaching by name, with any account

Anyone with a LakehouseBox account (free) can attach every table of a public catalog read-only in one step:

lhbox duckdb --catalog <handle>/<catalog>

The catalog is attached as <handle>_<catalog>, so a table reads as <handle>_<catalog>.<namespace>.<table>. The command fetches the catalog's shared public-reader key, which reads that catalog's tables and nothing else: no writes, no other catalog, not the private part of the file bucket. The key is replaced when the owner unpublishes, so it is fetched each time; --persist is refused for a public catalog. See engines and the CLI.

For an agent on MCP, the tool open_public_catalog takes <handle>/<catalog> and returns the tables with their columns (up to 200 listed), a DuckDB recipe that attaches the catalog read-only, and the catalog's AGENTS.md when it has one, labelled as the owner's words, not instructions. The MCP query tool does not read public catalogs of other organisations: attach them in your own DuckDB.

Limits: two storage tiers

Storage is counted in two tiers per organisation, and lhbox usage reports both:

tier limit name free allowance
private catalogs storage_bytes 5 GB
public catalogs public_storage_bytes 50 GB

A public catalog's bytes (its tables and its whole file bucket, published folder or not) count in the public tier. Publishing moves the catalog's bytes from the private tier to the public one. A publish that would take the public tier over its limit is refused with 409 quota_exceeded, naming public_storage_bytes. Publishing also sets the catalog's tier policy to hot.

Risks, stated plainly

  • Everything in a public catalog is readable by anyone, with no account, and can be copied. Unpublishing stops further reads; it cannot recall copies already made.
  • History is public too. Every retained metadata.json is readable, not only the current snapshot, so a row you deleted may still be readable in an older snapshot until snapshot and metadata retention removes it. Check what a table held before you publish it, not only what it holds now.
  • Object names can be listed, in the table storage and in the published folder.
  • Anything later written into the published folder is public too, including files an uploader drops there. Pick a folder that holds only what readers may fetch.
  • Downloads are not limited by you. Anyone can read the data as often as they like. LakehouseBox does not charge for egress today.
  • AGENTS.md is public while the catalog is; do not put anything in it you would not publish.

The LakehouseBox public data catalog

LakehouseBox publishes a catalog of public datasets itself: jatorre/pubdata, with weather, public holidays, countries, places, population, earthquakes, airports and rail data. /public-data describes the datasets; the catalog's page is lakehousebox.com/app/jatorre/pubdata. Read a table with no account:

INSTALL iceberg; LOAD iceberg; INSTALL httpfs; LOAD httpfs;
CREATE SECRET lhbox_public (TYPE S3, ENDPOINT 's3.lakehousebox.com', URL_STYLE 'path', USE_SSL true);
SELECT * FROM iceberg_scan('s3://jatorre--pubdata/reference/countries') LIMIT 10;

Run on 2026-09-29 with DuckDB 1.5.5 and no account: count(*) over this table answered 249 rows in 0.8 s.

Or attach it with an account, next to your own catalogs, and join its tables with yours:

lhbox duckdb --catalog jatorre/pubdata

Not yet

Publishing single tables rather than a whole catalog, more than one public folder per catalog, and a directory of public catalogs are not built.