FormaTeX

\begin{article}

The Complete Guide to LaTeX Engines: pdfLaTeX, XeLaTeX, LuaLaTeX, and latexmk

A practical comparison of all four LaTeX engines — what each one does, when to use it, and how to select the right engine via the FormaTeX API.

·5 min read·
The Complete Guide to LaTeX Engines: pdfLaTeX, XeLaTeX, LuaLaTeX, and latexmk

LaTeX is not a single compiler — it is a family of engines that share the same document format but differ in capabilities, speed, and output quality. Picking the wrong engine is one of the most common sources of compilation errors. This guide covers all four engines FormaTeX supports and gives you a decision framework.

Four Engines Overview

The four engines have a historical progression: pdfLaTeX was the standard for decades, XeLaTeX added Unicode and font support, LuaLaTeX added programmability, and latexmk is not a compiler at all — it is a build manager that runs the right engine the right number of times.

EngineYearLanguageUnicodeCustom FontsScripting
pdfLaTeX1997CVia inputencLimitedNo
XeLaTeX2004C/Obj-CNativeFull (OpenType)No
LuaLaTeX2007C+LuaNativeFull (OpenType)Yes (Lua 5.3)
latexmk1998PerlInheritsInheritsNo

pdfLaTeX Deep Dive

pdflatex is the default, fastest, and most compatible engine. It generates PDF directly without an intermediate DVI step. If you do not have a specific reason to use another engine, start here.

latex
\documentclass{article}
\usepackage[utf8]{inputenc}   % required for pdflatex
\usepackage[T1]{fontenc}      % required for pdflatex
\usepackage{microtype}        % enables microtypography

\begin{document}
Standard document. All CTAN packages work here.
\end{document}

Strengths:

  • Fastest compilation time (typically 2–5× faster than LuaLaTeX)
  • Widest package compatibility — every CTAN package supports pdflatex
  • Required by most academic journals (IEEE, ACM, arXiv default)
  • Available on the FormaTeX free plan

Limitations:

  • Requires inputenc for UTF-8 characters
  • Limited to fonts converted to Type 1 or TrueType
  • No Lua scripting
bash
curl -X POST https://api.formatex.io/api/v1/compile \
  -H "X-API-Key: $FORMATEX_KEY" \
  -d '{"engine":"pdflatex","content":"..."}'

XeLaTeX Deep Dive

xelatex was built to fix pdfLaTeX's font limitations. It uses the system's native font rendering (HarfBuzz) and supports any OpenType or TrueType font.

latex
\documentclass{article}
\usepackage{fontspec}         % replaces inputenc+fontenc
\setmainfont{TeX Gyre Termes} % any system or bundled OTF/TTF

\begin{document}
Native Unicode — no inputenc needed.
Arabic: مرحبا. Hebrew: שלום. CJK: 你好.
\end{document}

Strengths:

  • Native Unicode — write any language without encoding packages
  • Full OpenType font access via fontspec
  • Right-to-left languages via the bidi package
  • Better for multilingual documents

Limitations:

  • ~30–50% slower than pdflatex
  • Some older font packages conflict with fontspec
  • Requires Pro plan on FormaTeX

Remove \usepackage[utf8]{inputenc} when switching from pdflatex to xelatex. They are incompatible — including both causes a package clash error.

LuaLaTeX Deep Dive

lualatex has the same font capabilities as XeLaTeX but embeds a full Lua 5.3 interpreter. This enables programmatic document generation that is impossible in the other engines.

latex
\documentclass{article}
\usepackage{fontspec}
\usepackage{luacode}

\begin{document}

\begin{luacode}
-- Generate a multiplication table programmatically
for i = 1, 5 do
  for j = 1, 5 do
    tex.sprint(i * j)
    if j < 5 then tex.sprint(" & ") end
  end
  tex.sprint(" \\\\")
end
\end{luacode}

\end{document}

Strengths:

  • Full Lua scripting — loops, conditionals, string manipulation inside documents
  • Same font support as XeLaTeX
  • Access to TeX internals via the Lua FFI
  • Ideal for template-driven, data-heavy documents

Limitations:

  • Slowest engine — typically 2–4× slower than pdflatex
  • Requires Pro plan on FormaTeX
  • Less package compatibility than pdflatex (though much improved)

latexmk Deep Dive

latexmk is not a compiler — it is a build coordinator written in Perl. It determines which engine to run, how many times, and in what order to resolve all cross-references and bibliography entries.

A document with a bibliography requires:

  1. Run pdflatex (generates .aux file)
  2. Run biber or bibtex (generates .bbl file)
  3. Run pdflatex again (incorporates bibliography)
  4. Run pdflatex again (resolves references)

latexmk automates this entire sequence:

latex
\documentclass{article}
\usepackage[backend=biber]{biblatex}
\addbibresource{refs.bib}

\begin{document}
As shown by \cite{knuth1984tex}, TeX is powerful.

\printbibliography
\end{document}
bash
# latexmk handles the multi-pass compilation automatically
curl -X POST https://api.formatex.io/api/v1/compile \
  -H "X-API-Key: $FORMATEX_KEY" \
  -d '{"engine":"latexmk","content":"..."}'

Strengths:

  • Handles bibliography automatically (BibTeX, Biber)
  • Resolves cross-references, indexes, and glossaries
  • Eliminates "run pdflatex three times" errors
  • Detects which engine your document actually requires

Limitations:

  • Slower than running pdflatex directly (multiple passes)
  • Requires Pro plan on FormaTeX

Use latexmk whenever your document has a \bibliography{} or \addbibresource{} command. Without it, you will get [?] placeholders instead of citation text.

Decision Matrix

Your document needsEngine to use
Fast compilation, standard packagespdflatex
Custom fonts (TTF/OTF)xelatex
Non-Latin scripts (Arabic, CJK, Hebrew)xelatex
Lua scripting / programmatic contentlualatex
Bibliography / citationslatexmk
Cross-references, index, glossarylatexmk
Journal submission (IEEE, ACM, arXiv)pdflatex

Engine Selection via the API

typescript
type Engine = "pdflatex" | "xelatex" | "lualatex" | "latexmk";

function chooseEngine(options: {
  hasBibliography: boolean;
  hasLuaCode: boolean;
  needsCustomFonts: boolean;
  hasNonLatinScript: boolean;
}): Engine {
  if (options.hasBibliography) return "latexmk";
  if (options.hasLuaCode) return "lualatex";
  if (options.needsCustomFonts || options.hasNonLatinScript) return "xelatex";
  return "pdflatex";
}

const response = await fetch("https://api.formatex.io/api/v1/compile", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.FORMATEX_KEY!,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    engine: chooseEngine({ hasBibliography: true, hasLuaCode: false, needsCustomFonts: false, hasNonLatinScript: false }),
    content: latexSource,
  }),
});

Plan Requirements

EngineMinimum Plan
pdflatexFree
xelatexPro
lualatexPro
latexmkPro

\end{article}

Back to blog

\related{posts}

One quick thing

We track anonymous usage — page views, feature usage, compilation events — to understand what works and what doesn't. No ads, no personal data, no third-party sharing.

Cookie policy