← Wiki

From Obsidian to the site: publishing with GitHub Actions

  • 4 min read
On this page

GitHub Actions runs tasks on GitHub itself when something happens in a repository. Here, the task is the one you did by hand on the Cloudflare page: build the site and publish it. It runs on its own every time a push of the vault touches the blog or the site. On private repositories, a free GitHub account gets 2,000 minutes of GitHub Actions a month.

The complete workflow

name: Publish the site

on:
  push:
    branches: [main]
    paths:
      - "blog/**"
      - ".site/**"
      - ".github/workflows/publish.yml"
  workflow_dispatch:

permissions:
  contents: read

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - name: Download only blog/ and .site/
        uses: actions/checkout@v7
        with:
          persist-credentials: false
          sparse-checkout: |
            /blog/
            /.site/
          sparse-checkout-cone-mode: false

      - name: Set up Node
        uses: actions/setup-node@v7
        with:
          node-version: 22
          cache: npm
          cache-dependency-path: .site/package-lock.json

      - name: Build the site
        working-directory: .site
        run: |
          npm ci
          npm run build

      - name: Publish to Cloudflare
        working-directory: .site
        run: npx wrangler@4 deploy --assets ./dist --name my-blog --compatibility-date 2026-10-15
        env:
          CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}

Before using it, replace my-blog and the date with the ones you used for your first publish.

What each part does

When it runs (on). On a push to main that touches blog/, .site/ or the workflow itself. A note edited in any other folder of the vault publishes nothing. workflow_dispatch adds a Run workflow button to the Actions tab, so you can publish by hand.

permissions. Each run gets an automatic token from GitHub. This block limits it to reading the repository, which is all the workflow needs.

Download only blog/ and .site/. actions/checkout downloads the repository, and sparse-checkout leaves only the two folders on disk. The content of your other notes never reaches GitHub’s machine; only the list of file names does, because it is part of the commit. sparse-checkout-cone-mode: false makes the patterns apply exactly as written. persist-credentials: false keeps the token from being saved in the downloaded folder, where other programs in the same job, such as scripts from the dependencies that npm ci installs, could read it.

Set up Node. Installs the latest Node 22, the release line the template requires, and caches the dependencies for later runs.

Build the site. The same commands you run on your computer. The symbolic link .site/src/content/blog went into the repository as a link and points to blog/, which the first step downloaded. If the template refuses a note, this step fails and the next one does not run.

Publish to Cloudflare. The same wrangler deploy as your first publish. Instead of the browser login, Wrangler uses the two keys stored as secrets.

The secrets

Create the secrets before the workflow: committing the file already triggers the first run, and without them the publish fails. In the vault repository, under Settings → Secrets and variables → Actions → New repository secret, create the two secrets from the Cloudflare page:

Name Value
CLOUDFLARE_API_TOKEN The token created with the Edit Cloudflare Workers template
CLOUDFLARE_ACCOUNT_ID The account ID

Once saved, a secret is never shown again, not even in the logs. To replace an expired token, edit the secret with the same name.

Where to put it

The workflow is a file in the vault repository, at .github/workflows/publish.yml. Because the folder name starts with a dot, Obsidian does not show it. The simplest way to create it is on the GitHub website:

  1. Open the vault repository on GitHub.
  2. Add file → Create new file.
  3. For the name, type .github/workflows/publish.yml. The slashes create the folders.
  4. Paste the workflow and click Commit changes.

The file now exists on GitHub, not on your computer. Before your next push, bring the change down with Fetch origin and Pull origin in GitHub Desktop.

Check the first run

Move a note into blog/ and push the vault. In the repository’s Actions tab, a “Publish the site” run appears, with the log for each step. When it finishes, the note is live at the site’s address.

If it fails at Likely cause
Build the site A note that does not match what the template requires. The log shows the note and the property, as on the Astro template page
Publish to Cloudflare A missing secret, an expired token, or a token without the Edit Cloudflare Workers permission
Nothing ran The push did not touch blog/, .site/ or the workflow, or the file is not in .github/workflows/

Whatever fails, the live site stays as it was: publishing only happens after the site builds without errors.