A deep dive into Ghostty

By

Ghostty from scratch: install it, learn the shortcuts, write the config, pick fonts and themes, use splits, build keybindings, set up shell integration and SSH.

~~~

Ghostty is a terminal emulator for macOS, Linux, and FreeBSD. It’s fast, it uses native platform UI, and it supports the modern terminal protocols that programs like Neovim, Claude Code, and Yazi use today.

It also works with zero configuration. You install it, you open it, you have a good terminal.

Most of this guide covers the config file, fonts, themes, splits, keybindings, shell integration, and SSH.

Ghostty gives you a window for your shell. Most of the work comes from knowing that shell and its commands. That’s why I start with the shortcuts I use, my own setup, and links to my terminal guides, books, and courses.

I wrote this guide against Ghostty 1.3.1, the stable release at the time of writing.

What is Ghostty?

Ghostty was created by Mitchell Hashimoto (https://x.com/mitchellh), a co-founder of HashiCorp. He started it as a side project, ran a private beta for a couple of years, and released 1.0 in December 2024.

The code is MIT licensed. During the 1.3 cycle, Ghostty became a fiscally sponsored non-profit project through Hack Club.

Ghostty separates its core from the platform apps. The core is libghostty, a Zig library that handles terminal emulation, fonts, and GPU rendering.

The macOS app uses Swift, AppKit, and SwiftUI. The Linux app uses Zig, GTK4, and libadwaita. Both use libghostty underneath.

That split is what makes Ghostty feel native on both platforms. Tabs are real macOS tabs. Windows behave like GTK windows on Linux, and keyboard shortcuts follow the conventions of each system, so on a Mac you use Cmd and on Linux you use Ctrl+Shift.

cmux, for example, uses libghostty for its terminal panes. awesome-libghostty tracks projects built on the full library and projects that only use libghostty-vt, its terminal parser and state layer.

The list includes bindings for Go, Rust, Swift, Node, Python, and .NET. You will also find terminals for iOS, Android, Windows, Emacs, and even the Apple Watch. ghostty-web provides an xterm.js-compatible web version, while OrbStack uses Ghostty technology for its built-in terminal. A large group of macOS apps use it to run coding agents side by side.

In 1.3.1, the standalone libghostty API was still unversioned and a work in progress. Check the exact version before building an app around it.

There is no Windows version yet. It’s on the long term roadmap, but not planned for the near future.

Ghostty compared to the alternatives

You probably already have a terminal you like. Here is how Ghostty fits next to the common ones.

Terminal.app on macOS is fine. Ghostty’s own benchmarks show it falling behind with heavy output. Terminal.app has split panes, but both panes show the same session instead of opening independent shells. It also lacks features such as ligatures and the Kitty graphics protocol.

iTerm2 has a broad feature set, but it’s macOS only. Ghostty covers the features I use most from iTerm2: splits, tabs, search, and a quick terminal.

Alacritty is fast and minimal. It intentionally leaves managed tabs and splits to your window manager or a terminal multiplexer such as tmux. Ghostty includes those windowing features.

Kitty is also fast and feature rich, but it draws its own UI instead of using the native one, and its keyboard-first design takes some learning. Its author designed the Kitty graphics and keyboard protocols, which Ghostty supports too.

WezTerm is cross-platform, including Windows, and you configure it in Lua. Ghostty’s config is a plain text file with no programming language.

What sets Ghostty apart for me is the native UI combined with defaults good enough that many people never write a config file.

Install Ghostty

Download Ghostty from ghostty.org. The site also has the Linux install instructions.

The ghostty.org homepage, with the ASCII ghost logo and the Download and Documentation buttons

macOS

Download the .dmg from ghostty.org/download and drag the app into Applications. Or use Homebrew:

brew install --cask ghostty

The cask repackages the same signed and notarized binary, so both methods give you the same app.

Ghostty needs macOS 13 or newer. 1.3 is the last release that supports macOS 13. Starting with 1.4 you need macOS 14.

Linux

The Ghostty project only ships official binaries for macOS. Linux packages come from distribution maintainers, community maintainers, and the Ghostty project itself, depending on the package. The main ones:

# Arch Linux
sudo pacman -S ghostty

# Ubuntu 26.04 and newer
sudo apt install ghostty

# Omarchy
omarchy pkg add ghostty

# Fedora (community COPR)
sudo dnf copr enable scottames/ghostty
sudo dnf install ghostty

# Snap
sudo snap install ghostty --classic

Nix, Void, Gentoo, Solus, Alpine, and an AppImage are also covered on the install page.

Check the version

Open Ghostty and run:

ghostty +version

You get the version plus some build details:

Ghostty 1.3.1

Version
  - version: 1.3.1
  - channel: stable
Build Config
  - Zig version   : 0.15.2
  - build mode    : .ReleaseFast
  - app runtime   : .none
  - font engine   : .coretext
  - renderer      : renderer.generic.Renderer(renderer.Metal)
  - libxev        : kqueue

Output of ghostty +version in a Ghostty window: version 1.3.1, stable channel, Zig 0.15.2, CoreText font engine, Metal renderer

On macOS this works inside Ghostty because its shell integration adds the app’s binary folder to your PATH. From another terminal, like the one inside your editor, you may need the full path: /Applications/Ghostty.app/Contents/MacOS/ghostty.

The +actions

That +version is one of Ghostty’s CLI actions. The ghostty binary is both the terminal and a small toolbox. Run ghostty +help to list them:

  +version
  +help
  +list-fonts
  +list-keybinds
  +list-themes
  +list-colors
  +list-actions
  +ssh-cache
  +edit-config
  +show-config
  +validate-config
  +show-face
  +crash-report
  +boo
  +new-window

Output of ghostty +help: usage, the note that on macOS the CLI only runs actions, and the list of available +actions

We’ll use most of these in the rest of the guide. +boo shows the Ghostty animation, so you can skip that one. +new-window only works on Linux.

Each action has its own help: ghostty +list-themes --help.

What you get with no config

A fresh Ghostty install already gives you plenty.

The font is JetBrains Mono, which Ghostty embeds so it works even if you don’t have it installed. The Nerd Fonts symbols are built in too, so prompts like Starship and tools like eza show their icons right away, without installing a patched font.

Shell integration is injected automatically for bash, zsh, fish, and nushell. Ghostty makes its Elvish module available, but you must load it yourself. New tabs open in the current directory, the cursor becomes a bar at the prompt, and closing a tab at an idle prompt doesn’t ask for confirmation.

Tabs, splits, a command palette, search in the scrollback, and native scrollbars are all there with default shortcuts. Cmd+D splits right, Cmd+T opens a tab, Cmd+F searches.

The TERM variable is xterm-ghostty, and macOS Secure Input turns on by itself when you type a password.

My advice is to use it for a day with no config, and then come back here for the parts you miss.

Default shortcuts

These are the defaults you’ll use every day, on both platforms. They work with no config, so learn them before you change anything. ghostty +list-keybinds --default prints the complete list for your version.

ActionmacOSLinux
New windowCmd+NCtrl+Shift+N
New tabCmd+TCtrl+Shift+T
Close current split or tabCmd+W
Close tab and all its splitsCmd+Option+WCtrl+Shift+W
Close windowCmd+Shift+WAlt+F4
QuitCmd+QCtrl+Shift+Q
Next / previous tabCmd+Shift+] / [Ctrl+Page Down / Up
Go to tab 1 to 8Cmd+1 to 8Alt+1 to 8
Last tabCmd+9Alt+9
Split rightCmd+DCtrl+Shift+O
Split downCmd+Shift+DCtrl+Shift+E
Focus split by directionCmd+Option+ArrowCtrl+Alt+Arrow
Next / previous splitCmd+] / [Ctrl+Super+] / [
Resize splitCmd+Ctrl+ArrowCtrl+Shift+Super+Arrow
Equalize splitsCmd+Ctrl+=
Zoom splitCmd+Shift+EnterCtrl+Shift+Enter
FullscreenCmd+EnterCtrl+Enter
CopyCmd+CCtrl+Shift+C
PasteCmd+VCtrl+Shift+V
Select allCmd+ACtrl+Shift+A
SearchCmd+FCtrl+Shift+F
Next / previous matchCmd+G / Cmd+Shift+G
Jump to previous / next promptCmd+Up / DownCtrl+Shift+Page Up / Down
Scroll to top / bottomCmd+Home / EndShift+Home / End
Scroll a pageCmd+Page Up / DownShift+Page Up / Down
Clear screen and scrollbackCmd+K
Font bigger / smaller / resetCmd+= / - / 0Ctrl+= / - / 0
Command paletteCmd+Shift+PCtrl+Shift+P
Open configCmd+,Ctrl+,
Reload configCmd+Shift+,Ctrl+Shift+,
InspectorCmd+Option+ICtrl+Shift+I
Undo closeCmd+Z
Screen to file, paste pathCmd+Shift+JCtrl+Shift+J

The blank Linux cells are actions with no default binding there. You can bind them yourself, and the keybindings section explains how.

How I use Ghostty

My config is short. This is all of it:

font-size = 18
macos-option-as-alt = false
keybind = super+bracket_right=increase_font_size:1

The font is the default JetBrains Mono, the theme is the default. I bumped the size to 18, which is big, and I like it that way.

macos-option-as-alt = false keeps the Option key as macOS intends it. I type on an Italian keyboard, and I want Option to keep producing the characters it normally does.

The extra keybind is about that same keyboard. The + key on an Italian Mac keyboard sits where a US keyboard has ], so I bound the physical bracket_right key to increase the font size. Cmd and the plus key do what I expect, whatever the layout thinks that key is called.

