Math alphabets (\mathbf, \mathbb, \mathcal)

Math mode in LaTeX has no notion of “switching the font” the way running text does. What it has are math alphabets\mathbf, \mathbb, \mathcal and friends, each of which reassigns every character inside it to a different typeface. The catch is that the slots are finite: on the classic engines a formula may use at most sixteen. That ceiling was fixed in 1978 and is still with us, surfacing without warning as ! LaTeX Error: Too many math alphabets used in version normal. This page runs from the seven commands that need no package, through the blackboard-bold \mathbb that needs amssymb and the \mathscr that needs mathrsfs, to bold maths with \bm and the \sym… commands of unicode-math — held together by one question: how do you spend those sixteen slots?

A math alphabet is a family, not a font

A letter in math mode is treated as a variable and set in math italic; that is the default math alphabet. Wrapping it in a command such as \mathbf{v} moves just that span into a different family — TeX’s own word is \fam. This is where math alphabets part company with the text-mode font commands. TeX stores every character of a formula as “family number, slot number”, so a typeface is not a continuous stream the way running text is; it is a label stuck onto each individual symbol. That is why \mathbf{fit} is not the word “fit” but a product of three bold symbols f, i and t, with inter-variable space between them. When you want a real word set upright inside a formula, use \text{…} from amsmath.

Standard LaTeX ships seven math-alphabet commands. They all take the form \math…, named to parallel the text-mode \textbf, \textsf and the rest. The easily confused pair is \mathnormal and \mathit: \mathnormal (the default) sets each letter as a variable, with the wider inter-variable spacing, whereas \mathit is the text italic and suits a multi-letter word set as one slanted unit, as in \mathit{diff}. \mathrm and \mathbf are upright roman, the latter bold. \mathsf turns up in tensor and category names, \mathtt when a code-like token has to sit inside a formula.

CommandLookNotes
\mathnormalThe default math italicBuilt in; the default look of a variable, with inter-variable spacing
\mathrmUpright romanBuilt in; upright constants, operators and abbreviations
\mathbfUpright boldBuilt in; upright, so poor for variables, and it does not reach Greek
\mathsfSans serifBuilt in; tensors, category names and the like
\mathttMonospace (typewriter)Built in; code-like tokens inside a formula
\mathitText italicBuilt in; a multi-letter word as one slanted unit, as in \mathit{diff}
\mathcalCalligraphic; uppercase onlyBuilt in; families of sets, categories, transforms. The glyphs come from Computer Modern’s cmsy

Which package \mathbb, \mathscr and \mathfrak need

Blackboard bold \mathbb and Fraktur \mathfrak need amssymb (or the lighter amsfonts); script \mathscr needs mathrsfs. Only \mathcal is built in. \mathbb is a bold whose strokes are doubled — it imitates the blackboard habit of drawing a stroke twice to mean boldface — and its use is all but fixed to the number sets: the reals ℝ, complex ℂ, integers ℤ, rationals ℚ, naturals ℕ. It covers the capitals A–Z and nothing else: no lowercase, no digits.

Choosing between \mathcal and \mathscr gets much easier once you know where each comes from. The font behind \mathscr is rsfs, short for Ralph Smith’s Formal Script, released in October 1991. Its author says in the README that it is a formal script based on the Spencerian or copperplate hands of the eighteenth century, closely modelled on a face by the type designer R. Hunter Middleton, and similar to what Springer Verlag’s typesetters used. \mathcal, by contrast, is the more informal ornamental capital that lives in Computer Modern’s symbol font cmsy. So ℒ and 𝓛 are a contrast between a formal hand and a casual flourish, not a right-and-wrong pair. The formality is exactly why rsfs is preferred for the domain 𝒟 in functional analysis and the Lagrangian ℒ in field theory.

