Clean up stale PlanetScale branches before they cost you money

Every morning, find the development branches nobody is using anymore, skip anything with a migration still in flight, delete the rest, and post a Slack recap.

Deterministic Code
PlanetScaleSlack BotEngineeringOperationsNotifications & AlertsDaily Digests
PromptCreate

Every day at 7am, clean up development branch sprawl across our PlanetScale databases before it quietly costs us money. Build this as a deterministic code workflow on a cron trigger. Every step is a known operation, so no agent reasoning is needed.

Expose these as configurable inputs with sensible defaults: the PlanetScale organization name, the age threshold in days (default 14), a list of protected branch names that must never be deleted (default should include staging), and the Slack channel that receives the summary.

Step one, use PlanetScale List databases to get every database in the configured organization. For each database, use PlanetScale List branches to get its branches. Both of these endpoints are paginated, so page through until there are no more results rather than reading only the first page.

Step two, select the deletion candidates. From each database's branches, drop the production branch, identified by the branch's production flag rather than by guessing at its name. Drop any branch whose name appears in the configured protected list. From what remains, keep only branches whose created_at timestamp is older than the age threshold, comparing against the current time in UTC.

Step three, protect in flight migrations. For each database, use PlanetScale List deploy requests and collect the branch names attached to any deploy request that is still open. Remove those branches from the candidate list. This rule matters more than the cleanup itself, so an unfinished migration is never destroyed, and if the deploy request lookup fails for a database, skip that database's deletions entirely rather than deleting without the safety check.

Step four, use PlanetScale Delete a branch on each remaining candidate. If an individual delete fails, do not abort the whole run. Record the failure and carry on to the next branch, then include the failures in the summary.

Step five, post exactly one Slack message to the configured channel using the Slack Bot Send a Message operation. Group the results by database, listing the branch names that were deleted along with their age in days, and the count of branches remaining on that database afterwards. Add a short trailing line covering what was intentionally skipped and why, separating branches held back for an open deploy request from ones excluded as protected or production. Post the message even when nothing was deleted, stating that the check ran and found nothing old enough, so that a silent failure never looks the same as a clean result. Format the message with Slack mrkdwn, using single asterisks for bold.

Example output

PlanetScale branch cleanup, 7:00am checkout-api: deleted 4 stale branches • fix-tax-rounding (31 days old) • bruno-local-test (27 days old) • revert-webhook-retry (22 days old) • schema-spike-2 (19 days old) 6 branches remain identity-service: deleted 1 stale branch • drop-legacy-sessions (16 days old) 3 branches remain billing-core: nothing to delete, 2 branches remain Skipped: add-invoice-index (open deploy request), staging (protected), main (production)

What does this prompt do?

  • Checks every one of your PlanetScale databases each morning and finds development branches older than a cutoff you choose, 14 days by default.
  • Leaves your production branch alone, plus any branch you add to a protected list, so long lived staging branches are never touched.
  • Skips any branch that still has an open deploy request, so a migration that is mid flight is never destroyed.
  • Deletes what is left and posts a single Slack message showing what was removed from each database and how many branches remain.

What do I need to use this?

  • A PlanetScale account, with permission to view and delete branches on the databases you want cleaned up
  • The name of the PlanetScale organization that holds those databases
  • A Slack workspace and the channel where the daily summary should land

How can I customize it?

  • Change the age cutoff. Fourteen days is the default, but teams that move faster often drop it to seven.
  • Add branch names to the protected list so long lived staging or demo branches are always skipped.
  • Move the run time or the destination channel, or switch it to weekly if daily feels noisy.

FAQs

Could this delete our production branch by accident?
No. The production branch of every database is excluded before anything is considered for deletion, and you can add any other branch names to a protected list that is skipped as well.
What happens if someone is in the middle of a migration?
Before deleting anything, the workflow checks the open deploy requests on each database. Any branch attached to one is left in place, so work that is still in flight is never thrown away.
Why does leaving old branches around cost money?
PlanetScale bills development branches for the time they are in use, so branches that were created for a change that shipped months ago quietly keep adding to the bill. Removing them is the point of running this daily.
Does PlanetScale not already clean up branches on its own?
It can delete a branch automatically once a deploy request finishes, which covers changes that made it all the way through. It does not cover branches that were abandoned and never got a deploy request, and those are usually the ones that pile up. This workflow fills that gap.
What does the Slack message look like if nothing needed deleting?
It still posts, showing that the check ran and that nothing was old enough to remove. That way a silent failure never looks the same as a clean result.

Related templates

Build a credential rotation checklist when someone leaves

When someone leaves, we check which shared passwords they used in their final months and post a ranked rotation list to your security channel.

1Password
Rippling
Slack Bot
+1
Agentic Task
Weekly Amazon S3 bucket security audit posted to Slack

Every Monday, check every S3 bucket for public exposure, missing encryption and weak backup settings, then get the risks ranked in Slack.

Amazon S3
Slack Bot
Google Sheets
Agentic Task
Log Agorapulse social conversations to HubSpot contacts

Twice every weekday, the conversations from your social inbox land on the right HubSpot contact timelines, with a Slack recap for sales.

Agorapulse
HubSpot
Slack Bot
Agentic Task
Clean up HubSpot contacts from your Amazon SES suppression list

Every morning, find the addresses that hard bounced or filed a spam complaint, update the matching HubSpot contacts, and post a short Slack recap.

Amazon SES
HubSpot
Slack Bot
Agentic Task
Draft polite follow-ups for emails that never got a reply

Every weekday at 4pm, spot the threads that went quiet, stage a ready-to-send nudge in your mailbox, and get a ranked Slack recap.

Aurinko
Google Sheets
Slack Bot
Agentic Task
Replay failed SQS messages when a bug fix is merged

When you merge a fix in GitHub, this agent checks the matching dead-letter queue, replays the failed messages, and reports back on the pull request and in Slack.

Amazon SQS
GitHub
Slack Bot
Agentic Task

Stop paying for branches nobody remembers creating.

Set the cutoff once and let the cleanup run every morning, with a Slack recap so the team always knows what was removed.