> For the complete documentation index, see [llms.txt](https://saveyourtime.gitbook.io/saveyourtime/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://saveyourtime.gitbook.io/saveyourtime/github-actions/github-deploying-a-react-next.js-app-to-aws-s3-with-github-actions.md).

# Github - Deploying a React Next.js App to AWS S3 with Github Actions

### Create a workflow for staging and production instances

Click on **Actions** tab within the Github repo and then Press on **New workflow**

![](/files/-MDTiQ_etQAMyhwidJkR)

![](/files/-MDTilvyQQh7RHhbz3UR)

> You can skip this (Choose a workflow template) and click the ***Setup a workflow yourself*** and start from scratch.

### Setup workflow files

![](/files/-MDTj9_1WQkqnX54NSXG)

`production.yml`

```yaml
# This is a basic workflow to help you get started with Actions

name: Build and Deploy

# Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the master branch
on:
  push:
    branches: [master]
  pull_request:
    branches: [master]

# A map of environment variables that are available to all jobs and steps in the workflow
env:
  NEXT_PUBLIC_APP_ENV: production
  NEXT_PUBLIC_API_URL: https://api.website.com/v1
  AWS_REGION: ap-northeast-1
  SOURCE_DIR: out

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  build:
    # The type of runner that the job will run on
    runs-on: ubuntu-latest

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: actions/checkout@v2
        with:
          lfs: true

      - uses: actions/setup-node@v1
        with:
          node-version: '12.x'
          registry-url: 'https://registry.npmjs.org'

      - name: Install
        run: |
          node -v
          yarn -v
          yarn install

      - name: Build
        run: |
          yarn build
          yarn export
        env:
          NEXT_PUBLIC_APP_ENV: ${{ env.NEXT_PUBLIC_APP_ENV }}
          NEXT_PUBLIC_API_URL: ${{ env.NEXT_PUBLIC_API_URL }}

      - name: Duplicate files without html extension
        run: |
          find ./out -type f -name '*.html' | while read HTMLFILE; do
            BASENAME=${HTMLFILE##*/};
            FILENAME=${BASENAME%.*};
            if [[ "$FILENAME" != "index" ]];
            then
            mkdir -p "./out/_html" && cp ${HTMLFILE} ./out/_html/${FILENAME};
            fi
          done

      - name: Deploy
        uses: jakejarvis/s3-sync-action@master
        with:
          args: --acl public-read --follow-symlinks --delete
        env:
          AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          AWS_REGION: '${{ env.AWS_REGION }}' # optional: defaults to us-east-1
          SOURCE_DIR: '${{ env.SOURCE_DIR }}' # optional: defaults to entire repository

      - name: Deploy files without html extension
        uses: jakejarvis/s3-sync-action@master
        with:
          args: --acl public-read --follow-symlinks --content-type text/html
        env:
          AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          AWS_REGION: '${{ env.AWS_REGION }}' # optional: defaults to us-east-1
          SOURCE_DIR: 'out/_html' # optional: defaults to entire repository

      - name: Invalidate Cloudfront
        uses: chetan/invalidate-cloudfront-action@master
        env:
          DISTRIBUTION: ${{ secrets.DISTRIBUTION }}
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          AWS_REGION: '${{ env.AWS_REGION }}'
          PATHS: '/*'
```

`staging.yml`

```yaml
# This is a basic workflow to help you get started with Actions

name: Build and Deploy

# Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the staging branch
on:
  push:
    branches: [staging]
  pull_request:
    branches: [staging]

# A map of environment variables that are available to all jobs and steps in the workflow
env:
  NEXT_PUBLIC_APP_ENV: staging
  NEXT_PUBLIC_API_URL: https://api-staging.website.com/v1
  AWS_REGION: ap-northeast-1
  SOURCE_DIR: out

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  build:
    # The type of runner that the job will run on
    runs-on: ubuntu-latest

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: actions/checkout@v2
        with:
          lfs: true

      - uses: actions/setup-node@v1
        with:
          node-version: '12.x'
          registry-url: 'https://registry.npmjs.org'

      - name: Install
        run: |
          node -v
          yarn -v
          yarn install

      - name: Build
        run: |
          yarn build
          yarn export
        env:
          NEXT_PUBLIC_APP_ENV: ${{ env.NEXT_PUBLIC_APP_ENV }}
          NEXT_PUBLIC_API_URL: ${{ env.NEXT_PUBLIC_API_URL }}

      - name: Duplicate files without html extension
        run: |
          find ./out -type f -name '*.html' | while read HTMLFILE; do
            BASENAME=${HTMLFILE##*/};
            FILENAME=${BASENAME%.*};
            if [[ "$FILENAME" != "index" ]];
            then
            mkdir -p "./out/_html" && cp ${HTMLFILE} ./out/_html/${FILENAME};
            fi
          done

      - name: Deploy
        uses: jakejarvis/s3-sync-action@master
        with:
          args: --acl public-read --follow-symlinks --delete
        env:
          AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET_STAGING }}
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          AWS_REGION: '${{ env.AWS_REGION }}' # optional: defaults to us-east-1
          SOURCE_DIR: '${{ env.SOURCE_DIR }}' # optional: defaults to entire repository

      - name: Deploy files without html extension
        uses: jakejarvis/s3-sync-action@master
        with:
          args: --acl public-read --follow-symlinks --content-type text/html
        env:
          AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET_STAGING }}
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          AWS_REGION: '${{ env.AWS_REGION }}' # optional: defaults to us-east-1
          SOURCE_DIR: 'out/_html' # optional: defaults to entire repository

      - name: Invalidate Cloudfront
        uses: chetan/invalidate-cloudfront-action@master
        env:
          DISTRIBUTION: ${{ secrets.DISTRIBUTION_STAGING }}
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          AWS_REGION: '${{ env.AWS_REGION }}'
          PATHS: '/*'
```

{% hint style="info" %}
Replace `NEXT_PUBLIC_APP_ENV` with the environment where you're running this app.\
Replace `NEXT_PUBLIC_API_URL` with your backend API host.\
Replace `AWS_REGION` with the region where you created your bucket.\
Replace `SOURCE_DIR` with the local directory (or file) you wish to sync/upload to S3.\
Replace `PATHS` with a list of one or more space-separated paths to invalidate.
{% endhint %}

### Add AWS secrets to Github

![](/files/-MDTk9JBlPGvhYll2PVw)

### Push code to Github then Github Action will deploy your app to an S3 Bucket automatically

{% embed url="<https://medium.com/trackstack/deploying-a-react-app-to-aws-s3-with-github-actions-b1cb9ba75c95>" %}

{% embed url="<https://itnext.io/deploy-next-js-apps-using-github-actions-6322261757bc>" %}
