Guidance to design SPA for blue/green deployments
This article explains an architecture pattern for blue/green deployment of SPAs using Amazon API Gateway stage variables and Amazon S3. Two private S3 buckets hold different application versions, and API Gateway controls which version users see. Switching between versions is a single API call that takes effect in approximately one second — no redeployment or infrastructure changes required.
Architecture Overview
Users → API Gateway (prod/blue/green stages)
│
├── Stage Variable: bucketName
│
┌────┴────┐
▼ ▼
Blue S3 Green S3
Bucket Bucket
(v1) (v2)
Detailed Design
S3 Buckets — Version Isolation
Each application version is stored in its own private S3 bucket (e.g., react-app-blue-{ACCOUNT_ID} and react-app-green-{ACCOUNT_ID}). Public access is blocked on both buckets — they are only accessible through API Gateway via an IAM role with s3:GetObject and s3:ListBucket permissions.
Using separate buckets rather than folders within a single bucket provides complete isolation between versions. Each bucket contains an index.html at the root along with hashed JS/CSS assets in an assets/ directory. The identical file structure in both buckets is what makes seamless switching possible.
API Gateway — Traffic Routing with Stage Variables
An API Gateway REST API sits in front of the S3 buckets. It uses an AWS service integration to proxy GET requests directly to S3.
The key mechanism is the path override in the integration configuration:
${stageVariables.bucketName}/{proxy}
This tells API Gateway to resolve the target S3 bucket from a stage variable called bucketName at request time. A proxy resource ({proxy+}) with a URL path parameter mapping (integration.request.path.proxy → method.request.path.proxy) ensures the full file path is forwarded to S3.
Three stages are created from the same deployment:
| Stage | Purpose | bucketName variable |
|---|
prod | User-facing | Points to blue or green bucket |
blue | Testing version 1 | Always points to blue bucket |
green | Testing version 2 | Always points to green bucket |
Binary media types (*/*) are enabled on the API so that JS, CSS, and other static assets are served correctly.
Version Switching — How It Works
Promoting a new version to production is a single update-stage API call that changes the bucketName stage variable on the prod stage. For example, switching from blue to green:
aws apigateway update-stage --rest-api-id {API_ID} --stage-name prod \
--patch-operations op=replace,path=/variables/bucketName,value=react-app-green-{ACCOUNT_ID}
This takes effect in approximately one second. Rolling back is the same operation pointing back to the original bucket. No new deployment is created — the same API deployment serves different content based on the stage variable value.
SPA Design Considerations
Two design choices in the SPA are critical for this architecture to work:
Relative asset paths: The SPA build must use relative paths (e.g., ./assets/index.js instead of /assets/index.js) for all asset references. Since API Gateway serves the app under a stage prefix (/prod/, /blue/, /green/), absolute paths would resolve to the wrong location. Relative paths ensure the browser loads JS and CSS from the same stage prefix that served the HTML.
Hash-based routing: The SPA uses hash-based routing (/#/about instead of /about). The URL fragment after # is never sent to the server, so every request hits index.html regardless of the client-side route. This eliminates the need for server-side rewrite rules and prevents 404 errors on page refresh.
IAM Role — Secure Access
An IAM role with a trust policy for apigateway.amazonaws.com is created and granted read access to both S3 buckets. This role is specified as the execution role in the API Gateway integration, allowing API Gateway to fetch objects from S3 on behalf of the user without making the buckets public.
Sample Implementation
A complete working implementation with AWS CDK infrastructure code, two React demo applications, build configurations, and deployment scripts is available at:
GitHub: spa_bluegreen_deployment
Related Information