Alright, let’s talk about deployments. You’ve built your beautiful API, a collection of routes and integrations that are a work of art. But it’s just sitting there in your AWS account, a glorious sculpture locked in a dark room. A stage is how you turn on the lights and open the door for the world (or at least your frontend team) to see it.

Think of a stage as a named snapshot of your API Gateway API. You might have a dev stage for your bleeding-edge work, a staging stage for final testing, and a prod stage that your customers actually hit. The magic, and the occasional foot-gun, is in how these snapshots are created and managed.

The Deployment: It’s a Snapshot, Not a Mirror

Here’s the first crucial, often-misunderstood point: making a change to your API resources—adding a route, tweaking an integration—does absolutely nothing by itself. Your live stages keep serving the old configuration. This is simultaneously brilliant and infuriating. Brilliant because you can tinker in peace without breaking anything. Infuriating because you’ll inevitably forget to deploy and spend ten minutes wondering why your brilliant new /unicorn endpoint returns a 404.

To make your changes live, you must create a deployment. This action takes the current state of your API definition and associates it with a specific stage.

# Using the AWS CLI to deploy your API to the 'dev' stage
aws apigateway create-deployment --rest-api-id your-api-id-here --stage-name dev

After this command, your changes are live on the dev stage. The URL will be something like https://your-api-id-here.execute-api.us-east-1.amazonaws.com/dev/your-resource.

Stage Variables: Your API’s Configuration Switches

Now, why are stages actually useful? Beyond just naming environments, their killer feature is stage variables. These are key-value pairs you define on a stage, and they are an absolute godsend for managing environment-specific configuration without hardcoding values into your API setup.

The classic use case is pointing your dev stage to a dev Lambda function and your prod stage to a prod Lambda function. Instead of hardcoding the Lambda ARN in your integration, you use a stage variable as a placeholder.

First, you define the variable on the stage itself. Let’s say we add a variable named lambdaAlias with the value dev for our dev stage.

Then, in your API method’s integration request, you use that variable in the Lambda function ARN:

arn:aws:lambda:us-east-1:123456789012:function:MyFunction:${stageVariables.lambdaAlias}

When a request hits the dev stage, API Gateway resolves ${stageVariables.lambdaAlias} to dev, invoking the MyFunction:dev version. A request to the prod stage would seamlessly invoke MyFunction:prod. This is clean, maintainable, and the right way to do things.

The Gotchas: Where They Get You

Of course, it’s not all rainbows. Stage variables have rules and sharp edges.

  1. They are not environment variables. I know, it’s confusing. Your Lambda function code cannot access the stage variables from API Gateway directly. They are only for use within the API Gateway configuration itself. If your Lambda needs to know the stage, you must pass it explicitly via the request, say, in a header or the request context, which API Gateway kindly provides.

    Here’s how you might pass the stage name to your Lambda in the request payload:

    // API Gateway Mapping Template (if using a non-proxy integration)
    {
      "stage" : "$context.stage",
      "request-body": "$input.json('$')"
    }
    
  2. They are strings. Only strings. Need a number or a boolean? You’ll be parsing that in whatever service receives it. This is a questionable design choice, but we work with what we have.

  3. Use them for configuration, not secrets. This is critical. Do not put sensitive information like database passwords in stage variables. They are visible to anyone with read permissions to your API Gateway configuration in the AWS Console or CLI. For secrets, use AWS Secrets Manager and have your Lambda function retrieve them.

Best Practices: Deploying Like a Pro

  • Automate Everything: You are not a human CLI. Tie your deployments into your CI/CD pipeline. Use CloudFormation, SAM, or Terraform to manage your stages and deployments. This ensures consistency and repeatability.
  • Canary Deployments: For your production stage, consider using canary deployments. This lets you send a small percentage of traffic (e.g., 10%) to a new deployment while monitoring for errors before shifting all traffic. It’s a fantastic safety net.
  • Stage Naming: Use clear, meaningful names. dev, staging, prod-v1, prod-canary are good. stage-13, test-bob, asdf are not. You will thank yourself later.

The mental model to keep is that your API definition is the source code. A deployment is a build. And a stage is an environment running that specific build. Master this workflow, and you’ll keep your different environments neatly separated and your sanity intact.