The face behind \mathfrak has a name too. amssymb writes \DeclareMathAlphabet{\mathfrak}{U}{euf}{m}{n}, and euf is Euler Fraktur — the AMSFonts README states that the Euler fonts were designed by Hermann Zapf and originally released in the 1990s. The same README records that Euler 3.0, in which Zapf reshaped many of the glyphs, was presented to Donald Knuth on his birthday, 10 January 2008. So the angular face you use for Lie algebras 𝔤 and ideals 𝔭 comes from one of the twentieth century’s great type designers — and unlike \mathbb and \mathcal it covers both upper- and lowercase. The Euler Script (eus) offered by the euscript package belongs to the same family.

document.tex
\usepackage{amssymb}   % \mathbb and \mathfrak
\usepackage{mathrsfs}  % \mathscr (Ralph Smith's Formal Script)
% ...
\[
  \mathbb{R} \subset \mathbb{C}, \qquad
  \mathcal{F}(f) = \hat{f}, \qquad
  \mathscr{L}(f) = F, \qquad
  \mathfrak{g} = \operatorname{Lie}(G).
\]
CommandPackage neededCoverage and typical use
\mathbbamssymb (or amsfonts)Capitals A–Z only; the number sets ℝ ℂ ℤ ℚ ℕ
\mathcalBuilt in (none)Uppercase only; set families, categories, transforms. Glyphs from cmsy
\mathscrmathrsfs (or euscript)Uppercase only; the more formal script. Glyphs from rsfs10
\mathfrakamssymb / amsfonts (euf)Upper- and lowercase; Lie algebras, ideals. Euler Fraktur

\mathbb{2} does not error — it prints a different symbol

Try to get a blackboard-bold one or two by writing \mathbb{1} or \mathbb{2} and you get a completely different symbol, with no warning and no error. Setting $\mathbb{2}$ with amssymb on TeX Live 2024 and pulling the character back out of the PDF returns U+22AD (⊭, “not true”). The reason is the alphabet mechanism itself: \mathbb simply looks up the same slot in the msbm font, so whatever sits in slot 2 of msbm10 — which is ⊭ — comes out. Nothing checks that the character exists. When you need the indicator function 𝟙, use \mathds{1} from dsfont (the Type 1 font dsrom10), or swap the whole blackboard alphabet with the mathalpha package. \mathbbm{1} from bbm is well known too, but the version in TeX Live has no Type 1 outlines and lands in the PDF as a Type 3 bitmap (you can see it in pdffonts), so it is best avoided where submission rules frown on bitmap fonts.

document.tex
% A blackboard-bold digit is NOT available from amssymb:
%   $\mathbb{2}$  ->  U+22AD, silently. Use one of these instead.
\usepackage{dsfont}                              % \mathds{1}, Type 1 outlines
\usepackage[bb=dsserif,scr=rsfs]{mathalpha}      % replace the whole \mathbb alphabet
% ...
\[ \mathds{1}_{A}(x), \qquad \mathbb{1}_{A}(x) \]

Sixteen alphabets, no more: Too many math alphabets

Keep adding alphabets and sooner or later you hit ! LaTeX Error: Too many math alphabets used in version normal. The ceiling is sixteen. TeX’s math character codes spend only four bits on the family number, so families 0 to 15 are all there can ever be. latex.ltx states it outright with \chardef\e@mathgroup@top=16, and raises it to 256 on engines that have \Umathcode (XeTeX and LuaTeX). A bare article already occupies four families at start-up — operators, letters, symbols, largesymbols — and amssymb plus mathrsfs take it to seven. That leaves about nine slots, into which \mathbf, \mathsf, \mathtt, \mathit, \mathcal, \mathbb, \mathfrak and \mathscr file one by one. The budget is closer to per-document than per-formula: slots fill in order of first use and are not handed back.

A second gatekeeper guards the same sixteen slots. \DeclareSymbolFont, which registers a symbol font, is protected inside latex.ltx by the hard-coded test \ifnum\count18<15, and past that you get ! LaTeX Error: Too many symbol fonts declared. This is the important trap: the number 15 applies regardless of engine, so although LuaLaTeX allows 256 alphabets, symbol fonts are still capped at sixteen. Writing a seventeenth \DeclareSymbolFont raises the same error under pdfLaTeX and LuaLaTeX alike. Only if you call the low-level \newfam yourself and run past the top does TeX’s own ! No room for a new \mathgroup. appear — note \mathgroup, not \fam, because LaTeX2e makes \newfam an alias for \new@mathgroup.

There is relief, too. Recent LaTeX kernels reserve the last two of the sixteen slots for recycling (\c@localmathalphabets defaults to 2). When a fifteenth or sixteenth alphabet is wanted inside the document body, the kernel lends the slot to that one formula and takes it back afterwards. So as long as no single formula needs more than two extra alphabets, a document can sail past fourteen without stopping — in a test run the counter simply froze at 14 and no error appeared. The flip side: cram three or more fresh alphabets into one formula and that is where it breaks. When the error fires on one formula and no other, suspect this first. The isomath documentation says outright that it makes its own \mathsfit optional because of this sixteen-alphabet limit. If you would rather not budget at all, moving to XeLaTeX or LuaLaTeX with unicode-math is the real fix.

Adding your own alphabet with \DeclareMathAlphabet

A new math alphabet is one line: \DeclareMathAlphabet{command}{encoding}{family}{series}{shape}. It is preamble-only. Want a slanted sans face for tensors? \DeclareMathAlphabet{\mathsfsl}{OT1}{cmss}{m}{sl} and you have it. If it should also thicken inside bold maths (the \mathversion{bold} below), follow it with \SetMathAlphabet{\mathsfsl}{bold}{OT1}{cmss}{bx}{sl}. When all you want is another name for a font already registered as a symbol font, \DeclareSymbolFontAlphabet does it without spending a slotmathrsfs.sty is essentially just those two lines. One more thing worth knowing: \DeclareMathAlphabet does not claim a slot when you declare it, only the first time it is actually used. A package you merely loaded cannot eat your budget, which makes diagnosis much easier.

document.tex
% preamble only
\DeclareMathAlphabet{\mathsfsl}{OT1}{cmss}{m}{sl}
\SetMathAlphabet{\mathsfsl}{bold}{OT1}{cmss}{bx}{sl}

% costs no slot: just another name for a symbol font already declared
\DeclareSymbolFont{rsfs}{U}{rsfs}{m}{n}
\DeclareSymbolFontAlphabet{\mathscr}{rsfs}
% ...
\[ \mathsfsl{T}_{ij} \]

Bold maths: \mathbf vs \boldsymbol vs \bm

\mathbf is an upright bold, so it suits neither variables nor vectors that ought to slant — and it has no effect whatsoever on Greek letters. A measurement makes that concrete: compile a document containing only $\mathbf{\alpha}$ with pdfLaTeX, run pdffonts on it, and exactly one font is embedded, CMMI10. The α came out in ordinary math italic, not the bold CMMIB10. That is by design — \mathbf switches families, and α sits in a slot whose shape does not change with the switch. Since neither an error nor a warning appears, this is the kind of thing that gets submitted unnoticed.

To bold while keeping the slant, the first candidate is \boldsymbol from amsmath (its amsbsy), and the most robust in practice is \bm from the bm package. Because bm is part of LaTeX’s required latex-tools bundle, every standard TeX distribution ships it — nothing to install. \bm{…} is designed to add weight and nothing else, preserving the slant, the rest of the shape and the surrounding spacing, and it handles variables, Greek and symbols — even complicated input — almost transparently. bm also redefines \boldsymbol as an alias for \bm. But \bm is not free: bm.sty carries a limit called \bmmax (default 4) that caps how many families it will claim for the bold version. Bold math alphabets come out of the same sixteen slots, which is why they belong on the budget from the previous section. If you run short you can raise it with \chardef\bmmax=6, at the cost of ordinary alphabets.

When a whole formula has to go bold — inside a heading, or a label on a figure — you switch the math version rather than reach for a command. That is what \boldmath and \mathversion{bold} do; standard LaTeX ships two versions, normal and bold. You can create a third: declare \DeclareMathVersion{heavy}, list the alphabets with \SetMathAlphabet{…}{heavy}{…}, and \mathversion{heavy} swaps the lot. The \hm of bm (alias \heavysymbol) is the command for that heavy version, with \hmmax defaulting to 3. Be careful, though: unless you have actually defined a heavy version, \hm is simply \bm, so writing \hm does not by itself give you anything heavier.

document.tex
\usepackage{amsmath}   % \boldsymbol
\usepackage{bm}        % \bm -- recommended
% \chardef\bmmax=6     % raise bm's family budget if it runs out
% ...
\[
  \mathbf{v} \neq \bm{v}, \qquad
  \bm{\beta} = (\beta_1, \dots, \beta_n), \qquad
  \nabla \bm{F} = \bm{0}.
\]
\section{\boldmath A whole heading in bold maths: $E = mc^2$}
  • \mathbf — upright bold; built in, but poor for variables that should slant, and it does not reach Greek (measured above).
  • \boldsymbol — from amsmath (amsbsy); keeps the slant and can bold Greek and symbols.
  • \bm — from the bm package; recommended. Adds only weight, preserving shape and surrounding spacing. Its family usage is capped by \bmmax (default 4).
  • \boldmath / \mathversion{bold} — switches the whole math version rather than one span; for headings and figure labels.

The \sym… commands: alphabets that map to Unicode

Load unicode-math on XeLaTeX or LuaLaTeX and the alphabet commands are replaced by the \sym… family: \symbf (bold), \symbb (blackboard), \symcal (calligraphic), \symscr (script), \symfrak (Fraktur), \symup (upright), \symit (italic), \symsf (sans serif). The old names survive, but \mathbb is in fact redefined as an alias for \symbb and \mathcal for \symcal. The decisive difference is that \sym… is not a family switch but a mapping onto Unicode’s Mathematical Alphanumeric Symbols. Set $\symbb{2}\ \symbb{r}\ \symcal{L}$ with STIX Two Math under LuaLaTeX and pull the characters back out of the PDF: you get U+1D7DA (𝟚), U+1D563 (𝕣) and U+2112 (ℒ). The \mathbb{2} that gave ⊭ in the previous section is a genuine blackboard-bold two here, and lowercase is available too. That mapping is also why a character copied out of the PDF keeps its meaning.

That mapping has one consequence you will trip over if nobody warns you: \symcal and \symscr map to the same Unicode characters. Unicode’s Mathematical Alphanumeric Symbols contain only one script alphabet, so \symcal{L} and \symscr{L} are both U+2112. To tell them apart visually you reach for the font’s OpenType stylistic sets through range=. With STIX Two Math, follow your main \setmathfont with \setmathfont{STIX Two Math}[range=\symscr,StylisticSet=1]; measured, that one line gives \symcal{L} a width of 6.99pt against 8.63pt for \symscr{L} — the numbers confirm that a different glyph was chosen. What the legacy route solved by spending two alphabet slots, unicode-math solves by naming a font feature.

document.tex
% compile with xelatex or lualatex
\usepackage{amsmath}
\usepackage{unicode-math}
\setmathfont{STIX Two Math}
\setmathfont{STIX Two Math}[range=\symscr,StylisticSet=1]  % a second script shape
% ...
\[
  \symbb{R} \subset \symbb{C}, \qquad \symbb{2}, \qquad
  \symcal{F} \neq \symscr{F}, \qquad \symfrak{g}, \qquad
  \symbfit{v} = \symbf{0}.
\]

One last caution about \symbf under unicode-math. With the default setting (bold-style=TeX), \symbf{v} is bold upright. Measured, \symbf{v} came out as U+1D42F (bold roman v) and \symbfit{v} as U+1D497 (bold italic v). If your convention writes vectors in bold italic, use \symbfit or set bold-style=ISO. Choosing the math font for the document as a whole — what to hand \setmathfont, and how to make it agree with the text face — is the subject of a separate page.