DEV Community

Cover image for Blue-Green Deployment for APIs: How to Test Before You Flip the Switch
Hassann
Hassann

Posted on • Originally published at apidog.com

Blue-Green Deployment for APIs: How to Test Before You Flip the Switch

Blue-green deployment can give you zero-downtime releases, but only if you verify the idle environment before users hit it. A load balancer health check that returns 200 OK proves the process is running. It does not prove the new build still returns the right JSON, honors the API contract, accepts existing tokens, or works with real client flows.

Try Apidog today

This guide shows how to test the green environment like a real user before switching production traffic. You’ll deploy to green, run smoke and full API test suites against it, block the cutover on failures, and wire the process into CI/CD. We’ll use Apidog and the Apidog CLI so the scenarios you build visually can run unattended in your pipeline.

If your current blue-green verification step is “click around for a minute,” replace it with an automated gate. Green is fully deployed and isolated, which makes it the perfect target for pre-production API validation.

TL;DR

Blue-green deployment runs two production-grade environments side by side. Blue serves live traffic. Green receives the new build. Before switching traffic from blue to green, run your API test suite directly against green.

With the Apidog CLI:

  1. Build API test scenarios once.
  2. Parameterize the base URL.
  3. Run the same tests against the green environment in CI.
  4. Fail the deployment if any assertion fails.
  5. Switch traffic only after the suite passes.

Health checks confirm the service is up. API tests confirm the contract still works.

What blue-green deployment actually is

Blue-green deployment keeps two production-grade environments available:

  • Blue: the current live environment.
  • Green: the idle environment where the new version is deployed.

You deploy the new build to green, verify it, then switch traffic using a router, load balancer target, DNS record, or Kubernetes service selector. Green becomes live. Blue stays warm as the rollback target.

The benefits are clear:

  • No maintenance window.
  • Near-instant cutover.
  • Fast rollback because the previous version is still running.
  • Safer releases than replacing live instances in place.

But the pattern only works if green is actually ready. A shallow /health check is not enough. Since green is already deployed and reachable before public traffic hits it, you should run realistic API tests against it.

For release strategy context, see this breakdown of continuous delivery vs continuous deployment vs continuous integration.

Why a health check is not a test

A typical load balancer probe looks like this:

# Load balancer health probe
GET /health -> 200 OK -> mark target healthy
Enter fullscreen mode Exit fullscreen mode

That endpoint often returns a static response:

{
  "status": "ok"
}
Enter fullscreen mode Exit fullscreen mode

This proves the process can respond. It usually does not verify:

  • Database access.
  • Authentication.
  • Business endpoints.
  • Serialization.
  • Response schemas.
  • Backward compatibility.
  • Required headers.
  • Real client workflows.

A build can pass /health while still breaking production traffic.

Common failures a health check misses:

  • A migration did not run, so GET /orders/{id} fails on a missing column.
  • user_id changed to userId, breaking downstream consumers.
  • Auth changes now reject tokens still issued by the mobile app.
  • A dependency changed date formatting from ISO 8601 to Unix timestamps.
  • A new required header causes old clients to receive 400.

The fix is not to overload /health. The fix is to run an API test suite that calls endpoints like clients do and asserts on:

  • Status codes.
  • Response bodies.
  • JSON schemas.
  • Headers.
  • Auth behavior.
  • Error cases.
  • Latency.

This is the same discipline behind API contract testing: verify that the running service still matches the contract consumers depend on.

The blue-green API testing workflow

Use this deployment flow:

  1. Deploy to green Push the new build to the idle environment, for example:
   https://green.internal.example.com
Enter fullscreen mode Exit fullscreen mode

