How to Use Chafa: The Beginner's Guide (First Render, Animated GIFs, Colors and Symbols, and the Sixel Lesson)
CodexFuse Team · 2026-11-07T03:35:25.612Z · 19 min read min read
How Do I Use Chafa?
Learning how to use chafa takes seven moves: install it once, render one image, check what your terminal can do, pick a protocol, play an animated GIF, tune the colors and symbols, and save the useful commands for scripts. Chafa is a terminal image viewer that turns photos, screenshots, and animated GIFs into pictures your terminal can display, using Unicode symbols or a graphics protocol your terminal understands. This chafa tutorial follows the official documentation, the man page, and the project repository, with every fact checked as of November 2026.
There is no graphical window to open and no image viewer to launch, because the terminal itself becomes the viewer. CodexFuse offers no Chafa tool, so this guide teaches the real project on your own machine, not a web version of it. The mental model is the whole lesson, and the rest of this guide is practice.
The VPS hosting guide covers the Linux server where most terminal work happens, and it is the pillar this page belongs to. This guide opens the terminal-images lane in the dev-tools terminal cluster, and it draws the line once against the file-tree tools: erdtree draws directory trees, while chafa renders images, so the two tools do different jobs in the same terminal.
- Install Chafa with your package manager.
- Run chafa on one image file and watch the terminal draw it.
- Check whether your terminal shows pixel graphics or symbol art.
- Force a protocol with --format when auto-detection picks the wrong one.
- Play an animated GIF with --animate and stop it with Ctrl-C.
- Tune the colors and symbols until the picture reads clearly.
- Save the winning command for scripts and file-manager previews.
What Is Chafa?
Chafa is a command-line utility that converts image data, including animated GIFs, into graphics formats or ANSI/Unicode character art suitable for display in a terminal. The name is short for Character Art Facsimile, and the project describes itself as terminal graphics for the 21st century. It is written in C, it is free software under the GNU Lesser General Public License version 3, and it ships both as a command and as a C library other programs can embed.
The tool reads JPEG, PNG, GIF, WebP, SVG, TIFF, AVIF, JPEG XL, QOI, and XWD files, and it handles alpha transparency in every color mode, including in animations. A single image renders with one command, and several images render one after another with the same command. The defaults are deliberately smart: Chafa probes the terminal, picks the best output format the terminal supports, and falls back to Unicode symbols when nothing better is available.
| Fact | Value (November 2026) |
|---|---|
| Repository | hpjansson/chafa |
| Created | 24 April 2018 |
| Current release | 1.18.3, published 23 September 2026 |
| Stars | 5,386 |
| Forks | 123 |
| Open issues | 54 |
| License | GNU Lesser General Public License version 3 |
| Language | C |
| Last push | 1 November 2026 |
The repository is 3,119 days old, which is about 8.54 years, and the current release is 45 days old, with the last push 6 days before this guide was written. Chafa earns 43.79 stars per fork and 1.00 open issues per 100 stars, which is a healthy ratio for a project of this size. The 1.18 line moved fast in 2026: 90 days from 1.18.0 to 1.18.1, 80 days to 1.18.2, and 147 days to 1.18.3, a span of 317 days from first to last.
How Do I Install Chafa?
A chafa install starts with your package manager on almost every platform, and the official download page lists the exact command for each one. On Debian, Ubuntu, and Kali, the command is sudo apt install chafa, and on Arch Linux it is pacman -S chafa. On macOS and Linux with Homebrew it is brew install chafa, on Fedora it is dnf install chafa, and on Windows it is scoop install chafa or winget install hpjansson.Chafa.
The package-manager version can lag behind upstream, and on Ubuntu 24.04 LTS the repository ships Chafa 1.14.0, not the current 1.18.3. That older build still renders images, but it lacks the 1.18 line features such as the --files and --files0 batch lists, the --link clickable labels, parallel decoding, and the tmux sixel fix in 1.18.3. Readers who want 1.18.3 on Ubuntu or Debian should use the official standalone binary from the download page, or build from the release tarball with ./configure, make, and sudo make install.
There is no cargo install route for the Chafa CLI, because Chafa is written in C and is not distributed as a Rust crate. The crates.io package named chafa is an unrelated third-party Rust binding library, and installing it does not give you the chafa command. The Python wrapper chafa.py is a different thing again: it needs the real Chafa installed first, and it exists for programs that embed Chafa, not for the command line.
| Platform | Install command |
|---|---|
| Debian, Ubuntu, Kali | apt install chafa |
| Arch Linux | pacman -S chafa |
| Fedora | dnf install chafa |
| Homebrew | brew install chafa |
| MacPorts | port install chafa |
| Gentoo | emerge media-gfx/chafa |
| openSUSE | zypper in chafa |
| FreeBSD | pkg install chafa |
| Windows, Scoop | scoop install chafa |
| Windows, Winget | winget install hpjansson.Chafa |
| Build from source | ./configure, make, and sudo make install |
sudo apt install chafa brew install chafa pacman -S chafa chafa --version
How Do I Render My First Image?
The first render is one command: chafa followed by the image path, with no flags at all. Chafa detects the terminal size, probes the terminal capabilities, and draws the image to fit the window. The command returns exit code 0 on success, 1 when some files fail to display, and 2 when every file fails, including when you run it with no arguments at all.
Size is the first control worth learning, because the default is the terminal size minus the margins. The --size flag takes a width and height in columns and rows, such as -s 80x40, and --fit-width fits to the terminal width even if the picture grows taller than the window. The --scale flag works in pixel terms instead: a value of 1.0 means roughly the original pixel dimensions, and max means use all the available space.
One warning belongs here, because a popular roundup guide prints it: chafa -w 80 -h 40 is wrong, since -w means --work and -h means --help. The size flag is -s, so the correct command is chafa -s 80x40, and the same guide prints other errors this article does not repeat.
Labels help when you render many files, because --label adds the filename under each image, and --link turns those labels into clickable links when the terminal supports them. The --clear flag clears the screen before each file, which keeps a slideshow tidy. The --align flag positions the picture, with values such as left, right, center, top, and bottom, and two values can be combined, such as center and right.
| Flag | What it does |
|---|---|
| --size, -s | Maximum output size in columns and rows |
| --scale | Size in pixel terms, 1.0 or max |
| --label, -l | Print the filename under each image |
| --link | Turn labels into clickable links |
| --clear | Clear the screen before each file |
| --align | Position the picture, such as center and right |
| --fit-width | Fit to the terminal width |
chafa photo.png chafa -s 80x40 photo.jpg chafa --scale max photo.png chafa --label --clear photo.png photo.jpg
Why Does Chafa Look Different in Different Terminals?
Chafa terminal images look different in different terminals because the output format depends on what the terminal can display, not on what you ask for. Chafa probes the terminal first, then picks the best format available: iTerm2 inline images, the Kitty graphics protocol, sixels, or plain Unicode symbols as the fallback. The same command can therefore produce a crisp photo in one terminal and a block-character mosaic in another, and both results are correct for their terminal.
A chafa sixel render sends a 256-color bitmap as escape sequences, and the protocol dates to DEC graphics terminals of the 1980s, which is why it works over SSH with no extra setup. Chafa added sixel support in version 1.4.0, published on 1 April 2020, with its own encoder built for fast animation playback. The 1.18.3 release fixed a tmux edge case: sixels are no longer used inside tmux when the outer terminal cannot display them, because tmux used to claim the capability on its own behalf.
GNOME Terminal supports neither Sixel nor the Kitty protocol, so beginners on stock Ubuntu see the Unicode-symbols fallback and nothing else. That fallback is still readable, because it uses colored block, half-block, and braille characters to approximate the picture. Readers who want pixel output should use a terminal that supports it, such as kitty, WezTerm, Foot, Konsole, or the VS Code terminal, and the --format flag forces a choice when auto-detection picks the wrong one.
| Format | What it is | Terminals that support it |
|---|---|---|
| Sixels | 256-color bitmap sent as escape sequences | xterm, foot, Konsole, WezTerm, iTerm2 3.3 and later, VS Code 1.80 and later, Windows Terminal 1.22 and later |
| Kitty protocol | 24-bit RGB images sent as base64 escape sequences | kitty, WezTerm, Konsole, Ghostty |
| iTerm2 inline images | 24-bit RGB images sent as base64 | iTerm2, WezTerm, Konsole |
| Symbols | Colored Unicode characters in the terminal grid | Every terminal |
Probing is what makes the choice automatic, and --probe controls it with values of auto, on, or off, waiting up to 5.0 seconds by default. The --probe-mode flag chooses how the probe reads the terminal, with values of any, ctty, or stdio. Probing can also read the terminal background and foreground colors, so the defaults for --bg and --fg follow the terminal theme when probing is enabled.
chafa --format sixels photo.png chafa -f kitty photo.png chafa -f symbols --symbols ascii -c none photo.png chafa --probe off photo.png
How Do I Show Animated GIFs in the Terminal?
A chafa animate gif render needs no special flag, because animation is on by default. A single animated GIF loops until you press Ctrl-C, and several files play once each, because multiple files default to a duration of zero. The zero duration still plays every animation through at least once, so nothing is skipped.
The --animate flag turns animation off with --animate off, which shows a still frame from each animation instead. The --duration flag sets the show time in seconds for each file, and --speed changes the playback speed as a multiplier such as 0.5, or as a frame rate such as 24fps. The --watch flag watches one input file and redraws it whenever the file contents change, which is useful while you edit an image.
Sixel animation is fast because the encoder was built for it, and in sixel mode the dither defaults to noise while full color builds a fresh 256-color palette for every frame. Multiple files behave differently on purpose: the man page says animations will not loop forever when more than one input file is given. The rule is simple to remember: one file loops, many files play once, and --duration overrides both.
chafa animation.gif chafa --animate off animation.gif chafa -d 5 animation.gif chafa --speed 0.5 animation.gif chafa --watch animation.gif
How Do I Tune Colors and Symbols?
Colors are the biggest quality lever, and the --colors flag takes values of none, 2, 8, 16, 240, 256, and full, with full meaning 24-bit color as the default. The 240-color mode is recommended over the 256-color mode, because the lower 16 colors are unreliable and tend to differ between terminals. In sixel mode, full color generates a dynamic 256-color palette per image or frame, while other modes use built-in palettes.
Symbols are the second lever, and the --symbols flag picks the character classes Chafa may use, such as block, half, vhalf, braille, dot, ascii, and geometric. The default set depends on the terminal, and most terminals get block, border, and space-wide-inverted, while the Linux console gets ascii. A pixelated look comes from --symbols vhalf, a monochrome look comes from -c none with --symbols braille, and a small palette looks better with --dither ordered.
Three more flags shape the result: --font-ratio sets the target font width to height ratio and defaults to 1 over 2, --dither picks none, ordered, diffusion, or noise, and --color-space picks rgb or din99d, where din99d is slower but more perceptually accurate. The --work flag sets how hard Chafa works on a scale of 1 to 9 and defaults to 5, and --optimize compresses the output with control sequences on a scale of 0 to 9 and defaults to 5. The --preprocess flag enhances colors and contrast before conversion, but it only affects output at 16 colors or fewer.
| Color mode | Best for |
|---|---|
| none | Monochrome text output with no escape sequences |
| 2 | Reverse video only |
| 16 | Classic 16-color terminals |
| 240 | The recommended limited palette |
| 256 | The built-in 256-color palette |
| full | 24-bit color, the default |
chafa -c full photo.png chafa -c 16 --dither ordered photo.png chafa --symbols vhalf photo.png chafa -c none --symbols braille photo.png chafa -c 16 --color-space din99d --symbols -dot photo.jpg
How Do I Use Chafa in Scripts and File Managers?
To view images in terminal workflows, Chafa reads from stdin, so a pipeline can feed it directly, and a curl command piped into chafa with a dash reads an image from the web. The --files flag reads a list of paths from a file or from stdin, one per line, and --files0 reads NUL-separated paths, which pairs with find and print0. Both flags can be given more than once, and paths on the command line are processed last.
The Git beginner guide covers the version control most script collections live in, and a Chafa preview script belongs in the same repository as the rest of your dotfiles. The Gum beginner guide covers the terminal prompts that pair well with Chafa, because a Gum chooser can pick an image and hand the path to Chafa. The Neovim beginner guide covers the editor where terminal users spend their day, and Chafa previews fit the same keyboard-first workflow.
The erdtree beginner guide covers the file-tree tool that lists a directory as a tree, and it is the closest kin to Chafa in the terminal-tooling cluster. File managers such as ranger, lf, nnn, and vifm use Chafa as their image previewer, so a picture appears in the preview pane while you browse. The --grid flag lays several images out as a contact sheet, and --label names each one, which turns a directory of photos into a browsable gallery.
curl -s https://example.com/image.png | chafa - find . -type f -print0 | chafa --files0 - -g -l chafa --files list.txt chafa --scale max photo.jpg
Chafa vs timg: Which Terminal Image Viewer Should I Pick?
Chafa vs timg is the comparison most readers ask about, because both tools render images in the terminal and both auto-detect the best protocol. The short answer is that timg is the viewer and Chafa is the engine: timg plays video and opens PDFs, while Chafa ships a C library and a far deeper symbol engine. The rest of this section is the evidence behind that sentence.
| Feature | Chafa | timg |
|---|---|---|
| Language | C | C++ |
| License | LGPL-3.0 | GPL-2.0 |
| Created | 24 April 2018 | 18 June 2016 |
| Stars | 5,386 | 2,794 |
| Forks | 123 | 91 |
| Latest release | 1.18.3, 23 September 2026 | v1.6.3, 27 September 2025 |
| Video playback | No | Yes |
| PDF viewing | No | Yes |
| Grid view | Yes, with --grid | Yes, with --grid |
| C library | Yes, libchafa | No |
| Symbol engine | Extensive, with --symbols classes | Basic half and quarter blocks |
| Protocols | iterm, kitty, sixels, symbols | kitty, iterm2, sixel, half and quarter blocks |
The release gap tells the maintenance story: Chafa 1.18.3 is 45 days old, while timg v1.6.3 is 406 days old, and timg predates Chafa by 675 days. Chafa holds 1.93 times the stars of timg, with 43.79 stars per fork against 30.70, and 1.00 open issues per 100 stars against 1.36. The numbers favor Chafa on activity, but they do not settle the choice, because timg wins on video, PDFs, and its grid view, which the LinuxLinks review calls genuinely useful.
Pick timg when you need video playback, PDF previews, or a grid contact sheet, and pick Chafa when you need the library, the symbol engine, or the freshest release. Both tools install from the same package managers, and the terminal image viewer linux beginners reach for first is usually the one their distribution ships. The LinuxLinks review from 2022 sums it up: Chafa runs timg pretty close as the recommended terminal image viewer, and if you can live without the grid view, Chafa may be everything you need.
Seven Mistakes Beginners Make With Chafa
Most Chafa mistakes come from copying commands out of roundup guides without checking them against the man page, and the errors are easy to make because the flags look familiar. Two rows below correct flags that never existed: there is no --mode flag in Chafa, and there is no plain --margin flag, only --margin-bottom and --margin-right. The table lists all seven mistakes with the wrong form and the right one, and every correction was verified against the current man page on 7 November 2026.
| Mistake | What happens | Do this instead |
|---|---|---|
| chafa -w 80 -h 40 | -w means --work and -h means --help | chafa -s 80x40 |
| cargo install chafa | Installs an unrelated Rust library | Use apt, brew, or pacman |
| --mode | No such flag exists in Chafa | Use --colors to pick the color mode |
| --margin | No plain --margin flag exists | Use --margin-bottom or --margin-right |
| Expecting pixel output in GNOME Terminal | GNOME Terminal supports neither protocol | Use kitty, WezTerm, Foot, or Konsole |
| Expecting apt to give 1.18.3 on Ubuntu 24.04 | The repository ships 1.14.0 | Use the official standalone binary |
| Expecting one GIF to loop in a multi-file run | Multiple files play once each | Render one file, or set --duration |
Sources
The project facts come from the Chafa homepage at hpjansson.org/chafa, the official download page, and the GitHub API for the hpjansson/chafa repository, all fetched on 7 November 2026. The flag list and the duration rules come from the chafa(1) man page source in the repository and the rendered Arch manual page. The install-lag table comes from Repology, and the Homebrew version comes from the Homebrew formula API, with its checksum matching the GitHub release tarball.
The terminal support list comes from arewesixelyet.com, and the sixel history comes from the official 1.4.0 release post dated 1 April 2020. The timg facts come from the GitHub API for the hzeller/timg repository and its README, and the LinuxLinks review from 22 June 2022 supplies the third-party verdict. The copyprogramming roundup guides were read for coverage only, because they contain flag errors, and no fact in this article comes from them.
No terminal outputs in this guide were executed in a live testbed, so every command comes from the man page and the official documentation, not from a terminal session. The arithmetic in the computed block below was run in Python on 7 November 2026, and its inputs are the GitHub API dates and counts quoted above. No Facebook promotion applies to this article.
from datetime import date
today = date(2026, 11, 7)
created = date(2018, 4, 24)
released = date(2026, 9, 23)
pushed = date(2026, 11, 1)
r1180 = date(2025, 11, 10)
r1181 = date(2026, 2, 8)
r1182 = date(2026, 4, 29)
timg_created = date(2016, 6, 18)
timg_rel = date(2025, 9, 27)
print("repo age days", (today - created).days)
print("repo age years", round((today - created).days / 365.25, 2))
print("release age days", (today - released).days)
print("push age days", (today - pushed).days)
print("stars per fork", round(5386 / 123, 2))
print("open issues per 100 stars", round(54 / 5386 * 100, 2))
print("stars per day", round(5386 / (today - created).days, 2))
print("gap 1.18.0 to 1.18.1", (r1181 - r1180).days)
print("gap 1.18.1 to 1.18.2", (r1182 - r1181).days)
print("gap 1.18.2 to 1.18.3", (released - r1182).days)
print("span 1.18.0 to 1.18.3", (released - r1180).days)
print("timg age days", (today - timg_created).days)
print("timg age years", round((today - timg_created).days / 365.25, 2))
print("timg release age days", (today - timg_rel).days)
print("timg stars per fork", round(2794 / 91, 2))
print("timg open issues per 100 stars", round(38 / 2794 * 100, 2))
print("chafa stars divided by timg stars", round(5386 / 2794, 2))
print("timg older than chafa days", (created - timg_created).days)
Output:
repo age days 3119
repo age years 8.54
release age days 45
push age days 6
stars per fork 43.79
open issues per 100 stars 1.0
stars per day 1.73
gap 1.18.0 to 1.18.1 90
gap 1.18.1 to 1.18.2 80
gap 1.18.2 to 1.18.3 147
span 1.18.0 to 1.18.3 317
timg age days 3794
timg age years 10.39
timg release age days 406
timg stars per fork 30.7
timg open issues per 100 stars 1.36
chafa stars divided by timg stars 1.93
timg older than chafa days 675
Frequently Asked Questions
Can Chafa display images in any terminal?
Yes, Chafa renders in essentially any terminal, because the Unicode-symbols fallback works wherever colored text works. Pixel output needs a terminal that supports sixels, the Kitty protocol, or iTerm2 inline images, so kitty, WezTerm, Foot, and Konsole show the best results.
Why does Chafa show block characters instead of a photo?
Your terminal does not support a pixel protocol, so Chafa falls back to Unicode symbols, and GNOME Terminal behaves this way by default. Switch to kitty, WezTerm, Foot, or Konsole for pixel output, or force the choice with --format to confirm what your terminal supports.
How do I stop an animated GIF in the terminal?
Press Ctrl-C, because a single animated GIF loops until you press Ctrl-C in an interactive terminal. The --duration flag also stops it after a set number of seconds, and --animate off shows a still frame instead.
Is Chafa better than timg?
It depends on the job, because timg plays video and opens PDFs while Chafa offers the C library and the deeper symbol engine. Chafa is the fresher project, with release 1.18.3 only 45 days old, while timg v1.6.3 is 406 days old, so pick Chafa for images and timg for video.
Does Chafa work over SSH?
Yes, Chafa works over SSH, because sixels and Unicode symbols travel as plain escape sequences with no extra setup. The 1.18.3 release fixed a tmux case where sixels were used inside tmux even when the outer terminal could not display them.