I also ended up with two config files, one in ~/.config/ghostty and the template Ghostty created in ~/Library/Application Support. Both are loaded, the second wins. That’s a leftover from setting it up before I knew how the lookup works, and the XDG one is the one worth keeping.

My shell is fish, so shell integration is automatic. Cmd+Up between prompts, new splits in the current folder, and the bar cursor at the prompt all worked without any setup.

Most of my terminal time goes into coding agents, npm run dev, git, and SSH sessions. I want Ghostty to stay out of the way while I do that.

Learn the terminal, not just Ghostty

Ghostty runs a shell, and the shell runs your commands. Learning those commands helps in every terminal, while your Ghostty config only affects Ghostty.

I’ve written about the terminal for years, and all of it is free.

Start with the commands

The Command Line Guide is the overview. If you’ve never opened a terminal, start with The Command Line for Complete Beginners instead.

The free Shell Commands course goes through the commands one lesson at a time. The CLI Handbook has the same material as a PDF or EPUB you can keep around.

I also have a short post for most individual commands, including ls, cd, grep, find, tail, chmod, ps, kill, and tar. The full list is under the CLI tag.

Pick a shell

The Unix Shells Tutorial explains what a shell is and how bash, zsh, and fish differ. I use fish, and The Fish Shell: A Complete Guide is how I’d set it up today.

If you’d rather stay with bash, read The Bash shell and Introduction to Bash Shell Scripting. The Shell Scripting and Automation course takes the next step. You will also need how to set an alias and how to set environment variables.

Add the tools you need

Use tmux when you need sessions that survive. I compare it with Ghostty’s own splits later in this guide.

cmux helps when you run several coding agents at once. zoxide saves you from typing long cd paths, and jq handles the JSON returned by APIs and agent logs.

Connect to servers

The terminal is how you talk to a remote machine. SSH for developers covers keys, config, and tunnels. The SSH section of this guide covers the Ghostty-specific part.

The free Linux Basics, VPS, Linux Server Troubleshooting, and Build a Home Server courses take you from a fresh Ubuntu install to a machine you can run things on.

Set up your computer

The macOS for Developers course covers Homebrew, dotfiles, and the tools worth installing around your terminal. A practical guide to Homebrew is the standalone version of the Homebrew part.

Learn Git

You’ll use Git from the terminal more than from any GUI. The free Git course and the Git Cheat Sheet cover it.

The books and courses are all on the free library page.

The configuration file

Ghostty reads a plain text file, not Lua or JSON.

Where the file lives

On both macOS and Linux, the preferred XDG location is:

~/.config/ghostty/config.ghostty

The .ghostty extension arrived in 1.3 and helps editors pick the right syntax highlighting. The older file named config still works. If both files exist, Ghostty loads config first and config.ghostty second.

On macOS there is a second location that Ghostty also reads:

~/Library/Application Support/com.mitchellh.ghostty/config.ghostty

The older extensionless name works there too. Ghostty loads the XDG files first and the Application Support files second, so values in Application Support win. It creates a commented template there on first launch if it finds no config anywhere.

I’d pick one and stick to it. ~/.config/ghostty/config.ghostty also works on Linux, so that’s the one I’d keep in a dotfiles repo.

The syntax

Every line is key = value. Spaces around the = don’t matter. Lines starting with # are comments. Blank lines are ignored.

# Fonts
font-family = JetBrains Mono
font-size = 14

# Colors
theme = Catppuccin Mocha

# Behavior
copy-on-select = clipboard

Comments can’t go at the end of a line. Ghostty treats everything after = as the value, so background = #000 # black tries to parse the whole string as a color and fails validation.

An empty value resets the key to its default:

font-family =

Some keys can appear more than once. font-family and config-file keep every value. keybind, palette, and env keep different triggers, palette indexes, or variable names, but a later duplicate replaces the earlier one:

font-family = Iosevka
font-family = JetBrains Mono

This sets Iosevka as the main font and JetBrains Mono as the fallback for glyphs Iosevka lacks. To start over in a repeatable key, set it to an empty string first: font-family = "".

Values with special characters can be quoted: font-family = "Fira Code".

Reload the config

Press Cmd+Shift+, on macOS or Ctrl+Shift+, on Linux. The config reloads without restarting.

Not every option reloads. The docs for each option say if it applies at runtime, only to new terminals, or needs a full restart. Font size applies immediately. Padding applies to new windows, tabs, and splits. background-opacity on macOS needs a restart.

Cmd+, (or Ctrl+,) opens the config file in your default editor.

Validate the config

Typos in a config file are silent in many programs. Ghostty has a checker:

ghostty +validate-config

No output and exit code 0 means the file is fine. With a mistake, you get the file, line, and problem:

/Users/flavio/.config/ghostty/config:2:backgroun: unknown field

Ghostty also shows an error window at startup if the config has problems, but the command is what you want in a script or before a commit.

See the effective config

ghostty +show-config

This prints what Ghostty is using after merging every file. Add --default to see every option with its default value, and --docs to include the documentation comments:

ghostty +show-config --default --docs | less

That’s the complete reference, offline, for the exact version you’re running. Over 4,000 lines. When the website and your installed version disagree, this output is right for your machine.

Split the config into files

config-file includes another file. Paths are relative to the file that contains the directive:

config-file = fonts
config-file = keybinds
config-file = ?local

The ? prefix makes the file optional. If local doesn’t exist, nothing happens. This is how you keep a shared config in a dotfiles repo and a machine-specific file that stays out of git.

Ghostty processes included files after the whole current file. A value set in fonts overrides the same key set later in the main file.

Every option is a CLI flag

Any config key works as a command line flag when starting Ghostty:

ghostty --font-size=20 --theme="Rose Pine"

On macOS you can’t launch the app that way from a shell. Use open:

open -na Ghostty.app --args --font-size=20

The -n opens a new instance and -a names the app. Flags after --args go to Ghostty.

Fonts

Pick a family

List what Ghostty can see:

ghostty +list-fonts

You get every family with its styles, one block per family:

Output of ghostty +list-fonts, listing font families like Andale Mono, Berkeley Mono, DM Mono, and Menlo with their styles

Then set it:

font-family = Iosevka

Bold, italic, and bold italic are found automatically from the same family. If you want a different font for one of those styles, there are dedicated keys:

font-family-bold = Iosevka Heavy
font-family-italic = Victor Mono

When a font has no italic, Ghostty synthesizes one by slanting the regular glyphs. Same for bold, by thickening the outline. If you’d rather see the regular style than a fake one:

font-synthetic-style = no-italic

Fallbacks

Repeat font-family for fallbacks. The first entry is the main font, the rest are consulted in order when a character is missing:

font-family = Iosevka
font-family = Noto Sans Mono CJK JP

