Skip to content

The Best Terminal Fonts, and How Nerd Fonts Actually Work

Your terminal font is the one typeface you actually stare at for eight hours a day, and for most people it’s whichever one the terminal shipped with. Menlo or SF Mono on a Mac, DejaVu Sans Mono on Linux, Consolas on Windows.

None of them is a bad font, and if yours is working for you there’s no prize for changing. But they were picked as safe defaults a decade or more ago, and the field has moved on a good way since. If you’ve ever wondered what you’re missing, here’s the answer without the install: every font we’re allowed to redistribute is rendered below in itself.

JetBrains Monothe safe answer
0O1lI| {}[]() <> ;:.,const ok = a !== b ? x : y;rg -n 'TODO' ~/src --hidden
Iosevkanarrower, more columns
0O1lI| {}[]() <> ;:.,const ok = a !== b ? x : y;rg -n 'TODO' ~/src --hidden
You want Install
A good font and no further thought JetBrains Mono
Icons in your prompt and file listings JetBrainsMono Nerd Font
More columns on the same screen Iosevka
The ligature font everyone means Fira Code
Free, and already installed on Windows Cascadia Code
Five matched families to mix between Monaspace
To spend actual money Berkeley Mono, MonoLisa

On macOS, that’s the entire exercise:

Terminal window
brew install --cask font-jetbrains-mono-nerd-font

Select JetBrainsMono Nerd Font in your terminal’s settings and you are done. The rest of this is for when you want to know why — and for when the icons come out as rectangles anyway.

Four things, roughly in order of how much they’ll cost you:

Disambiguation. 0 against O, 1 against l against I, rn against m, ; against : at 12px on a bad display. A font that blurs these doesn’t inconvenience you; it costs you half an hour at some point, usually in a config file you can’t syntax-check. Look for a slashed or dotted zero and a lowercase l with a tail.

IBM Plex Mono
0 O o 1 l I |5 S 2 Z 8 B rn m
Source Code Pro
0 O o 1 l I |5 S 2 Z 8 B rn m
Hack
0 O o 1 l I |5 S 2 Z 8 B rn m
JetBrains Mono
0 O o 1 l I |5 S 2 Z 8 B rn m

Same characters, four fonts. Whichever one separates them fastest for you is the right answer, and your eyes are a better judge of that than we are.

Weight at small sizes. Terminal text is small text. Fonts drawn for headlines go thin and patchy at 12 or 13 points; fonts drawn for screens hold their stems. This is the reason a gorgeous specimen page can be miserable at the size you’ll use it.

Box drawing and block elements. tmux borders, btop, ranger, every progress bar you’ve ever seen. Patchy coverage produces borders with gaps in them. Increasingly moot, mind: kitty, Ghostty and WezTerm all draw these characters themselves rather than trusting the font, which is why a border that’s broken in iTerm2 is pristine two terminals over.

A real italic. Most monospace fonts ship an oblique — the roman, mechanically slanted, which is what you get when nobody drew an italic. A few (Monaspace Radon, Operator Mono, MonoLisa) ship genuinely cursive italics, which is the entire reason for those screenshots where the comments look like handwriting.

JetBrains Mono Italica slanted roman
// a slanted roman, which// is what most of them are
Monaspace Radon Italicdrawn as an italic
// drawn as a true italic,// with new letterforms

Ligatures are not on that list. They’re a preference, and they get their own section below.

The default answer. Licensed under the OFL 1.1, free commercially, and drawn specifically for the case where you read code for hours: a tall x-height, generous letterform spacing, eight weights each with a matching italic. Ligatures are on out of the box, and JetBrains Mono NL is the identical font with them stripped out for tools that can’t switch OpenType features off. Since version 2.304 it also ships stylistic sets and character variants, so you can change your mind about specific letterforms without changing font.

If you install one font from this page, install this one.

JetBrains Mono
0O1lI| {}[]() <> ;:.,const ok = a !== b ? x : y;rg -n 'TODO' ~/src --hidden

Narrow. Conspicuously narrower than everything else here, which is the whole point: you get noticeably more columns in the same window, which matters if you keep two panes side by side or have opinions about 100-character lines. The trade is that condensed text is harder to skim, so it suits people who read code more than prose.

It also has the most intimidating release page in the business, because the family is generated rather than drawn — there are dozens of prebuilt variants and you can build a bespoke one from a TOML file if the dozens don’t cover it. OFL, and in most package managers.

