kpg is a narrow, command-first CLI for connecting to Kubernetes-hosted Postgres databases.
V1 discovers supported Postgres operator resources, reads generated application credentials, opens a foreground port-forward to the read-write service, and exposes PG* environment variables for psql, pgcli, or any Postgres-compatible client.
kpg list
kpg list --output json
kpg connect
kpg connect <cluster|namespace/cluster|substring>
kpg connect <provider>:<namespace>/<cluster>
kpg connect <cluster|namespace/cluster|substring> -- psql
kpg connect <cluster|namespace/cluster|substring> --output shell
kpg connect <cluster|namespace/cluster|substring> --user <user> --database <db>
kpg last
kpg last --user <user> --database <db>
kpg last -- psql
kpg version
kpg completion <bash|zsh|fish|powershell>Shared flags:
-c, --context <name> kube context override
-n, --namespace <name> restrict discovery/lookup to one namespace
-p, --local-port <port> use a fixed local port
-o, --output shell|dotenv|json
-h, --helpRequirements:
- Go 1.26 or newer
- A kubeconfig with access to the target cluster
- CloudNativePG or Zalando Postgres Operator resources in the active context
psql,pgcli, or another Postgres client when using command mode
go install github.com/pscheid92/kpg@latestPrebuilt binaries for Linux, macOS, and Windows are attached to GitHub Releases.
Release builds set kpg version from the tag, commit, and build date. Releases
are created from tags named v*, for example:
git tag v0.1.0
git push origin v0.1.0Release archives and checksums.txt are signed with
pqsign. Each signed file has a matching
.pqsig asset in the release. Verify an archive with the committed release
public key:
pqsign verify kpg_0.1.0_linux_amd64.tar.gz -p release.key.pubThe release workflow expects these GitHub repository secrets:
PQSIGN_SECRET_KEY: base64-encoded encrypted pqsign secret key file matchingrelease.key.pubPQSIGN_PASSWORD: password for that secret key
In an interactive terminal, kpg connect opens a subshell with PG* environment values already exported. Exiting that shell closes the tunnel:
kpg connect app-db
psql
exitWhen run in an interactive terminal with no target, kpg connect opens a searchable target picker before starting the subshell. Type to filter, use arrow keys or j/k to move, press Enter to connect, or Esc to cancel. In non-interactive use, pass the target explicitly.
If a command is provided after --, kpg injects the same PG* environment values into that command and stops the tunnel when the command exits:
kpg connect app-db -- psql
kpg connect app-db -- pgcliUse --output to print connection values instead of entering a subshell or running a command. In this mode, kpg connect keeps the tunnel alive in the foreground until Ctrl-C:
export PGHOST=127.0.0.1
export PGPORT=15432
export PGUSER=app
export PGPASSWORD=secret
export PGDATABASE=app
export PGSSLMODE=disablekpg connect app-db --output shell
kpg connect app-db --output dotenv
kpg connect app-db --output jsonUse --user and --database to override the defaults discovered from the
operator resource and generated credentials:
kpg connect app-db --user reporting_user --database reports
kpg last --user reporting_user --database reportsTargets can be written as a cluster name, namespace/cluster, or a unique substring match. If multiple providers expose the same namespace and cluster, use a provider-qualified target:
kpg connect cnpg:app/app-db
kpg connect zalando:postgres/acid-mainAmbiguous matches fail with candidate suggestions. kpg list prints provider information when it is needed to distinguish targets. kpg list --output json emits script-friendly target metadata without secrets.
The last successful target is stored at the XDG state path, normally:
~/.local/state/kpg/last.json
Only the namespace and cluster are stored. Discovery data and secrets are not cached.
V1 supports CloudNativePG and Zalando Postgres Operator.
kpg uses Kubernetes API discovery to detect which supported provider
resources are registered, then lists only those resources. It does not list
CustomResourceDefinition objects. By default, discovery tries to list
supported resources across namespaces. If Kubernetes denies an all-namespace
provider list, kpg retries that provider in the current kube context
namespace. Use --namespace <name> to make discovery strictly namespaced, or
pass a namespace-qualified target such as app/app-db.
CloudNativePG:
postgresql.cnpg.io/v1 Cluster
For each cluster:
RW service: <cluster>-rw
App secret: <cluster>-app
Database and user are read from the generated app secret when present. Missing values fall back to spec.bootstrap.initdb.database and spec.bootstrap.initdb.owner.
Zalando Postgres Operator:
acid.zalan.do/v1 postgresql
For each Zalando cluster:
RW service: <cluster>
User secret: <username>.<cluster>.credentials.postgresql.acid.zalan.do
The first database in spec.databases, sorted by name, is used as the default database. Its owner is used as the default user. If spec.databases is empty, the first prepared database in spec.preparedDatabases, sorted by name, is used. If no database is available, the first user in spec.users, sorted by name, is used. Cross-namespace user notation like appspace.db_user is supported for the documented default secret naming convention. When --database selects a database with a known owner and --user is not set, that owner is used as the default user.
just check
just coverage
just coverage-html
just acceptance app/app-db
just release-snapshot
just release-snapshot-signedThe CLI is built with Cobra. Kubernetes access uses client-go: dynamic clients for provider CRDs, typed core clients for Secrets/Services/Pods/Namespaces, and client-go port-forwarding against the selected pod behind each provider's read-write service. Provider rules live in separate files under internal/kube.
just acceptance requires a working kube context, access to the target cluster, and psql on PATH.
just release-snapshot requires GoReleaser and writes unsigned local release artifacts to dist/.
just release-snapshot-signed also requires pqsign and expects PQSIGN_SECRET_KEY_PATH plus PQSIGN_PASSWORD.
Shell completion is provided by Cobra:
kpg completion zsh
kpg completion bash
kpg completion fishCompletions include:
kpg -c <TAB>for kubeconfig contextskpg -n <TAB>for namespaces in the selected contextkpg connect <TAB>for current Postgres targets
Namespace filtering is honored, for example kpg connect -n app <TAB>.
For a one-off zsh session:
source <(kpg completion zsh)For persistent zsh completion:
just install-completion-zshThen ensure your ~/.zshrc has the completion directory in fpath before compinit:
fpath=("$HOME/.zsh/completions" $fpath)
autoload -Uz compinit
compinitOpen a new shell, or run:
exec zshMIT