GuidesIntegrations
GitHub Action
A disposable preview database for every pull request - idempotent create, masked outputs, TTL backstop.
What it does
capy-base/capydb-preview-action@v1 creates a CapyDB preview database for a pull request, waits for it to be ready, and exports the connection strings into the job environment. It talks to the API with curl + jq (preinstalled on GitHub runners) — nothing to install, nothing to cache.
Usage
name: preview-database
on:
pull_request:
types: [opened, synchronize, reopened, closed]
jobs:
preview:
runs-on: ubuntu-latest
steps:
- name: Create preview database
if: github.event.action != 'closed'
id: capydb
uses: capy-base/capydb-preview-action@v1
with:
api-key: ${{ secrets.CAPYDB_API_KEY }}
project-id: ${{ vars.CAPYDB_PROJECT_ID }}
- name: Run migrations + tests against the preview
if: github.event.action != 'closed'
run: |
pnpm db:migrate
pnpm test
# DATABASE_URL / DATABASE_URL_UNPOOLED are already exported by the
# action (write-env defaults to true).
- name: Delete preview database
if: github.event.action == 'closed'
uses: capy-base/capydb-preview-action@v1
with:
api-key: ${{ secrets.CAPYDB_API_KEY }}
project-id: ${{ vars.CAPYDB_PROJECT_ID }}
command: deleteInputs
| Input | Default | Description |
|---|---|---|
api-key | — (required) | CapyDB API key. Use a project-scoped key stored in repo secrets. |
project-id | — (required) | The CapyDB project the preview belongs to. |
command | create | create (idempotent), reset, or delete. |
name | pr-<number> / branch slug | Preview name; re-running with the same name reuses the database. |
mode | clone | clone copies production data; empty starts blank. |
ttl-hours | 72 | Auto-delete after this many hours (1–168). |
api-url | https://capydb.dev/api/capydb | Override for self-hosted control planes. |
wait-timeout | 600 | Seconds to wait for the preview to become ready. |
write-env | true | Export DATABASE_URL / DATABASE_URL_UNPOOLED into the job env. |
Outputs
| Output | Description |
|---|---|
preview-id | ID of the preview database. |
preview-name | Resolved preview name. |
database-url | Pooled connection string (masked). |
database-url-unpooled | Direct connection string (masked). |
Behavior worth knowing
createis idempotent: pushing more commits to the same PR reuses the existing preview and extends its TTL instead of recreating it. Usecommand: resetif you want a fresh clone on every push.- Masked outputs: connection strings are registered with
::add-mask::so they never appear in logs. - TTL backstop: previews expire via their TTL even if the
closedjob never runs (force-pushed branch, cancelled workflow), so a missed cleanup cannot leak databases forever. - Key scoping: create the API key in the dashboard under Settings → API keys with a
project_id, scoped to the single project the workflow uses. A leaked project-scoped key cannot touch sibling projects or the org. See Authentication. - Ordering: unlike the Vercel/Netlify deploy-webhook flow, the Action is synchronous — database first, then your steps. Use it when build steps need the database to exist.