Skip to content

Configuration

The host, database, API and bucket are always the caller's. stacs has no defaults that point at any deployment, and reads a config only when one is named with --config.

# stacs.toml -- committed in the catalogue's own repository. Values are examples.
[catalogue]
api = "https://stac.example.org"            # STAC API base URL
collection_id = "my-collection"
bucket_url = "https://my-bucket.example.org" # serves collection.json and the items

[assets]
require = "data"        # every item must carry this asset key
forbid = ["legacy"]     # no item may carry any of these

[transport]             # only for commands that write
host = "user@stac-host.example.org"
db = "pgstac"
env_file = "/srv/stac/.env"           # sourced on the host before loading
workdir = "/srv/stac"                 # cd here on the host
path_prepend = "/usr/local/bin"
pg_host = "localhost"
pg_port = 5432
pg_user = "pgstac"
password_env = "POSTGRES_PASSWORD"    # the NAME of a variable the env_file defines
pypgstac = ["uv", "run", "pypgstac"]  # the launcher on the host

[tuning]                # optional
page_size = 10000       # keyset page size for full enumerations
chunk = 500             # ids per lookup when checking what was just written
fetch_workers = 20

[queryables."my:property"]  # optional: item properties clients can filter on
type = "string"             # a JSON Schema fragment, one table per property
title = "My property"

Flags override the catalogue and transport settings. The asset rules can be added to by a flag but never loosened: a declared require cannot be replaced, and --forbid-asset adds keys. Pointing at another collection id does not drop them.

Queryables are loaded for the catalogue's own collection_id and no other. pgstac serves /collections/<id>/queryables from its own table, never from the collection body, and its loader replaces every row of a name that the collection is served, including a shared or global one. So each catalogue declares its own, and rows for different collections coexist. register loads a queryable only when it is missing or served with a different definition, after the items, and never with an index (each load replaces the row, and with it any index set on that name by hand). Removing a declaration leaves its row in place: nothing is deleted. Queryables are loaded last, once the collection and items are verified and the collection is registered. A name the collection is then served with a different definition may come from a shared or global row, so register reads every other collection's definition of it just before the load and again after it, whatever happened in between, and fails if one was lost or changed. The host needs pypgstac 0.9.6 or later.

No setting is a secret. Writes go over ssh to the STAC host, which runs pypgstac load --method upsert there; the database password stays on the host and is named (password_env), never given. Each load first asks that connection which database it reached and refuses anything but db. The config refuses unknown keys, so a password line is an error rather than a silently ignored secret.