Deploy Next.js to AWS Lambda with GitHub Actions
Automate your Next.js deployments to AWS Lambda using GitHub Actions.
Example

You can find the finished example here:
GitHub repository
Prerequisites
Before you start make sure to configure your infrastructure providers.
You can do this by following the get started guide.
Guide
Setup GitHub actions
This example works with the “main” branch.
./github/workflows/production.yml
name: Deploy Production
on:
push:
branches: [main]
concurrency:
group: "production"
cancel-in-progress: false
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_DEFAULT_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_DEFAULT_ACCOUNT_ID }}
CLOUDFLARE_EMAIL: ${{ secrets.CLOUDFLARE_EMAIL }}
AWS_REGION: us-east-1
AWS_SDK_LOAD_CONFIG: 0
STAGE: "production"
jobs:
deploy-production:
runs-on: ubuntu-latest
environment: Production
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: latest
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "24.2.0"
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
- name: Deploy production
env:
CI: true
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ${{ env.AWS_REGION }}
AWS_PROFILE: "default"
AWS_SDK_LOAD_CONFIG: 1
run: |
aws configure set aws_access_key_id ${{ secrets.AWS_ACCESS_KEY_ID }}
aws configure set aws_secret_access_key ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws configure set region ${{ env.AWS_REGION }}
pnpm sst deploy --stage=${{ env.STAGE }}
Remember to add the secrets in your GitHub repository environment configuration.
Setup SST
Add sst.config.ts configuration. To initialize SST you can run:
pnpm dlx sst init
Note:
- 2.2 This example uses “open-deployments” name. Name it by your own app name.
- 2.3 This example uses opendeployments.com domain. Use your own domain name.
sst.config.ts
export default $config({
app(input) {
return {
name: "open-deployments",
removal: input?.stage === "production" ? "retain" : "remove",
protect: ["production"].includes(input?.stage),
home: "aws",
providers: {
aws: {
region: "us-east-1",
profile: input.stage === "production" ? "production" : undefined,
},
cloudflare: "latest",
},
};
},
async run() {
const isProduction = $app.stage === "production";
new sst.aws.Nextjs("OpenDeploymentsWebsite", {
domain: isProduction
? {
name: "opendeployments.com",
dns: sst.cloudflare.dns(),
aliases: ["www.opendeployments.com"],
}
: undefined,
});
},
});
Last updated on