“This diagram commutes” may be the shortest load-bearing sentence in mathematics: it stands in for a set of equations that would take several lines to write out. A commutative diagram turns objects into points and maps into arrows, and asserts that any two directed paths between the same pair of objects compose to the same map. In LaTeX the current standard for drawing one is \usepackage{tikz-cd} — the environment is tikzcd, without the hyphen — while the AMS package amscd still serves for plain rectangular grids. This page builds a commutative square from nothing, hangs labels on either side of the arrows, bends them, and ends on the question of which package to load.
What “the diagram commutes” actually claims
To commute means that every directed path with the same start and the same end yields the same composite. Take a square with A, B, C, D at the corners: f along the top from A to B, β down the right from B to D, α down the left from A to C, and g along the bottom from C to D. Saying that this square commutes is exactly the single equation β∘f = g∘α. A triangle states one equation, a square one, a cube six — one per face — all folded into a single picture. The larger the diagram, the wider the gap between what the picture holds and what the written-out equations would cost. A commutative diagram is not decoration; it is compression.
This compression pays off most in diagram chasing. Proofs in homological algebra — the five lemma, the snake lemma — proceed by picking an element in one corner and pushing it along the arrows, walking around the diagram. Commutativity is the rule that guarantees, at each step of that walk, that both routes arrive at the same place. The diagram is therefore not only a picture but the board the proof is played on. Diagrams of this kind entered mathematical writing with the 1945 paper that founded category theory; that story, and the arrow symbols themselves, are covered on the arrows page.
A diagram is itself a piece of display mathematics, so it belongs inside \[ … \] or an equation environment, which gives it its own centred line. Historically a whole shelf of packages was written for the job — xypic, diagram, kuvio among them — but for new work the field has narrowed to two: tikz-cd, built on the general-purpose drawing package TikZ, and the AMS package amscd. We take them in turn.
\usepackage{tikz-cd} and the tikzcd environment
Put \usepackage{tikz-cd} in the preamble and wrap the diagram in \begin{tikzcd} … \end{tikzcd}. The package name has a hyphen; the environment name does not. Get it backwards and you get ! LaTeX Error: File 'tikzcd.sty' not found.; write the environment without loading the package and you get ! LaTeX Error: Environment tikzcd undefined. If TikZ is already loaded, \usetikzlibrary{cd} gives you the same thing. The current CTAN release is version 1.0, dated 4 May 2021, maintained by Augusto Stoffel. The arrowheads ship as a library of their own, drawn to match the arrows of the Computer Modern typeface — which is why the arrows in the diagram do not look like visitors from another font.
Inside tikzcd you write exactly what you would write in tabular or matrix: cells separated by &, rows by \\. Each cell becomes a node of the diagram, and its contents are set in math mode automatically, so no $ is needed. Adding \arrow to a cell grows an arrow out of it; the short alias \ar is the very same command. The arrow is written in the cell it starts from, and its target is given inside the brackets by direction keys: r right, l left, u up, d down. They combine as a string — [rd] reaches diagonally down-right, [rr] reaches two cells across. A single cell may emit as many arrows as you like.
\usepackage{tikz-cd} % package has a hyphen; environment does not
\[
\begin{tikzcd}
A \arrow[r, "f"] \arrow[d, "\alpha"'] & B \arrow[d, "\beta"] \\
C \arrow[r, "g"'] & D
\end{tikzcd}
\]That is the commutative square. A, B, C, D sit at the four corners; f runs rightward along the top, g rightward along the bottom, and α and β run downward on the left and right sides. & divides columns and \\ divides rows, so the skeleton is nothing more than A & B \\ C & D. The arrows are annotations dropped into that skeleton afterwards, and the positions of the objects are entirely unaffected by how the arrows are written — which is the most satisfying part of the tikzcd design.
Labelling an arrow above or below: "f" versus "f"'
A quoted string among the options becomes a label, and an apostrophe ' immediately after the closing quote moves it to the other side. The rule is not “above or below” but left of the direction of travel. For a rightward arrow, left of travel is above — so \arrow[r, "f"] sets f above the arrow and \arrow[r, "f"'] below it. For a downward arrow, left of travel is the left-hand side — so \arrow[d, "\alpha"] puts α on the left and \arrow[d, "\alpha"'] on the right. There is no need to memorise four cases; one rule, “left of travel”, explains them all.
A single arrow may carry any number of labels, each with its own options. "\phi" near start sits close to the source, "\eta" near end close to the target, and "h" description places the label on the arrow, knocking the line out behind it in the background colour — the standard move when a short arrow needs a long name. If the label text or its options contain a comma, protect them with braces: "{(x,y)}". Since everything inside is math mode, ordinary words need \text{…} from amsmath.
\[
\begin{tikzcd}
A \arrow[r, "\phi" near start, "\psi"', "\eta" near end] & B \\
X \arrow[r, "h" description] \arrow[rd] & Y \\
& Z
\end{tikzcd}
\]Bending arrows, and drawing two of them between the same objects
Use bend left and bend right, adding an angle if you want one: bend left=25. The reason to bend is almost always the same — there are two maps between the same pair of objects. An adjunction, a homotopy equivalence, the pair of maps in a coequaliser: each needs two arrows, and drawn straight they lie on top of one another and read as one. Bent, both are legible. If you want them parallel rather than curved, shift left and shift right (default 0.56ex) nudge a straight arrow sideways instead. As always, “left” is relative to the direction of travel, so bend left bows out to the arrow’s own left.
In three-dimensional diagrams — a cube flattened onto the page — the far edges cross the near ones. Adding crossing over to an arrow draws a thick line in the background colour underneath it first, so it reads as passing in front. Arrows are drawn in the order they are written, so when the arrow that should go underneath comes first, you defer the other one by specifying it backwards from a later cell, as in from=uu. Knowing those two facts is the whole difference between a cube diagram that works and one that does not.
\[
\begin{tikzcd}
A \arrow[r, bend left=25, "f"] \arrow[r, bend right=25, "g"'] & B
\end{tikzcd}
\qquad
\begin{tikzcd}
A \arrow[dr] & B \arrow[dl, crossing over] \\
C & D
\end{tikzcd}
\]Line styles and arrowheads are switched the same way, by adding keys to the \arrow options. The names come in two families: short descriptive names such as hook and two heads, and names taken from existing LaTeX commands with the backslash removed, such as dashrightarrow. Knowing the second convention means you can guess a key instead of looking it up. Keys combine, too: \arrow[r, tail, two heads, dashed] produces one arrow that is tailed, two-headed and dashed at once. The common keys are collected below.
| Key | What it draws |
|---|---|
hook | A hook (⊂) at the tail; inclusions and injections |
hook' | The same hook, curving to the other side |
tail | A tail at the start; the other mark for an injection |
two heads | A doubled arrowhead; surjections |
dashed | A dashed line; conventionally a uniquely determined map |
dotted | A dotted line; a key inherited from TikZ |
squiggly | A squiggly (wavy) arrow |
equal | A double line (an equality) instead of an arrow |
maps to | A vertical bar at the tail (the ↦ of \mapsto) |
Rightarrow | A double-shafted arrow; 2-cells and natural transformations |
dashrightarrow | The shape of \dashrightarrow (an example of the backslash-stripped naming) |
bend left | Bows into an arc on the left of travel; bend left=25 sets the angle |
bend right | Bows into an arc on the right of travel |
shift left | Offsets a straight arrow sideways (default 0.56ex); for parallel pairs |
crossing over | Lays a thick background-coloured line underneath, so the arrow reads as passing in front |
phantom | Makes the arrow invisible; only its labels remain, so a symbol can sit off the grid |
description | A label option: sets the label on the line and knocks the line out behind it |
Putting an isomorphism sign on an arrow as a label is another common idiom: \arrow[r, dashed, "\simeq"] sets ≃ over a dashed arrow (and \sim works the same way). And because tikz-cd is built on TikZ, it accepts TikZ’s own keys directly — color=…, dotted, in=…/out=… and the rest. Its expressive range is effectively that of all of TikZ, which also means that when you get stuck, the manual you need may be TikZ’s rather than tikz-cd’s.
Tightening the spacing, and marking a pullback square
Spacing is set in the environment’s optional argument: \begin{tikzcd}[column sep=large, row sep=small]. Both dimensions (2em) and names (tiny, small, large, huge) are accepted, and sep sets rows and columns together. Wanting to widen only the direction that carries the long labels is a common enough need that these two keys are worth remembering.
The little corner mark ⌜ that flags a pullback (fibre product) square has no key of its own. The idiom is to put a label on an invisible arrow: \arrow[rd, phantom, "\ulcorner", very near start]. The phantom key erases the arrow, and the surviving label lands just inside the upper-left corner (for a pushout, \lrcorner placed near the lower right). There is a trap here: \ulcorner is not a core LaTeX symbol but an AMSFonts one, so forgetting \usepackage{amssymb} stops the run with ! Undefined control sequence. Labels on a phantom arrow are also anchored at their centre and set at full \textstyle size, so add \scriptstyle explicitly if you want them small.
\usepackage{amssymb} % \ulcorner comes from AMSFonts, not core LaTeX
\[
\begin{tikzcd}[column sep=large, row sep=large]
P \arrow[r, "p"] \arrow[d, "q"'] \arrow[rd, phantom, "\ulcorner", very near start]
& X \arrow[d, "f"] \\
Y \arrow[r, "g"'] & Z
\end{tikzcd}
\]When amscd still suffices: the CD environment
When the diagram is a rectangular grid with no diagonals, and you would rather not pull TikZ into the build, amscd is the answer. \usepackage{amscd} gives you exactly one thing: the CD environment. It is part of the amsmath bundle, currently v2.1 (14 April 2017), and depends on nothing but amsgen. The engaging part is the package’s own documentation, which explains that it reproduces the commutative-diagram capability of AMS-TeX 2.x, states plainly that only simple rectangular diagrams are supported, with no diagonal arrows or more exotic features, and then adds that many users will be better served by a more powerful diagram package — naming diagram, xypic and kuvio. Not many packages send the reader elsewhere in their opening paragraph.
The contents are a matrix of & and \\, as in tikz-cd, but every arrow is written as a special token beginning with @. Horizontally, @>>> points right and @<<< left; vertically, @VVV points down (the V of “vertical”) and @AAA up (an A read as an upward arrowhead). The double-line equality is @= horizontally and @| vertically. A lattice point that should carry no arrow takes the “null arrow” @. to keep the columns aligned. Horizontal arrows go between two objects on the same row; vertical arrows go on the row directly beneath their object.
Labels go between the characters that make up an arrow, and here is the fact that explains everything else about them at once. The AMS documentation says that material between the first and second > is typeset as a superscript, and material between the second and third as a subscript. So @>f>> puts f above, @>>g> puts g below, and @>f>g> puts one on each side. That is also why the labels come out small: an amscd arrow is, in effect, a very wide relation symbol wearing scripts. Vertical arrows follow the same rule with the scripts on the sides — @VfVV puts f to the left of a downward arrow, @VVfV to the right.
| Token | Meaning |
|---|---|
@>>> | Rightward arrow |
@<<< | Leftward arrow |
@VVV | Downward arrow (V for “vertical”) |
@AAA | Upward arrow (an A read as an upward arrowhead) |
@>f>> | Rightward arrow with f above it (the superscript slot) |
@>>g> | Rightward arrow with g below it (the subscript slot) |
@>f>g> | f above and g below |
@VfVV | Downward arrow with f on its left |
@VVfV | Downward arrow with f on its right |
@= | Horizontal double line (an equality) |
@| | Vertical double line (@\vert is the same) |
@. | Null arrow: fills out a lattice point that carries no arrow |
\usepackage{amscd}
\[
\begin{CD}
A @>f>> B \\
@V\alpha VV @VV\beta V \\
C @>>g> D
\end{CD}
\]This is the very same square as the tikz-cd example. On the left side, @V\alpha VV places α to the left of the arrow; on the right, @VV\beta V places β to the right of it, so that both labels face outward from the square. Along the bottom, @>>g> puts g below its arrow. The CD environment is math mode too, so it goes inside display math just as tikz-cd does. Next is the example from the AMS manual, which assumes \End has been defined as an operator name (the \operatorname kind).
% from the AMS amscd manual; \End must be defined as an operator name
\[
\begin{CD}
S^{{\mathcal{W}}_\Lambda}\otimes T @>j>> T \\
@VVV @VV{\End P}V \\
(S\otimes T)/I @= (Z\otimes T)/J
\end{CD}
\]The top row runs an arrow from the left object to T on the right with j above it. The middle row makes the two vertical arrows: unlabelled in the left column, and with End P on the right of the arrow in the right column. The bottom row joins its two objects with the double line @=. The braces in {\End P} group a multi-token label into a single unit. And if you find yourself needing fat arrows, dashed arrows, bidirectional arrows or colour while staying inside amscd, the extension package amscdx (v2.2x, 2019) adds exactly those — while keeping the restriction to rectangular geometry intact.
tikz-cd or amscd: how to choose
The decision comes down to almost a single question — do you need a diagonal arrow? If you do, amscd is out of the running. If a rectangular grid is all you need, amscd is lighter in dependencies and shorter to write. The list below is that one question, broken up a little.
- Diagonal arrows or curves needed →
tikz-cd.amscddoes horizontal and vertical only; slanting is not merely awkward but impossible. - Fine control over arrowheads and line styles (injections
hook/tail, surjectionstwo heads, dashes, double lines) →tikz-cd. - A plain rectangular diagram is enough and dependencies should stay light →
amscd. Without TikZ the run is faster and the preamble stays short. - Notation taste:
amscd’s@>f>>is terse but idiosyncratic;tikz-cd’s\arrow[r, "f"]is longer but still legible to you six months later. - Output route:
tikz-cddiagrams do not display correctly in DVI viewers. They presumepdflatex,lualatexorxelatex— engines that emit PDF directly — or a DVI-to-PDF/PS conversion.amscdhas no such constraint. - Whether you need a diagram at all: for two objects and one arrow,
\xrightarrow{f}fromamsmathinline in the text is the whole job.
Two last notes, for when you inherit an old document. tikz-cd still carries the form that predates the quotes syntax — \arrow[options]{direction}{labels}, as in \arrow{r}{f} — kept alive for backward compatibility. There are also the shorthand commands \rar, \dar, \uar, \lar (plus diagonal ones like \drar), where \rar is simply \arrow{r}. Avoid both in new work: sticking to \arrow[r, "f"] throughout is a kindness to your future self.