Captain Codeman Captain Codeman

Deploy a SvelteKit App to GitHub Pages

The easy way

Contents

Introduction

GitHub is a great deploy option for static websites and works especially well for Svelte libraries where you can use SvelteKit to author the package (in the /lib folder) with the docs and examples published from the /routes pages.

There are already several guides on how to deploy a SvelteKit app to GitHub pages but I found many contain unnecessary complexity or required configuration changes that are not needed.

So I thought I’d share and describe the deploy action I use - the exact same file can be copied into any SvelteKit project as-is and “just works”.

Use the Static Adapter

Of course GitHub pages are static only, so you have to be using the Static Adapter for SvelteKit.

First install it as a dev dependency using your package manager of choice which really should be pnpm (trust me!):

pnpm i -D @sveltejs/adapter-static

Then change the adapter used in svelte.config.js which should be a case of replacing the default @sveltejs/adapter-auto with @sveltejs/adapter-static instead:

import adapter from '@sveltejs/adapter-static'

Configure the Repository

Go to the Settings tab on your GitHub repo and the Pages section on the left. The “Build and deployment” option should be set to use Github Actions.

github-pages

Add the Github Action

Now just add the following .github/workflows/deploy.yml file to your project and commit it. There is nothing project-specific that needs to be changed so the exact same file can be used for any project:

name: Deploy to GitHub Pages

on:
  # Trigger the workflow every time you push to the `main` branch
  # Using a different branch name? Replace `main` with your branch’s name
  push:
    branches: [master]

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

# Allow this job to clone the repo and create a page deployment
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:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Install pnpm
        uses: pnpm/action-setup@v2
        with:
          version: 8

      - name: Install Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 18
          cache: pnpm

      - name: Install dependencies
        run: pnpm install --frozen-lockfile

      - name: Setup Pages
        uses: actions/configure-pages@v3
        with:
          static_site_generator: sveltekit

      - name: Build
        run: pnpm run build

      - name: Upload Artifacts
        uses: actions/upload-pages-artifact@v1
        with:
          # this should match the `pages` option in your adapter-static options
          path: 'build/'

  deploy:
    needs: build
    runs-on: ubuntu-latest

    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}

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

Your SvelteKit project should now auto-deploy after a commit and appear on github pages.

github-action

How it Works

So how does it work and why is it different?

Well first, if you use GitHub actions you don’t need to bother with any .nojekyll file. That is simply a leftover from the-time-before-actions when pages could only be published by setting up a separate branch, and github pages were initially designd to use “Jekyll” for templating. For SvelteKit especially, it just makes sense to use GitHub actions rather than a separate branch - what you want to deploy is the app itself containing the routes.

Secondly, the action knows that it’s deploying a SvelteKit project, and it knows the name of the repository, so it can configure the base path for you without needing any environment setup or test for whether it’s running in production or development mode. Not having to configure the project to know it’s own name is one less change to make which seems easier to me.

As long as you are using pnpm (you really should be), the default branch name and out-the-box SvelteKit setup this should work as-is. You can of course customize it if you need to but I’ve found it’s re-usable and I can just re-use it across projects

Please let me know what you think and if you see any way to improve it!