Emoji don’t need a fallback. Ghostty always uses Apple Color Emoji on macOS and Noto Emoji on Linux unless you override it.

To find out which font renders a specific character:

ghostty +show-face --string="→ λ ⚡"
U+2192 « → » found in face "JetBrains Mono".
U+3BB « λ » found in face "JetBrains Mono".
U+26A1 « ⚡ » found in face "Apple Color Emoji".

This is the command to run when an icon in your prompt shows up as a box.

Size

font-size = 14

The unit is points, and decimals are allowed. On a retina display where 1pt is 2px, 13.5 gives you 27px, an odd pixel size you can’t reach with whole numbers.

Cmd+= and Cmd+- change the size in the current terminal. Cmd+0 resets it. On Linux it’s Ctrl instead of Cmd. New windows inherit the size of the focused one because window-inherit-font-size defaults to true.

Ligatures

Fonts like Fira Code and JetBrains Mono turn != and => into single glyphs. Some people love it, some hate it. To turn them off:

font-feature = -calt

calt is the OpenType feature most coding fonts use for ligatures. Some fonts also need -liga and -dlig. You can list several: font-feature = -calt, -liga, -dlig.

The same key enables stylistic sets. Iosevka and Fira Code ship alternate glyphs behind ss01, ss02, and so on:

font-feature = ss01
font-feature = zero

Ghostty breaks ligatures under the cursor by default, so you can see individual characters while editing. font-shaping-break = no-cursor turns that off.

Variable fonts

If your font is a variable font, you can set axes directly:

font-variation = wght=450
font-variation-bold = wght=700

Values outside the font’s range are ignored, not clamped.

Thicker text on macOS

macOS renders text thinner than Linux. If your font looks anemic:

font-thicken = true

font-thicken-strength goes from 0 to 255 and defaults to the max.

Fix metrics

Every adjust-* key nudges a measurement the font declares. Values are pixels or percentages, and they are relative changes:

adjust-cell-height = 10%
adjust-underline-position = 2
adjust-cursor-thickness = 1

adjust-cell-height is the one people use most. It adds line spacing without changing the font. Text stays vertically centered in the taller cell.

Map characters to a font

Sometimes one font has a better version of a specific symbol. font-codepoint-map forces a Unicode range to a font:

font-codepoint-map = U+E0B0-U+E0D4=Symbols Nerd Font Mono

This applies to new terminals only.

Themes and colors

Browse the built-in themes

Ghostty ships with over 450 themes. Run this inside Ghostty:

ghostty +list-themes

You get an interactive preview. Arrow keys move through the list, the right side shows the theme applied to sample text, F1 shows the other keys, and Escape exits.

Piped or with --plain, you get one theme per line, followed by its source marker:

ghostty +list-themes --plain | grep -i gruvbox

ghostty +list-themes --help explains the preview, the two folders it searches, and the --color flag that limits the list to dark or light themes:

Output of ghostty +list-themes --help, describing the TUI preview, the two theme directories, and the --path, --plain, and --color flags

Set a theme

theme = Catppuccin Mocha

Popular ones you’ll find in the list: Catppuccin Latte, Catppuccin Mocha, Dracula, GitHub Dark, Gruvbox Dark, Nord, One Half Dark, Rose Pine, TokyoNight, Solarized Dark Higher Contrast. Use the theme name exactly, without the (resources) or (user) marker.

Light and dark mode

Ghostty follows the system appearance if you give it two themes:

theme = light:Catppuccin Latte,dark:Catppuccin Mocha

Switch macOS to light mode and the terminal changes with it. Programs inside the terminal that support the color scheme notification (Neovim does) can switch their own theme at the same time.

Write your own theme

A theme file uses the regular Ghostty config syntax and normally sets colors. Put it in ~/.config/ghostty/themes/ and refer to it by file name.

Here is a small light theme in the colors of this site:

# ~/.config/ghostty/themes/newspaper
background = #f5f0e6
foreground = #101214
cursor-color = #ff4b0a
selection-background = #101214
selection-foreground = #f5f0e6
palette = 0=#101214
palette = 1=#e92820
palette = 2=#4a6b2a
palette = 3=#b8730a
palette = 4=#1f4b7a
palette = 5=#6b3a7a
palette = 6=#2a6b6b
palette = 7=#f5f0e6
palette = 8=#5a5a5a
palette = 9=#ff4b0a
palette = 10=#6b8f3a
palette = 11=#d69a1a
palette = 12=#2f6da8
palette = 13=#8f5aa8
palette = 14=#3a8f8f
palette = 15=#ffffff

Then:

theme = newspaper

Theme files can set almost any option, not only colors. theme and config-file are silently ignored inside a theme file. Don’t load themes from sources you don’t trust. The built-in ones are audited.

Override single colors

Anything you set in the main config wins over the theme:

theme = Nord
background = #1a1d24
cursor-color = #ff4b0a

palette sets one of the 256 colors. The first 16 are the ANSI colors programs use most:

palette = 1=#e92820
palette = 9=#ff4b0a

Colors accept #RRGGBB, RRGGBB, or X11 names like orange. ghostty +list-colors prints the names.

Cursor

cursor-style = bar
cursor-style-blink = false
cursor-color = #ff4b0a
cursor-text = #ffffff

Styles are block, bar, underline, and block_hollow. Shell integration switches the cursor to a bar at the prompt regardless of this setting. If you want your style everywhere, add shell-integration-features = no-cursor.

cursor-color and cursor-text can be cell-foreground or cell-background to follow the text under the cursor.

Selection colors

selection-background = #585b70
selection-foreground = #cdd6f4

Without these, selection inverts the window colors. selection-foreground = cell-foreground keeps syntax colors visible inside a selection.

Make text readable

Some themes let a program print dark blue on black. minimum-contrast forces a minimum ratio between text and background:

minimum-contrast = 3

The value is a WCAG contrast ratio from 1 to 21. Around 1.1 prevents invisible text. Around 3 makes everything readable. Higher values push more text toward pure black or white.

Bold and faint text

bold-color = bright
faint-opacity = 0.6

bold-color = bright makes bold text use the bright half of the palette, the way older terminals did. You can also set a fixed color.

Transparency and blur

background-opacity = 0.9
background-blur = true

On macOS this needs a full restart. background-blur = true uses a blur radius of 20. A number gives you a specific radius. On macOS 26 there are two glass options:

background-blur = macos-glass-regular

Cells with an explicit background color stay opaque, so a Neovim theme that paints its own background will look solid. background-opacity-cells = true applies the opacity to those too.

Opacity turns off in native macOS fullscreen. The toggle_background_opacity action flips a transparent window to opaque and back, and it’s in the command palette.

On Linux, blur works on KDE Plasma, where KWin’s global blur setting applies and the intensity value is ignored. Other desktops aren’t supported.

Background image

Since 1.2:

background-image = /Users/flavio/Pictures/paper.jpg
background-image-opacity = 0.3
background-image-fit = cover

PNG and JPEG only. The image is per terminal, so with splits it repeats in each one. Fit options are contain, cover, stretch, and none, plus background-image-position and background-image-repeat.

Themes and configs from other people

ghostty.town lets people share complete Ghostty configs with a preview. You can browse popular configs, copy the lines you like, and submit your own.

awesome-ghostty is a community list of themes, shaders, and tools. The original is no longer updated and points to a maintained fork. The Themes section is where you find the ones that ship as separate files: Catppuccin and Rosé Pine in their official versions, Everforest, Gruvbox Material, Night Owl, Monokai, the Kitty themes converted to Ghostty, and the base16 and base24 sets from tinted-terminal. Drop the file in ~/.config/ghostty/themes/ and use its name.

The same list also collects useful tools. ghostty-ghost moves settings over from Kitty and Alacritty. iterm-to-ghostty-colors converts an iTerm2 color profile into Ghostty lines.

For editor support, ghostty-ls is a language server for the config file. ghostty.nvim validates the config when you save it in Neovim. You can also use the unofficial web configurator if you’d rather click through the options than read +show-config --default --docs.

The window

Padding

window-padding-x = 10
window-padding-y = 8

Points, scaled for the display. Two values set different sides: window-padding-x = 10,4 is 10 left and 4 right.

The window size is rarely an exact multiple of the cell size, so a few extra pixels end up at the right and bottom. window-padding-balance = true spreads them evenly on all sides.

