← All TILs · github-pages

Publishing a TIL collection as a static GitHub Pages site

github-pages - 2026-09-05

I forked simonw/til to start my own "Today I Learned" collection, but its publishing pipeline was built around Simon's own infrastructure: build_database.py compiled every entry into a sqlite database, generate_screenshots.py rendered preview images via Playwright, and the GitHub Actions workflow pushed the result to an S3 bucket and deployed a Datasette instance on Fly.io. None of that infrastructure was mine, so the workflow just failed without those secrets configured.

Since I only wanted a browsable index of my own notes, I replaced the whole pipeline with a much smaller one:

That last part is a pattern Simon documented himself, in his own TIL: github-actions/github-pages.md. The minimal recipe is just:

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

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - run: |
        mkdir _site
        echo '<h1>Hello, world!</h1>' > _site/index.html
    - uses: actions/upload-pages-artifact@v3
  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - id: deployment
        uses: actions/deploy-pages@v4

Anything written into _site/ before the upload-pages-artifact step gets published. The three permissions are all required: contents: read for checkout, pages: write to publish, and id-token: write because deploy-pages needs it to authenticate.

One gotcha I hit: my repo has a topic folder literally named markdown/, which shadowed the pip markdown package the build script imports — Python adds the script's own directory to sys.path, so import markdown found the empty local folder instead of the real library. Fixed by stripping the script's directory from sys.path before importing it.

Enabling Pages with "build from GitHub Actions" as the source (rather than a branch) can be done from the repo settings UI, or via the API:

gh api -X POST repos/OWNER/REPO/pages -f 'build_type=workflow'

The site now lives at https://til.housni.eu/, with no Fly, S3, or Datasette involved. It started at abdelhousni.github.io/til/; with a custom domain set in the repository's Pages settings, GitHub redirects that address to the new one.

Created 2026-09-05T02:32:25+02:00, updated 2026-09-29T22:48:40+02:00 · History · Edit