Single Page Application (SPA)

Deploy any client-side Single Page Application (SPA) and static site generator (SSG) on AWS S3 and CloudFront.

Thunder provides a secure and battle-tested pattern for deploying any SPA/SSG on AWS infrastructure using AWS CDK. This pattern leverages the @thunderso/cdk-spa package, which implements best practices for static site hosting with CloudFront distribution, S3 origin, and Lambda@Edge functions for advanced routing capabilities.

Supported Frameworks

Hosting Architecture

The hosting architecture provides a globally distributed, secure, and performant infrastructure for serving static web applications.

Users
Route 53
CloudFront
S3

Route 53 handles DNS resolution, directing users to the nearest CloudFront edge location. CloudFront serves as a global CDN, caching static assets at edge locations worldwide for low-latency delivery. S3 stores the application files as the origin, providing durable and scalable object storage.

CI/CD Pipeline Architecture

The pipeline architecture automates the build and deployment process, ensuring consistent and reliable deployments from source code to production.

GitHub
CodePipeline
CodeBuild
S3
CloudFront

GitHub triggers the pipeline on code changes. CodePipeline orchestrates the deployment workflow, while CodeBuild executes the build process in a managed environment. Built assets are uploaded to S3 and CloudFront cache is invalidated to serve the latest version.

Quick Start

Get your static site deployed to AWS in minutes with the CDK-SPA package. This guide walks through installation, configuration, and deployment of a basic static site.

Installation

Terminal window
bun add -D @thunderso/cdk-spa

Basic Setup

Terminal window
mkdir stack && touch stack/index.ts

Configuration

stack/index.ts
import { Cdk, SPAStack, type SPAProps } from "@thunderso/cdk-spa";
const stackProps: SPAProps = {
env: {
account: 'your-account-id',
region: 'us-east-1'
},
application: 'my-app',
service: 'frontend',
environment: 'production',
rootDir: '', // supports monorepos, e.g. frontend/
outputDir: 'dist/',
};
new SPAStack(
new Cdk.App(),
`${stackProps.application}-${stackProps.service}-${stackProps.environment}-stack`,
stackProps
);

Deploy

Terminal window
bunx cdk deploy --all --app="bunx tsx stack/index.ts"

Custom Domain Setup

Connect your own domain to your static site using Route 53 and ACM certificates. Learn more about domain configuration.

const stackProps: SPAProps = {
// ... other props
domain: 'app.example.com',
hostedZoneId: 'Z1D633PJN98FT9',
globalCertificateArn: 'arn:aws:acm:us-east-1:123456789012:certificate/abcd1234-abcd-1234-abcd-1234abcd1234',
};

Advanced Features

URL Redirects and Rewrites

Configure URL redirects and rewrites using Lambda@Edge functions that run at CloudFront edge locations. Redirects return HTTP 301/302 responses to the client, while rewrites transparently serve different content without changing the URL. Perfect for handling SPA routing, legacy URL migrations, and A/B testing.

Learn more about redirects and rewrites configuration.

const stackProps: SPAProps = {
// ... other props
redirects: [
{ source: '/home', destination: '/' },
{ source: '/blog/:slug', destination: '/posts/:slug' }
],
rewrites: [
{ source: '/app/*', destination: '/index.html' }
],
};

Custom Headers

Add custom HTTP response headers using Lambda@Edge to control caching behavior. Headers are applied at the edge for optimal performance and can be configured per path pattern.

Learn more about response headers configuration.

const stackProps: SPAProps = {
// ... other props
headers: [
{
path: '/*',
name: 'Cache-Control',
value: 'public, max-age=31536000'
}
],
};

AWS CodePipeline Integration

Automate your deployment workflow with AWS CodePipeline and CodeBuild. Configure your GitHub repository as the source, define build commands, and let AWS handle the rest. Every push to your specified branch triggers a new build and deployment.

Learn more about build configuration.

const stackProps: SPAProps = {
// ... other props
githubAccessTokenArn: 'arn:aws:secretsmanager:us-east-1:123456789012:secret:github-token-XXXXXX',
sourceProps: {
owner: 'your-username',
repo: 'your-repo',
branchOrRef: 'main',
},
buildProps: {
runtime: 'nodejs',
runtime_version: '20',
installcmd: 'bun install',
buildcmd: 'bun run build',
},
};