htop and btop are interactive process monitors that replace the aging top command with color-coded dashboards, mouse support, and built-in process management. If you've ever stared at top trying to figure out which process is eating your CPU, these tools make it obvious in seconds.
In short: use htop for a fast, lightweight process viewer that works everywhere, and btop when you want a full system dashboard with CPU graphs, network stats, and disk I/O in one screen. Both let you kill processes, change priorities, and filter by name — all without leaving the terminal.
Why top Isn't Enough
The top command ships with every Linux system, and for quick checks it works. But after using it for years on production servers, I hit the same frustrations over and over:
- No mouse support — you navigate entirely with cryptic single-key commands
- No horizontal scrolling — long command lines get truncated with no way to see them
- Ugly defaults — monochrome output with no visual distinction between CPU, memory, and swap
- Killing a process requires typing the PID — you can't just select and kill
Here's what top actually shows you:
top - 14:32:01 up 47 days, 3:12, 2 users, load average: 2.31, 1.87, 1.45
Tasks: 312 total, 1 running, 308 sleeping, 0 stopped, 3 zombie
%Cpu(s): 15.2 us, 3.1 sy, 0.0 ni, 80.4 id, 0.8 wa, 0.0 hi, 0.5 si
MiB Mem : 15921.4 total, 1243.2 free, 8934.1 used, 5744.1 buff/cache
MiB Swap: 4096.0 total, 3891.2 free, 204.8 used. 6192.0 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1847 www-data 20 0 1245832 234112 18432 S 45.2 1.4 12:34.56 node
2103 postgres 20 0 987264 456320 32768 S 23.1 2.8 8:21.03 postgres
That's a wall of numbers. Now compare the same information in htop — you get color-coded CPU bars per core, memory gauges, and a scrollable process list where you can click to select. The information density is the same, but the cognitive load drops dramatically.
htop: The Interactive Upgrade
htop has been around since 2004 and is now maintained at htop-dev/htop on GitHub. Version 3.4.1 (April 2025) added GPU monitoring meters and improved Unicode handling.
Installation
# Debian / Ubuntu
sudo apt install htop
# Fedora / RHEL
sudo dnf install htop
# Arch Linux
sudo pacman -S htop
# macOS
brew install htop
On most distributions, htop is already in the default repositories. No PPAs or third-party repos needed.
What You See When You Launch htop
Run htop and you get three sections:
- Header — CPU bars (one per core), memory bar, swap bar, load average, uptime, and task count
- Process list — sortable, scrollable table with PID, user, CPU%, MEM%, command, and more
- Footer — function key shortcuts (F1–F10)
The CPU bars use colors to show what's consuming each core:
| Color | Meaning |
|---|---|
| Green | User-space processes (your applications) |
| Red | Kernel-space processes (system calls, I/O) |
| Blue | Low-priority (nice) processes |
| Teal/Cyan | IRQ handling time |
When I set up a new VPS for 32blog, the first thing I do after SSH is run htop to check the baseline. A fresh Ubuntu server should show CPU bars nearly empty and memory around 200–400 MB. If memory is already at 60% before deploying anything, something is wrong.
Essential Keyboard Shortcuts
These are the shortcuts I use daily:
| Key | Action |
|---|---|
F2 or S | Setup — configure meters, columns, color scheme |
F3 or / | Search — find a process by name |
F4 or \ | Filter — show only matching processes |
F5 or t | Tree view — show parent-child process hierarchy |
F6 or < > | Sort — change sort column |
F9 or k | Kill — send signal to selected process |
F10 or q | Quit |
Space | Tag a process (for batch operations) |
U | Untag all |
u | Show only processes from a specific user |
H | Toggle user threads |
K | Toggle kernel threads |
p | Toggle program path / basename |
The tree view (F5) is incredibly useful for debugging. When a Node.js app spawns child processes, the tree shows you exactly which parent owns which workers. I once spent 20 minutes with ps aux | grep node trying to untangle a process hierarchy that htop's tree view made obvious in seconds.
Customizing the Header
Press F2 to enter the setup screen. You can add meters like:
- CPU average — single bar for all cores combined
- Disk I/O — read/write throughput
- Network I/O — bytes in/out (htop 3.4+)
- System load — 1/5/15 minute averages
- Hostname and clock — useful when you have multiple SSH sessions open
I configure my servers with CPU (per-core) on the left, and memory + swap + load on the right. The config is saved to ~/.config/htop/htoprc, so you can copy it across machines with scp.
Filtering and Sorting
Sorting by memory to find leaks:
# Launch htop sorted by memory
htop --sort-key=PERCENT_MEM
Inside htop, press F6 and select PERCENT_MEM to sort by memory usage. The biggest consumers float to the top. This is how I spotted a PostgreSQL connection leak on a staging server — 47 idle connections each holding 30 MB of resident memory.
To filter by a specific process name, press F4 and type node or postgres. Unlike search (F3), filtering hides all non-matching processes, giving you a focused view.
btop: The Full Dashboard
btop is the C++ successor to bashtop and bpytop. Where htop focuses on the process list, btop gives you a full system overview — CPU graphs over time, network throughput, disk activity, and battery status in a single terminal window. Version 1.4.6 (December 2025) added process renice support and improved AMD CPU name trimming.
Installation
# Debian / Ubuntu (22.04+)
sudo apt install btop
# Fedora
sudo dnf install btop
# Arch Linux
sudo pacman -S btop
# macOS
brew install btop
# Snap (any distro)
sudo snap install btop
The btop Interface
btop divides the screen into boxes:
- CPU box — per-core usage bars + a rolling graph showing usage over time
- Memory box — RAM and swap usage with graphs
- Network box — upload/download speed in real-time
- Disk box — read/write throughput per mounted filesystem
- Process box — sortable, filterable process list (similar to htop)
The rolling CPU graph is what sold me on btop. When debugging a cron job that causes periodic CPU spikes, htop shows you the current snapshot. btop shows you the pattern over the last few minutes, making it obvious that the spike happens every 60 seconds.
Key Shortcuts
| Key | Action |
|---|---|
Esc / m | Main menu |
f | Filter processes |
t | Tree view |
k | Kill selected process |
r | Renice selected process |
+ / - | Increase/decrease update interval (100ms steps) |
1–4 | Toggle box visibility (CPU, memory, network, disk) |
Tab | Cycle focus between boxes |
e | Toggle per-core graphs |
Configuration
btop's config lives at ~/.config/btop/btop.conf. You can also press Esc → Options to configure via the built-in menu:
# ~/.config/btop/btop.conf (key settings)
color_theme = "Default"
theme_background = False # transparent background for tiling WM users
update_ms = 2000 # refresh every 2 seconds (default: 2000)
proc_sorting = "cpu lazy" # sort by CPU, but don't re-sort every frame
shown_boxes = "cpu mem net proc" # show these boxes
I set theme_background = False on my WSL2 setup so btop's background matches my Windows Terminal theme. Small touch, but it looks clean.
htop vs btop: When to Use Which
| Criteria | htop | btop |
|---|---|---|
| Startup time | Instant | ~1 second |
| Resource usage | ~5 MB RAM | ~20 MB RAM |
| Network / Disk I/O | Header meters only (3.4+) | Dedicated graph boxes |
| Historical graphs | No | Yes (rolling CPU/network/disk) |
| Mouse support | Yes | Yes |
| Tree view | Yes | Yes |
| GPU monitoring | Yes (3.4+) | Yes |
| Available on | Almost everywhere | Requires C++20 capable compiler |
My rule of thumb: htop on servers (lighter, faster, available everywhere), btop on my local workstation (more data, prettier). On a 512 MB VPS, every megabyte counts — htop wins. On my dev machine with 32 GB RAM, btop's graphs are worth the extra memory.
Process Management: Kill, Nice, and Signals
Both htop and btop let you manage processes directly from the UI, but understanding what happens behind the scenes makes you more effective.
Signals
When you press F9 (kill) in htop, you're actually sending a signal to the process. The most important ones:
| Signal | Number | Effect |
|---|---|---|
SIGTERM | 15 | Polite request to terminate. The process can catch this and clean up |
SIGKILL | 9 | Forced termination. The kernel kills the process immediately — no cleanup |
SIGHUP | 1 | Hang up. Many daemons reload config when they receive this |
SIGSTOP | 19 | Pause the process (like Ctrl+Z). Resume with SIGCONT |
SIGCONT | 18 | Resume a stopped process |
SIGINT | 2 | Interrupt — what happens when you press Ctrl+C |
Always try SIGTERM first. SIGKILL should be a last resort because the process can't clean up — temp files won't be deleted, database transactions won't be rolled back, and child processes may become orphans.
From the command line:
# Graceful shutdown
kill 1847
# Force kill (only when SIGTERM doesn't work after a few seconds)
kill -9 1847
# Kill by name
pkill -f "node server.js"
# Kill all processes by a user
pkill -u www-data
I learned the hard way not to kill -9 PostgreSQL. The database came back up fine, but it had to replay the WAL log, which took 4 minutes on a busy server. SIGTERM lets Postgres finish active queries and flush buffers first.
Nice and Renice
Every process has a nice value from -20 (highest priority) to 19 (lowest priority). The default is 0. Higher nice values mean the process is "nicer" to other processes — it yields CPU time.
# Start a CPU-heavy task with low priority
nice -n 10 ffmpeg -i input.mp4 -c:v libx264 output.mp4
# Change priority of a running process
renice 15 -p 1847
# Set highest priority (requires root)
sudo renice -20 -p 1847
In btop, press r on a selected process to renice it. In htop, you can use F7 (lower nice = higher priority) and F8 (higher nice = lower priority).
Practical Patterns
Find and kill a process eating CPU:
# In htop: press F6, sort by CPU%, select the process, press F9, choose SIGTERM
# From command line:
ps aux --sort=-%cpu | head -5
kill $(pgrep -f "runaway-script")
Kill zombie processes:
Zombies can't be killed directly — they're already dead. You need to kill the parent process:
# Find zombie processes
ps aux | awk '$8 ~ /Z/ {print $2, $11}'
# Find the parent PID
ps -o ppid= -p <zombie_pid>
# Kill the parent (or send SIGCHLD to nudge it)
kill -SIGCHLD <parent_pid>
Reading Process States Like a Pro
In htop's S column (or btop's State column), each process shows a single letter indicating its state. Knowing what these mean is essential for debugging:
| State | Symbol | Meaning |
|---|---|---|
| Running | R | Actively using CPU or waiting in the run queue |
| Sleeping | S | Waiting for an event (I/O, timer, signal). Most processes are here |
| Disk Sleep | D | Uninterruptible sleep — waiting for disk I/O. Cannot be killed |
| Stopped | T | Paused by SIGSTOP or Ctrl+Z |
| Zombie | Z | Process exited but parent hasn't read its exit status yet |
What to Worry About
Too many D (disk sleep) processes — this usually means your disk is overwhelmed. Check I/O wait in the CPU header (the wa value in top, or the red portion in htop if configured). If wa is above 20%, your storage is the bottleneck. On cloud VPSes, this often means you've exhausted your burst IOPS.
Zombie processes accumulating — a few zombies are normal and harmless (they consume almost no resources, just a slot in the process table). But if the count keeps growing, the parent process has a bug — it's not calling wait() on its children. Check which parent owns them and restart it.
Load average higher than CPU cores — if your system has 4 cores and the 1-minute load average is 12, processes are queuing up waiting for CPU time. Use htop's tree view to find which process tree is causing the load.
# Quick check: how many cores vs load average?
nproc # number of CPU cores
uptime # load averages at the end
# If load >> nproc, find the culprits:
htop --sort-key=PERCENT_CPU
One common mistake: high load average doesn't always mean high CPU usage. Processes in D state (disk sleep) also count toward load. If CPU is low but load is high, your bottleneck is storage, not compute.
Real-World Debugging with htop
Here's a scenario I hit on 32blog's VPS. The Next.js build was taking 3× longer than usual:
- Opened
htop, sorted by CPU — nothing unusual, CPU was at 40% - Checked load average — it was 8.2 on a 2-core machine
- Pressed
F5for tree view — saw 6nodeprocesses (Next.js build workers) - Looked at the
Scolumn — most were inDstate (disk sleep) - Diagnosis: the VPS had exhausted its burst IOPS. The build was I/O-bound, not CPU-bound
The fix was simple: upgrade to an SSD-backed VPS tier. But without htop showing me the process states at a glance, I would've wasted time trying to optimize the build config.
FAQ
Is htop better than top?
For interactive use, yes. htop adds color-coded CPU bars, mouse support, tree view, and in-place process management. top's advantage is that it's pre-installed everywhere, so it's useful on minimal containers or rescue shells where you can't install packages.
Can I use btop over SSH?
Yes, but your terminal needs to support the extended character set btop uses for graphs. Most modern terminals (Windows Terminal, iTerm2, Alacritty, kitty) work fine. If graphs render as broken characters, try setting TERM=xterm-256color or fall back to htop.
How do I kill a process that won't die with SIGTERM?
Wait a few seconds (the process might be cleaning up), then use kill -9 <PID> or press F9 in htop and select signal 9 (SIGKILL). If even SIGKILL doesn't work, the process is likely stuck in uninterruptible sleep (D state) waiting for a kernel operation — usually a dead NFS mount or stuck disk. In that case, you may need to reboot.
What's the difference between VIRT, RES, and SHR in htop?
VIRT is the total virtual memory the process has mapped — includes shared libraries, memory-mapped files, and allocated but unused memory. RES (resident) is what's actually in RAM right now. SHR is the portion of RES shared with other processes (mostly shared libraries). Focus on RES — that's the real memory footprint.
Do htop and btop work on macOS?
Yes. Install via Homebrew (brew install htop btop). Some Linux-specific features like per-core frequency or cgroup information won't be available, but the core monitoring and process management work the same.
How do I make htop start with my preferred sort order?
Use command-line flags: htop --sort-key=PERCENT_MEM to sort by memory. Or configure it in the setup screen (F2) and it saves to ~/.config/htop/htoprc.
Can I monitor a Docker container's processes with htop?
Yes. Run htop on the host and filter (F4) by the container's main process name. Or run htop inside the container with docker exec -it <container> htop — this shows only the container's processes, making it easier to focus.
How often do htop and btop refresh?
htop defaults to every 1.5 seconds, btop to every 2 seconds. Both are configurable — in htop via the setup screen, in btop with +/- keys or the update_ms config option.
Wrapping Up
top gets the job done in a pinch, but htop and btop turn process monitoring from a chore into something you can actually reason about. htop is my go-to on servers — it's everywhere, lightweight, and the tree view alone is worth the install. btop lives on my local machine where the CPU graphs and network monitoring give me a complete picture without opening five different tools.
The real value isn't in the pretty colors. It's in the workflow: see a spike, filter to the process, check its state, send a signal — all without leaving the terminal or memorizing PIDs. Once you build that muscle memory, you'll wonder how you ever managed processes any other way.
Next step: if you're managing background tasks that run on a schedule, check out the cron and systemd timer guide. And if you're writing scripts that spawn child processes, the shell scripting guide covers proper signal handling and cleanup traps.