Deploy NextJS app to GitHub Pages using GitHub Actions
Tags: react, nextjs, devops, github
Published: 2021-04-19 09:22:25

GitHub pages allow us to host static sites from a repository. NextJS can be used as a static site generator. If we combine these two things and add some GitHub Action we get a React-based website that is easy to maintain, test, and host.

## Prepare NextJS application

To generate static output we need to add `next export` command that creates a static version of the application.

```diff
  "scripts": {
    "dev": "next dev",
    "build": "next build",
+   "export": "next export",
    "start": "next start"
  },
```

According to the [NextJS documentation](https://nextjs.org/docs/advanced-features/static-html-export), there is a few caveats we must meet (e.g. we can not use `getServerSideProps` because of static rendering without a server) for successfully export. If you use a default **next/image** loader, you have to add an [default loader](https://nextjs.org/docs/basic-features/image-optimization#loader).

If our NextJS application is ready, we should try `npm run build && npm run export` command. Output `Export successful.` means that the application is ready to deploy.

> If you want to use a custom domain just add a CNAME file to `public` directory.

## GitHub Page

To host a website on GitHub Pages we have to activate it in repository settings. We can select a custom domain (in this case you have to add the `CNAME` file that contains an address and change DNS). You can also check the **Enforce HTTPS** option.

> Every **.dev** domain is on the HSTS preload list, which makes HTTPS required on all connections. So if you want to use **.dev** domain you have to check `Enforce HTTPS`

![Deploy NextJS app to GitHub Pages using GitHub Actions - GH Pages](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/466zx15abnfmuagkt981.jpg "GitHub Pages settings")

## GitHub Action

GitHub provides *2,000 Actions minutes/month* for free accounts. It is more than enough to check how it works and use it in some side projects.

Let's move to create GitHub Action. Enter your project on GitHub then navigate to **Actions** tab and choose **Node.js By GitHub Actions** (name of the action is up to you).

![Deploy NextJS app to GitHub Pages using GitHub Actions - GH Action](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nscvu4up3u872feyczcc.jpg "Choosing GitHub Action template")

I used the following script:

```yaml
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions

name: GitHub Pages deploy

on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout 🛎️
        uses: actions/checkout@v2.3.1
      - name: Use Node.js 14.x
        uses: actions/setup-node@v1
        with:
          node-version: "14.x"

      - name: Installing my packages
        run: npm ci

      - name: Build my App
        run: npm run build && npm run export && touch ./out/.nojekyll

      - name: Deploy 🚀
        uses: JamesIves/github-pages-deploy-action@4.1.0
        with:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          BRANCH: gh-pages # The branch the action should deploy to.
          FOLDER: out # The folder the action should deploy.
```

I think that this `yml` file is easy to understand. Some rough explanations:

- action will be triggered on every push to `main` branch,
- Ubuntu will be used as OS (you can also choose Windows or macOS),
- in the first step script will checkout our code from the repository and use NodeJS in the given version,
- `npm ci` is used to install packages instead of `npm install` because it is faster than what we care about due to GitHub Actions limitations,
- step named `Build my App` is the main one:
  - `npm run build && npm run export` builds and exports app,
  - `run: touch ./out/.nojekyll` is because the `_next` folder is by default not served by GitHub because of Jekyll processing, `.nojekyll` file prevents that,
- [github-pages-deploy-action](https://github.com/JamesIves/github-pages-deploy-action) is used to push a static exported site to `gh-pages` branch.

> `npm ci` used in action requires `package-lock.json` that isn't created by `yarn`. There are some ways to handle it (e.g. `yarn install --frozen-lockfile`), but I decided to just use `npm` instead of `yarn`.

## Summary

Now we can serve a static website on free hosting with automated deployment on push to `main`. Https is provided by GitHub Pages. The only cost is custom domain (if we want to). Other static site generators like [Gatsby](https://www.gatsbyjs.com/), [Jekyll](https://jekyllrb.com/), or [Hugo](https://gohugo.io/) (on almost every website you can read that their framework is the fastest one) can be used with GitHub Pages and Actions almost the same way as NextJS.

Check out a [repository](https://github.com/wozniaklukasz/blog-deploy-nextjs-app-to-github-pages-using-github-actions) with an example application of NextJS app built with described [GitHub Action](https://github.com/wozniaklukasz/blog-deploy-nextjs-app-to-github-pages-using-github-actions/actions) that is hosted right [here](https://wozniaklukasz.github.io/blog-deploy-nextjs-app-to-github-pages-using-github-actions/).

*Originally published at [https://lukaszwozniak.dev](https://lukaszwozniak.dev/blog/deploy-nextjs-app-to-github-pages-using-github-actions/) on April 18, 2021.*