Copyright © 2026 Rusty Nations. Released under MIT License.
Infrastructure-as-code solution for hosting Single Page Applications on AWS with automated CI/CD pipelines.
- Infrastructure-only: Application code is never modified
- AWS-native primitives: No additional control planes or frameworks
- Secure by default: Private S3, Origin Access Control, least privilege IAM
- Configuration-driven: Not framework-driven
- Easy to start, easy to extend, safe to abandon
The AWS SPA Hosting Kit provides a complete infrastructure setup for hosting your SPA on AWS with:
- S3 + CloudFront: Static hosting with global CDN delivery
- Automated CI/CD: CodePipeline triggered by GitHub commits
- Zero SPA Changes: Your existing SPA repository remains untouched
- Email Notifications: Optional deployment status alerts
- One Command Deploy: Simple setup and deployment
Each deployment is identified by a projectName, allowing multiple SPAs to be hosted safely in the same AWS account.
This kit can be used both to host a new SPA from scratch and to migrate an existing SPA to AWS. The design intentionally keeps infrastructure and application code separate, allowing teams to adopt AWS-native hosting and CI/CD without modifying their existing repositories or workflows.
This kit is designed for teams that want AWS-native hosting and CI/CD without adopting a new frontend framework, service control plane, or modifying their existing SPA repository.
The kit loads your configuration from config/config.yml and validates all required fields:
- GitHub repository URL and branch
- AWS region and account settings
- Optional notification email
- Optional build commands and output directory
The ConfigLoader class handles YAML parsing, applies sensible defaults, and validates configuration against AWS service requirements.
When you run npm run deploy, AWS CDK synthesizes and deploys CloudFormation templates that create:
- S3 Bucket: Private bucket with encryption enabled and all public access blocked
- CloudFront Distribution: CDN with Origin Access Control (OAC) for secure S3 access
- CodeStar Connection: GitHub OAuth integration for repository access
- CodeBuild Project: Build environment with Node.js 20 runtime
- CodePipeline: Three-stage pipeline (Source → Build → Deploy)
- SNS Topic: Optional notification system for deployment events
- Lambda Functions: CloudFront cache invalidation trigger
After initial deployment, you authorize the connection in the AWS Console:
- Navigate to Developer Tools → Settings → Connections
- Find your connection (named
{projectName}-github) - Complete OAuth authorization with your source code provider
Supported Providers: GitHub, Bitbucket, GitLab, GitHub Enterprise Server, GitLab self-managed, and Azure DevOps
Once authorized, the pipeline automatically triggers on every push to your configured branch:
- Source Stage: GitHub connection detects push and fetches source code
- Build Stage: CodeBuild runs
npm ciandnpm run buildto create production assets - Deploy Stage: Built artifacts are uploaded to S3 bucket
- Post-Deploy: Lambda function invalidates CloudFront cache for immediate updates
If configured, SNS sends email notifications for:
- Stack deployment completion
- Pipeline execution success
- Pipeline execution failure
- CloudFront cache invalidation
graph LR
Repo[Source Repository] --> Conn[CodeConnections]
Conn --> Pipe[CodePipeline]
Pipe --> Build[CodeBuild]
Build --> S3[S3 Bucket<br/>Private]
S3 --> CF[CloudFront<br/>OAC]
CF --> Users[End Users]
Pipe --> SNS[SNS<br/>Notifications]
Pipe --> Lambda[Lambda<br/>Cache Invalidation]
Lambda --> CF
Security: S3 bucket is private with CloudFront Origin Access Control (OAC) for secure access.
SPA Routing: CloudFront error response mapping (404/403 → index.html) ensures client-side routing works correctly.
| Component | Purpose | Implementation |
|---|---|---|
| ConfigLoader | Configuration parsing and validation | src/config/loader.ts |
| SpaHostingStack | Main CDK stack orchestration | src/stack/spa-hosting-stack.ts |
| PipelineConfigGenerator | BuildSpec generation for CodeBuild | src/pipeline/buildspec-generator.ts |
| NotificationManager | SNS topic and subscription management | src/notifications/notification-manager.ts |
- Amazon S3: Private bucket for static asset storage with server-side encryption
- Amazon CloudFront: Global CDN with Origin Access Control (OAC) for secure S3 access and HTTPS enforcement
- AWS CodePipeline: Three-stage CI/CD orchestration (Source → Build → Deploy)
- AWS CodeBuild: Serverless build environment with Node.js 20 runtime
- AWS CodeConnections: Source repository integration via OAuth (supports GitHub, Bitbucket, GitLab, GitHub Enterprise Server, GitLab self-managed, and Azure DevOps)
- Amazon SNS: Email notification system for deployment events
- AWS Lambda: CloudFront cache invalidation trigger on successful deployments
- Amazon EventBridge: Event-driven automation for pipeline state changes
- AWS IAM: Fine-grained permissions for service-to-service communication
The kit uses a declarative YAML configuration file that drives all infrastructure decisions. The ConfigLoader validates configuration at deployment time, preventing invalid deployments before any AWS resources are created.
Modern AWS-recommended approach for CloudFront-to-S3 security. The kit creates an OAC resource and configures S3 bucket policies to allow only CloudFront access using AWS:SourceArn conditions. This replaces the legacy Origin Access Identity (OAI) approach.
The PipelineConfigGenerator dynamically creates CodeBuild buildspec configurations based on your SPA's requirements. Supports custom install commands, build commands, and output directories while providing sensible defaults.
EventBridge rules monitor CodePipeline state changes and trigger SNS notifications. Lambda functions handle CloudFront cache invalidation and send completion notifications.
Built with AWS CDK (TypeScript), providing type safety, IDE autocomplete, and the full power of CloudFormation. All infrastructure is version-controlled and reproducible.
See PREREQUISITES.md for a complete checklist of required tools, permissions, and accounts.
Prefer guided setup? Use the AI-assisted setup prompt in IDEPrompt.md.
git clone https://github.com/rusty428/aws-spa-hosting-kit.git
cd aws-spa-hosting-kitnpm installCopy the example configuration and edit it:
cp config/config.example.yml config/config.ymlEdit config/config.yml with your settings:
projectName: "my-spa-project"
github:
repositoryUrl: "https://github.com/your-username/your-spa-repo"
branch: "main"
aws:
region: "us-east-1"
notifications:
email: "your-email@example.com"npm run deployCDK will display a summary of IAM permissions and security changes, then prompt for confirmation:
Do you wish to deploy these changes (y/n)?
This is a CDK safety feature that requires approval when creating IAM roles and policies. Review the changes and type y to proceed.
The deployment will:
- Create private S3 bucket for static assets
- Create CloudFront distribution
- Set up CodePipeline with GitHub integration
- Configure email notifications (if enabled)
Expected time: 5-10 minutes for initial deployment
After deployment, you'll see output with a Connection ARN. You need to authorize this connection:
Note: CDK deployment completes successfully even with an unauthorized connection. The pipeline won't work until you complete this authorization step, but there's no time pressure - you can do it immediately or later.
- Go to AWS Console → Developer Tools → Settings → Connections
- Direct link:
https://console.aws.amazon.com/codesuite/settings/connections?region=YOUR-REGION - Replace
YOUR-REGIONwith your deployment region (e.g.,us-east-1)
- Direct link:
- Find the connection (named after your
projectName, e.g., "my-spa-project-github") - Click "Update pending connection"
- Complete the OAuth authorization with your source code provider
Note: This kit is configured for GitHub by default, but AWS CodeConnections supports other providers including Bitbucket, GitLab, GitHub Enterprise Server, GitLab self-managed, and Azure DevOps. To use a different provider, modify the connection configuration in the CDK stack.
Your infrastructure is ready! Any push to the configured branch will automatically trigger a redeployment.
The CloudFront URL will be in the deployment output:
Outputs:
SpaHostingStack.CloudFrontUrl = https://d1234567890.cloudfront.net
projectName: "my-spa-project" # Unique identifier (namespace) for all AWS resources
# Changing this creates NEW infrastructure
github:
repositoryUrl: "https://github.com/owner/repo" # Your SPA repository
aws:
region: "us-east-1" # AWS region for deploymentgithub:
branch: "main" # Branch to monitor (default: "main")
notifications:
email: "you@example.com" # Deployment notifications
build:
outputDirectory: "dist" # Build output folder (default: "dist")
buildCommand: "npm run build" # Build command (default: "npm run build")
installCommand: "npm ci" # Install command (default: "npm ci")
tags: # Resource tags for cost allocation and organization
Environment: "production"
Team: "frontend"
CostCenter: "engineering"
Owner: "team@example.com"Note on Tags: All resources created by this kit will be tagged with:
- Default tags:
ProjectName(your projectName) andManagedBy: aws-spa-hosting-kit - Custom tags: Any tags you define in the
tagssection
Tags are useful for:
- Cost allocation and tracking in AWS Cost Explorer
- Resource organization across multiple projects/teams
- Compliance and governance requirements
This kit works with any SPA framework that builds to static files:
- ✅ React (Create React App, Vite, Next.js static export)
- ✅ Vue (Vue CLI, Vite)
- ✅ Angular
- ✅ Svelte
- ✅ Any framework that outputs HTML/CSS/JS
Constraint: Frameworks must produce a fully static output directory (e.g., dist/, build/). Server-side rendering is out of scope.
This kit does not:
- Modify your SPA repository or Git workflows
- Manage backend services, authentication, or APIs
- Replace your existing CI for non-frontend workloads
- Provide preview environments or PR-based deployments (yet)
Many teams start with this kit as a lift-and-shift hosting migration, then progressively enable custom domains, WAF, logging, or multi-environment deployments as their AWS footprint grows. It's equally suitable for greenfield SPAs that need production-grade AWS hosting from day one.
When notifications are enabled, you'll receive emails for:
- ✅ Stack deployment complete
- ✅ Pipeline execution succeeded
- ❌ Pipeline execution failed
- 🔄 CloudFront cache invalidated
# Build TypeScript
npm run build
# Deploy infrastructure
npm run deploy
# Deploy with specific AWS profile
npm run deploy -- --profile YOUR-PROFILE-NAME
# Skip confirmation prompt (for CI/CD)
npm run deploy -- --require-approval never
# Destroy infrastructure
npm run destroy
# Destroy with specific AWS profile
npm run destroy -- --profile YOUR-PROFILE-NAME
# Synthesize CloudFormation template
npx cdk synth
# Synthesize with specific AWS profile
npx cdk synth --profile YOUR-PROFILE-NAME
# View differences
npm run cdk diff
# View differences with specific AWS profile
npm run cdk diff -- --profile YOUR-PROFILE-NAMENote: The -- before --profile is required to pass arguments through npm to the underlying CDK command.
For detailed information about the CDK infrastructure, deployment process, and development workflow, see DEVELOPER.md.
Error: This CDK CLI is not compatible with the CDK library used by your application
Solution: The project uses npx cdk to ensure the correct CDK version. All npm scripts (npm run deploy, npm run destroy) already use the local CDK CLI. If you're running cdk commands directly, use npx cdk instead or upgrade your global CDK CLI:
npm install -g aws-cdk@latestIf you have multiple AWS profiles configured, pass the --profile flag:
# Deploy with specific profile
npm run deploy -- --profile YOUR-PROFILE-NAME
# Synthesize with specific profile
npx cdk synth --profile YOUR-PROFILE-NAMENote: The -- before --profile is required to pass arguments through npm to the CDK command.
Problem: Email notifications are not being delivered
Solution:
- Check your spam/junk folder for an SNS subscription confirmation email from AWS
- Click the confirmation link in the email to confirm your subscription
- If you don't see the confirmation email:
- Check that the email address in
config.ymlis correct - Request a new confirmation email from AWS Console → SNS → Subscriptions
- Look for emails from
no-reply@sns.amazonaws.com
- Check that the email address in
Note: Email subscriptions require confirmation before notifications are delivered. This is a security feature to prevent spam.
Alternative: Remove the email field from config.yml to disable notifications entirely.
Make sure your config.yml has:
- Valid project name (alphanumeric, hyphens, underscores only)
- Valid GitHub repository URL (format:
https://github.com/owner/repo) - Valid AWS region
Error: Resource timed out waiting for completion or Exceeded attempts to wait for CloudFront distribution
Cause: CloudFront distributions take 15-30 minutes to create. CDK may timeout before CloudFront finishes.
Solution:
- Check the actual status in AWS Console → CloudFormation → SpaHostingStack
- If stack shows
ROLLBACK_FAILED:- Select the stack in CloudFormation console
- Click "Delete" (this takes 20-30 minutes as CloudFront deletes)
- Once deleted, run
npm run deployagain
- If CloudFront is still creating, wait for it to complete before retrying
Note: CloudFront creation cannot be accelerated. Ensure stable network connection during deployment.
Warning: Bootstrap stack outdated or version < 21
Solution: Update the CDK bootstrap stack:
npx cdk bootstrap aws://ACCOUNT-ID/REGION --profile YOUR-PROFILE-NAMEReplace ACCOUNT-ID with your AWS account ID and REGION with your deployment region (e.g., us-east-1).
- Valid email format (if notifications enabled)
- Check that your source repository connection is authorized in AWS Console (Developer Tools → Settings → Connections)
- Direct link:
https://console.aws.amazon.com/codesuite/settings/connections?region=YOUR-REGION
- Direct link:
- Verify the branch name matches your configuration
- Verify the repository URL format matches your provider (GitHub, Bitbucket, GitLab, etc.)
- Check CodePipeline execution history in AWS Console
Check CodeBuild logs in AWS Console:
- Go to CodePipeline
- Click on your pipeline execution
- Click "Details" on the Build stage
- View logs for error messages
Common issues:
- Incorrect build command
- Wrong output directory
- Missing dependencies in package.json
- Most features work in any AWS region
- ACM certificates for CloudFront require
us-east-1 - If using custom domains, consider deploying to
us-east-1
The kit includes commented examples for:
- API Gateway integration
- Route 53 DNS configuration
- ACM certificate management
- Multi-environment setups (dev/staging/prod)
See config/config.example.yml for details.
Typical monthly costs for a small SPA:
- S3: $0.023/GB storage + $0.09/GB transfer
- CloudFront: $0.085/GB (first 10TB)
- CodePipeline: $1/active pipeline
- CodeBuild: $0.005/build minute
Estimated: $5-20/month for most SPAs
This kit is tested with: https://github.com/rusty428/aws-spa-react-example
A React + Vite + TypeScript SPA that demonstrates the complete workflow. This sample can be used as a starting point for new SPAs or as a reference for hosting an existing SPA.
Why not Amplify? Amplify is a full-stack framework with its own CLI, conventions, and abstractions. This kit is for teams that want direct control over AWS primitives without framework lock-in.
Why not Netlify/Vercel? Those are excellent platforms, but some teams need AWS-native infrastructure for compliance, existing AWS investments, or integration with other AWS services. This kit provides that without vendor lock-in.
Why CDK + primitives? CDK gives you the full power of CloudFormation with type safety and composability. You can extend this kit with any AWS service, customize IAM policies, or integrate with existing infrastructure—all in TypeScript.
This kit is infrastructure, not a framework. You own the code, you control the deployment, and you can evolve it as your needs grow.
- Sample SPA Repository - React + Vite + TypeScript reference implementation
This kit includes an AI prompt template for guided setup. If you're using an AI-powered IDE or coding assistant:
- Open IDEPrompt.md
- Copy the prompt template
- Fill in your project details (project name, repository URL, etc.)
- Paste into your AI assistant (Cursor, GitHub Copilot Chat, Kiro, Windsurf, etc.)
- Follow the AI's guidance through setup and deployment
The AI will help you:
- Clone and configure the repository
- Create a valid
config.ymlfile - Validate your configuration
- Build and deploy the infrastructure
- Understand post-deployment steps
Note: The AI follows this repository's documentation and does not replace reviewing README.md and PREREQUISITES.md.
This project is provided as infrastructure scaffolding.
- Breaking changes will be called out in release notes (see CHANGELOG.md)
- Configuration compatibility will be preserved when possible
- Issues and PRs are welcome; support is best-effort
- Versioning follows Semantic Versioning
This kit requires permission to create and manage:
- S3 buckets (static assets storage)
- CloudFront distributions (CDN delivery)
- CodePipeline and CodeBuild resources (CI/CD automation)
- CodeConnections (source repository integration)
- IAM roles (service execution with least privilege)
- SNS topics and subscriptions (deployment notifications)
- Lambda functions (CloudFront cache invalidation)
- EventBridge rules (event-driven automation)
See PREREQUISITES.md for detailed permission requirements.
All resources created by this kit are namespaced under your projectName. Running npm run destroy removes only resources created for that specific project, making it safe to use in shared AWS accounts. Other projects and resources remain untouched.
To completely remove all infrastructure:
npm run destroyOr with a specific AWS profile:
npm run destroy -- --profile YOUR-PROFILE-NAMEThis will delete:
- S3 bucket (and all contents)
- CloudFront distribution
- CodePipeline
- CodeBuild project
- CodeConnections connection
- SNS topic and subscriptions
- Lambda functions
- EventBridge rules
- IAM roles and policies
The deletion process takes 15-20 minutes due to CloudFront distribution removal.
- No PR preview environments: Pipeline triggers only on configured branch
- No blue/green deployments: Direct S3 replacement with cache invalidation
- Static-only output: Server-side rendering (SSR) is out of scope
- Single-region deployment: Multi-region replication not included
- No built-in auth: Authentication/authorization must be handled separately
These are intentional scope boundaries for v1. Future versions may address some of these.
MIT
For questions or custom configurations, contact @awsrusty
Last updated: 2026-02-10