View Data Files in the Terminal¶
Preview and explore tabular / data files — CSV, TSV, Parquet, Feather/Arrow,
Excel .xlsx, SQLite, and native DuckDB databases — without leaving the terminal, and
without opening an editor or a GUI.
Two layers:
- Inline previews in the yazi file manager — hover a data file and its rows
render as an aligned table in the right pane, powered by the
duckdb.yaziplugin (with two small fallbacks for the formats DuckDB can't read). - Interactive exploration with VisiData (
vd) — a fast, vim-keyed spreadsheet TUI for sorting, filtering, frequency tables, and describe.
The split is deliberate: DuckDB for the glance, VisiData for the deep-dive. We evaluated using
VisiData for previews too and rejected it — its non-interactive batch output is raw TSV (or a
--save-filetype fixed monochrome table), it can't preview SQLite data (only lists tables), can't
open .xlsx (its tool venv has no openpyxl), and is slow on the preview hot-path (~0.4 s for CSV,
up to ~10 s cold for parquet, because it imports pandas + pyarrow). DuckDB's -box renders a native
aligned table in ~0.1 s and can cheaply LIMIT to the first N rows.
TL;DR¶
| Format | yazi preview | Engine |
|---|---|---|
.csv .tsv |
✅ table | duckdb.yazi |
.parquet |
✅ table | duckdb.yazi |
.xlsx |
✅ table | duckdb.yazi (DuckDB spatial ext — see gotcha) |
.db .duckdb |
✅ table listing | duckdb.yazi (DuckDB auto-attaches SQLite) |
.sqlite .sqlite3 |
✅ table listing | piper → duckdb -readonly (fallback) |
.feather .arrow |
✅ table | piper → VisiData fixed (DuckDB has no Arrow-IPC reader) |
All formats open interactively in VisiData (vd <file>) regardless of the preview engine.
duckdb.yazi — the previewer¶
duckdb.yazi is a Yazi previewer/preloader plugin that
shells out to the duckdb CLI (already installed by the devtools role) and renders its -box
table into the preview pane. It reads CSV, TSV, Parquet, Excel, and DuckDB/SQLite databases.
Three pieces make it work in this repo:
| Piece | Path | Role |
|---|---|---|
| Lockfile (SSOT) | dot_config/yazi/package.toml |
pins wylie102/duckdb (rev + hash) |
| Init | dot_config/yazi/init.lua |
required require("duckdb"):setup({ mode = "standard" }), wrapped in pcall so a missing plugin warns instead of blocking yazi startup |
| Wiring | dot_config/yazi/yazi.toml [plugin] |
prepend_previewers + prepend_preloaders (run = "duckdb") |
The setup() call in init.lua is mandatory — without it the run = "duckdb" rules never activate.
We set mode = "standard" so hover shows actual data rows (the plugin default is summarized); press
K at the top of a preview to toggle to DuckDB's SUMMARIZE view (min/max/counts per column).
Keybindings¶
Added to dot_config/yazi/keymap.toml ([mgr] prepend_keymap):
| Key | Action |
|---|---|
K |
Toggle standard ⇄ SUMMARIZE view (built into the plugin; no keymap entry) |
H / L |
Scroll one column left / right in the preview |
g o |
Open the hovered file in the DuckDB CLI |
g u |
Open the hovered file in the DuckDB UI |
⚠
H/Loverride Yazi's default history back/forward (the capital-letter binds). Lowercaseh/l(leave / enter directory) are unaffected. On non-data filesH/Lno-op.
The two fallbacks (formats DuckDB can't read)¶
- Feather / Arrow (
.feather.arrow) — DuckDB has no Arrow-IPC file reader, so these route throughpiper.yazito VisiData's non-interactivefixedsaver:{ url = "*.feather", run = 'piper -- vd -b -f arrow "$1" -o - --save-filetype fixed 2>/dev/null | head -n 500' }-f arrowforces the pure-pyarrowArrowSheetloader (dodges the pandasStringDtypecrash — see the feather pitfall), and2>/dev/nullis mandatory: piper renders any stderr as an error preview, and VisiData logs status to stderr. - SQLite by
.sqlite/.sqlite3name — the plugin's internalextension_maponly knows.db(not.sqlite), so those two extensions route through piper to aduckdb -readonlytable listing. Plain.dbgets the full plugin treatment (DuckDB transparently attaches SQLite databases opened directly, so.dbcovers most SQLite files).
VisiData — interactive exploration¶
vd <file> opens a full-screen, vim-keyed spreadsheet over CSV/TSV/JSON/Parquet/Feather/Arrow/xlsx/
SQLite. This is the tool for actual analysis: sort, filter (| / \), frequency (Shift+F),
describe (Shift+I), pivot, and save-as. Defaults are already vim-flavored (h/j/k/l, gg/G,
/? search); the repo adds strict-vim column nav under enableVimMode. See
aliases.md → Data Viewers for the vd-arrow / vd-ro wrappers
and vim-mode.md → VisiData for the key rebinds.
VisiData and its companion ~/.visidatarc are installed/managed regardless (visidata is a required
uv tool with pandas + pyarrow); the .visidatarc carries the .feather → ArrowSheet reroute
that the preview fallback above also relies on.
Where things live¶
| Surface | Path |
|---|---|
| Plugin lockfile + installer | dot_config/yazi/package.toml, .chezmoiscripts/global/run_after_45_yazi_plugins.sh.tmpl |
| Plugin init | dot_config/yazi/init.lua |
| Previewers + preloaders | dot_config/yazi/yazi.toml [plugin] |
| Keybindings | dot_config/yazi/keymap.toml |
| DuckDB CLI install | dot_ansible/roles/devtools/tasks/main.yml |
| VisiData install + rc | dot_ansible/roles/python_uv_tools/defaults/main.yml, dot_visidatarc.tmpl |
| Upgrades | scripts/upgrade_tools.sh (just upgrade-yazi-plugins) |
Gotchas¶
- No plugins at all? Check for
ya, not duckdb. If yazi dies at startup withFailed to load plugin from ".../duckdb.yazi/main.lua", the usual cause is thatya(yazi's CLI companion, shipped alongsideyaziin every release asset) was never installed — so~/.config/yazi/plugins/was never created andpiper.yaziis missing too.ya --versionis the one-command diagnosis;ya pkg installis the fix.init.luanow wraps therequireinpcall, so yazi starts anyway and warns instead of refusing to launch. See pitfalls/yazi-lua-runtime-failed-plugin-main-lua.md. ya.errneedsYAZI_LOG. Plugin errors only reach~/.local/state/yazi/yazi.logwhen the env var is set —YAZI_LOG=debug yazi. Without it the log file doesn't even exist, which makes plugin problems look like they leave no trace..xlsxfirst preview needs internet. duckdb.yazi reads Excel via DuckDB'sspatialextension, which itINSTALLs on first use — the first.xlsxpreview on a fresh machine downloads it (cached in~/.duckdbafterwards). CSV/TSV/Parquet/DB previews use built-ins and need no network..xlsxpreview moved offview-office. Yazi now previews.xlsxwith duckdb.yazi, notmarkitdown. Theview-office --preview budget.xlsxCLI is unchanged (still markitdown → glow); only Yazi's previewer wiring moved. See office-viewers.md.- Lowercase globs. The
urlglobs are lowercase (*.csv); a file namedDATA.CSVwon't trigger the previewer. (VisiData opened directly still works.) - DuckDB normalizes display.
-boxmay render1200.50as1200.5(type inference) — it's a display artifact of the preview, not a change to the file. view-officefor.xls/.ods. Legacy binary.xlsand OpenDocument.odsstay on the LibreOffice → OOXML path (DuckDB can't read those); only modern.xlsxuses duckdb.yazi.
See also¶
- Office viewers — the
.docx/.pptx+ legacy/ODF sibling stack (doxx / markitdown / LibreOffice), and theya pkg/piper.yazimechanism shared here. - Data Viewers (aliases) — VisiData
vd-arrow/vd-rowrappers. - tool-managers.md § 15 —
ya pkgplugin mechanism (piper.yazi, duckdb.yazi). - Feather / StringDtype pitfall — why
.featherneeds the ArrowSheet loader.