No public traffic reaches it yet.

  1. Smoke test green

    Run a small critical-path suite. For example: login, fetch a resource, create a resource, read it back. Fail fast if any step breaks.

  2. Run the full API suite against green

    Execute happy paths, error cases, auth flows, schema assertions, and latency checks.

  3. Gate the cutover

    If the suite passes, continue. If it fails, stop the pipeline. Blue is still serving production traffic.

  4. Switch traffic

    Repoint the load balancer, DNS, router, or Kubernetes service selector from blue to green.

  5. Smoke test production after cutover

    Run the same smoke suite against the live production URL.

  6. Keep blue warm

    Hold blue during the rollback window. If monitoring shows problems, switch back.

The important part: steps 2, 3, and 6 should use the same test definitions. Only the target environment changes.

Build the test scenarios in Apidog

Start by building test scenarios in Apidog. Download Apidog and create a project for the service you deploy.

In Apidog, a test scenario is an ordered set of API requests with assertions and variable passing between steps.

For a blue-green readiness gate, build scenarios that represent real client behavior.

Example starter suite for an orders API:

  • Auth flow

    • POST /auth/login
    • Assert 200
    • Extract the bearer token into a variable
    • Use that token in later requests
  • Read path

    • GET /orders
    • Assert 200
    • Assert the response is an array
    • Assert each item has id, status, and total
  • Single resource

    • GET /orders/{id}
    • Assert the response matches the OpenAPI schema
    • Assert total is a number greater than zero
  • Write path

    • POST /orders
    • Assert 201
    • Assert the returned id is non-empty
    • GET the new order by id
    • Assert it persisted correctly
  • Negative cases

    • GET /orders/{id} with an invalid token
    • Assert 401
    • POST /orders with a missing required field
    • Assert 400

Focus on two assertion types:

  1. Schema assertions

    Validate responses against JSON Schema or OpenAPI definitions. This catches renamed fields, missing fields, and type changes.

  2. Response assertions

    Check specific values, headers, and response time. This catches subtle drift such as changed date formats, unexpected null, or latency regressions.

Parameterize the base URL

Do not hardcode this in test requests:

https://blue.example.com
Enter fullscreen mode Exit fullscreen mode

Instead, define an environment variable:

{{baseUrl}}
Enter fullscreen mode Exit fullscreen mode

Then configure separate environments:

  • Local
  • Green
  • Production
  • Blue, if needed

Example:

{{baseUrl}}/orders
{{baseUrl}}/orders/{{orderId}}
{{baseUrl}}/auth/login
Enter fullscreen mode Exit fullscreen mode

This lets the same suite run against green before cutover and production after cutover.

This environment and secrets model is also covered in this guide to an API client with environment and secrets management.

To run multiple scenarios together, use Apidog test suites.

Run the suite from the command line

Build and debug scenarios in the desktop app. Run them in CI with the Apidog CLI.

Install the CLI with npm:

npm install -g apidog-cli
Enter fullscreen mode Exit fullscreen mode

You need Node.js v16 or later.

In Apidog, generate a CI config for your test scenario or suite. The command has this shape:

apidog run "https://api.apidog.com/api/v1/api-test/ci-config/<config-id>/detail?token=<token>" \
  -r html,cli \
  --out-file green-readiness
Enter fullscreen mode Exit fullscreen mode

Reporter options:

  • cli: prints results in the terminal.
  • html: generates a report you can archive as a CI artifact.
  • json: useful if another tool needs to consume the results.

To run against green, pass the green environment:

# Test the green idle environment before cutover
apidog run "<ci-config-url>" \
  --environment <greenEnvironmentId> \
  -r cli,html \
  --out-file green-pre-switch
Enter fullscreen mode Exit fullscreen mode

You can also run from exported scenario files if you want test assets in the repository:

apidog run --exported-data ./tests/orders-readiness.json \
  --variables ./tests/green.variables.json \
  -r cli
Enter fullscreen mode Exit fullscreen mode

For more CLI usage in pipelines, see how to automate API tests in CI/CD.

The key behavior for blue-green deployment: the CLI exits non-zero when an assertion fails. That exit code is your deployment gate.

Wire it into GitHub Actions