Iosevkasame three lines — note how much narrower they run
0O1lI| {}[]() <> ;:.,const ok = a !== b ? x : y;rg -n 'TODO' ~/src --hidden

Microsoft’s, under the OFL, bundled with Windows Terminal and the default in Visual Studio — so on Windows you may already have it. It comes in four flavours, and the naming rewards five seconds of attention:

Variant What it adds
Cascadia Code The standard version, ligatures included
Cascadia Mono The same, ligatures removed
Cascadia Code/Mono PL Powerline symbols embedded
Cascadia Code/Mono NF Nerd Font symbols embedded

That last one matters: if you use Cascadia NF, you don’t need a separate Nerd Font at all. Note that the Nerd Fonts project’s own patched build of the same typeface is called Caskaydia Cove, for licensing reasons, which is precisely the sort of detail that costs you ten minutes in a font picker wondering where Cascadia went.

Cascadia Code
0O1lI| {}[]() <> ;:.,const ok = a !== b ? x : y;rg -n 'TODO' ~/src --hidden

GitHub Next’s superfamily: five metrics-compatible families — Neon, Argon, Xenon, Radon and Krypton — that you can swap between, or mix across editor and terminal, without anything shifting by a pixel. It also does “texture healing”, where the font quietly redistributes space in cramped sequences like /// or mi so the texture of the line evens out. Enabled via calt, which means it rides along with the same switch as ligatures.

OFL. The Nerd Fonts build is called Monaspice, continuing a proud tradition of renamed patches.

Monaspace NeonNeon — the neo-grotesque one
0O1lI| {}[]() <> ;:.,const ok = a !== b ? x : y;rg -n 'TODO' ~/src --hidden
Monaspace Radon ItalicRadon — the same metrics, handwritten
0O1lI| {}[]() <> ;:.,const ok = a !== b ? x : y;rg -n 'TODO' ~/src --hidden
Font Why you’d pick it
Fira Code The font that made programming ligatures a thing. Still excellent.
IBM Plex Mono Warmer and more humanist than most. Pairs well with everything IBM.
Hack Deliberately unexciting, built on Bitstream Vera. Very legible small.
Source Code Pro Adobe’s, older, conservative, entirely safe.
Inconsolata The classic. Compact, friendly, no ligatures, no drama.
Fira Code
0O1lI| {}[]() <> ;:.,const ok = a !== b ? x : y;rg -n 'TODO' ~/src --hidden
IBM Plex Mono
0O1lI| {}[]() <> ;:.,const ok = a !== b ? x : y;rg -n 'TODO' ~/src --hidden
Hack
0O1lI| {}[]() <> ;:.,const ok = a !== b ? x : y;rg -n 'TODO' ~/src --hidden
Source Code Pro
0O1lI| {}[]() <> ;:.,const ok = a !== b ? x : y;rg -n 'TODO' ~/src --hidden
Inconsolata
0O1lI| {}[]() <> ;:.,const ok = a !== b ? x : y;rg -n 'TODO' ~/src --hidden

macOS ships Menlo and Monaco, and SF Mono arrives with Xcode and Terminal.app. SF Mono is genuinely good and Apple’s licence is rather more restrictive than “it’s on my Mac” suggests, so read it before you embed it in anything. Windows has Consolas and Cascadia Mono. Most Linux distributions bring DejaVu Sans Mono, Liberation Mono and often Ubuntu Mono.

There’s nothing wrong with any of these; they’re the reason most people never have to think about terminal fonts at all. They are simply older and less specialised than the options above — fewer weights, no ligatures, and less fuss made over telling 0 from O. Whether that’s worth a download is a matter of taste.

Free fonts got very good roughly a decade ago, which changed what paid ones are for. You are not buying capability any more — you are buying someone’s taste, a wider range of weights, and their continued attention. That’s a reasonable thing to buy for a tool you use daily; it’s just worth being clear that it’s a want.

  • Berkeley Mono — Berkeley Graphics. Retro-technical, strongly characterful, and currently the terminal font most likely to appear in someone’s screenshot on purpose.
  • MonoLisa — large x-height, many weights, sold hard at developers. Divisive, well made.
  • Operator Mono — Hoefler&Co. The cursive italic that launched a thousand italic-comment configurations.
  • Comic Code — Comic Sans, monospaced, with ligatures. Sounds like a joke, reads genuinely well, and guarantees at least one comment in your next code review.

