Run pdftex --version and you get three numbers stacked together: pdfTeX 3.141592653-2.6-1.40.26. The first is not pdfTeX's at all — it is Knuth's TeX, caught partway through its convergence on π, and XeTeX and LuaTeX carry the same digits. pdfTeX is that TeX with one thing added: it writes PDF directly. It is what actually runs when you type pdflatex, and it is still the default engine for LaTeX. This page covers why it stayed the default, the older design in which fonts are resolved through TFM metrics and map files, and pdfTeX's real contribution — the microtypography that microtype turns on: character protrusion and font expansion. Every claim below comes from a run on TeX Live 2024.
The difference between pdflatex, latex and pdftex
All three are the same executable. Look inside the bin directory of TeX Live 2024 and pdflatex and latex are both symbolic links to pdftex; so are amstex and csplain. What differs is only the format loaded at start-up. A format is a .fmt file holding a set of macros already expanded and frozen, and the line pdflatex pdftex ... *pdflatex.ini in fmtutil.cnf says: when invoked under the name pdflatex, run the pdftex engine with the LaTeX macros loaded. Engine (the program) and format (the system of commands) are therefore separate axes, and “pdfLaTeX” is simply the name for the pdfTeX engine combined with the LaTeX format.
$ readlink $(which pdflatex) latex amstex
pdftex
pdftex
pdftex
$ grep -E '^(latex|pdflatex|pdftex) ' $(kpsewhich fmtutil.cnf)
latex pdftex language.dat -translate-file=cp227.tcx *latex.ini
pdflatex pdftex language.dat -translate-file=cp227.tcx *pdflatex.ini
pdftex pdftex language.def -translate-file=cp227.tcx *pdfetex.iniTwo things fall out of that table. First, the command latex is not “old TeX” at all — it is pdfTeX running in DVI mode. Run it and the banner reads This is pdfTeX, ... (preloaded format=latex), and what you get is a .dvi. Second, the pdftex format is built from pdfetex.ini: the e stands for e-TeX, the set of extensions — \protected, \unexpanded, the enlarged register space, \middle — that modern LaTeX simply assumes. Test whether \eTeXversion is defined on each of the three engines and pdfTeX, XeTeX and LuaTeX all answer yes. e-TeX is no longer optional. \pdftexversion, by contrast, exists only on pdfTeX, which is how packages recognise the engine they are running on.
Writing PDF directly, and going back to DVI with \pdfoutput=0
One integer parameter decides the output format: \pdfoutput. A positive value means PDF, 0 means classic DVI. Knuth's original TeX emitted only DVI (device independent) and left conversion to PostScript or PDF to a separate program; pdfTeX folded that step in, right after the page builder — but it never closed the DVI exit. Packages that depend on PostScript \specials, PSTricks above all, sometimes still need the DVI → PS → PDF route, and \pdfoutput=0 is what keeps that route open.
The trap is where you set it. \pdfoutput has to be fixed before the first page is shipped out; change it later and pdfTeX stops with ! pdfTeX error (setup): \pdfoutput can only be changed before anything is written to the output., followed by ! ==> Fatal error occurred, no output PDF file produced!. Neither a PDF nor a DVI survives. Because LaTeX's driver detection happens quite early, the safe place is above \documentclass, at the very top of the file.
% Force DVI output even when the file is compiled with pdflatex.
% This line must come before \documentclass.
\pdfoutput=0
\documentclass{article}
\begin{document}
This run writes a .dvi file, not a .pdf.
\end{document}What microtype actually does: protrusion and font expansion
That single \usepackage{microtype} line switches on two independent mechanisms. Open the .log and you find them side by side: Package microtype Info: Character protrusion enabled (level 2). and Package microtype Info: Automatic font expansion enabled (level 2), stretch: 20, shrink: 20, step: 1. The first is protrusion, also called margin kerning: periods and hyphens at a line end are allowed to hang slightly outside the text block, so an edge that is mechanically flush looks optically straight — a generalisation of the old hanging punctuation. The second is font expansion: glyphs may be stretched or condensed horizontally by up to 2 % (20/1000), and that slack is folded into the line-breaking decision itself. Interword spaces even out, and the white “rivers” running down a paragraph thin out with them.
Neither idea began with TeX. Both trace back to the hz-program, the composition engine the type designer Hermann Zapf developed from 1988 with Peter Karow and colleagues at URW in Hamburg, aiming at an even grey page with no holes and no rivers. URW patented it (European patent EP 0466953; the rights lapsed in July 2010), and the algorithms eventually passed to Adobe, which built them into InDesign. But the same idea travelled a second road. Hàn Thế Thành, from Vietnam, analysed hz and implemented it in TeX as his doctoral work at the Faculty of Informatics of Masaryk University in Brno — the thesis Micro-typographic extensions to the TeX typesetting system, October 2000, supervised by Jiří Zlatuška. One idea, two destinations: the top of the commercial market, and a free implementation anyone can run. \usepackage{microtype} is the second of those.
\documentclass{article}
\usepackage{microtype} % protrusion + expansion, sensible defaults
\begin{document}
With microtype loaded, pdfTeX nudges punctuation into the margin
and flexes glyph widths by a hair, so justified text looks far
more even. Nothing else in the document has to change.
\end{document}You can also drive both from raw primitives. On the protrusion side: \pdfprotrudechars (0 off, 1 on, 2 also reflected in width computations) together with \lpcode and \rpcode, which set the per-character amount at the left and right edge. On the expansion side: \pdfadjustspacing (=2 folds the stretch into line-breaking), \efcode for each character's willingness to stretch, and \pdffontexpand to declare the stretched instances of a font. You will almost never touch these — microtype ships a configuration file per typeface (mt-cmr.cfg for Computer Modern) and picks the values for you. Knowing the names is still worth it: it makes the warnings in your log legible.
| Primitive | Feature | What it controls |
|---|---|---|
\pdfprotrudechars | protrusion | 0 off, 1 on, 2 also affects width computation |
\lpcode / \rpcode | protrusion | per-character overhang at the left / right edge (per mille) |
\pdfadjustspacing | expansion | =2 folds the stretch into the line-breaking decision |
\efcode | expansion | per-character willingness to stretch; absent from XeTeX |
\pdffontexpand | expansion | declares the stretched instances of a font |
Fonts are resolved through TFM metrics and map files
pdfTeX gets metrics and glyph shapes from two different places. The metrics come from a .tfm (TeX Font Metric): kpsewhich cmr10.tfm returns fonts/tfm/public/cm/cmr10.tfm, and that file holds only each character's width, height, depth and a kerning table — not a single outline. Only when typesetting is done and the PDF has to be assembled is the map file consulted, and the real font named there (a Type 1 .pfb, or a TrueType) is read. The entry for cmr10 is a single line: cmr10 CMR10 <cmr10.pfb — TFM name, PostScript name, and < meaning “embed this file”. The pdftex.map that updmap generates on TeX Live 2024 runs to 45,443 lines; that one text file is the lookup table for every font in the distribution.
$ kpsewhich cmr10.tfm cmr10.pfb
/usr/local/texlive/2024/texmf-dist/fonts/tfm/public/cm/cmr10.tfm
/usr/local/texlive/2024/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb
$ grep -m1 '^cmr10 ' $(kpsewhich pdftex.map)
cmr10 CMR10 <cmr10.pfb
# The same one-line document, compiled by three engines:
$ pdffonts min-pdflatex.pdf
INJFRF+CMR10 Type 1 Builtin yes yes yes
$ pdffonts min-xelatex.pdf
HOLJOD+LMRoman10-Regular-Identity-H CID Type 0C Identity-H yes yes yes
$ pdffonts min-lualatex.pdf
YIRABR+LMRoman10-Regular CID Type 0C Identity-H yes yes yesCompile the same one-line document with all three engines and run pdffonts, and the design difference shows up directly in the output. pdfLaTeX embeds CMR10 as Type 1; XeLaTeX and LuaLaTeX embed LMRoman10-Regular as CID Type 0C. The page looks like Computer Modern either way, but the route taken and the file embedded are entirely different. Map files can be extended from inside a document with \pdfmapfile and \pdfmapline — and, interestingly, both of those still exist in XeTeX. The assets of the 8-bit era live on more widely than you would guess.
The 8-bit ceiling: ! Bad character code, and why fontspec refuses
256 characters per font. That is pdfTeX's hardest ceiling. Write \font\x=cmr10 \x \char"1234 and it stops with ! Bad character code (4660).. Feed the identical input to LuaTeX and nothing happens — its fonts are wide internally. This 256-slot wall is why accented Latin letters have to be repacked into a font encoding such as T1, and why Greek letters and symbols get pushed off into separate fonts. Once you see the ceiling, it becomes obvious what fontenc is actually for.
The input side is where the misconception lives. A UTF-8 source compiles under modern LaTeX without loading inputenc at all — since 2018 that is the default. What compiles, though, is only the set of characters LaTeX has declared. A .tex file containing → goes through pdflatex without complaint; put 日 in it and you get ! LaTeX Error: Unicode character 日 (U+65E5) not set up for use with LaTeX.. So pdfTeX's limitation is not “it cannot read UTF-8” but “it can only set characters that have been provided for”. And there is no way to name an OpenType font installed on the operating system: load fontspec and the run dies at once with ! Fatal Package fontspec Error: The fontspec package requires either XeTeX or LuaTeX.. Those three facts — 256 slots, declared characters only, no system fonts — account for nearly every migration to XeTeX or LuaTeX.
- Reasons to stay: compatibility with existing templates, speed, and thirty years of field testing. For a mostly-English paper,
pdflatexis the choice with the fewest surprises. - Reasons to move: multilingual Unicode, operating-system fonts, Japanese, Lua-driven processing. If you genuinely need even one of these, switching beats stacking workarounds.
- The common accident: loading
fontspecwhile still on pdfLaTeX.fontspecbelongs to XeLaTeX and LuaLaTeX. - The other accident: putting
\pdfoutputafter\documentclass. The run dies leaving neither a PDF nor a DVI.
Images: PNG, JPEG and PDF straight in, EPS converted for you
pdfTeX reads three image formats directly — PNG, JPEG and PDF — through the low-level \pdfximage, with graphicx's \includegraphics sitting on top for daily use. Only EPS has to be converted to PDF first, and even that is now automatic: with TeX Live's default restricted shell escape enabled, \includegraphics{fig.eps} quietly calls repstopdf, drops a fig-eps-converted-to.pdf beside your file and embeds that. Here is the trap. Run with -no-shell-escape and no conversion happens — and there is no error and no warning either. You get an empty frame with the file name printed inside it, and a perfectly valid PDF. This is the classic way figures vanish in CI.
Because it writes the PDF itself, pdfTeX also exposes primitives that reach into PDF features. \pdfliteral injects raw PDF drawing operators; \pdfobj creates a PDF object; \pdfannot places an annotation — a link, a form field. hyperref's links and bookmarks are built on that layer. For document-wide settings there are \pdfinfo, which writes metadata such as title and author, \pdfcompresslevel, which sets how hard the output is compressed, and \pdfpageattr, which attaches attributes to every page.
\pdfinfo{
/Title (My Report)
/Author (A. Author)
}
\pdfcompresslevel=9
% a thin rule drawn with a raw PDF operator
\pdfliteral{0 0 m 100 0 l 0.4 w S}| Primitive | What it does in pdfTeX | Spelling in LuaTeX |
|---|---|---|
\pdfoutput | chooses PDF or DVI output | \outputmode |
\pdfliteral | injects raw PDF drawing operators | \pdfextension literal |
\pdfobj / \pdfannot | creates a PDF object or annotation | \pdfextension obj / annot |
\pdfinfo | writes metadata such as title and author | \pdfextension info |
\pdfcompresslevel | compression level of the output PDF (0–9) | \pdfvariable compresslevel |
\pdfximage | reads in a PNG / JPEG / PDF image | \saveimageresource |
\pdfsavepos | records the current position on the page | \savepos |
\pdfprotrudechars | enables protrusion | \protrudechars |
\pdfadjustspacing | enables font expansion | \adjustspacing |
What pdfTeX's \pdf... primitives left behind in later engines
LuaTeX was built on pdfTeX and inherited most of its machinery, but the sprawling \pdf... namespace was tidied up. Much of it now goes through three gateways — \pdfextension, \pdfvariable and \pdffeedback — which take a keyword and arguments. \pdfliteral became \pdfextension literal, \pdfoutput became \outputmode, \pdfximage became \saveimageresource, and \pdfprotrudechars / \pdfadjustspacing became \protrudechars / \adjustspacing. \lpcode, \rpcode and \efcode, on the other hand, kept their names outright. Knowledge from the pdfTeX era carries over almost intact; only the spelling shifts.
XeTeX inherited only part of it, and that partial inheritance has practical consequences. Probing the primitives one by one on TeX Live 2024 shows that XeTeX has \lpcode and \rpcode but does not have \efcode; its protrusion switch is not \pdfprotrudechars either but a differently named \XeTeXprotrudechars. So under XeLaTeX protrusion works while font expansion cannot be implemented at all, and asking for it explicitly with \usepackage[expansion=true]{microtype} stops the run: ! Package microtype Error: Font expansion does not work with xetex.. Load microtype without options and the expansion line simply vanishes from the log without comment — which is why people report that microtype “does less” under XeLaTeX without knowing why.
When pdflatex is still the right call
If the document is mostly English, the venue or your collaborators have already fixed the template, and the deadline is close, use pdfLaTeX. On the same 417-page mathematical document, timed on this machine, pdfLaTeX was the fastest of the three engines — and it is also the least likely to trip over an existing package. It asks little of you: add \usepackage{microtype}, keep figures as PNG / JPEG / PDF, and do not turn shell escape off if you rely on EPS. Conversely, piling workarounds onto pdfTeX for a document that needs Japanese or system fonts is a poor trade; past that point the job belongs to XeLaTeX or LuaLaTeX. pdfTeX itself is now largely in maintenance mode and new development has moved to LuaTeX — but those 45,443 lines of pdftex.map and thirty years of accumulated templates are not going anywhere.