Here is a GitHub Actions workflow that:

  1. Deploys the build to green.
  2. Runs the readiness suite against green.
  3. Switches traffic only if the suite passes.
  4. Runs a post-cutover smoke test against production.
name: deploy-blue-green

on:
  push:
    branches: [main]

jobs:
  deploy-green:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Deploy build to green environment
        run: ./scripts/deploy-green.sh

      # green is now reachable at https://green.internal.example.com

  test-green:
    needs: deploy-green
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install Apidog CLI
        run: npm install -g apidog-cli

      - name: Run readiness suite against green
        run: |
          apidog run "${{ secrets.APIDOG_CI_CONFIG_URL }}" \
            --environment "${{ vars.GREEN_ENV_ID }}" \
            -r cli,html \
            --out-file green-readiness

      - name: Archive HTML report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: green-readiness-report
          path: ./green-readiness.html

  switch-traffic:
    needs: test-green
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Flip router from blue to green
        run: ./scripts/switch-to-green.sh

      - name: Smoke test production URL post-switch
        run: |
          npm install -g apidog-cli
          apidog run "${{ secrets.APIDOG_SMOKE_CONFIG_URL }}" \
            --environment "${{ vars.PROD_ENV_ID }}" \
            -r cli
Enter fullscreen mode Exit fullscreen mode

The gate is handled by this line:

needs: test-green
Enter fullscreen mode Exit fullscreen mode

If test-green fails, switch-traffic never runs. Blue keeps serving users.

Use secrets for sensitive values:

${{ secrets.APIDOG_CI_CONFIG_URL }}
${{ secrets.APIDOG_SMOKE_CONFIG_URL }}
Enter fullscreen mode Exit fullscreen mode

Environment IDs can be repository variables if they are not sensitive:

${{ vars.GREEN_ENV_ID }}
${{ vars.PROD_ENV_ID }}
Enter fullscreen mode Exit fullscreen mode

The same structure works in GitLab CI, Jenkins, CircleCI, and Azure Pipelines: a test stage exits non-zero and blocks the switch stage.

For more GitHub Actions setup detail, see automating API tests in GitHub Actions.

Run smoke tests first, then the full suite

Do not wait twelve minutes to discover that login is broken. Split verification into two passes.

1. Smoke test

Keep this fast: three to five requests, ideally under thirty seconds.

Example:

POST /auth/login
GET /orders
POST /orders
GET /orders/{newId}
Enter fullscreen mode Exit fullscreen mode

If this fails, stop immediately.

2. Full suite

Run this only after the smoke test passes. Include:

  • All critical endpoints.
  • Happy paths.
  • Error cases.
  • Auth permutations.
  • Pagination.
  • Rate-limit headers.
  • Schema validation.
  • Response-time assertions.

This maps well to test scenario vs test case: the smoke scenario gives fast confidence, while the full suite provides broader coverage.

Handle test data carefully

Green may be production-grade infrastructure, so be intentional with write-path tests.

Options:

  • Use a dedicated test account and clean up created records.
  • Use idempotent test data.
  • Run write tests against a green instance backed by staging data before promoting the data layer.
  • Tag test-created records for cleanup.

The goal is to verify real behavior without polluting production data. This is where the distinction between a sandbox vs a test environment matters.

Common mistakes to avoid

Testing blue instead of green

If the suite points at the live URL before cutover, you are testing the version already in production.

Always target the green base URL explicitly:

https://green.internal.example.com
Enter fullscreen mode Exit fullscreen mode

Only checking status codes

A 200 with the wrong body is still broken. Assert on payload shape, required fields, types, and key values.

Skipping negative cases

Happy-path tests will not catch auth and validation regressions.

Include cases such as:

Invalid token -> 401
Missing required field -> 400
Forbidden action -> 403
Enter fullscreen mode Exit fullscreen mode

Tearing down blue too early