There are no specimens for those four: every font shown on this page is one we’re permitted to redistribute, and the paid ones aren’t. Judge them from the foundries’ own specimen pages — and whilst you’re there, check what the licence permits, since several restrict embedding, streaming and redistribution in ways that matter if you record your screen for a living.

A ligature is a rendering trick: the font substitutes a single drawn glyph for a sequence of characters, so != appears as and => as a proper arrow. The important part, and the bit that causes most of the arguing, is that nothing changes in the buffer. The terminal still holds two characters in two cells. Selection, cursor movement and column counts are unaffected. You are looking at a drawing, not an edit.

Which is easier to believe when you can toggle it. Both halves below are Fira Code, at the same size, rendering identical text; the right-hand one simply has calt switched off in CSS:

Fira Codeligatures on
!= >= <= === => -><=> :: ... |> ++ --
Fira Codeligatures off — font-feature-settings: "calt" 0
!= >= <= === => -><=> :: ... |> ++ --

Count the character cells in each: they are identical, because the ligature changes the drawing and not the text.

The case for: operators read as the single concept they represent, and dense expressions get quieter. The case against: >= and => collapse into similar-looking arrows, which is fine in a language you know and a genuine hazard in one you don’t, and the moment you’re counting characters in a diff you’d rather see what’s actually there.

Two things worth knowing before you commit either way. First, Alacritty does not support ligatures, by long-standing design decision — if that’s a dealbreaker, kitty, Ghostty and WezTerm all do, and our terminal emulator roundup covers what else you’d be trading. Second, you don’t need to change font to be rid of them:

# Ghostty — ~/.config/ghostty/config
font-feature = -calt
font-feature = -liga
font-feature = -dlig
# kitty — ~/.config/kitty/kitty.conf
disable_ligatures cursor
-- WezTerm — ~/.wezterm.lua
config.harfbuzz_features = { 'calt=0', 'clig=0', 'liga=0' }

kitty’s cursor value is the quietly clever option: ligatures everywhere except the line the cursor is on, so you get the tidy rendering whilst reading and the literal characters whilst editing. Its other values are always and never.

A Nerd Font is not a font. It’s a patcher, plus around seventy families that have already been through it. The patch takes over 10,000 icons — Font Awesome, Material Design Icons, Devicons, Octicons, Powerline, Weather Icons, Codicons and several more — and adds them to an existing typeface at codepoints in the Unicode private use area.

That last detail is the whole explanation for the rectangles. Private use means exactly what it says: no standard font carries those codepoints, because they don’t have agreed meanings. When Starship draws a branch marker, or eza puts a Rust logo next to a .rs file, they are emitting characters that only a patched font can draw. Everything else renders them as a hollow box, correctly, because it has no idea what you meant.

Patched, the payoff looks like this:

Terminal window
node_modules
󰣞 src
app.py
Dockerfile
index.ts
main.rs
package.json
󰂺 README.md
styles.css

The three variants, which is what everyone gets wrong

Section titled “The three variants, which is what everyone gets wrong”

Install a Nerd Font and you get three families, not one:

Terminal window
fc-list : family | tr ',' '\n' | grep -i nerd | sort -u
Inconsolata Nerd Font
Inconsolata Nerd Font Mono
Inconsolata Nerd Font Propo

They differ only in how wide the icons are drawn:

Family suffix Icon width Use it for
Nerd Font Double width Terminals. Start here.
Nerd Font Mono Single cell Anything insisting on strict cells — VS Code, mostly
Nerd Font Propo Proportional GUI apps. Not this.

The rule of thumb: plain Nerd Font in the terminal, and switch to Nerd Font Mono in any editor where the icons come out clipped or overlapping. If your prompt icons collide with the text after them, you have the wrong one of those two — it’s nearly always that, and nearly never the terminal.

On macOS, Homebrew carries the lot:

Terminal window
brew install --cask font-jetbrains-mono-nerd-font
brew search '/nerd-font$/' # all ~70 of them

On Linux, fetch the family you want from the releases and rebuild the font cache:

Terminal window
mkdir -p ~/.local/share/fonts
curl -fL --output-dir ~/.local/share/fonts -O \
https://github.com/ryanoasis/nerd-fonts/releases/latest/download/JetBrainsMono.zip
unzip -o ~/.local/share/fonts/JetBrainsMono.zip -d ~/.local/share/fonts/JetBrainsMono
rm ~/.local/share/fonts/JetBrainsMono.zip
fc-cache -fv

