This guide walks you through the lifecycle of adding a new extension, from setting up your environment to submitting a Pull Request.
Important
Please ensure you have also read the general CONTRIBUTING.md for CloudNativePG before proceeding.
Before proposing a change, ensure your local machine is compatible with the build stack.
- Fork the cloudnative-pg/postgres-extensions-containers repository.
- Clone your fork and enter the directory:
git clone https://github.com/<your-username>/postgres-extensions-containers.git
cd postgres-extensions-containers- Verify the Environment: Run the following to ensure you can build the existing project ecosystem.
task prereqs # Check if Go, Task, and Docker are ready
task checks:all # Validate current configurations
task bake:all # Optional: build all existing extensions to confirm the Dagger engineTo maintain high standards and avoid duplicated effort or architectural conflicts, every new extension begins with a formal proposal. During this phase, you must verify that the extension is available in the PGDG (PostgreSQL Global Development Group) repositories and identify its versioning logic.
You must verify the package across both the current Debian stable and
oldstable distributions to ensure compatibility. Use a temporary container to
search the repositories:
For Debian stable (13, trixie):
docker run -u root -ti --rm ghcr.io/cloudnative-pg/postgresql:18-minimal-trixieFor Debian oldstable (12, bookworm):
docker run -u root -ti --rm ghcr.io/cloudnative-pg/postgresql:18-minimal-bookwormThen, inside the container:
apt update && apt search <EXTENSION_NAME>Take note of both the package name and the version string.
Using pgvector as an example, you will notice that while the package name
remains constant, the versioning reflects the underlying Debian release:
trixie:0.8.2-1.pgdg13+1bookworm:0.8.2-1.pgdg12+1
Important
The pgdg13 or pgdg12 suffix is critical. Correctly identifying this
versioning pattern ensures that renovate can automatically monitor the
upstream repositories and trigger update Pull Requests once your extension is
merged.
If you want to get a list of the files contained in the package, you need to first install the extension in the disposable container:
apt install <package-name>Then, list the content of the package with:
dpkg -L <full-package-name>Confirm that .control and .sql files are present in the expected PostgreSQL
paths.
Important
If the package doesn't contain any .control file, it is likely to be a
PostgreSQL module rather than an extension. In this case, remember to set
the create_extension option to false in your metadata.hcl file.
Important
Community Commitment: By opening the issue, you are confirming your intent to help maintain this extension on behalf of the CloudNativePG community.
After gathering the package details and verifying the extension's license, submit your proposal:
- Point your browser to "New Extension Proposal".
- Provide the package name, versioning info, and a link to the upstream source.
- State the license clearly:
- CNCF-Allowed: licenses on the CNCF Allowlist (e.g., Apache-2.0, MIT, or PostgreSQL) are generally pre-approved.
- Other Open Source: licenses like FSF-approved (GNU GPL) will be evaluated on a case-by-case basis.
- Redistribution: since we redistribute unmodified software, ensure you identify where the upstream source code can be found (required for GNU GPL compliance).
Note
You do not need to wait for maintainer approval to begin development or submit your PR. You are encouraged to proceed immediately; however, please be aware that if a fundamental issue (e.g., licensing) is discovered during the proposal review, you may need to modify or discard your work.
git checkout -b dev/<extension-name>Generate the directory structure automatically:
task create-extension NAME=<extension-name>Note
For advanced scaffolding (custom distros or versions), see
BUILD.md.
The scaffolding generates metadata.hcl, Dockerfile, and README.md.
Follow the specific instructions and "TODO" comments found within each
generated file to finalize your extension.
Your metadata.hcl file requires two version fields:
-
package: The full Debian package version (e.g.,0.8.2-1.pgdg13+1). This includes packaging metadata and is used to install the correct package. -
sql: The PostgreSQL extension version as it appears in the catalog (e.g.,0.8.2). This is the version of the extension that will be verified as part of the automatic testing of the resulting containers. It should match what is defined by thedefault_versionfield in the control file.
Warning
The sql version is optional and only needed if your extension uses
CREATE EXTENSION (when create_extension = true in metadata).
Tip
Pay close attention to the // renovate: comments in the metadata and
README.md files; these are required for automated version tracking.
Testing is the most critical part of the lifecycle.
Note
For a detailed breakdown of the testing infrastructure, refer to
BUILD.md.
The repository provides a framework for full End-to-End validation. Ensure that the entire pipeline is working:
task checks:allThen run the full E2E tests for the extension. This task will build your image, push it to a local registry, spin up a Kind cluster, and run the functional tests:
task e2e:test:full TARGET="<extension-name>"Once the automated tests have run, the Kind cluster remains active. You can
"drop in" to this environment to verify the instructions you wrote in your
README.md.
task e2e:export-kubeconfig KUBECONFIG_PATH=./kubeconfig
export KUBECONFIG=$PWD/kubeconfigOnce the image is built and pushed to the local registry (localhost:5000),
you should verify the generated tags. You can use tools like skopeo to
inspect the local registry:
skopeo list-tags --tls-verify=false docker://localhost:5000/<extension-name>-testingImportant
Remember to add the -testing suffix to the container registry.
Verify that the output lists tags for all expected PostgreSQL and Debian version combinations.
Create a Cluster resource using the instructions from your README.md.
Pay close attention to the image location. Inside the Kubernetes cluster, the
local registry is reachable at registry.pg-extensions:5000:
image: registry.pg-extensions:5000/<extension-name>-testing:<tag>While the framework provides a generic smoke test, we highly encourage you to
add extension-specific tests. Review the postgis directory
for an example of additional testing using the Chainsaw framework.
Once you have finished your manual verification, tear down the test environment:
task e2e:cleanupThe README.md is typically the last file you complete. A clear, professional
README.md makes an extension successful. Ensure it includes YAML examples for
Cluster and Database resources so users can immediately adopt your work.
Once you have verified your extension locally and are satisfied with the results, it is time to submit your contribution.
To maintain a clean and searchable history, we require a specific commit format. If you have multiple experimental commits on your branch, please squash them into a single commit before submitting.
Format:
feat: add `<extension-name>` container image
<DESCRIPTION: Explain what the extension does and why it's being added.>
Closes #<issue-id>
Submission Requirements:
- DCO Compliance: All commits must be signed (
git commit -s) to certify that you have the right to submit the code under the project's license. - Upstream Target: Ensure your Pull Request is targeting the
mainbranch of the upstream repository.
By submitting, you confirm your commitment to maintain this extension on behalf of the CloudNativePG Community.