The padding area is normally the background color. When a program like Neovim paints a different background, the padding shows a strip of your terminal color around it. window-padding-color = extend fixes that by extending the nearest cell’s color into the padding.

The macOS titlebar

macos-titlebar-style has four values:

macos-titlebar-style = tabs

native is the standard macOS titlebar. transparent (the default) lets your background color show through it. tabs merges the tab bar into the titlebar, which saves a row of vertical space. hidden removes the titlebar but keeps the rounded window frame.

With hidden you drag the window with Option+click on the edges, which is a macOS thing, not a Ghostty one.

macos-window-buttons = hidden removes the traffic lights. macos-titlebar-proxy-icon = hidden removes the little folder icon.

Window decorations

window-decoration = none

This removes the titlebar and borders. On macOS it also disables tabs, because macOS tabs need a titlebar. On Linux, auto, client, and server pick how decorations are drawn. auto is right for almost everyone.

Size and position

window-width = 120
window-height = 40

In cells, not pixels, and both must be set. This only affects new windows. window-position-x and window-position-y set the starting position in pixels on macOS, and those two options must also be set together.

maximize = true starts new windows maximized. fullscreen = true starts them fullscreen.

Fullscreen on macOS

Cmd+Enter toggles fullscreen. By default that’s native macOS fullscreen, with the animation and the separate space.

macos-non-native-fullscreen = true

This is instant and has no animation, but tabs don’t work in it because the titlebar is gone. visible-menu keeps the menu bar. padded-notch avoids the notch on laptops.

Working directory

New windows, tabs, and splits open in the directory of the terminal you were in. Since 1.3 each is a separate switch:

window-inherit-working-directory = false
tab-inherit-working-directory = true
split-inherit-working-directory = true

This needs shell integration, because that’s how Ghostty learns where your shell is.

working-directory sets the folder for terminals that don’t inherit. home and inherit are special values, or use a path.

Save window state

On macOS, Ghostty can restore windows, tabs, and splits. With window-save-state = default, it saves them only when macOS forces termination or asks the app to restore state. Use always if you also want restoration after a normal quit, or never to disable it.

Resize overlay

When you resize a window, a box shows the new size in columns and rows. resize-overlay = never hides it. resize-overlay-position moves it to a corner.

Tabs

Cmd+T opens a tab. Cmd+W closes the current tab, split, or window, whichever is focused. Cmd+Shift+W closes the whole window. On Linux, Ctrl+Shift+T opens a tab, while Ctrl+Shift+W closes the entire tab and all its splits.

Move between tabs with Cmd+Shift+[ and Cmd+Shift+], or Ctrl+Tab and Ctrl+Shift+Tab. Cmd+1 through Cmd+8 jump to a tab by number, and Cmd+9 goes to the last one. On Linux the number shortcuts use Alt.

Double-click a tab title on macOS to rename it inline. Right-click a tab to give it a color. The command palette has “Change Tab Title” too.

window-new-tab-position = end

New tabs open after the current one by default. end puts them at the end of the list.

Closing a tab with a running process asks for confirmation. Sitting at a shell prompt doesn’t, thanks to shell integration. confirm-close-surface = always asks every time, false never asks.

Undo works on tabs and splits. Cmd+Z brings back a tab you closed by accident, with its process still running, as long as you do it within the undo-timeout, which is 5 seconds by default. This is macOS only.

Splits

Cmd+D splits the current terminal to the right. Cmd+Shift+D splits below. On Linux, Ctrl+Shift+O and Ctrl+Shift+E.

Move focus with Cmd+Option+Arrow in a direction, or Cmd+[ and Cmd+] to cycle in creation order. Linux uses Ctrl+Alt+Arrow.

Resize with Cmd+Ctrl+Arrow. Each press moves the divider 10 pixels, and Cmd+Ctrl+= equalizes all splits.

Cmd+Shift+Enter zooms the focused split to fill the tab. Press again to unzoom. By default, moving to another split unzooms. This keeps the zoom and moves it to the new split instead:

split-preserve-zoom = navigation

Unfocused splits are dimmed to 70% so you can see where you are:

unfocused-split-opacity = 0.85
split-divider-color = #ff4b0a

Set the opacity to 1 to turn dimming off.

On macOS since 1.3 you can rearrange splits with the mouse. Drag a split into another position, into another tab, or out into a new window. The running process moves with it, and undo works here too.

focus-follows-mouse = true focuses a split when the pointer moves over it, without clicking.

Scrollback

Size

scrollback-limit = 100000000

Bytes, per terminal. The default is 10 MB. Memory is allocated lazily, so a big limit costs nothing until you fill it. There’s no unlimited setting yet.

Scroll with the keyboard

Cmd+Home and Cmd+End jump to the top and bottom. Cmd+Page Up and Cmd+Page Down move a page. On Linux, Shift+Home, Shift+End, Shift+Page Up, Shift+Page Down.

Cmd+Up and Cmd+Down jump between prompts. This is one of the best features once you’re used to it. You ran a command with a lot of output, and you want to see the command before it. Cmd+Up takes you straight there. It needs shell integration. On Linux it’s Ctrl+Shift+Page Up and Page Down.

Typing scrolls to the bottom. New output doesn’t, so you can read old output while a build runs. scroll-to-bottom = keystroke,output changes that.

Cmd+F opens the search bar (Ctrl+Shift+F on Linux). Every match in the view is highlighted. Cmd+G and Cmd+Shift+G move to the next and previous match. Escape closes it. Cmd+E searches for the current selection.

Search is a 1.3 feature. Before that you had to pipe output through grep or dump the scrollback to a file.

search-background = #ffe082
search-selected-background = #f2a57e

These set the colors of candidate matches and the focused match.

Scrollbars

Native scrollbars arrived in 1.3. They’re overlaid on the content, so they don’t steal a column. scrollbar = system follows your OS setting, which on macOS usually means visible only while scrolling. never hides them.

Save the screen to a file

Cmd+Shift+J writes the visible screen to a temporary file and pastes its path into the terminal. Cmd+Ctrl+Shift+J copies the path instead. Cmd+Option+Shift+J opens the file in your editor.

The actions behind these are write_screen_file, write_scrollback_file for the entire history, and write_selection_file. Each takes copy, paste, or open:

keybind = cmd+shift+s=write_scrollback_file:open

Useful when a command produces more output than you want to read in the terminal, and you’d rather search it in your editor.

Select a command’s output

With shell integration, Cmd+triple-click on a command’s output selects all of it. Handy for copying the whole result of a test run.

Clear the screen

Cmd+K clears the screen and the scrollback. This is the terminal clearing itself, not the shell’s clear, so it also works while a program is running.

Keybindings

A keybinding maps a key to a Ghostty action. The binding system also supports ideas you may know from tmux and Vim.

The basic syntax

keybind = trigger=action

The trigger is modifiers and one key joined with +. The action is one of the actions from ghostty +list-actions, with an optional parameter after :.

keybind = cmd+shift+r=reload_config
keybind = ctrl+shift+enter=new_split:down
keybind = cmd+shift+z=toggle_split_zoom

Modifiers are shift, ctrl, alt, and super. Aliases work too: cmd and command for super, opt and option for alt, control for ctrl.

Duplicate triggers override the earlier one. keybind = cmd+d=unbind removes a binding, including a default one. keybind = clear wipes everything set so far, including the defaults, so put it first if you want to start from nothing.

List the actions

ghostty +list-actions --docs

Ghostty 1.3.1 has 85 actions, each with a description. The ones you’ll reach for: new_tab, new_split, goto_split, resize_split, toggle_split_zoom, goto_tab, jump_to_prompt, scroll_page_up, copy_to_clipboard, paste_from_clipboard, increase_font_size, toggle_quick_terminal, toggle_command_palette, reload_config, open_config.

See the current bindings

ghostty +list-keybinds

Shows your bindings merged with the defaults. --default shows only the defaults, which is the fastest way to answer “what’s the shortcut for X on this platform”.

Keys by character or by position

a matches whatever key produces the letter a in your keyboard layout. On an AZERTY keyboard that’s the physical Q key. This is usually what you want.

