# xu-cheng/latex-action: compiling LaTeX PDFs in GitHub Actions

> xu-cheng/latex-action is a GitHub Action that compiles one or more LaTeX root files inside a Docker container with TeXLive. It fits repositories that already use GitHub Actions and need reproducible PDF builds, custom packages, fonts, or selectable LaTeX engines, but its container and input configuration add constraints.

**xu-cheng/latex-action** — :octocat: GitHub Action to compile LaTeX documents

- Repository: https://github.com/xu-cheng/latex-action
- Website: https://github.com/xu-cheng/latex-action
- Stars: 1,425 · Forks: 153
- Language: Shell
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/xu-cheng-latex-action

## Why latex-action Fits GitHub-hosted LaTeX Builds

xu-cheng/latex-action solves a narrow CI problem: compiling LaTeX documents into PDFs during a GitHub Actions workflow. It is intended for repositories that contain LaTeX source files and want the build environment packaged as a Docker-based action rather than assembled manually in every workflow. The README describes support for multiple root documents, several TeXLive versions, Alpine and Debian images, additional system packages, custom fonts, and pre- or post-compile scripts.

The action is not a general command runner for every tool that needs TeXLive. Its README explicitly directs users who want arbitrary commands in a TeXLive environment to `texlive-action`. That distinction matters because `latex-action` is centered on document compilation and exposes inputs for compiler selection, root files, working directories, dependencies, and scripts. It is therefore more appropriate for a CI job whose output is a built PDF than for a broader containerized toolchain workflow.

The target user is likely a GitHub repository maintainer who wants a repeatable LaTeX build on `ubuntu-latest` or another GitHub-hosted runner. The action moves the TeXLive environment into Docker, but it does not remove the need for the repository to contain usable LaTeX sources, package dependencies, and any custom files required by the document.

## The Docker and TeXLive Build Path

The documented execution model starts with a GitHub Actions step that invokes `xu-cheng/latex-action@v4`. The action runs through a Docker image containing a full TeXLive installation. By default, the image is Alpine based and uses the latest TeXLive version. A workflow can instead request Debian, choose a historic TeXLive release from `2020` through `2026`, or provide a custom Docker image.

Compilation is driven by the `root_file` input. It can name one file, contain several files across multiple lines, or use glob patterns. For a multi-document build, `work_in_root_file_dir` can change into each root file's directory before compilation. This is useful when each document has its own local structure. The action then invokes the configured compiler. When no compiler is supplied, the default is `latexmk`, whose default arguments are `-pdf -file-line-error -halt-on-error -interaction=nonstopmode`.

The engine inputs have an important boundary. `latexmk_use_xelatex` selects XeLaTeX, while `latexmk_use_lualatex` selects LuaLaTeX. The README says these inputs work only with the default `latexmk` compiler. A project that supplies another compiler configuration must handle its own LaTeX engine selection, such as through a `.latexmkrc` file when using `latexmk`.

## Installing and Running the First Document Build

The README's example uses `actions/checkout@v6`, followed by the LaTeX action and an artifact upload. This is a complete first workflow for a repository whose root document is `main.tex`. The checkout step gives the action access to the repository files, while the action places the resulting PDF beside the source file.

```yaml
name: Build LaTeX document
on: [push]
jobs:
  build_latex:
    runs-on: ubuntu-latest
    steps:
      - name: Set up Git repository
        uses: actions/checkout@v6
      - name: Compile LaTeX document
        uses: xu-cheng/latex-action@v4
        with:
          root_file: main.tex
      - name: Upload PDF file
        uses: actions/upload-artifact@v6
        with:
          name: PDF
          path: main.pdf
```

The workflow should be placed in the repository's GitHub Actions workflow configuration. The README does not document a separate installation command because the action is consumed through the `uses` entry. After the build, the generated `main.pdf` is available to the upload step. The upload action version shown in the main example is `actions/upload-artifact@v6`.

For XeLaTeX, the action input is added without changing the rest of the workflow:

```yaml
- uses: xu-cheng/latex-action@v4
  with:
    root_file: main.tex
    latexmk_use_xelatex: true
```

This selects XeLaTeX through the default `latexmk` integration. The README does not claim that this changes output naming or adds a new post-processing stage, so the upload path should remain `main.pdf` unless the LaTeX source or compiler settings produce a different filename.

## Multiple Documents, Fonts, and System Dependencies

Multi-document support is handled through the `root_file` input rather than by requiring every workflow to contain a separate action step. The documented format accepts a multiline list:

```yaml
- uses: xu-cheng/latex-action@v4
  with:
    root_file: |
      file1.tex
      file2.tex
```

By default, failure of one document stops the build. Setting `continue_on_error: true` allows the action to continue building remaining documents, but the action still reports failure if any document fails. This is useful for a build matrix represented as several root files, although it does not make failed documents successful.

The action can install OS packages through `extra_system_packages`. It uses `apk` on Alpine and `apt-get` on Debian. This input is separate from TeX package management, which is why the README's pre-compile example uses `tlmgr`:

```yaml
pre_compile: "tlmgr update --self && tlmgr update --all"
```

Custom fonts for `fontspec` are supplied through `extra_fonts`, using `.ttf` or `.otf` paths and glob patterns. For example:

```yaml
extra_fonts: |
  ./path/to/custom.ttf
  ./fonts/*.otf
```

These inputs address common failures caused by missing OS tools or fonts. They do not remove the need to ensure that the document requests the corresponding packages and that the files are present in the checked-out repository or otherwise available inside the action's environment.

