# thunder

<p>
    <a href="https://www.npmjs.com/package/@thunder-so/thunder"><img alt="Version" src="https://img.shields.io/npm/v/@thunder-so/thunder.svg" /></a>
    <a href="https://www.npmjs.com/package/@thunder-so/thunder"><img alt="License" src="https://img.shields.io/npm/l/@thunder-so/thunder.svg" /></a>
</p>

Build full-stack apps on your own AWS.

Thunder is a CDK library and CLI for deploying modern web applications on AWS. One library to rule them all: [Static SPAs](#static), [Lambda Functions](#lambda), [Containers on Fargate](#fargate) and [EC2](#ec2), and [Serverless Full-stack Frameworks](#serverless-frameworks).

## Table of Contents

- [Features](#features)
- [Supported Frameworks & Patterns](#supported-frameworks--patterns)
- [Quick Start](#quick-start)
- [Stacks](#stacks)
  - [Static](#static) - S3 + CloudFront + Route53
  - [Lambda](#lambda) - API Gateway + Lambda
  - [Fargate](#fargate) - ECS Fargate + ALB + CloudFront
  - [EC2](#ec2) - EC2 + Docker + Elastic IP
  - [Serverless Frameworks](#serverless-frameworks) - Full-stack meta-frameworks with Lambda + S3 + CloudFront
  - [Template](#template) - Coolify-style templates
- [CLI Commands](#cli-commands)
- [Documentation](#documentation)
- [License](#license)

## Features

- **Constructs:** One-line deployment for `Static`, `Lambda`, `Fargate`, `EC2`, `Serverless`, and framework-specific constructs.
- **Thunder CLI (`th`):** Context-aware CLI for initializing, deploying, and managing your infrastructure.
- **VPC Link Pattern:** Easily connect your compute resources to a shared VPC.
- **High-Performance Serving:** Pre-configured [CloudFront](https://aws.amazon.com/cloudfront/) distributions with OAC, security headers, and edge optimizations.
- **Built-in CI/CD:** Optional [AWS CodePipeline](https://aws.amazon.com/codepipeline/) integration with GitHub support.

## Supported Frameworks & Patterns

- **Static:** Vite (React, Vue, Svelte, Solid), Next.js (SSG), Astro (SSG), Gatsby.
- **Serverless:** Node.js Lambda, Bun, Container-based Lambda.
- **Containers:** [ECS Fargate](https://aws.amazon.com/fargate/) with ALB, Docker on [EC2](https://aws.amazon.com/ec2/) with Elastic IP.
- **Full-stack SSR:** [Nuxt](https://nuxt.com/), [Astro](https://astro.build/), [TanStack Start](https://tanstack.com/start), [SvelteKit](https://kit.svelte.dev/), [Solid Start](https://start.solidjs.com/), [AnalogJS](https://analogjs.org/).

## Quick Start

### 1. Install

```bash
bun add @thunder-so/thunder --development
```

### 2. Initialize

```bash
npx th init
```

### 3. Configure

Create a stack file (e.g., `stack/dev.ts`):

```typescript
import { Cdk, Static, type StaticProps } from "@thunder-so/thunder";

const myApp: StaticProps = {
  env: {
    account: "123456789012",
    region: "us-east-1",
  },
  application: "myapp",
  service: "web",
  environment: "prod",

  rootDir: ".",
  outputDir: "dist",
};

new Static(
  new Cdk.App(),
  `${myApp.application}-${myApp.service}-${myApp.environment}-stack`,
  myApp,
);
```

### 4. Deploy

```bash
npx cdk deploy --app "npx tsx stack/dev.ts" --profile default
```

## Stacks

### Static

Deploy static websites to [S3](https://aws.amazon.com/s3/) with [CloudFront](https://aws.amazon.com/cloudfront/) CDN and [Route53](https://aws.amazon.com/route53/) DNS.

**Best for:** Static sites, SPAs, JAMstack applications

**AWS Resources:**

- [S3 Bucket](https://aws.amazon.com/s3/) - Static file hosting
- [CloudFront Distribution](https://aws.amazon.com/cloudfront/) - Global CDN with caching
- [Route53](https://aws.amazon.com/route53/) - DNS management (optional)
- [ACM Certificate](https://aws.amazon.com/certificate-manager/) - SSL/TLS certificates (optional)
- [Lambda@Edge](https://aws.amazon.com/lambda/edge/) - Request/response manipulation (optional)

**Example:**

```typescript
import { Cdk, Static, type StaticProps } from "@thunder-so/thunder";

const config: StaticProps = {
  env: { account: "123456789012", region: "us-east-1" },
  application: "myapp",
  service: "web",
  environment: "prod",
  rootDir: ".",
  outputDir: "dist",

  // Optional: Custom domain
  domain: "example.com",
  globalCertificateArn: "arn:aws:acm:us-east-1:...",
  hostedZoneId: "Z123456789",

  // Optional: Lambda@Edge for redirects/headers/rewrites
  redirects: [{ source: "/old", destination: "/" }],
  rewrites: [{ source: "/old", destination: "/new" }],
  headers: [{ path: "/*", name: "X-Custom-Header", value: "value" }],
};

new Static(new Cdk.App(), "myapp-web-prod-stack", config);
```

---

### Lambda

Deploy serverless functions with [API Gateway](https://aws.amazon.com/api-gateway/) and optional [Lambda Function URL](https://docs.aws.amazon.com/lambda/latest/dg/lambda-urls.html).

**Best for:** Serverless APIs, microservices, event-driven applications

**AWS Resources:**

- [Lambda Function](https://aws.amazon.com/lambda/) - Compute layer
- [API Gateway](https://aws.amazon.com/api-gateway/) - HTTP API with custom domain support
- [CloudWatch Logs](https://aws.amazon.com/cloudwatch/) - Logging and monitoring
- [Secrets Manager](https://aws.amazon.com/secrets-manager/) - Secure secret injection (optional)

**Example:**

```typescript
import { Cdk, Lambda, type LambdaProps } from "@thunder-so/thunder";

const config: LambdaProps = {
  env: { account: "123456789012", region: "us-east-1" },
  application: "myapp",
  service: "api",
  environment: "prod",
  rootDir: ".",

  functionProps: {
    runtime: Cdk.aws_lambda.Runtime.NODEJS_22_X,
    architecture: Cdk.aws_lambda.Architecture.ARM_64,
    codeDir: "src",
    handler: "index.handler",
    memorySize: 512,
    timeout: 30,
    url: true, // Enable function URL
    keepWarm: true, // Prevent cold starts
    variables: [{ NODE_ENV: "production" }],
    secrets: [{ key: "DATABASE_URL", resource: "arn:aws:secretsmanager:..." }],
  },

  // Optional: Custom domain
  domain: "api.example.com",
  regionalCertificateArn: "arn:aws:acm:us-east-1:...",
  hostedZoneId: "Z123456789",
};

new Lambda(new Cdk.App(), "myapp-api-prod-stack", config);
```

---

### Fargate

Deploy containerized applications on [ECS Fargate](https://aws.amazon.com/fargate/) with Application Load Balancer and [CloudFront](https://aws.amazon.com/cloudfront/).

**Best for:** Containerized web applications, microservices, long-running processes

**AWS Resources:**

- [ECS Cluster](https://aws.amazon.com/ecs/) - Container orchestration
- [Fargate Task](https://aws.amazon.com/fargate/) - Serverless containers
- [Application Load Balancer](https://aws.amazon.com/elasticloadbalancing/) - Traffic distribution
- [ECR Repository](https://aws.amazon.com/ecr/) - Container registry (via CodePipeline)
- [CloudWatch Logs](https://aws.amazon.com/cloudwatch/) - Container logging

**Example:**

```typescript
import { Cdk, Fargate, type FargateProps } from "@thunder-so/thunder";

const config: FargateProps = {
  env: { account: "123456789012", region: "us-east-1" },
  application: "myapp",
  service: "api",
  environment: "prod",
  rootDir: ".",

  serviceProps: {
    architecture: Cdk.aws_ecs.CpuArchitecture.ARM64,
    desiredCount: 2,
    cpu: 512, // 0.5 vCPU
    memorySize: 1024, // 1 GB
    port: 3000,
    healthCheckPath: "/health",
    variables: [{ NODE_ENV: "production" }],
    dockerFile: "Dockerfile",
  },

  // Optional: Custom domain
  domain: "api.example.com",
  globalCertificateArn: "arn:aws:acm:us-east-1:...",
  hostedZoneId: "Z123456789",
};

new Fargate(new Cdk.App(), "myapp-api-prod-stack", config);
```

---

### EC2

Deploy Docker containers on [EC2](https://aws.amazon.com/ec2/) instances with Elastic IP for simple, cost-effective hosting.

**Best for:** Single-instance applications, development environments, simple Docker deployments

**AWS Resources:**

- [EC2 Instance](https://aws.amazon.com/ec2/) - Virtual server
- [Elastic IP](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html) - Static public IP
- [VPC](https://aws.amazon.com/vpc/) - Network isolation
- [Security Group](https://docs.aws.amazon.com/vpc/latest/userguide/security-groups.html) - Firewall rules
- [Route53](https://aws.amazon.com/route53/) - DNS records (optional)

**Example:**

```typescript
import { Cdk, Ec2, type Ec2Props } from "@thunder-so/thunder";

const config: Ec2Props = {
  env: { account: "123456789012", region: "us-east-1" },
  application: "myapp",
  service: "api",
  environment: "prod",
  rootDir: ".",

  serviceProps: {
    instanceType: "t3.micro",
    port: 3000,
    authorizedKeys: ["ssh-rsa AAAAB3... user@example.com"],
    dockerFile: "Dockerfile",
    variables: [{ NODE_ENV: "production" }],
  },

  // Optional: Custom domain with SSL
  domain: "api.example.com",
  hostedZoneId: "Z123456789",
  acmeEmail: "admin@example.com", // For Let's Encrypt
};

new Ec2(new Cdk.App(), "myapp-api-prod-stack", config);
```

---

### Serverless Frameworks

Deploy modern meta-frameworks as serverless applications with unified infrastructure - Lambda for server-side rendering and S3 for static assets, all behind CloudFront.

**Best for:** Full-stack applications with server-side rendering, API routes, and static asset optimization

**Supported Frameworks:** Nuxt, Astro, TanStack Start, SvelteKit, Solid Start, AnalogJS, or any Vite/Nitro-based framework using the generic `Serverless` construct.

**AWS Resources:**

- [Lambda Function](https://aws.amazon.com/lambda/) - SSR server with container support
- [S3 Bucket](https://aws.amazon.com/s3/) - Static assets with OAC
- [CloudFront Distribution](https://aws.amazon.com/cloudfront/) - Global CDN with custom domain
- [API Gateway](https://aws.amazon.com/api-gateway/) - HTTP API for server functions
- [Route53](https://aws.amazon.com/route53/) - DNS management (optional)
- [ACM](https://aws.amazon.com/certificate-manager/) - SSL certificates (optional)

**Supported Frameworks:**

- [TanStack Start](https://tanstack.com/start) - Type-safe full-stack React framework
- [Nuxt](https://nuxt.com/) - Vue-based full-stack framework
- [Astro](https://astro.build/) - Content-focused web framework with islands architecture
- [SvelteKit](https://kit.svelte.dev/) - Svelte-based full-stack framework
- [Solid Start](https://start.solidjs.com/) - SolidJS full-stack framework
- [AnalogJS](https://analogjs.org/) - Angular-based full-stack framework

#### TanStack Start

**Example:**

```typescript
import {
  Cdk,
  TanStackStart,
  type TanStackStartProps,
} from "@thunder-so/thunder";

const config: TanStackStartProps = {
  env: { account: "123456789012", region: "us-east-1" },
  application: "myapp",
  service: "web",
  environment: "prod",
  rootDir: ".",

  serverProps: {
    runtime: Cdk.aws_lambda.Runtime.NODEJS_22_X,
    architecture: Cdk.aws_lambda.Architecture.ARM_64,
    memorySize: 1792,
    timeout: 10,
    keepWarm: true,
    variables: [{ NODE_ENV: "production" }],
  },

  // Optional: Custom domain
  domain: "myapp.com",
  globalCertificateArn: "arn:aws:acm:us-east-1:...",
  hostedZoneId: "Z123456789",
};

new TanStackStart(new Cdk.App(), "myapp-web-prod-stack", config);
```

#### Nuxt

**Example:**

```typescript
import { Cdk, Nuxt, type NuxtProps } from "@thunder-so/thunder";

const config: NuxtProps = {
  env: { account: "123456789012", region: "us-east-1" },
  application: "myapp",
  service: "web",
  environment: "prod",
  rootDir: ".",

  serverProps: {
    runtime: Cdk.aws_lambda.Runtime.NODEJS_22_X,
    architecture: Cdk.aws_lambda.Architecture.ARM_64,
    memorySize: 1792,
    timeout: 10,
    keepWarm: true,
    streaming: true,
    variables: [{ NODE_ENV: "production" }],
    secrets: [{ key: "DATABASE_URL", resource: "arn:aws:secretsmanager:..." }],
  },

  // Optional: Custom domain
  domain: "myapp.com",
  globalCertificateArn: "arn:aws:acm:us-east-1:...",
  hostedZoneId: "Z123456789",
};

new Nuxt(new Cdk.App(), "myapp-web-prod-stack", config);
```

#### Astro

**Example:**

```typescript
import { Cdk, Astro, type AstroProps } from "@thunder-so/thunder";

const config: AstroProps = {
  env: { account: "123456789012", region: "us-east-1" },
  application: "myapp",
  service: "web",
  environment: "prod",
  rootDir: ".",

  serverProps: {
    runtime: Cdk.aws_lambda.Runtime.NODEJS_22_X,
    architecture: Cdk.aws_lambda.Architecture.ARM_64,
    memorySize: 1024,
    timeout: 10,
    keepWarm: true,
    variables: [{ NODE_ENV: "production" }],
  },

  // Optional: Custom domain
  domain: "myapp.com",
  globalCertificateArn: "arn:aws:acm:us-east-1:...",
  hostedZoneId: "Z123456789",
};

new Astro(new Cdk.App(), "myapp-web-prod-stack", config);
```

#### SvelteKit

**Example:**

```typescript
import { Cdk, SvelteKit, type SvelteKitProps } from "@thunder-so/thunder";

const config: SvelteKitProps = {
  env: { account: "123456789012", region: "us-east-1" },
  application: "myapp",
  service: "web",
  environment: "prod",
  rootDir: ".",

  serverProps: {
    runtime: Cdk.aws_lambda.Runtime.NODEJS_22_X,
    architecture: Cdk.aws_lambda.Architecture.ARM_64,
    memorySize: 1024,
    timeout: 10,
    keepWarm: true,
    variables: [{ NODE_ENV: "production" }],
  },

  // Optional: Custom domain
  domain: "myapp.com",
  globalCertificateArn: "arn:aws:acm:us-east-1:...",
  hostedZoneId: "Z123456789",
};

new SvelteKit(new Cdk.App(), "myapp-web-prod-stack", config);
```

#### Solid Start

**Example:**

```typescript
import { Cdk, SolidStart, type SolidStartProps } from "@thunder-so/thunder";

const config: SolidStartProps = {
  env: { account: "123456789012", region: "us-east-1" },
  application: "myapp",
  service: "web",
  environment: "prod",
  rootDir: ".",

  serverProps: {
    runtime: Cdk.aws_lambda.Runtime.NODEJS_22_X,
    architecture: Cdk.aws_lambda.Architecture.ARM_64,
    memorySize: 1024,
    timeout: 10,
    keepWarm: true,
    variables: [{ NODE_ENV: "production" }],
  },

  // Optional: Custom domain
  domain: "myapp.com",
  globalCertificateArn: "arn:aws:acm:us-east-1:...",
  hostedZoneId: "Z123456789",
};

new SolidStart(new Cdk.App(), "myapp-web-prod-stack", config);
```

#### AnalogJS

**Example:**

```typescript
import { Cdk, AnalogJS, type AnalogJSProps } from "@thunder-so/thunder";

const config: AnalogJSProps = {
  env: { account: "123456789012", region: "us-east-1" },
  application: "myapp",
  service: "web",
  environment: "prod",
  rootDir: ".",

  serverProps: {
    runtime: Cdk.aws_lambda.Runtime.NODEJS_22_X,
    architecture: Cdk.aws_lambda.Architecture.ARM_64,
    memorySize: 1024,
    timeout: 10,
    keepWarm: true,
    variables: [{ NODE_ENV: "production" }],
  },

  // Optional: Custom domain
  domain: "myapp.com",
  globalCertificateArn: "arn:aws:acm:us-east-1:...",
  hostedZoneId: "Z123456789",
};

new AnalogJS(new Cdk.App(), "myapp-web-prod-stack", config);
```

---

### Template

Deploy [Coolify](https://coolify.io/)-style templates on EC2. Automatically fetches and hydrates Docker Compose templates from the [Coolify templates repository](https://github.com/coollabsio/coolify).

**Best for:** Self-hosted applications, databases, dev tools (e.g., n8n, WordPress, databases)

**AWS Resources:** Same as [EC2](#ec2)

**Example:**

```typescript
import {
  Cdk,
  Template,
  type TemplateProps,
  fetchTemplate,
  hydrateTemplate,
} from "@thunder-so/thunder";
import { InstanceType, InstanceClass, InstanceSize } from "aws-cdk-lib/aws-ec2";

async function main() {
  // Fetch template from Coolify repository
  const { parsed: parsedTemplate, port } = await fetchTemplate("n8n");

  // Hydrate template with variables
  const hydrateResult = hydrateTemplate(parsedTemplate, {
    domain: "n8n.example.com",
    fallbackPort: port,
  });

  const config: TemplateProps = {
    env: { account: "123456789012", region: "us-east-1" },
    application: "myapp",
    service: "n8n",
    environment: "prod",

    templateSlug: "n8n",
    instanceType: InstanceType.of(InstanceClass.T3, InstanceSize.MICRO),
    authorizedKeys: ["ssh-rsa AAAAB3... user@example.com"],
    hydrateResult,

    // Optional: Custom domain with SSL
    domain: "n8n.example.com",
    hostedZoneId: "Z123456789",
    acmeEmail: "admin@example.com",
  };

  new Template(new Cdk.App(), "myapp-n8n-prod-stack", config);
}

main();
```

**Available Templates:** See the [Coolify templates repository](https://github.com/coollabsio/coolify/tree/v4.x/templates/compose) for available templates.

---

## CLI Commands

| Command      | Description                       |
| :----------- | :-------------------------------- |
| `th init`    | Scaffold a new project or service |
| `th deploy`  | Deploy stacks to AWS              |
| `th destroy` | Remove resources from AWS         |

## Documentation

For detailed documentation on each construct and advanced configurations, see the [Wiki](https://github.com/thunder-so/thunder/wiki).

### Static

| Guide                                                       | Description                                             |
| :---------------------------------------------------------- | :------------------------------------------------------ |
| [static-basic.md](./docs/static-basic.md)                   | Deploy a static site or SPA to S3 + CloudFront          |
| [static-edge-functions.md](./docs/static-edge-functions.md) | Redirects, rewrites, and custom headers via Lambda@Edge |
| [static-full.md](./docs/static-full.md)                     | Full `StaticProps` configuration reference              |

### Lambda

| Guide                                               | Description                                       |
| :-------------------------------------------------- | :------------------------------------------------ |
| [lambda-basic.md](./docs/lambda-basic.md)           | Deploy a serverless API with Lambda + API Gateway |
| [lambda-containers.md](./docs/lambda-containers.md) | Container images and Bun runtime                  |
| [lambda-full.md](./docs/lambda-full.md)             | Full `LambdaProps` configuration reference        |

### Fargate

| Guide                                             | Description                                   |
| :------------------------------------------------ | :-------------------------------------------- |
| [fargate-basic.md](./docs/fargate-basic.md)       | Deploy a containerized service on ECS Fargate |
| [fargate-nixpacks.md](./docs/fargate-nixpacks.md) | Auto-generate Dockerfiles with Nixpacks       |
| [fargate-full.md](./docs/fargate-full.md)         | Full `FargateProps` configuration reference   |

### Serverless (Full-Stack Frameworks)

| Guide                                 | Description                                |
| :------------------------------------ | :----------------------------------------- |
| [serverless.md](./docs/serverless.md) | Deploy full-stack meta-frameworks with SSR |

### Framework Guides

**Static Deployment:**

- [Next.js Static](./docs/frameworks/nextjs-static.md)
- [Astro Static](./docs/frameworks/astro-static.md)

**Serverless (Lambda + S3 + CloudFront):**

- [Nuxt](./docs/frameworks/nuxt-serverless.md)
- [Astro SSR](./docs/frameworks/astro-serverless.md)
- [TanStack Start](./docs/frameworks/tanstack-start-serverless.md)
- [SvelteKit](./docs/frameworks/sveltekit-serverless.md)
- [Solid Start](./docs/frameworks/solidstart-serverless.md)
- [AnalogJS](./docs/frameworks/analogjs-serverless.md)

**Fargate (Containers):**

- [Next.js with Dockerfile](./docs/frameworks/nextjs-fargate-dockerfile.md)
- [Next.js with Nixpacks](./docs/frameworks/nextjs-fargate-nixpacks.md)
- [Astro](./docs/frameworks/astro-fargate.md)
- [Nuxt](./docs/frameworks/nuxt-fargate.md)
- [TanStack Start](./docs/frameworks/tanstack-start-fargate.md)
- [SvelteKit](./docs/frameworks/sveltekit-fargate.md)
- [Solid Start](./docs/frameworks/solidstart-fargate.md)
- [AnalogJS](./docs/frameworks/analogjs-fargate.md)

## License

Apache-2.0
