Codapult includes equivalent AWS infrastructure templates in infra/terraform/ and infra/pulumi/.
What Gets Provisioned
| Resource | Purpose |
|---|---|
| VPC + public subnets | Isolated network across availability zones |
| Security groups | ALB ingress and ECS task access |
| ECR | Docker image registry with image scanning and lifecycle policy |
| ECS Fargate | Serverless container hosting for the Next.js app |
| ALB | HTTP/HTTPS load balancing with /api/health checks |
| ACM + Route53 | Optional TLS certificate and DNS record when domain_name is set |
| S3 | Optional private upload bucket for the S3 storage adapter |
| SSM Parameter Store | Encrypted application secrets |
| CloudWatch | Container logs and ECS observability |
The templates do not provision a database. Use Turso/libSQL or managed PostgreSQL and pass the connection values as secrets.
Terraform
cd infra/terraform
cp terraform.tfvars.example terraform.tfvars
terraform init
terraform plan
terraform apply
Build and push the app image:
ECR_URL=$(terraform output -raw ecr_repository_url)
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin "$ECR_URL"
docker build -t "$ECR_URL:latest" ../..
docker push "$ECR_URL:latest"
aws ecs update-service \
--cluster "$(terraform output -raw ecs_cluster_name)" \
--service "$(terraform output -raw ecs_service_name)" \
--force-new-deployment
Important variables:
| Variable | Description |
|---|---|
project, environment, aws_region | Resource naming and target region |
vpc_cidr, availability_zones | Network layout |
container_cpu, container_memory, desired_count | Fargate sizing |
domain_name, route53_zone_id | Optional HTTPS custom domain |
enable_s3_storage | Create private S3 upload bucket |
turso_database_url, turso_auth_token | Turso/libSQL database connection |
better_auth_secret | Better Auth signing secret |
stripe_secret_key, stripe_webhook_secret | Stripe billing |
resend_api_key, openai_api_key | Email and AI integrations |
Pulumi
cd infra/pulumi
pnpm install
pulumi stack init production
pulumi config set aws:region us-east-1
pulumi config set tursoUrl "libsql://..." --secret
pulumi config set tursoToken "..." --secret
pulumi config set authSecret "..." --secret
pulumi up
Useful Pulumi config keys:
| Key | Description |
|---|---|
project, environment | Resource naming |
containerPort, cpu, memory, desiredCount | ECS task configuration |
domainName, route53ZoneId | Optional TLS and DNS |
enableS3 | Optional S3 uploads bucket |
healthCheckPath | ALB health check path |
tursoUrl, tursoToken | Database connection |
authSecret, stripeKey, stripeWebhook, resendKey, openaiKey | App secrets |
Outputs
Both templates expose the app URL, ECR repository URL, ECS cluster/service names, S3 bucket name, and CloudWatch log group. Use these outputs from CI/CD to push images and trigger ECS deployments.
Production Notes
- Store secrets in
terraform.tfvarsonly for local operator workflows; prefer CI secret stores for automated deployments. - Set
domain_name/domainNameonly when the Route53 zone is available in the AWS account. - Use private subnets and NAT gateways if your compliance requirements prohibit public ECS task IPs; the included template favors a lower-cost public-subnet baseline.
- Configure
STORAGE_PROVIDER="s3"and S3 env vars when using the provisioned bucket for uploads.