🖥️ ragTech Website: Deploying a Next.js App on GitHub Pages With Our Custom Domain

🖥️ ragTech Website: Deploying a Next.js App on GitHub Pages With Our Custom Domain

Hello, and welcome to ragTech's blog, where we engage in bytes and banter --- not on screen or microphone, but on text! 📝

If this is your first time seeing anything from us, we are a team of three techies, Victoria Lo , Natasha Ann and Saloni Kaur , who came together to create a tech podcast show to talk about the realities of life in tech in a relatable and authentic manner.

Our episodes are available to watch on video on YouTube; on audio on Spotify, Apple Music and Amazon Music; and we also have our socials on Instagram, Tiktok and LinkedIn! Links are at the end of this article 💚

So... You're Creating a Website?

As part of branding review efforts that our team has embarked on, we've been wanting to create our own website for awhile now. This will help lend credibility to our brand name, and allow for a space to help friends of ragTech (yes, you!) find us, keep updated on our shenanigans, and explore our show on our various platforms and socials better.

In the spirit of sharing about everything and anything tech, we're also detailing our exact process in creating our website, just in case anybody wants to follow along! It's also great for our personal documentation purposes, so that's two birds with one stone! 🐦🐦🪨

🧠 Our Considerations...

Our main considerations in building out our website were:

  1. Cheap: Costs us practically nothing to create as we aren't earning any money and costs are out of pocket from us...

  2. Collaborative: All three of us can work on any part of it easily, and the stack is familiar to us!

  3. Customizable and Flexible: We can easily customize pages and functionality relevant to our tech show needs, which might have unique functionality that requires some logic. While our website right now will generally be a static site and rather simple, we want to cater for potential for it to become a little bit more complex and dynamic in the future as our community grows!

  4. Compatible: We're already using Hashnode for our blog, and would want a stack that can easily use Hashnode's API to fetch our blog posts without needing to migrate to a new platform.

For these three reasons, we've decided on the following tech stack relevant to this initial setup:

  • Web Development Framework: Next.js

  • Code Collaboration: GitHub, with a team repository

  • Deployment: GitHub Pages

Isn't Next.js Overkill for a Static Site?

Not really, with its newest release! Next.js offers both Static Site Generation (SSG) and Server-Side Rendering (SSR), which you can easily choose based on your needs.

With Static Site Generation (SSG), the page is pre-rendered during build time, before it is deployed to be seen by the world. With Server-Side Rendering (SSR), the page is pre-rendered upon each new request and updated frequently.

Not only does Next.js offer both implementations, it automatically determines if a page is static and renders and optimizes it accordingly. Within the same app, you can have some pages that implement SSG, and some pages that enable SSR - all automatically optimized by Next.js!

As mentioned above in our considerations, we want to have the flexibility to customize our website as it grows, and that includes catering for the potential for more dynamic website functionality in the future. With Next.js, we can primarily use Static Site Generation (SSG), and later on if the need calls for it, use Server-Side Rendering (SSR)!

Why GitHub Pages for Deployment?

We were initially considering Vercel, a cloud platform for static sites, for deployment instead of GitHub Pages due to its ease of integration with GitHub and Next.js (especially since the team at Vercel also created Next.js).

However, while it is free to use for personal projects in personal repositories, we would have to purchase Vercel Pro in order to deploy our team projects.

In light of this, GitHub Pages surfaced as another option for us to consider as a free static site hosting service, since we were already using GitHub to collaborate on our code.

GitHub Pages, however, is designed to serve static sites in HTML, CSS and Javascript, so we knew we would have to use some workarounds in order to deploy our Next.js application onto it.

Henceforth, this walkthrough's highlight is detailing how we worked around these limitations to achieve the best of both worlds - of using a team repository for GitHub for our project, while being able to deploy our project for free on GitHub Pages!

Pre-installation Requirements

These were the pre-installation requirements we started out with. In general, it's great to start out with the latest versions for new projects, so that's what we did here. If you are following this walkthrough and do not have the same pre-install requirements, feel free to click on the links to each requirement below to find out how to set it up on your environment!

Creating Our Next.js App

Using create-next-app

npx create-next-app@latest

Using create-next-app, we first created a new Next.js application with the npx NPM package runner (you can use any of your choice!). For simplicity, we used mostly the default configuration, including using:

  • Typescript

  • ESLint

  • Tailwind CSS

Running our Development Server

npm run dev

Of course, to make sure everything is running well locally, we'll have to run it for the first time. Fortunately for us, the development server started up like a smooth engine and we were able to see the default Next.js landing page!

Setting up GitHub Pages

Initializing a Git Repository

git init 
git commit -m "chore: setup nextjs app"
git branch -M main
git remote add origin <our origin>
git push -u origin main

After initializing a git repository in our new Next.js app, we went ahead to create a remote repository on our team's organizational GitHub account, added it as our origin on our local git repository, and pushed our first commit!

ragTech website remote repository on GitHub

Setting up our Custom Domain with GitHub Pages

As we had already previously purchased our domain 'ragtech.dev' from GoDaddy, we wanted to be able to use it for this website instead of the default GitHub domain. You can skip this step if you do not have your own domain and do not mind the default domain! Otherwise, you would have to purchase your own custom domain from domain name providers like GoDaddy.

Adding our Custom Domain to Our Website Repository

We first set our deployment source to deploy from our main branch. This will be our production branch that deploys directly to our live site, served by GitHub Pages!

