Check staging against production before your next Heroku deploy

By General Input

Open one screen, pick two Heroku apps, and see every setting, dyno, and add-on that differs, then fix the drift before you ship.

Integrations

  • Heroku
  • Slack

Type

App

Categories

  • Engineering
  • Operations

Build me an app I open right before a release, in the moment where staging is working fine and I need to know why production might not. It is a side by side parity console for two of my Heroku apps, and its whole reason to exist is that I can fix what I find without leaving the screen.

At the top, two dropdowns pick the left app and the right app, typically staging on the left and production on the right. Populate both pickers from Heroku List Apps and List Team Apps so personally owned and team owned apps both appear, sorted by name with the owning team shown next to team apps. Remember the last pair I compared so reopening the app puts me straight back where I was.

The main view is a three column config comparison. Call Get Config Vars on each of the two apps and split the keys into: settings only in the left app, settings only in the right app, and settings present in both but with different values. Each column has a count in its header. Keys that are identical in both apps collapse behind a single "in sync" count that I can expand if I want, because they are not what I came here for. Sort each column alphabetically and let me filter by key name.

Mask values by default. Anything whose key or value looks like a credential (names containing KEY, SECRET, TOKEN, PASSWORD, CREDENTIAL, DSN, connection strings with embedded credentials, or long high entropy values) renders masked, with a per row reveal control that unmasks only that row. Re-mask everything when I switch apps. For rows where values differ, once revealed, show the two values aligned so the actual difference is readable rather than making me eyeball two long strings.

Let me mark any key as "expected to differ". Those rows move into a collapsed section with a count and an undo, so per environment database links, add-on managed values, and anything else that is legitimately different per environment stop showing up as noise on every visit. This list persists for the workspace, not just for me, so a teammate opening the console before their own release gets the same cleaned up view. Seed it with nothing and let it build up through use.

Below the config comparison, compare the process formation. Call List Formation on each app and render one row per process type (web, worker, release, and so on) with the dyno size and quantity for each side. Highlight rows where the size or the quantity differs, and rows where a process type exists on one side only. This is the section that makes it obvious when staging runs one small web dyno and production runs four standard ones.

Under that, compare attached add-ons. Call List App Add-ons on each app, match them up by add-on service, and show the plan on each side. Flag add-ons attached to only one of the two apps and add-ons where the plan tier differs, so a missing Redis or a Postgres on a smaller plan in one environment is immediately visible.

The write controls are the point of the app. On any config key that differs or is missing on one side, give me a copy control that writes that value into the other app using Update Config Vars. Send only that one key. The Heroku config update merges keys rather than replacing the whole set, so this must never send a full config object, and setting a key to null is how a key gets deleted. The confirmation dialog names the target app and the key, shows the value being written (masked, with a reveal), and states plainly that saving this restarts the target app. After it succeeds, refresh that app's config and move the row into the in sync group.

Give the formation rows the same treatment: on any process type where the size or quantity differs, a control that matches one environment to the other using Scale Formation on the target app. The confirmation should read like "web on production goes from 2 Standard-1X to 4 Standard-2X" and note that this changes what the app costs to run. Never write anything without a confirmation, and surface Heroku's error message plainly if a write is rejected.

Add an "Explain this diff" button that kicks off a background agent. The agent reads both apps' config vars (Get Config Vars), process formations (List Formation), attached add-ons (List App Add-ons), and their recent deploy history (List Releases, the last twenty or so on each side), then writes a risk note. The note classifies each difference as either intentional per environment configuration or a probable mistake, ranks what should be fixed before shipping (blocking, worth a look, fine as is), and uses the release history to call out differences that appeared recently. It should pay particular attention to settings that change how the app actually runs rather than just what it points at, since something like a memory allocator enabled in production but not staging produces behaviour differences that look inexplicable from the outside. Keys I have marked expected to differ get acknowledged in one line rather than analysed.

The note lands back in the app in a panel below the comparison, timestamped, with the previous notes for the same pair kept as history so I can see whether we are getting better or worse at this. The agent also posts the same note to a Slack channel I choose using the Slack Send a Message action, formatted with Slack's own markup, opening with the two app names and the count of blocking items so the channel gets the headline without expanding. Remember the chosen channel for the workspace and let me turn the posting off if I just want the note in the app.

The agent must refer to config keys by name only. It should never write a secret value into the note or into Slack, even for keys I have revealed on screen.

Write the interface in the voice of someone about to ship, not the voice of configuration management. When the two apps line up, the empty state should say so with confidence rather than showing an empty table. Reading is always safe and instant; writing always asks first.

Related prompts

Explore more prompts
Call overdue Xero customers with an AI collections agentWin back LiveChat visitors whose chats went unansweredChat quality review board for LiveChat support leadsWin back no-show and cancelled appointments every morningLive Loop returns analytics with product-level drill-downNewsletter pre-flight and approval board for Mailjet sendsTurn a prospect spreadsheet into personalized sequence enrollmentsMailjet email delivery lookup console for support teamsCatch feature flags that never got switched on in productionKajabi customer support console for member access fixes