## Container Selection and TeXLive Compatibility

The default environment is Alpine with the latest TeXLive, but the action allows a different base or version. This flexibility matters for documents that depend on a specific TeX distribution, although it also makes configuration mistakes easier. The documented version choices are `2020` through `2026`, or `latest`.

```yaml
- uses: xu-cheng/latex-action@v4
  with:
    root_file: main.tex
    texlive_version: 2024
```

To change the base operating system, set `os` to `debian`:

```yaml
- uses: xu-cheng/latex-action@v4
  with:
    root_file: main.tex
    os: debian
```

A custom `docker_image` overrides both `texlive_version` and `os`. The README recommends the `latex-docker` images and shows digest pinning as a way to select a fixed image:

```yaml
- uses: xu-cheng/latex-action@v4
  with:
    root_file: main.tex
    docker_image: ghcr.io/xu-cheng/texlive-alpine@sha256:<hash>
```

The `<hash>` placeholder is part of the README's illustrative form, not a usable digest. A workflow author must supply an actual digest. The README does not document image signing verification, rollback behavior for a failed custom image, or compatibility guarantees for arbitrary Docker images. Those omissions should be considered before replacing the managed image.

## Shell Escape, Scripts, and Search Paths

Some LaTeX documents invoke external commands. The action exposes `latexmk_shell_escape`, which defaults to `false`. Enabling it changes the compilation environment by allowing external command execution through `latexmk`:

```yaml
- uses: xu-cheng/latex-action@v4
  with:
    root_file: main.tex
    latexmk_shell_escape: true
```

The README also provides `pre_compile` and `post_compile` for Bash commands around the build. A post-compile command can clean generated files with `latexmk -c`:

```yaml
post_compile: "latexmk -c"
```

For custom `.sty` or `.cls` files, the README recommends setting `TEXINPUTS`. Its example downloads a custom template and then passes the environment variable to the action:

```yaml
- name: Download custom template
  run: |
    curl -OL https://example.com/custom_template.zip
    unzip custom_template.zip
- uses: xu-cheng/latex-action@v4
  with:
    root_file: main.tex
  env:
    TEXINPUTS: ".:./custom_template//:"
```

The README warns not to use `{{ github.workspace }}` or `$GITHUB_WORKSPACE` in `TEXINPUTS`, because the action runs in a separate Docker container where that workspace reference may not resolve correctly. The documented example uses a path relative to the action's working environment instead.

## Operational Limits and the TeXLive Alternative

The main limitation is scope. `latex-action` is designed to compile LaTeX documents, not to provide a general-purpose TeXLive execution environment. A workflow that needs to run package installation commands, arbitrary shell steps, or unrelated TeX tooling may fit `texlive-action` better. The README gives that direct alternative rather than claiming that the two actions have identical purposes.

The second limitation is that configuration is distributed across several inputs with dependencies between them. `docker_image` supersedes `texlive_version` and `os`, and the engine-selection inputs are limited to the default `latexmk` compiler. A custom compiler therefore changes the meaning of the documented engine switches. Multi-document builds also have a deliberate failure model. `continue_on_error` allows later documents to run, but the overall action still fails if any document fails.

The action's maintenance record is positive in a narrow factual sense. The repository is not archived, and its last push was on 2026-07-30. Release history includes `4.1.0` on 2026-04-02 and `v4` on 2025-07-07. The README does not provide a detailed upgrade policy, compatibility matrix between every TeXLive release and every image, or a stated support window, so those details require verification in the repository and workflow logs before adoption. The MIT license permits use and modification under its terms, but license interpretation for a particular deployment should be handled separately from build configuration.

## Conclusion

Adopt xu-cheng/latex-action when a repository already builds LaTeX documents in GitHub Actions and needs a container-based TeXLive environment. Do not choose it for arbitrary command execution, since the project points that use case to texlive-action. Verify first that the repository's TeXLive version, base operating system, root-file paths, compiler engine, fonts, and package requirements match the action inputs. The relevant project-specific boundary is that `docker_image` overrides `texlive_version` and `os`, while the XeLaTeX and LuaLaTeX options only apply to the default `latexmk` compiler.

## FAQ

### How do I use XeLaTeX or LuaLaTeX with xu-cheng/latex-action?

Set `latexmk_use_xelatex: true` for XeLaTeX or `latexmk_use_lualatex: true` for LuaLaTeX. These inputs work with the default `latexmk` compiler, and a `.latexmkrc` file is the alternative documented by the README.

### Where does xu-cheng/latex-action place the compiled PDF?

The README states that the compiled PDF is placed in the same directory as the LaTeX source file. In the documented single-file example, `main.tex` produces `main.pdf`, which can be uploaded as an artifact.

### Can xu-cheng/latex-action build multiple LaTeX documents?

Yes. `root_file` accepts glob patterns and a multiline list of root files. By default, a failed document stops the build; `continue_on_error: true` allows remaining documents to be attempted, while the action still reports failure if any document fails.

## Sources

- [License: MIT](https://github.com/xu-cheng/latex-action/blob/master/LICENSE)
- [Project website](https://github.com/xu-cheng/latex-action)
- [README](https://github.com/xu-cheng/latex-action/blob/master/README.md)
- [Releases](https://github.com/xu-cheng/latex-action/releases)
- [xu-cheng/latex-action on GitHub](https://github.com/xu-cheng/latex-action)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/xu-cheng-latex-action