Next, we started configuring our custom domain, ragtech.dev. In order to pass the DNS checks, we had to configure our apex domain back on GoDaddy. In our case, we created A and AAAA records that point back to GitHub Pages' IP addresses.

After doing so, our DNS check was successful and we were able to enforce HTTPS on our site!

Verifying our Domain Name (Optional)

To verify our domain on GitHub Pages and eventually have a 'Verified' badge beside our website link on our GitHub organization repository home page, we had to go to our GitHub organizational account home page, and go to Settings > Pages > Add a Verified Domain.

From there, we were prompted to setup our DNS configuration on GoDaddy so that our domain provider would recognize the GitHub Pages hostname for our site so that GitHub could verify that we owned the domain.

Configuring GitHub Pages to Deploy Next.js App

Right now, as GitHub Pages is designed to only serve static files (i.e. HTML, CSS, JavaScript), our site is only showing our README file when you navigate to the configured custom domain.

Configure Next.js Build Process for GitHub Pages

Following this tutorial, we overcame this limitation by configuring our Next.js app to generate static pages so that the build output will export static pages instead of a Node.js app.

Navigating to our next.config.mjs file in the root directory of our Next.js app, we changed the configuration output to export static pages.

//next.config.mjs or
/** @type {import('next').NextConfig} */
const nextConfig = {
  basePath: "/ragtech-website",
  output: "export",  // <=== enables static exports
  reactStrictMode: true,
};

export default nextConfig;

After making this change, a folder directory named out will be exported on building the application, containing all the static assets in our app, which will be used to upload onto GitHub Pages.

We also added a default base path to fix any issues with missing images that might surface on the site, due to GitHub Pages' way of publishing images and their subpaths in relation to the name of our repository.

Using GitHub Actions to Deploy our Next.js App

Going back to our GitHub Pages settings in our repository, we selected GitHub Actions to customize our build process for deployment instead of the standard GitHub Pages deployment, which as mentioned, only serves static pages.

On selecting GitHub Actions, we were immediately presented with the Next.js suggested workflow, which is a pre-written GitHub Actions workflow designed for Next.js deployment to GitHub Pages written by the team at GitHub Pages themselves!

As can be seen in the code snippet below, the pre-written workflow contains steps to:

  1. Checkout the main branch

  2. Detect the package manager

  3. Setup Node

  4. Setup Pages

  5. Restore Cache

  6. Install dependencies

  7. Build with Next.js

  8. Deploy to GitHub Pages

# Sample workflow for building and deploying a Next.js site to GitHub Pages
#
# To get started with Next.js see: https://nextjs.org/docs/getting-started
#
name: Deploy Next.js site to Pages

on:
  # Runs on pushes targeting the default branch
  push:
    branches: ["main"]

  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
  contents: read
  pages: write
  id-token: write

# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
  group: "pages"
  cancel-in-progress: false

jobs:
  # Build job
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Detect package manager
        id: detect-package-manager
        run: |
          if [ -f "${{ github.workspace }}/yarn.lock" ]; then
            echo "manager=yarn" >> $GITHUB_OUTPUT
            echo "command=install" >> $GITHUB_OUTPUT
            echo "runner=yarn" >> $GITHUB_OUTPUT
            exit 0
          elif [ -f "${{ github.workspace }}/package.json" ]; then
            echo "manager=npm" >> $GITHUB_OUTPUT
            echo "command=ci" >> $GITHUB_OUTPUT
            echo "runner=npx --no-install" >> $GITHUB_OUTPUT
            exit 0
          else
            echo "Unable to determine package manager"
            exit 1
          fi
      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: "20"
          cache: ${{ steps.detect-package-manager.outputs.manager }}
      - name: Setup Pages
        uses: actions/configure-pages@v5
        with:
          # Automatically inject basePath in your Next.js configuration file and disable
          # server side image optimization (https://nextjs.org/docs/api-reference/next/image#unoptimized).
          #
          # You may remove this line if you want to manage the configuration yourself.
          static_site_generator: next
      - name: Restore cache
        uses: actions/cache@v4
        with:
          path: |
            .next/cache
          # Generate a new cache whenever packages or source files change.
          key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}-${{ hashFiles('**.[jt]s', '**.[jt]sx') }}
          # If source files changed but packages didn't, rebuild from a prior cache.
          restore-keys: |
            ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}-
      - name: Install dependencies
        run: ${{ steps.detect-package-manager.outputs.manager }} ${{ steps.detect-package-manager.outputs.command }}
      - name: Build with Next.js
        run: ${{ steps.detect-package-manager.outputs.runner }} next build
      - name: Upload artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: ./out

  # Deployment job
  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4

Once we commit this new workflow file to our GitHub repository, this will automatically trigger the new workflow to run in GitHub actions (since the workflow file was written to trigger on any committed changes on our main branch).

After waiting for the build and deploy steps to run, our Next.js app was successfully deployed using GitHub Pages!

On navigation to our custom domain, we could now see the same Next.js landing page that we saw on our local development server!

Conclusion

That concludes the first part of the setup process of creating our ragTech website! In the following parts, we'll be slowly building out the various features in our website in our Next.js app, including integrating our existing Hashnode blog into our website, having an RSS feed of our audio podcast on our website, and showcasing our YouTube episodes.

If you enjoyed this walkthrough, do like and comment on this blogpost and subscribe to our blog and newsletter.

And don't forget to watch/listen to our tech podcast show episodes, where we publish new episodes biweekly, and help us like, comment and subscribe on these platforms too:

▶️Watch

🎶Listen

📝Read

📢Stay Updated