key_a (or KeyA) matches the physical key where A sits on a US keyboard, regardless of layout. The names come from the W3C key code list: bracket_right, digit_1, arrow_up, backquote, f5, page_down.

Physical keys always win over character keys when both are bound.

This matters for international layouts. On an Italian keyboard the + key sits where a US keyboard has ], so cmd+bracket_right targets that physical key no matter what it prints.

Send text or escape sequences

Three actions send bytes to the program instead of doing something in Ghostty:

keybind = cmd+backspace=text:\x15
keybind = alt+arrow_left=esc:b
keybind = cmd+arrow_up=csi:A

text: uses Zig string literal syntax, so \x15 is Ctrl+U (delete to line start). esc:b sends Escape then b, which bash and zsh read as “word backwards”. csi:A sends the cursor up sequence.

Ghostty’s macOS defaults use this to make Cmd+Left and Cmd+Right go to line start and end, like a text field. Cmd+Backspace deletes to the start of the line.

Key sequences (a leader key)

Separate triggers with > to require them in order:

keybind = ctrl+a>c=new_tab
keybind = ctrl+a>n=next_tab
keybind = ctrl+a>p=previous_tab
keybind = ctrl+a>-=new_split:down
keybind = ctrl+a>|=new_split:right
keybind = ctrl+a>z=toggle_split_zoom
keybind = ctrl+a>x=close_surface
keybind = ctrl+a>ctrl+a=text:\x01

Press Ctrl+A, then C, and you get a new tab. That’s the tmux prefix model, and if you already know tmux your fingers will thank you.

Once ctrl+a is a prefix, pressing it alone does nothing because Ghostty waits for the next key. The final binding sends a real Ctrl+A to the shell when you press it twice, so you can still go to the start of the line.

An unbound key during a sequence sends everything through to the program as if no binding existed.

Prefixes that change how a binding works

Put these before the trigger:

global: makes the binding work even when Ghostty isn’t focused. This is how the quick terminal is meant to be opened. On macOS it needs Accessibility permission, which Ghostty asks for. On Linux it needs a desktop that implements the Global Shortcuts portal (KDE Plasma 5.27 and newer, GNOME 48 and newer).

keybind = global:cmd+backquote=toggle_quick_terminal

all: sends the action to every terminal, not only the focused one. For example, keybind = all:cmd+shift+w=close_window closes every window.

unconsumed: runs the action but also passes the key to the program. unconsumed:cmd+s=reload_config reloads the config and still sends Cmd+S to whatever is running.

performable: only takes the key if the action can do something. With performable:cmd+c=copy_to_clipboard, Cmd+C copies when there’s a selection and otherwise goes through to the program. The macOS defaults use this for copy and paste. The Linux defaults also use it for split navigation when there’s only one split.

Prefixes can stack, but global: and all: bindings always consume the key. Adding unconsumed: to either one does not pass the key through.

Chain actions

Since 1.3, one key can run several actions in order:

keybind = cmd+shift+n=new_window
keybind = chain=toggle_fullscreen

Each chain appends to the most recent binding. You can chain as many as you like, and chains work with sequences too.

Key tables (modal bindings)

Also since 1.3. A key table is a named set of bindings you activate on demand. Inside a table, keys mean something else until you leave.

Here is a resize mode:

keybind = resize/arrow_up=resize_split:up,20
keybind = resize/arrow_down=resize_split:down,20
keybind = resize/arrow_left=resize_split:left,20
keybind = resize/arrow_right=resize_split:right,20
keybind = resize/equal=equalize_splits
keybind = resize/escape=deactivate_key_table
keybind = resize/catch_all=ignore

keybind = cmd+shift+r=activate_key_table:resize

Cmd+Shift+R enters resize mode. Arrows resize in bigger steps than the defaults, = equalizes, Escape leaves. catch_all=ignore swallows every other key so nothing leaks into the shell while you’re in the mode. Ghostty shows an indicator while a table is active, so you know which mode you’re in.

activate_key_table_once:resize is the one-shot version. It leaves the table after the first binding fires.

Table names go before a /. Bindings in the default table stay available inside a custom table unless you shadow them.

catch_all

catch_all matches any key that isn’t otherwise bound. Combined with modifiers, ctrl+catch_all=ignore eats every unbound Ctrl combination. Inside a sequence, ctrl+a>catch_all=end_key_sequence ends the sequence and sends the Ctrl+A through, without the extra key.

Remap modifiers

key-remap = ctrl=super

This makes the physical Ctrl key act as Cmd inside Ghostty only. It’s one way, so Cmd stays Cmd. Sided names like left_ctrl and right_alt work too. It doesn’t change what characters keys produce, only how modifiers are read.

One catch on macOS: menu shortcuts fire before the remap, because macOS handles the menu itself. If a remapped combination collides with a menu item, unbind that item and rebind it with the modifier you want.

Debug a binding with the inspector

Cmd+Option+I (Ctrl+Shift+I on Linux) opens the terminal inspector. Its Keyboard tab shows every key event as Ghostty sees it, with the modifiers and what was sent to the program. When a binding doesn’t fire, this tells you what Ghostty received.

The inspector also shows the raw VT stream and, since 1.3, an overlay of the shell integration prompt regions.

Shell integration

Shell integration is a small script Ghostty loads into your shell. It uses escape sequences to tell Ghostty where the prompt starts, when a command begins and ends, and what the current directory is.

You get:

  • New tabs and splits in the current directory
  • Cmd+Up and Cmd+Down between prompts
  • No close confirmation at an idle prompt
  • A bar cursor at the prompt
  • Prompts that redraw cleanly on resize
  • Cmd+triple-click on macOS, or Ctrl+triple-click on Linux, to select command output
  • Click in the prompt to move the cursor
  • Command finished notifications, if you enable them

How it’s injected

Ghostty looks at the name of the command it’s about to run. If it’s bash, zsh, fish, or nu, it injects the matching script through environment variables. Nothing is written to your dotfiles.

For Elvish, Ghostty adds its module directory to XDG_DATA_DIRS, but it does not load the module. Add this to ~/.config/elvish/rc.elv:

use ghostty-integration
shell-integration = detect

detect is the default. Set a shell name to force it when your shell has an unusual binary name. none disables it.

The Bash that ships with macOS at /bin/bash can’t use automatic injection because of an Apple-specific change to how it handles ENV for interactive shells. Install Bash from Homebrew or source the script manually.

Check that it’s working

Inside Ghostty:

echo $TERM_PROGRAM $TERM $GHOSTTY_RESOURCES_DIR
ghostty xterm-ghostty /Applications/Ghostty.app/Contents/Resources/ghostty

Then open a new tab from a subfolder. If it opens in that folder, integration works.

Source it manually

Automatic injection only covers the first shell. If you start another shell from it, or switch shells with a tool like nix-shell, the new shell has no integration. Sourcing the script in your shell config fixes that. Ghostty sets GHOSTTY_RESOURCES_DIR, so you can guard on it.

Fish, in ~/.config/fish/config.fish:

if set -q GHOSTTY_RESOURCES_DIR
    source "$GHOSTTY_RESOURCES_DIR/shell-integration/fish/vendor_conf.d/ghostty-shell-integration.fish"
end

Zsh, in ~/.zshrc:

if [[ -n $GHOSTTY_RESOURCES_DIR ]]; then
  source "$GHOSTTY_RESOURCES_DIR/shell-integration/zsh/ghostty-integration"
fi

Bash, at the top of ~/.bashrc:

if [ -n "${GHOSTTY_RESOURCES_DIR}" ]; then
    builtin source "${GHOSTTY_RESOURCES_DIR}/shell-integration/bash/ghostty.bash"
fi

If you want to know more about fish, I wrote a complete guide to the Fish shell.

Features

shell-integration-features = cursor,no-sudo,title,no-ssh-env,no-ssh-terminfo,path

That’s the default. Each one can be turned on or off with the no- prefix.

cursor sets the bar cursor at the prompt. title sets the window title from the shell. path adds Ghostty’s binary folder to PATH, which is why ghostty +version works on macOS. sudo wraps sudo so it keeps the TERMINFO variable, fixing the “unknown terminal type” error under sudo. ssh-env and ssh-terminfo are covered in the SSH section.

Command finished notifications

