Logo

[S3] Deploying a Next.js SSG App to S3 with GitHub Actions

GHA

What is SSG again?

SSG (Static Site Generation) builds HTML at build time, not per request. It means fast page loads and zero server costs! This is ideal for S3 hosting and hosting static sites affordably.

Update next.config.js

Tell Next.js to export the app as a static site.

1// next.config.js
2const nextConfig = {
3 output: 'export',
4}
5
6module.exports = nextConfig

GitHub Actions Workflow

Automate the deployment with GitHub Actions. This workflow builds the Next.js app and uploads it to S3.

1name: Deploy to S3
2on:
3 push:
4 branches: ['main']
5
6permissions:
7 actions: write
8 contents: read
9 id-token: write
10
11jobs:
12 upload:
13 runs-on: ubuntu-latest
14
15 steps:
16 - name: Checkout
17 uses: actions/checkout@v4
18
19 - name: Configure AWS credentials (OIDC)
20 uses: aws-actions/configure-aws-credentials@v4
21 with:
22 role-to-assume: arn:aws:iam::<your-account-id>:role/<your-gha-role>
23 aws-region: ap-northeast-1
24
25 - name: Setup Node.js
26 uses: actions/setup-node@v4
27 with:
28 node-version: 20
29
30 - name: Cache node modules
31 id: cache-npm
32 uses: actions/cache@v4
33 env:
34 cache-name: cache-node-modules
35 with:
36 path: ~/.npm
37 key: \${{ runner.os }}-build-\${{ env.cache-name }}-\${{ hashFiles('**/package-lock.json') }}
38 restore-keys: |
39 \${{ runner.os }}-build-\${{ env.cache-name }}-
40
41 - name: Install Dependencies
42 run: npm ci
43
44 - name: Build
45 run: npm run build
46
47 - name: Deploy to s3
48 run: |
49 aws s3 cp --recursive ./out/ s3://your-static-site-bucket-name --acl public-read

Notes

  • Don't use getServerSideProps() — only getStaticProps() or plain pages.
  • Dynamic routes won't work unless they're pre-rendered.
  • S3 doesn't handle client-side routing. Might need CloudFront + fallback if routing breaks.