Swap JetBrainsMono.zip for CascadiaCode.zip, Iosevka.zip and so on — the asset names match the family names on the releases page. On Windows, download the same zip, select the .ttf files and use Install for all users, or add the nerd-fonts bucket if you’re a Scoop household.

Brace yourself for the size: that one archive is around 130MB and unpacks to 98 files, because it carries six families of sixteen styles each — the three width variants above, and then all three again in an NL edition with the ligatures removed. Which is worth knowing for its own sake, since JetBrainsMonoNL Nerd Font is the icons-without-ligatures option, and it’s already in the download you just made. Install the ones you’ll use and delete the rest.

Then find out what the machine decided to call it, because the family name is not the file name and your config needs the family name:

Terminal window
fc-list : family | grep -i jetbrains

Patching couples your choice of typeface to somebody else’s build process. If you want Berkeley Mono, or a font nobody has patched, install the icons separately as a fallback font and let the terminal pull the private-use codepoints from there:

Terminal window
brew install --cask font-symbols-only-nerd-font
# Ghostty — first family wins, the second fills the gaps
font-family = "Berkeley Mono"
font-family = "Symbols Nerd Font Mono"
-- WezTerm
config.font = wezterm.font_with_fallback { 'Berkeley Mono', 'Symbols Nerd Font Mono' }

Any font you like, icons that work, no patched build to keep up to date. And if you use Ghostty, it already does this for you: it embeds JetBrains Mono along with the symbols-only font as a fallback, so the icons work on a fresh install with no font configuration and no fonts installed at all.

# Ghostty — ~/.config/ghostty/config
font-family = "JetBrainsMono Nerd Font"
font-size = 13
# kitty — ~/.config/kitty/kitty.conf
font_family JetBrainsMono Nerd Font
font_size 13.0
-- WezTerm — ~/.wezterm.lua
config.font = wezterm.font 'JetBrainsMono Nerd Font'
config.font_size = 13.0
# Alacritty — ~/.config/alacritty/alacritty.toml
[font]
size = 13.0
[font.normal]
family = "JetBrainsMono Nerd Font"
// Windows Terminal — settings.json, inside a profile
"font": { "face": "CaskaydiaCove Nerd Font", "size": 12 }
// VS Code — settings.json. The terminal is configured separately from the editor
"terminal.integrated.fontFamily": "JetBrainsMono Nerd Font Mono"

iTerm2 keeps it behind Settings → Profiles → Text → Font, and applies it per profile, which is worth remembering when you change it once and wonder why the other window still looks wrong.

In rough order of likelihood:

1. The name is wrong. The family name is not the filename and not the download name. fc-list above is the authority; on macOS, Font Book’s family list works too. JetBrains Mono and JetBrainsMono Nerd Font are different fonts, and only one of them has the icons.

2. The terminal hasn’t noticed. Font caches are read at startup. Quit the application properly — not just the tab, not just the window — and reopen it. On Linux, run fc-cache -fv first.

3. You’re on SSH. Rendering happens on the machine in front of you, always. The fonts on the server are irrelevant; the font on your laptop is the one that matters. If your remote prompt is rectangles and your local one isn’t, you’ve installed it in exactly the wrong place. Worth a look at the SSH config guide whilst you’re there.

4. It’s the wrong variant. Icons that overlap the following character, or get clipped in half, mean the plain/Mono distinction above has gone the wrong way for that application. This is the single most common cause of “it works in my terminal but not in VS Code”.

5. Your config predates Nerd Fonts 3. Version 3.0 moved the entire Material Design Icons block out of U+F500–U+FD46 and up to U+F0001–U+F1AF0, and dropped the old codepoints entirely. Any prompt, status line or waybar config that hardcoded the old values renders boxes on a current font, and will keep doing so until the codepoints are updated. If a handful of icons broke at once and the rest are fine, this is why.

A font is the cheapest upgrade on this site, but it’s the prompt that gives it something to do — Starship’s modules are where most of those icons end up. The modern CLI starter pack adds the rest, eza and its file icons included. And once you’ve settled on a font, put the terminal config that names it into a dotfiles repo, so the next machine doesn’t start you at Menlo again.

If you’re going to stare at a screen this much, the keyboard is the other half of the argument.