Ghostty 1.3 added command-finish notifications, disabled by default. Enable them, start a long build, and switch to your browser. Ghostty can tell you when the command finishes:

notify-on-command-finish = unfocused
notify-on-command-finish-action = no-bell,notify
notify-on-command-finish-after = 30s

unfocused notifies only when the terminal isn’t focused. always and never are the alternatives. The action can be a bell, a desktop notification, or both. The duration filters out short commands such as ls.

Click to move the cursor

Ghostty 1.3 also lets you click in the current prompt line to move the cursor, like a text field. Fish 4.1 and Nushell 0.111 support this natively. Bash and zsh get it through the Ghostty scripts. cursor-click-to-move = false turns it off.

The quick terminal

The quick terminal slides in from the edge of the screen with a global shortcut. Press the shortcut again to hide it. It works like Quake’s console or iTerm2’s hotkey window.

There’s no default binding. Add one:

keybind = global:cmd+backquote=toggle_quick_terminal

global: means it works from any app. On macOS the first time you’ll be asked for Accessibility permission.

quick-terminal-position = bottom
quick-terminal-size = 40%
quick-terminal-animation-duration = 0
quick-terminal-autohide = true

Position can be top, bottom, left, right, or center. Size is a percentage or pixels, and you can give two values like 50%,900px. On macOS, set the animation duration to 0 if the slide bothers you. That option has no effect on Linux, where slide animation only works through KDE’s Sliding Popups effect. autohide hides the quick terminal when it loses focus. On macOS, quick-terminal-screen = mouse opens it on the screen where the pointer is, useful with several monitors.

Changing the position needs a restart on macOS.

Only one quick terminal exists, and it doesn’t restore after a restart. On macOS it has no tabs because tabs need a titlebar, but splits work. On Linux it only works on Wayland compositors that support wlr-layer-shell, which rules out GNOME.

Inside the quick terminal the GHOSTTY_QUICK_TERMINAL variable is set, so your prompt can look different there.

If you want Ghostty to be only a quick terminal, macos-hidden = always removes it from the Dock and app switcher.

The command palette

Cmd+Shift+P (Ctrl+Shift+P on Linux) opens a searchable list of most actions useful in an interactive session. The complete list stays in ghostty +list-actions. Type a few letters and press Enter to run an action you use rarely, such as copying the screen as HTML or toggling read-only mode.

On macOS the palette also lists your open terminals. Type part of a title or a working directory and jump to it.

Add your own entries:

command-palette-entry = title:"Reset styles",description:"Clear stuck colors and attributes",action:"csi:0m"
command-palette-entry = title:"Split for logs",description:"Open a split below",action:"new_split:down"

Fields are title, description, and action. Quote the values, as the built-in entries do, so commas and colons inside them don’t confuse the parser. Setting command-palette-entry = with no value removes the defaults.

Clipboard and mouse

Copy and paste

Cmd+C and Cmd+V, or Ctrl+Shift+C and Ctrl+Shift+V on Linux. Ctrl+C on Linux still kills the process, which is why the copy shortcut has Shift.

Since 1.3 a copy puts both plain text and HTML on the clipboard, so pasting into a rich text editor keeps colors. If a program you paste into misbehaves, bind copy to plain text only:

keybind = cmd+c=copy_to_clipboard:plain

Formats are mixed, plain, html, and vt. vt includes the escape sequences, for pasting styled text into another terminal.

copy-on-select = clipboard

The default is true. It copies to the selection clipboard on Linux, which is the one middle-click normally pastes from, and to the system clipboard on macOS. clipboard copies to both. false turns it off. On GTK, the desktop setting gtk-enable-primary-paste can disable middle-click paste.

clipboard-trim-trailing-spaces is on by default and strips trailing whitespace from copied lines. selection-clear-on-copy = true deselects after copying.

Paste protection

Pasting text with newlines into a shell runs every line. Ghostty asks first when the paste looks unsafe. clipboard-paste-protection = false turns that off. Programs with bracketed paste mode on, like most shells and editors, are considered safe already.

Programs writing to your clipboard

Tools like Neovim and tmux use OSC 52 to write to the system clipboard, which is how clipboard sharing works over SSH.

clipboard-write = allow
clipboard-read = ask

Writing is allowed by default. Reading asks you, because a program that can read your clipboard can read a password you just copied.

Right click

right-click-action = copy-or-paste

The default shows a context menu. copy-or-paste copies when there’s a selection and pastes otherwise, which matches Windows Terminal. paste, copy, and ignore are the other values.

Word selection

Double-click selects a word. selection-word-chars (1.3) lists the characters that end a word. The default stops at spaces, quotes, brackets, |, $, and punctuation like :;,. To select user:password as one word, set the whole list again without the colon:

selection-word-chars = " \t'\"│`|;,()[]{}<>$"

Hold Cmd (Ctrl on Linux) and hover a URL to underline it, then click to open it in your browser. A preview of the destination appears at the bottom. Cmd+click also opens file paths, including ones with ~.

link-previews = osc8 limits the preview to hyperlinks made with OSC 8, where the visible text differs from the destination. false hides previews.

Mouse in TUI programs

Programs like Vim, htop, and lazygit can capture the mouse. Then a drag selects inside the program instead of in Ghostty. With the default mouse-shift-capture = false, hold Shift to force a Ghostty selection. A TUI can request Shift for itself through XTSHIFTESCAPE; use mouse-shift-capture = never if you always want Shift to select in Ghostty.

mouse-reporting = false

This stops programs from getting mouse events at all. The toggle_mouse_reporting action flips it at runtime, and there’s a palette entry for it.

mouse-hide-while-typing = true hides the pointer as soon as you type. mouse-scroll-multiplier = 2 scrolls faster with a wheel. You can set it separately for precision devices like a trackpad: precision:1,discrete:5.

SSH and terminfo

Ghostty sets TERM=xterm-ghostty. That name tells programs which capabilities the terminal has, by looking up an entry in the terminfo database.

The problem is that most servers don’t have that entry yet. It landed in ncurses at the end of 2024, so it will spread with distro updates, but right now when you SSH into a server you often see:

missing or unsuitable terminal: xterm-ghostty

Programs like less, vim, and htop fail or complain. You have three fixes.

Fix 1: copy the terminfo to the server

infocmp -x xterm-ghostty | ssh myserver -- tic -x -

infocmp dumps the local entry, tic compiles it on the server. Run it once per server. You may see a warning about “older tic versions” from tic, which is safe to ignore.

On macOS before Sonoma, the built-in infocmp is too old for this entry. Install ncurses with Homebrew and use its infocmp instead.

This is the best option because the server gets the full Ghostty capabilities, including styled underlines.

Fix 2: send a different TERM to that host

In ~/.ssh/config:

Host myserver
  SetEnv TERM=xterm-256color

Needs OpenSSH 8.7 or newer. The server sees a terminal type it knows. You lose the features xterm doesn’t advertise, but everything works.

Fix 3: let Ghostty do it

shell-integration-features = ssh-env,ssh-terminfo

With these on, Ghostty’s shell integration wraps ssh. ssh-terminfo tries to install the terminfo on the remote host the first time you connect, using infocmp locally and tic remotely, and remembers the hosts where it succeeded. Until that host is in the cache, the wrapper uses TERM=xterm-256color. With ssh-env enabled, it also sends COLORTERM, TERM_PROGRAM, and TERM_PROGRAM_VERSION.

The cache of hosts is managed with an action:

ghostty +ssh-cache
ghostty +ssh-cache --remove='flavio@203.0.113.10'
ghostty +ssh-cache --clear

List the cache first and copy the exact user@hostname key it shows. The wrapper resolves SSH aliases before it creates that key, so removing the alias itself may do nothing.

Whether the remote accepts the environment variables depends on the server’s sshd_config (AcceptEnv). If you’re setting up servers regularly, my SSH for developers guide covers that side.

sudo

sudo can cause the same error because it resets the environment and drops TERMINFO. Either add Defaults env_keep += "TERMINFO" to your sudoers, or turn on the sudo shell integration feature and Ghostty wraps sudo for you.

What programs can do inside Ghostty

The programs running inside Ghostty can use its modern terminal protocols.

