Greg Rickaby

Full-Stack Developer

5 min read 路 #code

Next.js Github Pages

Learn how to deploy a Next.js app on Github Pages with Github Actions.

Introduction

Vercel promotes itself as "The easiest way to deploy your Next.js app"...and it's really great. You could totally use it. Netlify offers a similar service for building modern web apps which is also amazing.

However, I feel like Vercel and Netlify really want you on their SaaS. If you're interested in owning your own data (like I am), hosting on a SaaS could be problem. I've also found almost no current documentation around deploying a static NextJS app to Github Pages. Well, I figured it out and I'm sharing my findings with you.

Caveats

Because Github Pages doesn't support serverless functions, some functionality, such as API Routes will be disabled. You can learn more here:

Vercel has since published an official gh-pages example. While the implementation I wrote about below still works, I recommend looking at their example before making any major decisions.

Getting Started

I'm going to gloss over this part, because I assume you already know how to create a Github repo and generate a Next.js app. You'll also need to place a .nojekyll file in /public to bypass Github Pages from trying to auto-generate a static Jekyll site.

Specify the Asset Directory

Next.js allows you to prefix the assets directory with the assetPrefix setting. You'll need to do this so assets served from /_next/static work correctly on Github pages.

  1. Create next.config.js file
  2. Add the following and edit your-github-repo-name to match your Github repo name:
const isProd = process.env.NODE_ENV === 'production'

module.exports = {
  // Use the prefix in production and not development.
  assetPrefix: isProd ? '/your-github-repo-name/' : ''
}
  1. Save the next.config.js

Generate Deploy Key

Before Github Actions can commit and push to the gh-pages branch, it needs to authenticate with itself (sorry, I find this hilarious 馃槅). You'll need to generate new Public and Private keys. Don't worry, these new keys won't override your personal SSH keys.

In your next.js app directory, run the following command:

ssh-keygen -t rsa -b 4096 -C "$(git config user.email)" -f gh-pages -N ""

Now open the keys in your code editor. In just a minute, you're going to copy and paste the contents into your Github repository settings.

Public Key

In your Github repository:

  1. Go to Settings --> Deploy Keys
  2. Title: Public key of ACTIONS_DEPLOY_KEY
  3. Key: (copy and paste the public key)
  4. Check: Allow write access
  5. Click: Add key

screenshot

Private Key

In your Github repository:

  1. Go to Settings --> Secrets
  2. Click: Add a new secret
  3. Name: ACTIONS_DEPLOY_KEY
  4. Value: (copy and paste the private key)
  5. Click: Add key

screenshot

Now Github Actions will be able to authenticate with your Github repository. You can safely delete the two keys from your computer.

Github Actions

This is where the magic happens. The workflow file is running a few commands to deploy the app.

screenshot

Here are the steps:

  1. Check out /main branch
  2. Setup Node LTS
  3. Get NPM's cache from the last build 馃殌
  4. Build the app
  5. Deploy the app to the /gh-pages branch (using a the ACTIONS_DEPLOY_KEY you generated earlier).

My Github Action workflow uses this action to handle the actual deployment. I went with a third-party action, because I don't want to have to maintain it.

Here's the workflow in .yml:

name: Deploy to Github Pages

on:
  push:
    branches:
      - main

  workflow_dispatch:

jobs:
  deployment:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [14.x]

    steps:
      - uses: actions/checkout@v2

      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v1
        with:
          node-version: ${{ matrix.node-version }}

      - name: Use NPM 7
        run: npm i -g 

      - name: Cache dependencies
        uses: actions/cache@v2
        with:
          path: ~/.npm
          key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.OS }}-node-
            ${{ runner.OS }}-

      - name: Build
        run: |
          npm ci --legacy-peer-deps
          npm run build
          npm run export

      - name: Deploy
        uses: peaceiris/actions-gh-pages@v3
        with:
          deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }}
          publish_dir: ./out

Github Pages

This is the easiest step, because as soon as Github recognizes there's a /gh-pages branch, it'll automatically activate the Github Pages feature.

You should be able to see your app right away at https://your-username.github.io/your-repo-name/

Wrap up

Thanks for reading and I hope this helps. If you noticed someting wrong, please file an issue. Good luck!

-Greg