Deploy to AWS
Enterprise-scale deployment with full infrastructure control
AWS provides complete infrastructure control for applications requiring specific compliance, scaling, or regional requirements. The framework supports AWS Amplify (recommended), ECS with Fargate, and serverless Lambda.
Pro Tip
AWS Amplify offers the fastest path to production with automatic scaling and preview deployments. For containerized control, use ECS with Fargate. For maximum cost efficiency, consider serverless Lambda.
Option 1: AWS Amplify (Recommended)
Create App
Navigate to AWS Amplify Console and select New app → Host web app.
Connect your Git repository (GitHub, GitLab, or Bitbucket). Amplify detects Next.js automatically.
Monorepo Detection
Deploy apps/marketing
and apps/dashboard
as separate Amplify apps. Each requires its own project with distinct build configurations.
Configure Build Settings
Select Monorepo and configure:
version: 1
applications:
- frontend:
phases:
preBuild:
commands:
- cd ../..
- npm install -g pnpm@9
- pnpm install --frozen-lockfile
build:
commands:
- pnpm turbo run build --filter=marketing
artifacts:
baseDirectory: apps/marketing/.next
files:
- '**/*'
cache:
paths:
- node_modules/**/*
- .turbo/**/*
appRoot: apps/marketing
Turbo Cache Acceleration
The cache paths preserve Turbo's build cache across deployments, reducing build times from minutes to seconds after the first deploy.
version: 1
applications:
- frontend:
phases:
preBuild:
commands:
- cd ../..
- npm install -g pnpm@9
- pnpm install --frozen-lockfile
build:
commands:
- pnpm turbo run build --filter=dashboard
artifacts:
baseDirectory: apps/dashboard/.next
files:
- '**/*'
cache:
paths:
- node_modules/**/*
- .turbo/**/*
appRoot: apps/dashboard
Set Environment Variables
In Environment variables, configure production credentials:
# Core Application (update after deploy)
APP_BASE_URL=https://your-amplify-domain.amplifyapp.com
DASHBOARD_BASE_URL=https://dashboard.amplifyapp.com
NEXT_PUBLIC_DASHBOARD_BASE_URL=https://dashboard.amplifyapp.com
# Authentication
BETTER_AUTH_SECRET=<generate: openssl rand -base64 32>
GOOGLE_CLIENT_ID=<from Google Cloud Console>
GOOGLE_CLIENT_SECRET=<from Google Cloud Console>
# Database
NEXT_PUBLIC_CONVEX_URL=https://your-prod.convex.cloud
CONVEX_DEPLOYMENT=production
# Billing
AUTUMN_SECRET_KEY=am_sk_live_<your-production-key>
# Security
ALLOWED_WEB_ORIGINS=https://your-domain.com
ENABLE_HSTS=1
HSTS_PRELOAD=0
TRUSTED_IP_HEADER=x-forwarded-for
# AWS Amplify
_LIVE_UPDATES=[{"pkg":"@aws-amplify/cli","type":"npm","version":"latest"}]
# Analytics (optional)
NEXT_PUBLIC_POSTHOG_KEY=phc_<your-key>
NEXT_PUBLIC_POSTHOG_HOST=https://app.posthog.com
# Preview environment uses staging credentials
APP_BASE_URL=https://preview.amplifyapp.com
NEXT_PUBLIC_CONVEX_URL=https://your-preview.convex.cloud
CONVEX_DEPLOYMENT=preview
# Test billing key
AUTUMN_SECRET_KEY=am_sk_test_<your-test-key>
# Relaxed security for previews
ENABLE_HSTS=0
HSTS_PRELOAD=0
Sync Convex Environment
Mirror credentials to Convex so BetterAuth and billing run in the hosted runtime:
# Set production deployment
npx convex deploy --prod
# Configure environment variables
npx convex env set APP_BASE_URL https://main.app-id.amplifyapp.com --prod
npx convex env set DASHBOARD_BASE_URL https://dashboard.app-id.amplifyapp.com --prod
npx convex env set ALLOWED_WEB_ORIGINS https://main.app-id.amplifyapp.com --prod
npx convex env set BETTER_AUTH_SECRET <same-value-as-amplify> --prod
npx convex env set GOOGLE_CLIENT_ID <same-value-as-amplify> --prod
npx convex env set GOOGLE_CLIENT_SECRET <same-value-as-amplify> --prod
npx convex env set AUTUMN_SECRET_KEY <same-value-as-amplify> --prod
Environment Parity Critical
Mismatched environment variables between Amplify and Convex cause authentication failures and billing errors. Rerun these commands whenever credentials change.
Deploy and Update URLs
Click Save and deploy. Amplify compiles and distributes to AWS infrastructure.
After deployment completes, Amplify assigns:
https://main.[app-id].amplifyapp.com
Update Environment variables with this production URL:
APP_BASE_URL=https://main.[app-id].amplifyapp.com
ALLOWED_WEB_ORIGINS=https://main.[app-id].amplifyapp.com
Trigger redeploy via App settings → Redeploy this version.
Option 2: ECS with Fargate
Container deployment provides complete control over runtime environment. ECS with Fargate eliminates server management while maintaining flexibility. Teams scale precisely based on traffic patterns, optimizing costs while ensuring performance.
Create Dockerfile
Add to repository root:
FROM node:20-alpine AS builder
RUN apk add --no-cache libc6-compat
WORKDIR /app
# Install pnpm
RUN corepack enable && corepack prepare pnpm@9 --activate
# Copy monorepo configs
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml turbo.json ./
COPY apps/marketing/package.json ./apps/marketing/
COPY packages/ ./packages/
# Install dependencies
RUN pnpm install --frozen-lockfile
# Copy source and build
COPY apps/marketing/ ./apps/marketing/
RUN pnpm turbo run build --filter=marketing
# Production image
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
# Copy built artifacts
COPY --from=builder /app/apps/marketing/.next/standalone ./
COPY --from=builder /app/apps/marketing/.next/static ./apps/marketing/.next/static
COPY --from=builder /app/apps/marketing/public ./apps/marketing/public
EXPOSE 3000
CMD ["node", "apps/marketing/server.js"]
Standalone Output Required
Ensure next.config.ts
includes output: 'standalone'
for optimized container images.
Push to ECR
# Authenticate Docker to ECR
aws ecr get-login-password --region us-east-1 | \
docker login --username AWS --password-stdin $ECR_URI
# Build and tag
docker build -t starterapp-marketing .
docker tag starterapp-marketing:latest $ECR_URI/starterapp-marketing:latest
# Push to registry
docker push $ECR_URI/starterapp-marketing:latest
Create ECS Task Definition
{
"family": "starterapp-marketing",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "512",
"memory": "1024",
"containerDefinitions": [
{
"name": "marketing",
"image": "$ECR_URI/starterapp-marketing:latest",
"portMappings": [
{
"containerPort": 3000,
"protocol": "tcp"
}
],
"environment": [
{
"name": "APP_BASE_URL",
"value": "https://your-domain.com"
}
],
"secrets": [
{
"name": "BETTER_AUTH_SECRET",
"valueFrom": "arn:aws:secretsmanager:region:account:secret:prod/auth-secret"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/starterapp-marketing",
"awslogs-region": "us-east-1",
"awslogs-stream-prefix": "ecs"
}
}
}
]
}
Deploy Service
# Create ECS service
aws ecs create-service \
--cluster starterapp-cluster \
--service-name marketing \
--task-definition starterapp-marketing \
--desired-count 2 \
--launch-type FARGATE \
--network-configuration "awsvpcConfiguration={subnets=[subnet-xxx],securityGroups=[sg-xxx],assignPublicIp=ENABLED}" \
--load-balancers "targetGroupArn=arn:aws:elasticloadbalancing:...,containerName=marketing,containerPort=3000"
ECS handles rolling deployments with zero downtime.
Option 3: Serverless Lambda
Serverless deployment eliminates all infrastructure management. Applications scale automatically from zero to millions of requests, charging only for actual usage. This option maximizes cost efficiency for variable traffic patterns.
Install SST
pnpm add -D sst
Why SST over Serverless Framework
SST provides native Next.js 15 support with streaming, edge runtime compatibility, and superior local development experience.
Configure Infrastructure
Create sst.config.ts
at repository root:
import { SSTConfig } from "sst";
import { NextjsSite } from "sst/constructs";
export default {
config(_input) {
return {
name: "starterapp",
region: "us-east-1",
};
},
stacks(app) {
app.stack(function Site({ stack }) {
const marketing = new NextjsSite(stack, "marketing", {
path: "apps/marketing",
buildCommand: "cd ../.. && pnpm turbo run build --filter=marketing",
environment: {
APP_BASE_URL: process.env.APP_BASE_URL!,
NEXT_PUBLIC_CONVEX_URL: process.env.NEXT_PUBLIC_CONVEX_URL!,
},
});
stack.addOutputs({
MarketingUrl: marketing.url,
});
});
},
} satisfies SSTConfig;
Deploy
# Deploy to production
npx sst deploy --stage prod
SST creates Lambda functions, API Gateway, and CloudFront distribution automatically.