CI (GitHub Actions, etc.)

CI (continuous integration) means a server builds your PDF automatically on every push. You always have the latest output without compiling locally, and “works on my machine” problems surface early. For LaTeX the common choice is GitHub Actions: it checks out the repository, compiles in a TeX Live environment, and saves the resulting PDF as an artifact.

Why build in CI

On every push, the document is built automatically in a clean, reproducible TeX Live environment. The benefits: you catch bugs that depended on your local setup, the document is always known to compile, co-authors and reviewers without TeX installed can still get the latest PDF, and you can publish it as a release if needed. You define the build in a workflow file (YAML) under .github/workflows/.

A minimal GitHub Actions workflow

Drop the following YAML in as .github/workflows/build.yml and it works: actions/checkout fetches the source, xu-cheng/latex-action compiles it, and actions/upload-artifact saves the PDF. GitHub Actions major versions move over time; this example uses the current major lines as of 2026: checkout v6 and upload-artifact v7.

terminal
# .github/workflows/build.yml
name: Build LaTeX
on: [push]
permissions:
  contents: read
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: xu-cheng/latex-action@v4
        with:
          root_file: main.tex
      - uses: actions/upload-artifact@v7
        with:
          name: PDF
          path: main.pdf

xu-cheng/latex-action requires root_file and uses pdfLaTeX by default. To change engine, set latexmk_use_xelatex: true or latexmk_use_lualatex: true. For workflows such as upLaTeX + dvipdfmx that need more detailed steps, commit a .latexmkrc and let the action read the same configuration as your local build.

This YAML is the smallest shape for checking whether the PDF can be produced. For a thesis or collaborative paper, run it on both push and pull_request so a broken PDF is caught before review. Action major versions move over time; for a long-lived template, either accept dependency-update PRs or schedule a yearly check against the official READMEs.

The TeX Live environment — the texlive/texlive image

The build needs TeX Live, and latex-action bundles one. When you want fine control of the environment (specific packages, Japanese, …), use the texlive/texlive Docker image from the Island of TeX directly. Since latest is rebuilt over time, pin a dated or TeX Live year tag for reproducible submissions, and use latest for day-to-day checks. Name it as the job’s container: and run latexmk yourself.

terminal
jobs:
  build:
    runs-on: ubuntu-latest
    container: texlive/texlive:latest
    steps:
      - uses: actions/checkout@v6
      - run: latexmk -pdf main.tex
      - uses: actions/upload-artifact@v7
        with:
          name: PDF
          path: main.pdf

When CI fails, read the log

Split CI failures into three buckets first: a LaTeX error, a missing package, or a wrong artifact path. If the log shows ! LaTeX Error or Undefined control sequence, debug the document. If File ... not found indicates a missing TeX Live package, adjust the image or installation step. If upload-artifact reports no files, check path: against the actual output filename. When it passes locally but fails in CI, suspect fonts, images, or generated .bbl files that exist only on your machine.

PDF as an artifact — and as a release

  • The PDF saved by actions/upload-artifact is downloadable from the workflow run page (kept per run).
  • To distribute a public version, you can attach the PDF to a GitHub Release (e.g. triggered by pushing a tag).
  • For Japanese, build with latexmk configured for uplatex + dvipdfmx inside the texlive/texlive container.
  • Ship the build config (.latexmkrc, etc.) in the repo so local and CI follow the same steps.
  • For a submission workflow, enable -halt-on-error and keep logs so warnings can be traced back.