The Kitty graphics protocol lets Yazi show image previews, timg display pictures, and Neovim plugins render diagrams. image-storage-limit caps this memory per screen at 320 MB by default. Set it to 0 to disable images.

Ghostty also supports the Kitty keyboard protocol. It gives programs unambiguous key events, so Neovim can distinguish Ctrl+I from Tab and detect Shift+Enter. Helix and Zellij use it too.

OSC 8 lets a program print clickable text with a hidden URL. GNU ls --hyperlink on Linux and rg --hyperlink-format=default use it. macOS ships BSD ls, which has no --hyperlink option. In Ghostty you Cmd+click the file name.

Mode 2026 provides synchronized output. A program can ask Ghostty to wait before painting, which removes tearing in editors and TUI apps.

Programs send desktop notifications through OSC 9 and OSC 777. Set desktop-notifications = false to block them. The ConEmu OSC 9;4 sequence provides progress indicators for long tasks, while progress-style = false tells Ghostty to ignore them.

Programs can ask Ghostty whether it uses a light or dark color scheme. They also get notified when it changes, which lets Neovim switch its theme with macOS. Editors can use colored curly, dotted, and dashed underlines for diagnostics.

Shell integration uses OSC 133 to mark prompts and commands. Those marks power prompt jumping, output selection, and finish notifications. OSC 52 provides the clipboard support covered earlier.

Programs can also set the window title. title = " " (a space) forces a blank title and ignores those requests. title-report lets programs read the title back, and it’s off by default because it’s a known attack vector.

Ghostty documents its implemented sequences in the VT reference. The project labels that reference as incomplete, so treat it as a useful starting point rather than an exhaustive list.

Run a command instead of a shell

Set command to replace your shell:

command = /opt/homebrew/bin/fish

command is what every new terminal runs. If you leave it unset, Ghostty uses your SHELL variable or the login shell from the system. Arguments are fine, and the command runs through /bin/sh -c when it has them. direct:nvim notes.md skips the shell. shell: forces one.

initial-command is the same but only for the first terminal after launch.

From the command line, -e runs a command in a new instance:

ghostty -e top

On macOS, from another terminal:

open -na Ghostty.app --args -e top

When the command exits the window closes. wait-after-command = true keeps it open until you press a key, which is useful for a script you launch from a Finder icon and want to read the output of.

env = EDITOR=nvim
env = PAGER=less
input = raw:echo hello\n
working-directory = ~/dev

env adds environment variables to every terminal. input (1.2 and later) types text into the terminal at startup. path: reads it from a file instead of raw:.

Notifications and the bell

A program rings the bell by printing \a. Ghostty can respond in several ways:

bell-features = attention,title,border,audio
bell-audio-path = ~/sounds/ping.wav
bell-audio-volume = 0.4

attention bounces the Dock icon once when Ghostty isn’t focused (on Linux it depends on the desktop). title puts a 🔔 in the tab title until you interact. border draws a border around the terminal that rang. audio plays your file, on macOS since 1.3. system uses the system alert sound.

The defaults are attention and title, no border and no sound. A relative audio path is resolved from the config file’s folder, and ~/ works.

Custom shaders

Ghostty can run GLSL fragment shaders over the rendered terminal, in the Shadertoy format. This is how people get CRT curvature, scanlines, glowing cursors, and cursor trails.

Write a mainImage function. iChannel0 is the rendered terminal, iResolution its size, iTime the seconds since start. A vignette:

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
  vec2 uv = fragCoord.xy / iResolution.xy;
  vec4 color = texture(iChannel0, uv);
  float d = distance(uv, vec2(0.5));
  fragColor = color * (1.0 - d * 0.4);
}

Save it and point the config at it:

custom-shader = /Users/flavio/.config/ghostty/shaders/vignette.glsl
custom-shader-animation = false

Several custom-shader lines run in order, each receiving the previous output. custom-shader-animation = true keeps redrawing so time-based shaders animate, at some CPU cost. false redraws only on terminal updates. always animates even unfocused terminals.

Ghostty adds uniforms that Shadertoy doesn’t have: iCurrentCursor and iPreviousCursor with position and size, iTimeCursorChange, iCurrentCursorColor, iFocus, the whole iPalette, and the background and foreground colors. These are what make cursor trail shaders possible.

A broken shader is ignored, and the error only shows in the logs. If the window goes black, remove the custom-shader line and reload.

The Shaders section of awesome-ghostty collects ready-made files. hackr-sh/ghostty-shaders includes cursor_blaze.glsl, cursor_lightning.glsl, a smear cursor, bloom, CRT, matrix, and starfield variants.

There is also a separate CRT shader with scanlines and chromatic aberration. Download the .glsl file, point custom-shader at it, and reload.

macOS specifics

The Option key

On a US layout, Option+B types . Terminal programs want Option to work as Alt, so Alt+B means “back a word” in your shell.

macos-option-as-alt = true

