Cartoon person steering a space ship

Automating and deploying workflows with GitHub Actions

Bekah Whittle
Bekah Whittle // Director, Field Services // GitHub

Our application successfully builds and passes our test, and our deployment environment is ready. We have just one job left to do in our workflow: deploying our Next.js application to GitHub Pages with GitHub Actions!


In this guide, you will learn:

  • How to set permissions for specific use-cases

  • How to choose a deployment environment in a workflow

  • How to deploy a Next.js static site to GitHub Pages with GitHub Actions


Add a deploy job to run after a successful test

With GitHub Pages enabled and our environment created and configured, we’re finally ready to build our deploy job.

Open the Code tab of your actions-learning-pathway repository, navigate to the .github/workflows directory and open the build-test-deploy.yml workflow file. It should look like this to start:

name: build-test-deploy
on: push
jobs: 
  build:
    runs-on: ubuntu-latest
    steps: 
      - name: checkout repo
        uses: actions/checkout@v3
      - name: use node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18.x'
      - run: npm install
      - run: npm run build
  test: 
    needs: build
    runs-on: ubuntu-latest
    steps: 
      - name: checkout repo
        uses: actions/checkout@v3
      - name: use node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18.x'
      - run: npm install
      - run: npm test

Similar to how we don’t want to run tests on a failed build, we don’t want to deploy a build that has failed our tests, so our first task is to check if our test job completed successfully. We’ll do that by again using the needs keyword after defining the deploy job:

deploy:
    needs: test

Define permissions

In Actions, the permissions keyword controls what tasks or processes our workflow can perform. Setting the right permissions ensures that our workflow can interact with various parts of our GitHub repository without any issues.

For our specific task, we're adjusting permissions for the GitHub token. This token acts like a key, allowing our workflow to access and modify parts of our repository. Since we're deploying to Pages, it's essential that our token has the necessary “write” access.

    permissions:
      contents: write
      pages: write     
      id-token: write

Choose your deployment environment

In the last guide, we created a production environment. Now that it’s time to deploy our application, we need to identify that environment as the deployment target. We pass two parameters to environment: the name of the environment we want to deploy to and the url of our deployment. For url, steps.deployment.outputs.page_url grabs the deployed page URL from the final deployment step. We’ll show you how we identified this step for reference in just a moment when we get there. 

While we’re at it, we again specify a GitHub-hosted runner with ubuntu-latest

    environment:
      name: production
      url: ${{ steps.deployment.outputs.page_url }}
    
  runs-on: ubuntu-latest

Check out the repository with authentication

Just as with our other build and test jobs, our first step uses the checkout action to fetch our repository content. This time, however, we are planning to write, not just read, so we want to be sure to authenticate with GitHub to gain those permissions. The token: ${{ secrets.GITHUB_TOKEN }} is the default authentication provided by Actions. Combined with the permissions we just previously declared, it ensures that our workflow has the necessary permissions. 

    steps:
      - name: checkout repo
        uses: actions/checkout@v3
        with:
          token: ${{ secrets.GITHUB_TOKEN }}

Set up Node and build the application for deployment

Use the setup-node action to set up the node environment again for the deploy job. Remember, every job runs independently, so you need to repeat these steps for each job:

      - name: use node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18.x'

Configure Pages for deployment

Before we build our application, the configure-pages action configures our project for Pages deployment. We specify static_site_generator: next to alert the action that we're working with a Next.js static site. 

      - name: configure github pages
        uses: actions/configure-pages@v3
        with:
          static_site_generator: next

Next, npm install fetches and installs all the project dependencies as defined in package.json, which primes our environment with all the necessary libraries and packages. Following that, npm run build triggers the build script within package.json, culminating in a compiled version of the application that’s ready for deployment. In the context of a Next.js app, this produces a ./out directory that lives in the runner while the job is active and contains the built static site.

      - run: npm install
      - run: npm run build 

Upload artifacts to Pages

In the CI/CD context, an “artifact” is a package or set of files, resulting from a build process, that are meant for distribution or deployment. In this step, the upload-pages-artifact action packages the static site that Next.js built during the npm run build step. We do this by specifying path: ‘./out’. The upload-pages-artifact action then uploads the artifact to Pages.

      - name: upload artifacts
        uses: actions/upload-pages-artifact@v1
        with: 
          path: "./out"

Deploy to Pages

In this final step, the deploy-pages action takes our prepared artifacts, which we built and uploaded in the previous steps, and deploys them directly to Pages. 

By giving this step an id: deployment, we've labeled it, which provides us with a unique identifier. This is useful if we need to reference this particular step in subsequent tasks or to check on its status in more intricate workflows. If you look back a few steps to when we set the environment, you’ll see that we used this identifier to grab the URL for our site with url: ${{ steps.deployment.outputs.page_url }}.

Once this step completes successfully, your Next.js static content will be live and accessible on Pages.

      - name: deploy
        id: deployment
        uses: actions/deploy-pages@v1

Putting it all together, the deploy job should now look like this:

  deploy:
    needs: test

    permissions:
      contents: write
      pages: write     
      id-token: write  

    environment:
      name: production
      url: ${{ steps.deployment.outputs.page_url }}

    runs-on: ubuntu-latest

    steps:
      - name: checkout repo
        uses: actions/checkout@v3
        with:
          token: ${{ secrets.GITHUB_TOKEN }}

      - name: use node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18.x'
      
      - name: configure github pages
        uses: actions/configure-pages@v3
        with:
          static_site_generator: next

      - run: npm install
      - run: npm run build

      - name: upload artifacts
        uses: actions/upload-pages-artifact@v1
        with: 
          path: "./out"

      - name: deploy
        id: deployment
        uses: actions/deploy-pages@v1

With that, you’re ready to finally deploy your site to GitHub Pages!

  1. Click Commit changes….

  2. Enter a commit message and click Commit changes in the dialog box. 

  3. Select the “Actions” tab.

  4. Click the commit message you just entered—or Update build-test-deploy.yml if you left it blank—to see the details of the workflow run.

Chances are, you’ll get to the page quickly and find that the workflows are still in progress. Once all three workflows show as completed, you can view a variety of information about your deployment, such as the total duration to execute the workflow, or the number of artifacts created and their size. You can also download the artifact created during the build step by clicking on its name—github-pages.

Most importantly, your deploy job is followed by a link to your live GitHub Pages site that you just deployed. Click the link to see your site live!

After a moment, all three jobs should display that they have successfully run, with a link to your live GitHub Pages site following the deploy job.

Congrats, you've successfully set up an automated workflow with GitHub Actions to deploy your Next.js application to Pages. 

Up next: Essentials automation module wrap-up

Now that we’ve covered the basics of writing workflow files and creating a simple CI/CD pipeline, it’s time to explore workflow automation at scale. In our next module, you’ll learn how to manage larger projects effectively while keeping your codebase clean and your team efficient. Before we move on, though, let's recap what we've done so far and round up some useful resources.