lecture.studio

Publish Marp slides on GitHub Pages with Actions or Docker

Publish Marp decks on GitHub Pages with one workflow: check out the repository, run marp-cli over the slides folder to produce HTML (and PDF) in a dist/ folder, upload that folder as the Pages artifact, deploy. Every push updates the course site, and students get a stable link per week. The Docker image marpteam/marp-cli runs the same build on any machine without installing Node.

This guide gives the workflow file, the folder layout, the PDF step, the Docker command, and the two things that break (local images and custom themes) with their fixes.

Folder layout

course/
  slides/
    week-01.md
    week-02.md
    assets/           images
  themes/
    cs101.css
  .github/workflows/pages.yml

marp-cli converts a whole folder with --input-dir (-I), keeping the structure, so slides/week-01.md becomes dist/week-01.html.

The workflow

# .github/workflows/pages.yml
name: Publish slides
on:
  push:
    branches: [main]
permissions:
  contents: read
  pages: write
  id-token: write
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - name: Build HTML
        run: npx @marp-team/marp-cli@latest -I slides -o dist --theme-set themes --html
      - name: Build PDF
        run: npx @marp-team/marp-cli@latest -I slides -o dist --theme-set themes --pdf --allow-local-files
      - name: Copy assets
        run: cp -r slides/assets dist/assets
      - uses: actions/upload-pages-artifact@v3
        with:
          path: dist
  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

In the repository settings, set Pages to deploy from GitHub Actions. The PDF step needs a browser; the ubuntu-latest runner has Chrome, which marp-cli finds on its own. --allow-local-files is what lets the PDF include the images in slides/assets; --html is only needed if the decks use inline styles or iframes.

A community action (KoharaKazuya/marp-cli-action) wraps the conversion step; the npx line above does the same with no extra dependency.

Students bookmark https://user.github.io/course/week-05.html. Keep file names fixed across the term (week-05, not scheduling-v2), and when a deck changes, push; the link stays. For a PDF per week, the same name with .pdf. An index.md in slides/ converted like the others makes a landing page listing the weeks.

Docker

The same build without Node on the machine:

docker run --rm -v "$PWD:/home/marp/app/" -e LANG=$LANG marpteam/marp-cli -I slides -o dist --pdf --allow-local-files

The image ships a browser, so PDF and PPTX work inside it. It is the right tool for a lab machine or a CI system that is not GitHub.

What breaks and the fix

Lecture Studio and git

Lecture Studio keeps a course as a folder with one deck per unit and shows a git bar when the folder is a repository; commit and push from the app, and the workflow above publishes the decks. Nothing in the app needs to change for this to work, since the decks are plain Marp files. The app runs on macOS 15 or later; the assistant needs an Oberik project key.

FAQ

How do I publish Marp slides on GitHub Pages?

A workflow that runs npx @marp-team/marp-cli -I slides -o dist on push, uploads dist with actions/upload-pages-artifact, and deploys with actions/deploy-pages. Set Pages to deploy from Actions.

Can GitHub Actions build Marp PDFs?

Yes. The Ubuntu runner has Chrome; run marp-cli with --pdf --allow-local-files.

Is there a Marp Docker image?

marpteam/marp-cli (also on ghcr.io). Mount the folder at /home/marp/app/ and pass the usual flags.

How do I convert a whole folder of Marp decks?

marp -I slides -o dist converts every Markdown file in slides, keeping the structure.