left and right let you keep one Option key for special characters and use the other as Alt. When unset, Ghostty picks true for the US layouts and false for everything else, because on most European layouts you need Option to type characters like @ and [.

Secure input

When Ghostty detects a password prompt, it enables macOS Secure Input, which stops other apps from reading your keystrokes. macos-auto-secure-input = false turns off the detection, and Ghostty > Secure Keyboard Entry in the menu toggles it by hand. The detection is a heuristic and it doesn’t work over SSH, so for a password on a server turn it on from the menu.

The app icon

macos-icon = retro

Variants are blueprint, chalkboard, microchip, glass, holographic, paper, retro, and xray. custom uses your own .icns or PNG from macos-custom-icon. custom-style recolors the official icon with macos-icon-ghost-color and macos-icon-screen-color. macos-icon-frame chooses the frame material.

Default terminal

The Ghostty menu has “Set Ghostty as Default Terminal App” since 1.3. After that, opening a .command file or a folder with “Open in Terminal” services uses Ghostty.

Shortcuts and AppleScript

Ghostty exposes actions to the Shortcuts app: create terminals, send text, run commands, and invoke keybind actions. The available actions depend on your macOS version. Command-palette actions need macOS 14, while New Terminal and its command parameter need macOS 15. macos-shortcuts = ask prompts the first time, then remembers.

AppleScript support arrived in 1.3 as a preview. You can address windows, tabs, and terminals, and send them text:

tell application "Ghostty"
    set term to focused terminal of selected tab of front window
    input text "git status\n" to term
end tell

macos-applescript = false disables it. macOS asks for Automation permission before another app can control Ghostty.

Updates

Ghostty updates itself on macOS through Sparkle. auto-update = check notifies you, download also fetches the update, off disables it. Ghostty doesn’t add any tracking to this: it downloads the version info and compares it locally. “Check for Updates” is in the command palette.

auto-update-channel = tip

tip gets a build from every commit to the main branch. It’s what the private beta ran on, and it’s how you get features before the next stable release. Needs a restart to take effect.

Small things

macos-window-shadow = false removes the shadow, which looks better with transparency. macos-dock-drop-behavior = new-window opens a new window when you drop a folder on the Dock icon, instead of a tab. window-step-resize = true resizes in whole cells. toggle_window_float_on_top keeps a window above everything else. toggle_visibility hides and shows all windows.

Linux specifics

Ghostty on Linux needs GTK 4.14 or newer and libadwaita 1.5 or newer. It follows the system light or dark appearance and works on both Wayland and X11. Arbitrary third-party GTK themes aren’t guaranteed to carry through libadwaita.

One process or many

gtk-single-instance = detect

With single instance, running ghostty again opens a new window in the existing process instead of a second app. detect chooses a separate process when you pass CLI flags or TERM_PROGRAM is already set. That environment check is a heuristic for launching Ghostty from another terminal. ghostty +new-window opens a window in the running instance, which is handy from a script or a launcher.

Titlebar and tabs

gtk-titlebar-style = tabs
gtk-tabs-location = bottom
gtk-wide-tabs = false
gtk-titlebar-hide-when-maximized = true

tabs merges tabs into the titlebar like the macOS option. gtk-tabs-location = hidden replaces the bar with a tab counter button that opens the tab overview. window-show-tab-bar = always shows the bar even with one tab. gtk-toolbar-style picks flat, raised, or raised-border.

The tab overview (toggle_tab_overview) is a grid of all your tabs, GNOME style.

Decorations

window-decoration = server asks the compositor to draw the titlebar, which KDE and most non-GNOME desktops support. client draws it with GTK. none removes it, which tiling window manager users usually want.

Cgroups

linux-cgroup = always
linux-cgroup-memory-limit = 4294967296

Each terminal can run in its own systemd scope. The default is single-instance, so Ghostty attempts this when it runs as a single instance. The memory limit is a soft MemoryHigh limit in bytes. It does not kill the tab by itself. Configure an OOM monitor such as systemd-oomd if you want pressured scopes terminated, and remember that Ghostty continues if cgroup creation fails.

Custom CSS

gtk-custom-css = /home/flavio/.config/ghostty/ghostty.css

GTK widgets are styled with CSS, so you can restyle the tab bar or titlebar. Run env GTK_DEBUG=interactive ghostty to get the GTK inspector and see what to target. This syntax works in fish too.

Quick terminal and global shortcuts

The quick terminal needs Wayland and a compositor with wlr-layer-shell. KDE, Hyprland, and Sway work. GNOME doesn’t. gtk-quick-terminal-layer picks where it stacks. Slide animations only happen on KDE with the Sliding Popups effect.

Global keybinds need the XDG Global Shortcuts portal. KDE Plasma 5.27 and GNOME 48 have it. Other desktops depend on their portal implementation, so check yours before spending time on a global: binding that will never fire.

quick-terminal-autohide defaults to false on Linux, because global shortcuts are harder to set up there and you may want the terminal to stay while you go set it up.

GTK keyboard defaults

Since Ctrl+C has to reach the shell, most shortcuts use Ctrl+Shift. The full table is in the Default shortcuts section near the start of the article. ghostty +list-keybinds --default prints them for your version.

Ghostty and coding agents

I run coding agents in the terminal most of the day.

Agents like Claude Code, Codex, and cursor-agent produce a lot of output with hyperlinks, emoji, and colored regions. Ghostty 1.3 fixed a memory leak that showed up with Claude Code running for hours. If you noticed Ghostty’s memory growing with an agent open, update.

An agent can also help you configure Ghostty. Ghostty ships no official MCP server or agent plugin, although community projects exist. The CLI already gives an agent everything it needs. If you keep your dotfiles in a repo, this is what I’d put in its AGENTS.md:

## Ghostty

- The preferred config file is `~/.config/ghostty/config.ghostty`.
- Run `ghostty +show-config --default --docs` for the full option reference of the installed version. Do not rely on memory for option names.
- Validate changes with `ghostty +validate-config` before finishing.
- List actions with `ghostty +list-actions --docs` and current bindings with `ghostty +list-keybinds`.
- There is no `+reload-config` CLI action. On macOS, reload with Cmd+Shift+, or use AppleScript to perform the `reload_config` action on the focused terminal.

The +edit-config action opens the file but does not reload it. An agent on macOS can trigger the reload itself:

osascript -e 'tell application "Ghostty" to perform action "reload_config" on focused terminal of selected tab of front window'

On Linux and FreeBSD, the GTK app reloads its configuration when it receives SIGUSR2.

The TERM_PROGRAM=ghostty variable lets a script or an agent detect it’s running inside Ghostty and use features like OSC 8 links or images.

On macOS, AppleScript and Shortcuts make Ghostty scriptable from outside. An agent can type into a specific terminal without a separate Python API. iTerm2 has long supported targeted input through AppleScript too.

If you run several agents at once and want notification rings, workspaces, and a browser next to the terminals, that’s what cmux does, on top of libghostty. Ghostty itself stays a terminal.

Ghostty with tmux

Ghostty has tabs and splits, so do you still need tmux?

For local work, Ghostty’s splits are nicer: native, mouse-friendly, and they don’t interfere with scrollback or copy and paste the way tmux panes do. The key sequences let you drive them with a prefix key if that’s what your fingers know.

The main reason I still use tmux is session persistence. Close Ghostty, or lose an SSH connection, and a tmux session keeps running on the server. Ghostty can’t do that. Tmux also provides sharing, scripting, remote control, and reusable layouts.

Ghostty has no finished tmux control-mode integration yet. Control mode is a tmux protocol that iTerm2 uses to show tmux windows as native tabs. Ghostty 1.3.1 contains parser groundwork, but it isn’t connected to the desktop interface.

For that split, I’d use Ghostty tabs and splits locally, then tmux on servers where the session must keep running.

Common problems

Option+key types a strange character

Set macos-option-as-alt = true, or left to keep the right Option for special characters.

'xterm-ghostty': unknown terminal type on a server

See the SSH section. The one-liner with infocmp and tic is the quickest fix.

sudo reports an unknown terminal type

Turn on the sudo shell integration feature or preserve TERMINFO in sudoers.

New tabs don’t open in the current folder

Shell integration isn’t running. Check echo $GHOSTTY_RESOURCES_DIR.

Nested shells normally inherit this variable but lose automatic integration, so source the script manually when the variable exists. If it’s empty, Ghostty’s resource environment is missing or has been cleared.

A config change did nothing after reload

Some options apply only to new terminals, including padding, font-codepoint-map, and scrollback-limit. On macOS, background-opacity and quick-terminal-position need a restart.

Use ghostty +show-config to check that the value loaded. Then run ghostty +validate-config to check that the file parses.

The ghostty command isn’t found

On macOS it’s only on PATH inside Ghostty, through the path shell integration feature. Elsewhere use /Applications/Ghostty.app/Contents/MacOS/ghostty, or symlink it.

Tabs disappeared after going fullscreen

You’re using non-native fullscreen or window-decoration = none. Both remove the titlebar, and macOS tabs live in the titlebar.

Text looks thin on macOS

Set font-thicken = true.

A global: keybind does nothing on macOS

Grant Accessibility permission in System Settings > Privacy & Security > Accessibility. Ghostty asks once, and if you dismissed it you have to add it by hand.

Ctrl+Shift shortcuts on Linux conflict with an app

Rebind them. keybind = ctrl+shift+e=unbind frees a key for the program.

Vim can’t tell some keys apart

Ghostty supports the Kitty keyboard protocol. Neovim enables it automatically. In Vim, check :help keyprotocol.

The terminal is stuck after a program crashes

Use the reset action or the reset command. The action is available in the command palette.

I want the old plain text copy

Use keybind = cmd+c=copy_to_clipboard:plain. The 1.3 default copies both plain text and HTML.

A complete starter config

Here is a config that pulls together the pieces from this guide. Copy what you want, leave the rest.

# ~/.config/ghostty/config.ghostty

# Font
font-family = JetBrains Mono
font-size = 14
font-feature = -calt
adjust-cell-height = 5%

# Theme
theme = light:Catppuccin Latte,dark:Catppuccin Mocha
minimum-contrast = 1.1
cursor-style = bar
cursor-style-blink = false

# Window
window-padding-x = 8
window-padding-y = 6
window-padding-balance = true
window-padding-color = extend

# Scrollback
scrollback-limit = 50000000

# Clipboard
copy-on-select = clipboard
right-click-action = copy-or-paste

# Shell integration
shell-integration-features = cursor,sudo,title,ssh-env,ssh-terminfo,path
notify-on-command-finish = unfocused
notify-on-command-finish-action = no-bell,notify
notify-on-command-finish-after = 20s

# Quick terminal
keybind = global:cmd+backquote=toggle_quick_terminal
quick-terminal-position = bottom
quick-terminal-size = 40%
quick-terminal-animation-duration = 0

# Splits
unfocused-split-opacity = 0.85
split-preserve-zoom = navigation

# Resize mode
keybind = resize/arrow_up=resize_split:up,20
keybind = resize/arrow_down=resize_split:down,20
keybind = resize/arrow_left=resize_split:left,20
keybind = resize/arrow_right=resize_split:right,20
keybind = resize/equal=equalize_splits
keybind = resize/escape=deactivate_key_table
keybind = resize/catch_all=ignore
keybind = cmd+shift+r=activate_key_table:resize

# Machine-specific overrides, not in git
config-file = ?local

Run ghostty +validate-config after saving, then Cmd+Shift+, to reload.

Tagged: CLI · All topics

Want me to talk about your product? You can sponsor this site.

~~~

Related posts about cli: