cheat sheet

htop

Interactive process and resource monitor for the terminal. Covers function keys, sorting, filtering, signal sending, tree view, threads, and how to read load averages and memory correctly. Compares with top, btop, and bottom.

htop — Interactive Process Viewer

What it is

htop is an interactive, color, full-screen process and resource monitor for the terminal, written in C by Hisham Muhammad in 2004 (and maintained today by the htop-dev collective). It reads /proc to show every running process, sortable and filterable in real time, plus CPU, memory, and swap meters across the top. Reach for htop whenever a one-shot ps aux or top snapshot isn't enough — it's the standard tool for "what's hogging the CPU?" or "kill this stuck worker"; top is the always-present POSIX fallback, and btop (newer, written in C++) is the visually richer alternative.

Install

htop is packaged on every mainstream Linux distribution and macOS via Homebrew, and ships as a single static binary if you need to drop it on a stripped-down container.

bash
# Debian/Ubuntu
sudo apt install htop

# Fedora
sudo dnf install htop

# Arch
sudo pacman -S htop

# macOS
brew install htop

# Alternatives
brew install btop     # nicer UI, more meters
# top ships with every Unix already

Output: (none — exits 0 on success)

Syntax

htop is launched without arguments for the default view, or with a small set of flags to pre-filter what it shows. Once running, all interaction is keyboard-driven (mouse is supported in most terminals).

bash
htop [OPTIONS]
htop -p PID[,PID...]
htop -u USER
htop -s COLUMN

Output: (none — exits 0 on success)

Essential CLI options

OptionMeaning
-p PID[,PID...]Watch only the listed PIDs
-u USERShow only USER's processes
-s COLUMNSort by COLUMN at startup (e.g. PERCENT_CPU, PERCENT_MEM)
-d DELAYRefresh delay in tenths of a second (default 15 = 1.5s)
-tStart in tree view
-HShow user threads (kernel threads off)
-CMonochrome (no colors) — NO_COLOR=1 env var works too (3.5+)
--no-mouseDisable mouse support
--no-metersHide the header meters (3.5+)
--no-function-barHide the F1–F10 bar at the bottom (3.5+)
--readonlyDisable kill / nice / setpriority (safe for shared boxes)
--helpShow all options
--versionPrint version

Default screen layout

The interface is divided into a header (CPU/memory/swap meters plus load average and uptime), the process list (scrollable, sortable table), and a function-key bar at the bottom showing F1F10 actions.

text
  1  [|||||||||||||||                   38.2%]   Tasks: 142, 287 thr; 3 running
  2  [|||||||||||||||||||||||||||       72.4%]   Load average: 0.84 0.61 0.40
  3  [||||||||||                        21.7%]   Uptime: 2 days, 04:13:55
  4  [||||||||||||                      27.0%]
  Mem[|||||||||||||||         3.42G/15.6G]
  Swp[                              0K/2.00G]

    PID USER      PRI  NI  VIRT   RES   SHR S CPU% MEM%   TIME+  Command
   4521 alice      20   0  712M  402M  20M R 88.4  2.6   1:42.11 python3 train.py
   1234 www-data   20   0  124M   15M  12M S  0.7  0.1   0:02.31 nginx: worker
   8800 root       20   0   23M  6.4M 5.6M S  0.0  0.0   0:00.04 sshd
   8821 alice      20   0   18M  4.2M 3.4M S  0.0  0.0   0:00.02 -bash
    ...
  F1Help F2Setup F3Search F4Filter F5Tree F6SortBy F7Nice- F8Nice+ F9Kill F10Quit

Function keys

F1F10 are the discoverable, always-visible actions. They also have single-letter equivalents that don't require an Fn key (useful in macOS terminals where function keys go to the system).

KeyAltAction
F1hHelp screen
F2SSetup — meters, columns, colors
F3/Search (incremental, highlights matches)
F4\\Filter (only matching processes shown)
F5tToggle tree view
F6< >Choose sort column
F7[Decrease nice value (raise priority)
F8]Increase nice value (lower priority)
F9kKill — send signal to selected process
F10qQuit
bash
htop          # then press F4, type "nginx", Enter — only nginx procs remain

Output:

text
    PID USER      CPU% MEM% Command
   1234 www-data   0.5  0.1 nginx: master process /usr/sbin/nginx
   1235 www-data   0.3  0.1 nginx: worker process
   1236 www-data   0.3  0.1 nginx: worker process

Sorting keys

< and > move through the sort-column list; the on-screen heading shows the active column highlighted. The three most-used one-key shortcuts pre-select the typical sorts:

KeySort by
MMemory (descending)
PCPU% (descending)
TCumulative TIME+
NPID
IInvert current sort order
bash
htop -s PERCENT_MEM    # pre-sort by RAM at launch
htop -s TIME           # pre-sort by cumulative CPU time

Output (M sort):

text
    PID USER      MEM%   RES  Command
   4521 alice      2.6  402M  python3 train.py
   2100 postgres   1.2  192M  postgres
   1234 www-data   0.1   15M  nginx: master

Tree view (F5 / t)

Tree view replaces the flat process list with parent → child indentation, so you can see at a glance which daemon spawned a runaway worker. Toggling it preserves the current sort and filter; the indented children still sort by the active column within each parent.

bash
htop -t       # start in tree view
# or press F5 / t at any time to toggle

Output:

text
    PID USER      CPU% MEM% Command
      1 root       0.0  0.0 /sbin/init
    423 root       0.0  0.1 ├─ systemd-journald
    611 root       0.0  0.0 ├─ cron
    800 root       0.0  0.0 ├─ sshd
   8800 root       0.0  0.0 │  └─ sshd: alicedev [priv]
   8820 alice      0.0  0.0 │     └─ sshd: alicedev@pts/0
   8821 alice      0.0  0.0 │        └─ -bash
   9210 alice      0.0  0.0 │           └─ htop
   1234 www-data   0.5  0.1 └─ nginx: master process
   1235 www-data   0.3  0.1    ├─ nginx: worker
   1236 www-data   0.3  0.1    └─ nginx: worker

Threads (H)

By default htop shows one row per process. Pressing H toggles user-thread visibility, which is essential for diagnosing multi-threaded apps (a JVM, a Python process with thread pools) — without it, a 16-thread process eating 800% CPU shows up as a single 800% row with no way to see which thread is hot. K toggles kernel threads on/off similarly.

bash
htop -H       # threads visible at launch

Output (Java app, H enabled):

text
    PID USER      CPU% Command
   5821 alice    104.0 java -jar app.jar
   5822 alice     32.1 GC Thread#0
   5823 alice     28.7 GC Thread#1
   5824 alice     18.2 main
   5825 alice     12.0 http-worker-1

Search vs. filter (F3 vs. F4)

These look similar but behave differently. Search (F3 / /) jumps the cursor to each matching process but keeps every row visible; press the key repeatedly to walk through hits. Filter (F4 / \\) hides every non-matching row until you press F4 again with an empty query.

bash
# Inside htop:
#   /nginx  → cursor jumps from match to match; all rows still visible
#   \nginx  → only matching rows shown; counter at top updates
#   \       → with empty pattern, restores full list

Output (after \\nginx):

text
    PID USER      CPU% Command
   1234 www-data   0.5 nginx: master process
   1235 www-data   0.3 nginx: worker process

Sending signals (F9 / k)

Pressing F9 opens a signal-picker side panel; the default is SIGTERM (15) — polite. Use SIGKILL (9) only as a last resort, after SIGTERM and SIGINT (2) have been ignored. SIGHUP (1) is the canonical "reload config" signal for daemons.

SignalNumberUse
SIGTERM15Polite "please exit" (default)
SIGINT2Like Ctrl-C
SIGHUP1Reload config (for daemons)
SIGKILL9Force kill — process can't catch or ignore
SIGSTOP / SIGCONT19 / 18Pause / resume
SIGUSR1 / SIGUSR210 / 12App-defined
text
   Send signal:
   ✱ 15 SIGTERM
     9  SIGKILL
     2  SIGINT
     1  SIGHUP
     ...

You can also select multiple processes with Space (toggles a tag), then press F9 to signal all tagged processes at once.

Watching a single PID (-p)

htop -p <PID> (one or comma-separated PIDs) pins the view to just those processes, with the meters still showing system-wide stats. Combined with pgrep, this is the quickest way to live-monitor one service.

bash
htop -p $(pgrep -d, nginx)            # all nginx PIDs as a single arg
htop -p $(pgrep -d, -f 'python.*train.py')

Output:

text
    PID USER      CPU% MEM% Command
   1234 www-data   0.5  0.1 nginx: master process
   1235 www-data   0.3  0.1 nginx: worker
   1236 www-data   0.3  0.1 nginx: worker

Setup (F2)

F2 opens a configuration screen where you can change meters in the header, add or remove columns from the process list, and pick a color scheme. Changes are written to ~/.config/htop/htoprc and persist across launches.

text
Active                                Available
  Left column                           Meters
    > CPU                                 - CPU
    > Memory                              - Memory
                                          - Swap
  Right column                            - Load average
    > Tasks                               - Uptime
    > Load average                        - Battery
    > Uptime                              - Hostname
                                          - All CPUs
                                          - Disk IO
                                          - Network IO
bash
# Common customisations
# - Show all CPU cores as one bar to save space:
#   F2 → Meters → CPUs (1/1) [Bar] or [Text]
# - Add Disk IO and Network IO meters
# - Add IO_RATE column to the process list

Output: (none — exits 0 on success)

Configuration

htop persists everything you change in F2 Setup to ~/.config/htop/htoprc — meters, columns, colour scheme, refresh delay, hide-kernel-threads, and so on. The file is plain key=value text and is safe to edit by hand, copy between machines, or version-control alongside your dotfiles. Since 3.4 htop and pcp-htop keep separate config files so the two don't clobber each other.

bash
# Inspect the live config
cat ~/.config/htop/htoprc

# Back up before experimenting
cp ~/.config/htop/htoprc ~/.config/htop/htoprc.bak

# Reset to defaults (htop rewrites the file on next quit)
rm ~/.config/htop/htoprc
htop                # change nothing, then F10 — fresh file is written

Output (cat, abridged):

text
fields=0 48 17 18 38 39 40 2 46 47 49 1
sort_key=46
sort_direction=-1
tree_sort_key=0
hide_kernel_threads=1
hide_userland_threads=0
shadow_other_users=0
show_thread_names=0
show_program_path=1
color_scheme=0
delay=15
left_meters=AllCPUs Memory Swap
left_meter_modes=1 1 1
right_meters=Tasks LoadAverage Uptime
right_meter_modes=2 2 2
KeyMeaning
fields=…Process-list columns, by numeric column ID
sort_key / sort_directionDefault sort column and direction (-1 desc)
delayRefresh delay in tenths of a second
hide_kernel_threads / hide_userland_threadsWhat to hide by default
show_program_path1 = full path, 0 = command basename only
color_scheme0=default, 1=monochrome, 5=broken-grey, 6=Nord (3.5+)
left_meters / right_metersHeader meters by name (CPU, Memory, GPU, DiskIO, …)

htop writes the file when you quit cleanly; if you edit it while htop is running, your changes will be overwritten on exit. Make sure no other instance is active before hand-editing.

What's new in htop 3.4 and 3.5

The htop-dev team have been steadily landing modern monitoring features. 3.4 (March 2025) added a GPU meter and per-process GPU time column — the first time htop could show NVIDIA/AMD GPU utilisation alongside CPU. 3.5 (released later in 2025) added a backtrace screen built on libunwind-ptrace so you can inspect the call stack of any process without dropping to gdb, plus a clean Nord colour theme, a proper inline line editor for search/filter/screen-rename, and --no-meters / --no-function-bar for embedding htop in tmux panes without visual clutter.

VersionHeadline additions
3.5.xBacktrace screen (libunwind-ptrace); Nord theme; line editor for search/filter; --no-meters, --no-function-bar; NO_COLOR env support; CPU SMT label option; redesigned DiskIO meter (rate + time sub-meters); macOS GPU meter; OpenRC support
3.4.xGPU meter (Linux + PCP); per-process GPU time column; single-column header layout; per-platform config file (~/.config/htop/htoprc vs. pcp-htop); dynamic CPU-column width based on max PID; better ARM Darwin support
3.3.xDocker / Podman container ID shortening (12 chars); FreeBSD truss support; Darwin NetworkIOMeter; 3-column header layouts; container-name filtering from cgroup names
bash
# Add the GPU meter (3.4+) — F2 → Meters → GPU → add to a column
# Add the GPU time column   — F2 → Columns → GPU_TIME

# Open the backtrace screen (3.5+) — select a process, then
#   F2 → Screens → add "Backtrace" → assign to F6 or a Tab key

# Embed htop in a tmux pane with no chrome
htop --no-meters --no-function-bar

Output: (none — exits 0 on success)

Reading the header

The header has more nuance than it looks. Load average is a running average of runnable + uninterruptible processes over 1, 5, and 15 minutes — not a CPU percentage. Mem colors mean: green = used, blue = buffers, yellow = cache. The cache portion is "free if anything else needs it" — Linux deliberately uses spare RAM as disk cache, so a host showing 90% used is usually healthy.

DisplayWhat to look for
Load average: 1.20 0.80 0.40First number > number of CPU cores → over-saturated
`Mem[
Swp[ 0K/2.00G]Any swap use is a yellow flag; sustained use is a red flag
Tasks: 142, 287 thr; 3 running"3 running" should generally be ≤ core count
bash
# Sanity-check load average against core count
nproc
uptime

Output:

text
4
 10:14:33 up 2 days,  4:13,  1 user,  load average: 0.84, 0.61, 0.40

htop vs. top vs. btop vs. bottom

top is POSIX and present on every Unix — when you SSH into a box with nothing installed, it's the fallback. htop is the everyday upgrade: colour, scrollable, mouse-aware, function keys for kill/nice/sort, and (since 3.4/3.5) GPU meters and a backtrace screen. btop (the C++ successor to bpytop, which was itself the Python successor to bashtop) is the maximalist option — Braille graphs for CPU/network/disk, mouse-driven menus, animated time-series. bottom (binary name btm) is the keyboard-first Rust alternative with a unique TOML layout system so you can carve the screen into any arrangement of panes you like. bpytop itself is no longer actively developed — it's been fully superseded by btop (and the Rust rewrite is now landing in distros as btop 4.x).

Featuretophtopbtopbottom (btm)
In every base installyesnonono
Language / runtimeCCC++ (Rust 4.x)Rust
Colour UIoptionalyesyesyes
Mouse supportnoyesyesyes
Scroll horizontallynoyesyesyes
Tree viewpartial (V)yes (F5)yesyes
Per-thread viewyes (H)yes (H)yesno
CPU/Net/Disk graphsnobasic metersrich Braillerich Braille
GPU meternoyes (3.4+)yesyes
Backtrace screennoyes (3.5+)nono
Custom layoutnoheader onlypreset viewsfull TOML config
Colour themesnoa few (Nord 3.5+)manymany
Footprinttinysmallmediumsmall
bash
top -o +%CPU       # POSIX top, sorted by CPU
top -H             # show threads (Linux top)
btop               # if installed; q to quit
btm                # bottom; press ? for help, q to quit
btm --basic        # bottom in compact, no-graph mode

Output (top -o +%CPU, abridged):

text
top - 10:14:33 up 2 days,  4:13,  1 user,  load average: 0.84, 0.61, 0.40
Tasks: 142 total,   3 running, 139 sleeping
%Cpu(s): 38.2 us,  5.1 sy,  0.0 ni, 56.0 id

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
 4521 alice     20   0  712340 402100  20012 R  88.4   2.6   1:42.11 python3
 1235 www-data  20   0  126484  15280  12044 S   0.7   0.1   0:02.31 nginx

Rule of thumb: reach for top on a stripped-down jumpbox, htop for everyday triage and the backtrace screen, btop when you want pretty graphs over time on a desktop or home-lab box, and bottom when you need a custom multi-pane layout you can check into dotfiles.

Common pitfalls

  1. "100% CPU" with one core saturated — the per-process CPU% is summed across cores, so a single thread maxing one of four cores reads as 100%, not 25%. Toggle to system-percent in Setup if you want the latter.
  2. Memory looks "full" but the system is fine — yellow bar segments are file cache that Linux will release on demand. Real pressure shows up as growing Swp usage or D-state processes blocked on I/O.
  3. Load average ≠ CPU percentage — a load of 8 on a 16-core box is half-utilised; a load of 8 on a 4-core box is queueing two-deep. Always compare to nproc.
  4. Threads invisible — by default htop hides user threads; press H (or launch with -H) when investigating Java/Python/Go programs.
  5. Sort column won't stay set — in tree view sorting groups within siblings only; press F5 again to leave tree mode if you need a global sort.
  6. Function keys hijacked by terminal — iTerm2 and macOS Terminal sometimes swallow F2/F9. Use the letter equivalents (S, k) instead, or remap in Terminal preferences.
  7. htop shows wrong colors over SSHTERM is set to xterm instead of xterm-256color. Run export TERM=xterm-256color (or tmux-256color inside tmux).

Real-world recipes

Find the top three CPU eaters and kill the worst

A two-shortcut workflow: P sorts by CPU, Space tags processes, F9 kills them all at once.

text
htop
  → press P            # sort by CPU
  → Space x3 on top 3  # tag them
  → F9 → 15            # SIGTERM tagged processes

Output: (the tagged rows disappear within a refresh tick)

text
    PID USER      CPU% Command
   1234 www-data   0.5 nginx: master
   8821 alice      0.0 -bash
   9210 alice      0.0 htop

Watch a single misbehaving service

When a service is the suspect, narrow the picker to just its PIDs and turn threads on so you can see which worker is hot.

bash
htop -H -p $(pgrep -d, -f 'gunicorn|uwsgi')

Output:

text
    PID USER      CPU% MEM% Command
   5021 www-data  62.1  3.4 gunicorn: worker [app:wsgi]
   5022 www-data  41.9  3.2 gunicorn: worker [app:wsgi]
   5020 www-data   0.1  3.1 gunicorn: master [app:wsgi]

"What changed?" snapshot for a bug report

Press F2 → enable "All CPUs (1/1) [Text]" to compact the header, then capture the screen with tmux capture-pane or your terminal's native screenshot. Pair with journalctl -u myapp -n 50 for the matching log slice.

bash
tmux capture-pane -p -S - > /tmp/htop-snapshot.txt
journalctl -u myapp -n 50 --no-pager > /tmp/myapp-50.log

Output: (none — exits 0 on success)

Stuck process: which syscall is it blocked on?

htop shows the S state column — D means "uninterruptible sleep" (usually disk I/O). When you spot one, drop to strace -p PID for the syscall it's stuck in.

bash
htop                       # find a D-state PID, say 7821
sudo strace -p 7821 -e trace=desc

Output:

text
strace: Process 7821 attached
read(8, ...

Quick comparison: are these workers balanced?

Run htop filtered to the worker pool. If one row is at 80% and the others near 0%, the load balancer or work queue is misrouting work.

bash
htop -p $(pgrep -d, -f 'celery worker') -s PERCENT_CPU

Output:

text
    PID USER      CPU% Command
   8801 alice     78.4 celery worker -A app -Q default
   8802 alice      2.1 celery worker -A app -Q default
   8803 alice      1.0 celery worker -A app -Q default
   8804 alice      0.7 celery worker -A app -Q default

On servers you administer alongside others, run htop --readonly — it disables kill / nice / setpriority so a misclick can't take down a process. Combine with alias htop='htop --readonly' for shared bastions.

If you live in tmux, bind a prefix key to "split + run htop": bind-key h split-window -h 'htop'. Press prefix h and you have a live process pane next to whatever you're working on.

Sources