Skip to main content

Community extensions

Registering the extension in duckdb/community-extensions is what turns "download a file from a GitHub Release" into:

INSTALL duckfn_palette FROM community; -- once, needs network
LOAD duckfn_palette;

The community build is signed and matches the user's DuckDB version, so -unsigned is no longer needed. The registration itself is a pull request that adds two files:

In this repositoryIn the community repository
community-extension/description.ymlextensions/duckfn_palette/description.yml
community-extension/docs/function_descriptions.csvextensions/duckfn_palette/docs/function_descriptions.csv

The directory name must equal extension.name exactly — the community repository's scripts/build.py checks it.

The CSV​

The Added Functions table on the community extension page gets a function's description, comment and example from this CSV and nowhere else: DuckDB's C extension API has no way to set them. The text comes from the description / comment / example arguments of the #[duck_*] attributes, so it lives next to the function it describes:

#[duck_scalar_function(
description = "Convert a color to another space without gamut clamping",
comment = "…",
example = "SELECT plt_to_hex(plt_convert(plt_srgb(1, 0.5, 0), 'oklch'))"
)]

Regenerate and copy it whenever those attributes change:

just docs_csv
cp target/function_descriptions.csv community-extension/docs/function_descriptions.csv

To see which functions are missing from the CSV, the CLI can export the undocumented ones as a list:

cargo run --bin duckfn -- function_descriptions --all # -> target/function_descriptions_all.csv

This loads no extension and queries no catalog: it reads what was recorded at compile time, so it needs no DuckDB around.

From the attribute to the page:

Several examples are joined with "; " on export and lose their trailing semicolons; newlines collapse into spaces, because the target is a Markdown table. Write one complete statement per entry, in English.

description.yml​

The file is copied to the community repository as it is, so it holds fields and no comments. The fields that need a decision:

FieldWhat to put there
extension.nameThe extension name, identical to the directory name and to the entry-point symbol.
extension.descriptionOne line, shown in the extension list.
extension.versionThe released version, without a -dev.N suffix.
extension.language / buildRust and cargo for a project built from this template.
extension.licenseMIT (the repository's LICENSE). Note the community docs page spells it licence; the real schema is license.
extension.requires_toolchains"rust;python3" — the same value the CI workflow passes as extra_toolchains.
extension.maintainersYour GitHub handle.
repo.githubowner/repository.
repo.refThe commit SHA (40 characters) of the released version — git rev-list -n 1 v0.1.0 — not main and not the tag name. A registration points at immutable code, and a build from a branch would claim a development version.
docs.hello_worldA runnable example, rendered into a code block. Do not write INSTALL / LOAD here: the page adds those itself.
docs.extended_descriptionThe prose around the function table.

community-extension/AGENTS.md explains each field's provenance and the submission steps in more detail.

Submitting​

# 1. in a clone of your fork of duckdb/community-extensions
git checkout -b add-duckfn-palette

# 2. copy the two files into place
mkdir -p extensions/duckfn_palette/docs
cp <this repo>/community-extension/description.yml extensions/duckfn_palette/
cp <this repo>/community-extension/docs/function_descriptions.csv extensions/duckfn_palette/docs/

# 3. commit, push, open the PR
git add extensions/duckfn_palette
git commit -m "Add duckfn_palette: …"
gh pr create --repo duckdb/community-extensions --base main --head <you>:add-duckfn-palette

The maintainers will run the build workflows (a first-time contributor's run shows up as action_required until someone approves it — that is normal). After the merge, INSTALL duckfn_palette FROM community works, and the README can point at it.

Keeping it in step​

repo.ref and extension.version are pinned to one release. After every release, update both in this repository's community-extension/, copy them into the community repository, and push to the same PR branch (or open a new one). just release_bump already rewrites the version field; the commit SHA is the part a human has to fill in.