You do not have to install TeX on your own machine: a Docker image packages the entire typesetting environment, so you can turn .tex into PDF with the same procedure anywhere. This pairs naturally with CI (continuous integration) such as GitHub Actions — every push can build the PDF automatically and save it as an artifact. This page covers the popular texlive/texlive image and how to make TeX builds automated and reproducible in CI.
Why typeset in a container
If a distribution is the “TeX environment itself” (see Distributions), a Docker image is the box that ships that environment frozen together with its OS. Inside the box are a specific version of TeX Live, the engines, the packages, and the fonts — so whether your host is Windows or macOS or a CI server, opening the same box gives you the same environment. Its biggest payoff is avoiding the “works on my machine but fails on my colleague’s setup or in CI” mismatch.
Containers and desktop installs are not mutually exclusive. A common split is to write day-to-day with your editor and a local TeX (see Desktop installation) and hand only the final build, collaboration, or publishing to a container or CI. The key word is reproducibility: pin the version with a tag, and rebuilding half a year later still yields the same PDF.
The texlive/texlive image
A widely used image for TeX Live is texlive/texlive, published as an Island of TeX image on Docker Hub (docker.io/texlive/texlive) and GitLab (registry.gitlab.com/islandoftex/images/texlive). Inside is TeX Live (the stable release in 2026 is TeX Live 2026), with engines, packages, and tools such as latexmk. Weekly builds track CTAN updates.
Tags let you pick a scheme (size tier). There are five — minimal, basic, small, medium, full — and latest maps to the largest, full (all packages). You can combine these with whether documentation and sources are included: the bare tag has neither, -doc adds docs, -src adds sources, and -doc-src adds both. Docs and sources are bulky; CI rarely needs them, so a bare or smaller scheme pulls faster. There are also -context variants for ConTeXt users.
| Tag | What you get | |
|---|---|---|
latest | Latest full scheme (all packages); no docs/sources | A reasonable default |
latest-small | Small scheme; lightweight, quick to pull | When you want fast CI |
latest-medium | Medium scheme; a mid-size install | A balanced middle ground |
latest-doc-src | Full + docs + sources; quite large | Local use where you also want texdoc |
historic tag / digest | A historical-release tag, or an image digest | To freeze a production build |
Usage is simple: docker run with the current directory mounted into the container, then run latexmk inside it. Here is a one-off build of a local main.tex. --rm discards the container afterwards, -v "$PWD":/work maps your current location to /work, and -w /work makes that the working directory. The resulting PDF lands right back in your folder.
docker run --rm -v "$PWD":/work -w /work texlive/texlive latexmk -pdf main.texFor a Japanese document, run a specific engine instead of plain latexmk — e.g. latexmk -lualatex main.tex for LuaLaTeX, or latexmk main.tex for the upLaTeX + dvipdfmx route once you provide a .latexmkrc. The mount works the same way: both input and output live in your local directory.
Freeze the environment for reproducibility. latest moves to a new TeX Live snapshot every week, so do not leave it as the default for a paper’s final build or released teaching material. First choose the TeX Live release year and flavor, and use a historical-release tag when appropriate. As the Docker Hub notes, though, even historical images can be rebuilt when the underlying OS image is updated. If you need the exact same container bit-for-bit later, pin an image digest as well as a tag, or save the known-good image in your own registry.
Automated builds with GitHub Actions
For a GitHub repository, GitHub Actions can compile your .tex on every push. The popular choice is xu-cheng/latex-action@v4. It uses a container with TeX Live inside and calls latexmk by default, so the workflow is just a few lines. Below is a minimal example that builds main.tex at the repo root on each push and saves the PDF as a build artifact.
name: Build LaTeX document
on: [push]
jobs:
build_latex:
runs-on: ubuntu-latest
steps:
- name: Check out the repository
uses: actions/checkout@v6
- name: Compile the document
uses: xu-cheng/latex-action@v4
with:
root_file: main.tex
- name: Upload the PDF
uses: actions/upload-artifact@v6
with:
name: PDF
path: main.pdfOn push, a container starts on GitHub’s runner and the main.tex named in root_file is compiled by latexmk. The default latexmk arguments are -pdf -file-line-error -halt-on-error -interaction=nonstopmode — a CI-friendly setting that stops on errors and runs to the end without prompting. The finished PDF can be downloaded as an artifact from the Actions run page.
Know the main inputs (with:). root_file is the build target (globs allowed). Switch engines with latexmk_use_lualatex: true for LuaLaTeX or latexmk_use_xelatex: true for XeLaTeX (LuaLaTeX is the easier route for Japanese). texlive_version selects 2020–2026 or latest, so you can pin by year for reproducibility. os is the base operating system — the default is the lightweight alpine, with debian available when you need it. For packages that use \write18, set latexmk_shell_escape: true.
To make builds faster, you can cache things that would otherwise be re-installed or re-downloaded on every run via actions/cache. That said, latex-action already bundles a substantial TeX Live, so most projects run at a practical speed out of the box. Start with the minimal setup and optimize only once slowness actually becomes a problem.
GitLab CI takes the same approach
GitLab CI follows the same idea, only you name the image directly instead of using a dedicated action. Set the job’s image: to texlive/texlive:latest (or a date-pinned tag), run latexmk -pdf main.tex in script:, and save the PDF via artifacts:. Because it rests on the same image, you get the same typeset result as GitHub Actions.
build:
image: texlive/texlive:latest
script:
- latexmk -pdf main.tex
artifacts:
paths:
- main.pdfThe essence is the same on any service: inside a version-pinned image, let latexmk drive a one-shot build, and collect the resulting PDF as an artifact. That is the shared pattern for running TeX in a container or CI. The mechanics of day-to-day automated builds are explored further on the “CI” and “Automated builds” pages.
Make the manuscript CI-ready
A manuscript that behaves well in CI does not depend on your editor settings. The root file, engine, helper commands, and output location are recorded in the repository. For Japanese work, put a .latexmkrc beside main.tex and explicitly choose upLaTeX or LuaLaTeX. If both your laptop and CI run the same latexmk main.tex, you avoid the last-minute “only my machine builds it” failure.
# .latexmkrc: upLaTeX + dvipdfmx
$latex = "uplatex -interaction=nonstopmode -halt-on-error %O %S";
$bibtex = "upbibtex %O %B";
$dvipdf = "dvipdfmx %O -o %D %S";
$pdf_mode = 3;Commit this .latexmkrc, and Docker and GitHub Actions will build the PDF under the same rules. Rather than installing packages ad hoc with tlmgr install during every run, choose a TeX Live scheme or pinned image tag that already contains what the project needs; builds are faster and failures easier to trace.