Request icon
OutputValues icon
If icon
Log icon
Loop icon
SlackIncomingWebhook icon
Schedule icon
Webhook icon

Prune Stale Ephemeral Preview Branches in Neon Serverless Postgres

Audit and prune inactive Neon Postgres preview branches from closed pull requests to reclaim storage and prevent branch quota exhaustion.

Categories
CloudData

Modern engineering teams running serverless PostgreSQL on Neon spin up isolated database branches for preview environments on every pull request. However, when pull requests merge or close without deleting their database branch, preview environments linger indefinitely. Over time, projects exhaust their account branch quota (preventing new CI preview builds) and accumulate ongoing storage costs for abandoned data copies.

This blueprint provides an automated FinOps guard that queries the Neon Cloud Management REST API, discovers idle preview branches older than a configurable retention threshold, enforces a safe deletion ceiling, and cleans up stale branches with dry-run protection and double-check readback verification.

How it works

  1. fetch_branches (io.kestra.plugin.core.http.Request) queries the Neon REST API for all branches in the target project.
  2. filter_stale_branches (io.kestra.plugin.core.output.OutputValues) evaluates branches using Pebble date math and jq filtering. It isolates branches matching inputs.preview_prefix, strictly excludes default and protected branches, and identifies those whose updated_at timestamp exceeds inputs.retention_hours.
  3. evaluate_stale_branches (io.kestra.plugin.core.flow.If) checks whether any stale branches require action.
  4. evaluate_dry_run_gate (io.kestra.plugin.core.flow.If) branches execution based on inputs.dry_run:
    • When dry_run: true, it logs the planned deletion list without mutating cloud resources.
    • When dry_run: false, prune_branches (io.kestra.plugin.core.flow.Loop) iterates sequentially over each branch with concurrencyLimit: 1 to dispatch DELETE requests to the Neon API.
  5. verify_readback (io.kestra.plugin.core.http.Request) performs an immediate post-deletion readback to verify that target branches are no longer present.
  6. notify_slack_summary (io.kestra.plugin.slack.notifications.SlackIncomingWebhook) dispatches an operational summary card to Slack detailing the reclaimed branches and current project branch count.

What you get

  • Automated preview branch hygiene preventing CI build failures caused by Neon branch quota limits.
  • Safe-by-default execution with dry_run: true and protection for default and protected branches.
  • Bounded blast radius through max_prune_count, capping how many branches can be deleted per execution.
  • Readback verification confirming cloud state before reporting success.
  • Native declarative orchestration requiring zero external container runners or custom Python scripts.

Who it's for

  • Platform Engineers and DevOps teams managing Neon serverless Postgres in CI/CD pipelines.
  • FinOps practitioners tracking and reducing non-production cloud database storage waste.
  • Database Administrators overseeing ephemeral preview environments for engineering teams.

Why orchestrate this with Kestra

Custom bash scripts and cron jobs querying cloud APIs often lack execution history, credential governance, and error handling. Running branch cleanup through Kestra provides unified secrets management for NEON_API_KEY, visual execution auditing, automated retries, and both scheduled and event-driven webhook execution directly linked to Slack notifications.

Pitfalls

  • Parent Branch Dependencies: Deleting a branch with child branches could fail if child dependencies exist. This blueprint targets leaf preview branches by filtering for the configured preview prefix (e.g., preview/).
  • Active Compute Endpoints: Neon automatically tears down ephemeral compute endpoints associated with a branch when the branch is deleted, but ensure long-running queries on preview environments are not abruptly disconnected by configuring a sufficient retention_hours buffer.
  • API Rate Limits: Neon management API endpoints enforce rate limits. The blueprint enforces concurrencyLimit: 1 on the deletion loop to avoid throttling during batch cleanups.

Prerequisites

  • A Neon serverless Postgres account and project.
  • A Neon Cloud API Key with project admin permissions.
  • A Slack incoming webhook endpoint for notifications.

Secrets

  • NEON_API_KEY: Neon API Key generated from the Neon Console account settings.
  • SLACK_WEBHOOK_URL: Slack Incoming Webhook URL for alerting.
  • WEBHOOK_KEY: Secret authentication key for the event-driven webhook trigger.

Quick start

  1. Store NEON_API_KEY, SLACK_WEBHOOK_URL, and WEBHOOK_KEY in your Kestra namespace secrets.
  2. Deploy this flow and run a manual execution with dry_run: true to review stale preview branches without deleting them.
  3. Once verified, set dry_run: false to enable active branch cleanup.
  4. Enable the daily_maintenance_schedule trigger for continuous automated pruning, or call pr_closed_webhook from your GitHub Actions workflow when a pull request closes.

How to extend

  • GitHub Pull Request Integration: Pass the pull request branch name directly to inputs.preview_prefix from a GitHub Actions webhook to trigger immediate branch deletion as soon as a pull request merges.
  • Threshold Alerting: Add an escalation step using core.execution.Fail if project branch usage exceeds 90% of your plan's branch limit.
  • Multi-Project Sweeps: Wrap this workflow in a parent flow using io.kestra.plugin.core.flow.Subflow to sweep multiple Neon projects across development and staging environments.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.