DEV Community

Sohana Akbar
Sohana Akbar

Posted on

How We Caught 12 Breaking API Changes Before They Hit Main: Our Journey to Ephemeral Staging Environments

The moment we realized our staging environment was broken

It was 3 PM on a Thursday, and our team was scrambling. A critical API change had just been merged to main, but the staging environment—our supposed safety net—was showing false positives. The integration tests passed, but the mobile app was completely broken in production.

That's when we knew: our shared staging environment was failing us.

The Problem: Shared Staging Is Broken by Design
Like many engineering teams, we operated with a single, shared staging environment. Every developer deployed their changes to the same place, leading to:

Deployment conflicts: "Who deployed that breaking change?"

Cascading failures: One broken PR would block the entire team

Test contamination: Data from one test would leak into another

Delayed feedback: You'd only discover issues after merging your PR and deploying to staging

The "works on my machine" syndrome, now at scale

The worst part? Our API contracts were changing constantly, but we only discovered breaking changes during integration testing—often too late.

The Solution: Ephemeral Environments per PR
We made a radical change: every PR gets its own isolated, short-lived environment.

Here's our architecture:

Our Implementation Stack
Infrastructure: Kubernetes (EKS) with namespace-per-PR

Orchestration: Custom GitHub Action workflow

Database: Isolated RDS instance per environment

Contract Testing: Pact flow + OpenAPI validation

Cleanup: AWS Lambda that runs every hour, destroying environments older than 2 hours

The Game Changer: Automated Contract Testing
The magic wasn't just in isolated environments—it was in what we did with them. Every time a PR deployed to its ephemeral environment, we ran:

  1. Consumer-Driven Contract Testing (Pact)
    Our mobile and web clients would verify their expectations against the actual deployed API. If a change broke what the client expected, the PR would fail.

  2. Provider Contract Validation
    We'd automatically verify that the deployed API matched our OpenAPI specification. If you added a required field without updating the spec, you'd know immediately.

  3. Schema Diff Detection
    We compared the new API schema against the production baseline. Any breaking changes (removing fields, changing types, adding required properties) would trigger a review.

  4. Integration Smoke Tests
    Each environment ran a suite of end-to-end tests with real client applications connecting to the backend.

The Results: 12 Breaking Changes Caught
In our first month with ephemeral environments, we caught 12 breaking API contract changes that would have:

Crashed our mobile app

Broken third-party integrations

Caused data corruption in production

Required emergency rollbacks

One Real Example
A developer modified the User object to rename user_id to userId for consistency. The OpenAPI spec was updated, but the mobile app's contract test immediately caught the mismatch:

text
❌ Contract violation: Expected 'user_id' but found 'userId'
Breaking change detected in GET /api/v2/users/123
The PR was blocked, the issue was fixed in 30 minutes, and the mobile app never broke.

The Economics: Cost vs. Value
You might think: "Ephemeral environments sound expensive." Let's do the math:

Before:

1 shared staging environment running 24/7: $500/month

1 production outage per month: $10,000+ in lost revenue

Developer hours wasted debugging environment issues: 40+ hours/month

After:

Ephemeral environments run ~8 hours/day (active PRs): ~$300/month

0 production-breaking API changes in 3 months

Developer productivity increased by ~30%

Net result: We're saving money AND shipping faster.

Lessons Learned

  1. Start Small, Scale Smart
    We didn't spin up full environments for every PR immediately. We started with just the critical backend services.

  2. Make Cleanup Aggressive
    2-hour TTL seemed short initially, but developers learned to work faster. For long-running PRs, they could request extensions.

  3. Invest in Observability
    Each environment had its own logging and metrics. We could debug failures without affecting others.

  4. Education is Key
    Developers needed to understand why userId vs user_id matters. We created "Breaking Change 101" docs.

  5. Contract Tests Are Only Half the Battle
    We also needed:

Load testing (some issues only appear under load)

Security scanning

Database migration testing

The Future: Beyond API Contracts
Now that we have the infrastructure, we're expanding:

Database migrations: Test schema changes on a copy of production data

Feature flags: Test features in isolation before global rollout

Performance benchmarks: Detect performance regressions per PR

Security scanning: Run vulnerability scans on each environment

Should You Do This?
Yes, if:

You have breaking changes that go to production

Your staging environment is a bottleneck

You have multiple services with dependencies

You want to ship faster with more confidence

Not yet, if:

You're a pre-revenue startup with no customers

Your infrastructure is manual and fragile

You're still working toward basic CI/CD

Getting Started: A Practical Roadmap
Week 1-2: Automation Foundation

Set up infrastructure-as-code (Terraform/CDK)

Create scripts to spin up/down environments

Define environment variables and secrets management

Week 3-4: Core Services

Start with your most critical microservice

Deploy it to an ephemeral environment per PR

Run basic smoke tests

Week 5-6: Contract Testing

Implement Pact or OpenAPI validation

Create test suites that verify contracts

Set up CI/CD integration

Week 7-8: Scale and Optimize

Add more services to the stack

Fine-tune resource allocation

Implement cost monitoring

Week 9+: Iterate

Gather developer feedback

Add database support

Enhance observability

The Bottom Line
Ephemeral staging environments transformed how we build software. We've gone from "breaking changes are inevitable" to "breaking changes are caught in PRs."

The 12 breaking changes we caught weren't just bugs—they were 12 production incidents that never happened.

That's not just a win for engineering. It's a win for every user who depends on our software.

Have you implemented ephemeral environments? What challenges did you face? Let's discuss in the comments!

Resources to Get Started
Kubernetes Namespaces: Kubernetes.io docs

Pact Contract Testing: Pact.io

GitHub Actions for Preview Deployments: GitHub Docs

AWS EKS Ephemeral Environments: AWS Quick Start

About the Author: I'm a lead engineer at a growing SaaS company, passionate about developer productivity and reliable systems. You can find me on GitHub and Twitter.

Have questions about implementing this in your org? Reach out—I'm happy to share our battle scars!

Top comments (0)