Blue-green rollback is fast only if blue stays warm. Keep it available through your monitoring window.

Hardcoding URLs

Hardcoded hosts make tests environment-specific. Use variables:

{{baseUrl}}/orders
Enter fullscreen mode Exit fullscreen mode

Treating /health as the release gate

A health check tells the load balancer a process exists. Your API tests tell you the contract still works.

Blue-green vs canary: where testing fits

Blue-green is not the only zero-downtime release pattern. Testing shifts depending on how traffic moves.

Strategy How traffic moves Where API testing fits
Blue-green All at once, blue to green Full suite against green before the switch; the gate is pre-cutover
Canary Gradually, small % to new version Continuous assertions on the canary slice; promote on clean metrics
Rolling Instance by instance, in place Per-instance smoke checks; harder to gate because rollout is already underway
Recreate Stop old, start new, with downtime Suite runs during the window; downtime is the trade-off

Blue-green gives the cleanest pre-release gate because green is fully deployed and isolated. Canary trades that clean gate for gradual exposure and relies more heavily on live monitoring.

For many API-backed services, blue-green plus a pre-cutover API suite is the simplest way to get high confidence without a maintenance window.

What this looks like in practice

A fintech team running a payments API uses blue-green for every release because a bad deploy can mean failed transactions. Their pre-switch gate is a forty-scenario suite against green covering:

  • Auth.
  • Idempotency keys.
  • Currency rounding.
  • Webhook signatures.
  • Schema compatibility.

The full run takes about six minutes. Production traffic does not switch until the suite is green, and the HTML report is attached to every deploy for auditing.

A SaaS team with a public API uses a leaner flow:

  1. Run a twelve-scenario smoke gate against green.
  2. Switch traffic.
  3. Run a post-cutover smoke test against the live URL.

Their highest-risk failure is schema drift, so schema assertions are the core of their gate.

Both teams build scenarios once in Apidog and run them from the CLI on every deployment.

Conclusion

Blue-green deployment gives you a fully deployed copy of production before every release. Do not waste that opportunity with only a shallow health probe. Test green like a real client before switching traffic.

Implementation checklist:

  • Build API scenarios for auth, reads, writes, negative cases, and schema assertions.
  • Use {{baseUrl}} so the same suite runs against any environment.
  • Run a fast smoke test against green.
  • Run the full suite against green.
  • Block the switch step on the CLI exit code.
  • Run a post-cutover smoke test against production.
  • Keep blue warm for rollback.

Set this up once and every deployment gets the same automated release gate. Your first real user should never be your first real test.

FAQ

What is blue-green deployment in simple terms?

It is running two identical production environments and switching traffic between them. Blue serves live users while green receives the new version. You test green, then switch traffic so green becomes live. Blue remains available for rollback.

How do I test the green environment before switching traffic?

Point your API test suite at the green environment base URL and run it in CI before the cutover step. With the Apidog CLI, use apidog run against the green environment and fail the deployment if any assertion fails.

Why is a load balancer health check not enough?

A health check usually confirms only that one endpoint returns 200. It will not catch a renamed JSON field, failed migration, broken auth flow, or schema change. API tests assert on real responses, schemas, and error cases.

Can I run the same API tests in CI that I built in the desktop app?

Yes. Scenarios built in Apidog can run from the Apidog CLI. Generate a CI config, call apidog run in your pipeline, and use the non-zero exit code to block failed deployments.

What is the difference between blue-green and canary deployment for testing?

Blue-green tests the fully deployed green environment before any user traffic reaches it. Canary sends a small percentage of live traffic to the new version and relies on monitoring that slice before promotion.

Should I run write-path tests against green production?

Be careful. Use a dedicated test account, clean up created records, or run write tests against a green environment backed by staging data before promoting the data layer.

How fast should the pre-switch test gate be?

Use two stages. Run a smoke test of three to five critical requests in under thirty seconds, then run the full suite only if the smoke test passes.

Top comments (0)