@mypolis.eu/aws-static-deploy
v4.1.0
Published
CLI for deploying static websites to AWS S3 and CloudFront
Maintainers
Readme
AWS Static Deploy CLI
CLI for deploying static websites to AWS S3 and CloudFront with versioning and promotion workflow.
This tool facilitates a robust deployment strategy by uploading versioned assets to S3 and using CloudFront KeyValueStore to point different environments (like staging and latest) to specific versions.
Features
- Uploads build assets to S3 under a versioned path.
- Supports semantic versioning, with easy bumping for patch, minor, and major releases.
- Auto-creates the CloudFront KeyValueStore on first publish.
- Auto-creates viewer-request and viewer-response CloudFront Functions on first publish.
- Auto-updates CloudFront Functions when the generated code changes (e.g., after extending the compressible extensions list).
- Supports host-based environment routing in the generated viewer-request function.
- Simple
promotecommand to move a version fromstagingtolatest. - Supports Gzip and Brotli compression for a wide range of file types.
- Progress indicators for asset compression.
Installation
npm install -g @mypolis.eu/aws-static-deployOr use it with npx:
npx @mypolis.eu/aws-static-deploy <command>Configuration
The CLI requires a deploy.config.json file in the root of your project.
{
"project": {
"name": "my-awesome-project"
},
"aws": {
"profile": "your-aws-profile",
"region": "eu-west-1",
"s3BucketName": "my-static-assets-bucket"
},
"environments": {
"default": "latest",
"hosts": {
"staging.example.com": "staging",
"example.com": "latest",
"www.example.com": "latest"
}
},
"build": {
"root": "dist",
"compression": {
"files": ["Build/**/*"],
"gzipLevel": 9,
"brotliQuality": 5
},
"cacheRules": [
{
"files": "index.html",
"cacheControl": "no-cache"
},
{
"files": "Build/**/*",
"cacheControl": "max-age=31536000, public, immutable"
},
{
"files": "StreamingAssets/**/*",
"cacheControl": "max-age=31536000, public, immutable"
},
{
"files": "TemplateData/**/*",
"cacheControl": "max-age=31536000, public, immutable"
}
]
}
}Configuration Fields
project.name: A unique name for your project. Used as a prefix for S3 paths, KeyValueStore keys, and CloudFront Function names.aws.profile: The AWS credentials profile to use (from~/.aws/credentials).aws.region: The AWS region for S3 and CloudFront KeyValueStore.aws.s3BucketName: The name of the S3 bucket to deploy assets to.aws.kvsArn(optional): The ARN of the CloudFront KeyValueStore. If omitted, the CLI auto-creates a KeyValueStore named{projectName}-versionsand caches the ARN in memory for the session.environments.default(optional): The environment to serve when no host rule matches. Defaults tolatest.environments.hosts(optional): A hostname-to-environment map used by the generated viewer-request function, e.g."staging.example.com": "staging".build.root: The path to the directory containing your built static assets.build.compression.files: An array of micromatch glob patterns for files that should be compressed with Gzip and Brotli.build.compression.gzipLevel(optional): The compression level for Gzip (1-9). Defaults to9.build.compression.brotliQuality(optional): The quality for Brotli compression (0-11). Defaults to5.build.cacheRules(optional): An array of objects defining caching rules. Each object must have:files: A micromatch glob pattern for files to apply the rule to.cacheControl: TheCache-Controlheader value to set for matching files. If not provided, a default set of rules will be applied:index.htmlwill beno-cache, and common assets (.js,.css,.ico,.png, etc.) will bemax-age=31536000, public, immutable.
AWS Setup
What the CLI automates
On first aws-static-deploy publish, the CLI creates these resources for you. On subsequent publishes, if the generated function code has changed (e.g., you added new compressible extensions or updated the version-routing logic), the functions are automatically updated and re-published.
| Resource | Name | Details |
|---|---|---|
| CloudFront KeyValueStore | {projectName}-versions | Maps environment names to version numbers |
| CloudFront Function (viewer-request) | {projectName}-viewer-request | Routes requests to versioned paths + serves pre-compressed assets |
| CloudFront Function (viewer-response) | {projectName}-viewer-response | Sets Content-Encoding for compressed responses |
Both functions use runtime cloudfront-js-2.0 and the viewer-request function is pre-associated with the KeyValueStore.
What you must create manually (one-time)
1. S3 Bucket
Create an S3 bucket matching aws.s3BucketName in your config.
- Block all public access — CloudFront will access it via Origin Access Control (OAC).
- Disable ACLs (recommended).
2. CloudFront Origin Access Control (OAC)
CloudFront > Origin Access Controls > Create control
- Name:
{projectName}-oac - Signing behavior:
Always sign origin requests - Origin type:
S3
Apply the suggested bucket policy to your S3 bucket.
3. CloudFront Distribution
CloudFront > Distributions > Create distribution
| Setting | Value |
|---|---|
| Origin | S3 bucket {s3BucketName} |
| Origin access | The OAC created above |
| Default root object | index.html |
| Viewer protocol policy | Redirect HTTP to HTTPS |
| Cache policy | CachingOptimized (or custom) |
Function associations (in the distribution's default behavior):
| Event | Function |
|---|---|
| Viewer Request | {projectName}-viewer-request |
| Viewer Response | {projectName}-viewer-response |
Error pages (for SPAs):
Add custom error responses if you're building a single-page app:
| Error code | Response page | Response status |
|---|---|---|
| 403 | /index.html | 200 |
| 404 | /index.html | 200 |
4. IAM Permissions
The AWS profile (aws.profile) needs the following permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:PutObject"
],
"Resource": [
"arn:aws:s3:::{s3BucketName}",
"arn:aws:s3:::{s3BucketName}/*"
]
},
{
"Effect": "Allow",
"Action": [
"cloudfront:DescribeKeyValueStore",
"cloudfront:GetKey",
"cloudfront:UpdateKeys",
"cloudfront:CreateKeyValueStore",
"cloudfront:ListKeyValueStores",
"cloudfront:CreateFunction",
"cloudfront:DescribeFunction",
"cloudfront:GetFunction",
"cloudfront:UpdateFunction",
"cloudfront:PublishFunction"
],
"Resource": "*"
}
]
}5. Test environment routing
# Host-based routing, if configured in environments.hosts
curl https://staging.example.com/
curl https://example.com/
# Manual override, kept for backwards compatibility
curl -H "x-environment: staging" https://your-distribution.cloudfront.net/
curl -H "x-environment: canary" https://your-distribution.cloudfront.net/Usage
publish [versionNumber]
Uploads a new version to S3, creates any missing infrastructure (KeyValueStore + CloudFront Functions), and sets the staging environment to the new version.
If [versionNumber] is not provided, it automatically bumps the latest version found in S3. Default bump is patch.
Options:
--patch,-p: Bumps the patch version (e.g.,1.0.0->1.0.1).--minor,-m: Bumps the minor version (e.g.,1.0.0->1.1.0).--major,-M: Bumps the major version (e.g.,1.0.0->2.0.0).
Examples:
# Publish a new patch version (e.g., if latest is 1.2.3, this creates 1.2.4)
aws-static-deploy publish
# Publish a new minor version
aws-static-deploy publish --minor
# Publish a specific version
aws-static-deploy publish 2.0.0promote
Promotes the version currently in staging to latest by updating the latest key in the KeyValueStore.
aws-static-deploy promoteset-version <environment> <versionNumber>
Manually points an environment to a specific, existing version.
# Point staging to version 1.5.0
aws-static-deploy set-version staging 1.5.0list-versions
Lists all deployed versions for the project, showing which are staging and which are latest.
aws-static-deploy list-versionsExample Workflow
Create your config file (
deploy.config.json).Build your application.
npm run buildPublish a new version. The first run auto-creates the KeyValueStore and CloudFront Functions.
aws-static-deploy publish --minorTest staging.
curl -H "x-environment: staging" https://your-distribution.cloudfront.net/Promote to production.
aws-static-deploy promote
