medialab/xanPublic

The CSV magician

AI summary: A highly optimized Rust command-line tool for parallel processing of massive CSV datasets.

Stars
4.5K
+2 today
Forks
93
Watchers
21
Open issues
121
Open PRs
5
Contributors
~65
Commits
3.4K
Branches
94

RustUnlicenseCreated Jul 10, 2018Last push 2d agoLatest release 0.61.0+8 stars this week+42 this month

Quick answers

What is xan?
A highly optimized Rust command-line tool for parallel processing of massive CSV datasets.
What does xan do?
xan acts as an extremely fast, memory-efficient command-line utility for manipulating gigabyte-sized CSV files directly from the shell. Written entirely in Rust, it aggressively leverages SIMD instructions for parsing and multithreading for parallel computations, allowing tasks to complete at the absolute maximum speed of the hardware. Beyond basic filtering and joining, it features a custom expression language tailored specifically for CSV data, vastly outperforming dynamic languages like Python. Originally rooted in web data collection for the social sciences, it also includes highly specialized utilities for lexicometry, graph theory, and terminal-based data visualization.
Who is xan for?
Data scientists, researchers, and backend engineers who frequently process very large tabular datasets and require maximum performance. It is highly optimized for users comfortable with shell scripting and command-line interfaces.
How do I get started with xan?
cargo install xan --locked
How popular is xan on GitHub?
medialab/xan has 4,532 stars and 93 forks on GitHub, and gained 8 stars in the last 7 days.
What license does xan use?
medialab/xan is released under the Unlicense license.

Star history

since Feb 4, 2024
02K4KFeb 2024Dec 2024Nov 2025Oct 2026
4.5K stars as of Oct 2, 2026. Before Jul 29, 2026, reconstructed from public GitHub event archives (checked against the repository's real star total); since then measured daily.

Contribution activity

commits per day, last 52 weeks
OctNovDecJanFebMarAprMayJunJulAugSepMonWedFri2025-10-05: 0 commits2025-10-06: 1 commit2025-10-07: 2 commits2025-10-08: 8 commits2025-10-09: 0 commits2025-10-10: 0 commits2025-10-11: 0 commits2025-10-12: 0 commits2025-10-13: 4 commits2025-10-14: 1 commit2025-10-15: 5 commits2025-10-16: 1 commit2025-10-17: 15 commits2025-10-18: 5 commits2025-10-19: 4 commits2025-10-20: 6 commits2025-10-21: 2 commits2025-10-22: 6 commits2025-10-23: 15 commits2025-10-24: 11 commits2025-10-25: 4 commits2025-10-26: 0 commits2025-10-27: 0 commits2025-10-28: 11 commits2025-10-29: 13 commits2025-10-30: 10 commits2025-10-31: 7 commits2025-11-01: 0 commits2025-11-02: 0 commits2025-11-03: 0 commits2025-11-04: 12 commits2025-11-05: 2 commits2025-11-06: 2 commits2025-11-07: 1 commit2025-11-08: 0 commits2025-11-09: 0 commits2025-11-10: 3 commits2025-11-11: 0 commits2025-11-12: 3 commits2025-11-13: 1 commit2025-11-14: 9 commits2025-11-15: 4 commits2025-11-16: 2 commits2025-11-17: 8 commits2025-11-18: 0 commits2025-11-19: 1 commit2025-11-20: 0 commits2025-11-21: 0 commits2025-11-22: 0 commits2025-11-23: 0 commits2025-11-24: 0 commits2025-11-25: 5 commits2025-11-26: 5 commits2025-11-27: 3 commits2025-11-28: 1 commit2025-11-29: 0 commits2025-11-30: 0 commits2025-12-01: 0 commits2025-12-02: 0 commits2025-12-03: 0 commits2025-12-04: 0 commits2025-12-05: 0 commits2025-12-06: 0 commits2025-12-07: 0 commits2025-12-08: 0 commits2025-12-09: 0 commits2025-12-10: 0 commits2025-12-11: 0 commits2025-12-12: 0 commits2025-12-13: 0 commits2025-12-14: 0 commits2025-12-15: 0 commits2025-12-16: 0 commits2025-12-17: 0 commits2025-12-18: 0 commits2025-12-19: 9 commits2025-12-20: 0 commits2025-12-21: 0 commits2025-12-22: 0 commits2025-12-23: 0 commits2025-12-24: 2 commits2025-12-25: 0 commits2025-12-26: 0 commits2025-12-27: 0 commits2025-12-28: 0 commits2025-12-29: 0 commits2025-12-30: 0 commits2025-12-31: 0 commits2026-01-01: 0 commits2026-01-02: 0 commits2026-01-03: 0 commits2026-01-04: 0 commits2026-01-05: 0 commits2026-01-06: 0 commits2026-01-07: 0 commits2026-01-08: 0 commits2026-01-09: 0 commits2026-01-10: 0 commits2026-01-11: 0 commits2026-01-12: 0 commits2026-01-13: 0 commits2026-01-14: 0 commits2026-01-15: 0 commits2026-01-16: 0 commits2026-01-17: 0 commits2026-01-18: 0 commits2026-01-19: 0 commits2026-01-20: 0 commits2026-01-21: 0 commits2026-01-22: 0 commits2026-01-23: 0 commits2026-01-24: 0 commits2026-01-25: 0 commits2026-01-26: 0 commits2026-01-27: 0 commits2026-01-28: 0 commits2026-01-29: 0 commits2026-01-30: 2 commits2026-01-31: 0 commits2026-02-01: 0 commits2026-02-02: 0 commits2026-02-03: 2 commits2026-02-04: 4 commits2026-02-05: 10 commits2026-02-06: 6 commits2026-02-07: 0 commits2026-02-08: 0 commits2026-02-09: 1 commit2026-02-10: 1 commit2026-02-11: 3 commits2026-02-12: 11 commits2026-02-13: 5 commits2026-02-14: 1 commit2026-02-15: 0 commits2026-02-16: 2 commits2026-02-17: 3 commits2026-02-18: 1 commit2026-02-19: 6 commits2026-02-20: 12 commits2026-02-21: 1 commit2026-02-22: 0 commits2026-02-23: 0 commits2026-02-24: 2 commits2026-02-25: 0 commits2026-02-26: 1 commit2026-02-27: 1 commit2026-02-28: 0 commits2026-03-01: 0 commits2026-03-02: 2 commits2026-03-03: 0 commits2026-03-04: 0 commits2026-03-05: 0 commits2026-03-06: 0 commits2026-03-07: 0 commits2026-03-08: 0 commits2026-03-09: 0 commits2026-03-10: 0 commits2026-03-11: 0 commits2026-03-12: 0 commits2026-03-13: 0 commits2026-03-14: 0 commits2026-03-15: 0 commits2026-03-16: 0 commits2026-03-17: 0 commits2026-03-18: 4 commits2026-03-19: 9 commits2026-03-20: 6 commits2026-03-21: 4 commits2026-03-22: 0 commits2026-03-23: 2 commits2026-03-24: 7 commits2026-03-25: 10 commits2026-03-26: 12 commits2026-03-27: 17 commits2026-03-28: 0 commits2026-03-29: 0 commits2026-03-30: 17 commits2026-03-31: 6 commits2026-04-01: 10 commits2026-04-02: 10 commits2026-04-03: 10 commits2026-04-04: 8 commits2026-04-05: 1 commit2026-04-06: 0 commits2026-04-07: 0 commits2026-04-08: 5 commits2026-04-09: 11 commits2026-04-10: 0 commits2026-04-11: 0 commits2026-04-12: 0 commits2026-04-13: 0 commits2026-04-14: 0 commits2026-04-15: 9 commits2026-04-16: 0 commits2026-04-17: 6 commits2026-04-18: 1 commit2026-04-19: 0 commits2026-04-20: 1 commit2026-04-21: 8 commits2026-04-22: 16 commits2026-04-23: 9 commits2026-04-24: 8 commits2026-04-25: 1 commit2026-04-26: 8 commits2026-04-27: 7 commits2026-04-28: 11 commits2026-04-29: 10 commits2026-04-30: 17 commits2026-05-01: 3 commits2026-05-02: 3 commits2026-05-03: 3 commits2026-05-04: 13 commits2026-05-05: 13 commits2026-05-06: 10 commits2026-05-07: 11 commits2026-05-08: 2 commits2026-05-09: 4 commits2026-05-10: 1 commit2026-05-11: 26 commits2026-05-12: 15 commits2026-05-13: 18 commits2026-05-14: 2 commits2026-05-15: 16 commits2026-05-16: 2 commits2026-05-17: 0 commits2026-05-18: 16 commits2026-05-19: 3 commits2026-05-20: 0 commits2026-05-21: 4 commits2026-05-22: 3 commits2026-05-23: 3 commits2026-05-24: 4 commits2026-05-25: 4 commits2026-05-26: 6 commits2026-05-27: 0 commits2026-05-28: 7 commits2026-05-29: 1 commit2026-05-30: 0 commits2026-05-31: 0 commits2026-06-01: 0 commits2026-06-02: 4 commits2026-06-03: 3 commits2026-06-04: 4 commits2026-06-05: 4 commits2026-06-06: 2 commits2026-06-07: 0 commits2026-06-08: 0 commits2026-06-09: 3 commits2026-06-10: 0 commits2026-06-11: 17 commits2026-06-12: 13 commits2026-06-13: 6 commits2026-06-14: 1 commit2026-06-15: 6 commits2026-06-16: 9 commits2026-06-17: 11 commits2026-06-18: 2 commits2026-06-19: 1 commit2026-06-20: 0 commits2026-06-21: 0 commits2026-06-22: 0 commits2026-06-23: 0 commits2026-06-24: 0 commits2026-06-25: 0 commits2026-06-26: 1 commit2026-06-27: 0 commits2026-06-28: 0 commits2026-06-29: 0 commits2026-06-30: 0 commits2026-07-01: 5 commits2026-07-02: 12 commits2026-07-03: 1 commit2026-07-04: 2 commits2026-07-05: 0 commits2026-07-06: 0 commits2026-07-07: 5 commits2026-07-08: 0 commits2026-07-09: 0 commits2026-07-10: 6 commits2026-07-11: 0 commits2026-07-12: 0 commits2026-07-13: 0 commits2026-07-14: 0 commits2026-07-15: 0 commits2026-07-16: 0 commits2026-07-17: 0 commits2026-07-18: 0 commits2026-07-19: 0 commits2026-07-20: 0 commits2026-07-21: 1 commit2026-07-22: 0 commits2026-07-23: 0 commits2026-07-24: 0 commits2026-07-25: 0 commits2026-07-26: 0 commits2026-07-27: 0 commits2026-07-28: 2 commits2026-07-29: 0 commits2026-07-30: 0 commits2026-07-31: 2 commits2026-08-01: 0 commits2026-08-02: 0 commits2026-08-03: 0 commits2026-08-04: 0 commits2026-08-05: 0 commits2026-08-06: 0 commits2026-08-07: 0 commits2026-08-08: 0 commits2026-08-09: 0 commits2026-08-10: 0 commits2026-08-11: 0 commits2026-08-12: 0 commits2026-08-13: 0 commits2026-08-14: 0 commits2026-08-15: 0 commits2026-08-16: 0 commits2026-08-17: 0 commits2026-08-18: 0 commits2026-08-19: 0 commits2026-08-20: 0 commits2026-08-21: 0 commits2026-08-22: 0 commits2026-08-23: 0 commits2026-08-24: 0 commits2026-08-25: 0 commits2026-08-26: 0 commits2026-08-27: 0 commits2026-08-28: 0 commits2026-08-29: 0 commits2026-08-30: 0 commits2026-08-31: 0 commits2026-09-01: 2 commits2026-09-02: 0 commits2026-09-03: 0 commits2026-09-04: 4 commits2026-09-05: 0 commits2026-09-06: 0 commits2026-09-07: 0 commits2026-09-08: 2 commits2026-09-09: 0 commits2026-09-10: 0 commits2026-09-11: 2 commits2026-09-12: 0 commits2026-09-13: 0 commits2026-09-14: 0 commits2026-09-15: 2 commits2026-09-16: 12 commits2026-09-17: 1 commit2026-09-18: 3 commits2026-09-19: 0 commits2026-09-20: 0 commits2026-09-21: 0 commits2026-09-22: 0 commits2026-09-23: 2 commits2026-09-24: 0 commits2026-09-25: 5 commits2026-09-26: 0 commits2026-09-27: 0 commits2026-09-28: 0 commits2026-09-29: 0 commits2026-09-30: 0 commits2026-10-01: 0 commits2026-10-02: 0 commits2026-10-03: 0 commits
893 commits in the last yearLessMore

Signals and awards

derived from tracked data
  • Battle-tested

    8 years of history

  • Very active

    893 commits in 52 weeks

  • Permissive license

    Unlicense

  • Continuous integration

    Automated checks passing

What xan does

xan acts as an extremely fast, memory-efficient command-line utility for manipulating gigabyte-sized CSV files directly from the shell. Written entirely in Rust, it aggressively leverages SIMD instructions for parsing and multithreading for parallel computations, allowing tasks to complete at the absolute maximum speed of the hardware. Beyond basic filtering and joining, it features a custom expression language tailored specifically for CSV data, vastly outperforming dynamic languages like Python. Originally rooted in web data collection for the social sciences, it also includes highly specialized utilities for lexicometry, graph theory, and terminal-based data visualization.

Data scientists, researchers, and backend engineers who frequently process very large tabular datasets and require maximum performance. It is highly optimized for users comfortable with shell scripting and command-line interfaces.

  • SIMD parsing: Utilizes a novel Single Instruction, Multiple Data parser to read and structure massive CSV files at extreme speeds.
  • Custom expression language: Executes complex logical filtering and transformations using a minimalistic language designed specifically for tabular data.
  • Parallel computations: Intelligently distributes processing tasks across multiple CPU threads to drastically reduce execution time on large datasets.
  • Terminal visualization: Renders basic data visualizations, including categorical histograms and scatterplots, directly within the terminal interface.
  • Format conversion: Seamlessly converts data between CSV, JSON, Excel, and specialized bioinformatics formats like VCF and SAM.

Where teams use it

Massive log filtering

Data engineers rapidly slicing and filtering multi-gigabyte server log files directly in the terminal without ever loading them entirely into memory.

Social science analysis

Researchers utilizing the specialized lexicometry tools to perform rapid preliminary analysis on heavily scraped web datasets.

Pipeline optimization

Backend developers replacing slow Python data transformation scripts in bash pipelines with highly optimized xan commands.

Bioinformatics wrangling

Scientists efficiently converting and joining massive VCF genomic data files directly from the command line.

Getting started: cargo install xan --locked

README

master branch

Build Status DOI

xan, the CSV magician

xan is a command line tool that can be used to process CSV files directly from the shell.

It has been written in Rust to be as fast as possible, use as little memory as possible, and can very easily handle large CSV files (gigabytes to terabytes). It leverages a novel SIMD CSV parser and is also able to parallelize some computations (through multithreading) to make some tasks complete as fast as your hardware will allow.

It can easily preview, filter, slice, aggregate, sort, join CSV files, and exposes a large collection of composable commands that can be chained together to perform a wide variety of typical tabular data processing tasks.

xan also offers its own expression language so you can perform complex tasks that cannot be done by relying on the simplest commands. This minimalistic language has been tailored for CSV data and is way faster than evaluating typical script languages such as Python, Lua, JavaScript etc.

Note that this tool is originally a fork of BurntSushi's xsv, but has been nearly entirely rewritten at that point, to fit SciencesPo's médialab use-cases, rooted in web data collection and analysis geared towards social sciences (you might think CSV is outdated by now, but read our love letter to the format before judging too quickly).

xan therefore goes beyond typical data manipulation and expose utilities related to lexicometry, graph theory and even scraping.

Beyond CSV data, xan is able to process a large variety of CSV-adjacent data formats from many different disciplines such as web archival (.cdx) or bioinformatics (.vcf, .gtf, .sam, .bed etc.). xan is also able to convert to & from many data formats such as json, ndjson, excel files, numpy arrays etc. using xan to and xan from. See this section for more detail.

Then, even though xan is fundamentally geared towards streams of row-oriented tabular data, it can sometimes leverage the benefits of the popular parquet file format to offer better performance. See this section for more detail.

Finally, xan can be used to display CSV files in the terminal, for easy exploration, and can even be used to draw basic data visualisations:

view command flatten command
view flatten
categorical histogram scatterplot
categ-hist correlation
categorical scatterplot histograms
scatter hist
parallel processing time series
parallel series
small multiples (facet grid) grouped view
small-multiples view-grid
correlation matrix heatmap heatmap
small-multiples view-grid

Summary

How to install

Cargo

xan can be installed using cargo (it usually comes with Rust):

cargo install xan --locked

You can also tweak the build flags to make sure the Rust compiler is able to leverage all your CPU's features:

CARGO_BUILD_RUSTFLAGS='-C target-cpu=native' cargo install xan --locked

You can also install the latest dev version thusly:

cargo install --git https://github.com/medialab/xan --locked

Scoop (Windows)

xan can be installed using Scoop on Windows:

scoop bucket add extras
scoop install xan

Homebrew (macOS)

xan can be installed with Homebrew on macOS thusly:

brew install xan

Arch Linux

You can install xan from the extra repository using pacman:

sudo pacman -S xan

NetBSD

A package is available from the official repositories. To install xan simply run:

pkgin install xan

Nix

xan is packaged for Nix, and is available in Nixpkgs as of 25.05 release. To install it, you may add it to your environment.systemPackages as pkgs.xan or use nix-shell to enter an ephemeral shell.

nix-shell -p xan

Pixi (Linux, macOS, Windows)

xan can be installed in Linux, macOS, and Windows using the Pixi package manager:

pixi global install xan

Conda Forge

xan can be installed through conda-forge thusly:

conda install conda-forge::xan

Pre-built binaries

Pre-built binaries can be found attached to every GitHub releases.

Currently supported targets include:

  • x86_64-apple-darwin

  • x86_64-unknown-linux-gnu

  • x86_64-unknown-linux-musl

  • x86_64-pc-windows-msvc

  • aarch64-apple-darwin

  • aarch64-unknown-linux-gnu

ppc64le targets are not built by the CI yet but prebuilt binaries can still be found in the conda-forge package's files if you need them.

Feel free to open a PR to improve the CI by adding relevant targets.

Installing completions

Note that xan also exposes handy automatic completions for command and header/column names that you can install through the xan completions command.

Run the following command to understand how to install those completions:

xan completions -h

For zsh, you can add the completion file to ~/.zfunc:

mkdir -p ~/.zfunc
xan completions zsh > ~/.zfunc/_xan

Then add this before compinit in your ~/.zshrc:

fpath=(~/.zfunc $fpath)
autoload -Uz compinit
compinit

Quick tour

Let's learn about the most commonly used xan commands by exploring a corpus of French medias:

Downloading the corpus

curl -LO https://github.com/medialab/corpora/raw/master/polarisation/medias.csv

Displaying the file's headers

xan headers medias.csv
0   webentity_id
1   name
2   prefixes
3   home_page
4   start_pages
5   indegree
6   hyphe_creation_timestamp
7   hyphe_last_modification_timestamp
8   outreach
9   foundation_year
10  batch
11  edito
12  parody
13  origin
14  digital_native
15  mediacloud_ids
16  wheel_category
17  wheel_subcategory
18  has_paywall
19  inactive

Counting the number of rows

xan count medias.csv
478

Previewing the file in the terminal

xan view medias.csv
Displaying 5/20 cols from 10 first rows of medias.csv
┌───┬───────────────┬───────────────┬────────────┬───┬─────────────┬──────────┐
│ - │ name          │ prefixes      │ home_page  │ … │ has_paywall │ inactive │
├───┼───────────────┼───────────────┼────────────┼───┼─────────────┼──────────┤
│ 0 │ Acrimed.org   │ http://acrim… │ http://ww… │ … │ false       │ <empty>  │
│ 1 │ 24matins.fr   │ http://24mat… │ https://w… │ … │ false       │ <empty>  │
│ 2 │ Actumag.info  │ http://actum… │ https://a… │ … │ false       │ <empty>  │
│ 3 │ 2012un-Nouve… │ http://2012u… │ http://ww… │ … │ false       │ <empty>  │
│ 4 │ 24heuresactu… │ http://24heu… │ http://24… │ … │ false       │ <empty>  │
│ 5 │ AgoraVox      │ http://agora… │ http://ww… │ … │ false       │ <empty>  │
│ 6 │ Al-Kanz.org   │ http://al-ka… │ https://w… │ … │ false       │ <empty>  │
│ 7 │ Alalumieredu… │ http://alalu… │ http://al… │ … │ false       │ <empty>  │
│ 8 │ Allodocteurs… │ http://allod… │ https://w… │ … │ false       │ <empty>  │
│ 9 │ Alterinfo.net │ http://alter… │ http://ww… │ … │ <empty>     │ true     │
│ … │ …             │ …             │ …          │ … │ …           │ …        │
└───┴───────────────┴───────────────┴────────────┴───┴─────────────┴──────────┘

On unix, don't hesitate to use the -p flag to automagically forward the full output to an appropriate pager and skim through all the columns.

Reading a flattened representation of the first row

# NOTE: drop -c to avoid truncating the values
xan flatten -c medias.csv
Row n°0
───────────────────────────────────────────────────────────────────────────────
webentity_id                      1
name                              Acrimed.org
prefixes                          http://acrimed.org|http://acrimed69.blogspot…
home_page                         http://www.acrimed.org
start_pages                       http://acrimed.org|http://acrimed69.blogspot…
indegree                          61
hyphe_creation_timestamp          1560347020330
hyphe_last_modification_timestamp 1560526005389
outreach                          nationale
foundation_year                   2002
batch                             1
edito                             media
parody                            false
origin                            france
digital_native                    true
mediacloud_ids                    258269
wheel_category                    Opinion Journalism
wheel_subcategory                 Left Wing
has_paywall                       false
inactive                          <empty>

Row n°1
───────────────────────────────────────────────────────────────────────────────
webentity_id                      2
...

Searching for rows

xan search -s outreach internationale medias.csv | xan view -s name,outreach
Displaying 2 cols from 10 first rows of <stdin>
┌───┬────────────────────┬────────────────┐
│ - │ name               │ outreach       │
├───┼────────────────────┼────────────────┤
│ 0 │ Businessinsider.fr │ internationale │
│ 1 │ Europe-Israel.org  │ internationale │
│ 2 │ France 24          │ internationale │
│ 3 │ RFI                │ internationale │
│ 4 │ fr.Sott.net        │ internationale │
│ 5 │ Voltairenet.org    │ internationale │
│ 6 │ Afp.com /fr        │ internationale │
│ 7 │ Euronews FR        │ internationale │
│ 8 │ Arte.tv            │ internationale │
│ 9 │ I24News.tv         │ internationale │
│ … │ …                  │ …              │
└───┴────────────────────┴────────────────┘

Selecting some columns

xan select foundation_year,name medias.csv | xan view
Displaying 2 cols from 10 first rows of <stdin>
┌───┬─────────────────┬───────────────────────────────────────┐
│ - │ foundation_year │ name                                  │
├───┼─────────────────┼───────────────────────────────────────┤
│ 0 │ 2002            │ Acrimed.org                           │
│ 1 │ 2006            │ 24matins.fr                           │
│ 2 │ 2013            │ Actumag.info                          │
│ 3 │ 2012            │ 2012un-Nouveau-Paradigme.com          │
│ 4 │ 2010            │ 24heuresactu.com                      │
│ 5 │ 2005            │ AgoraVox                              │
│ 6 │ 2008            │ Al-Kanz.org                           │
│ 7 │ 2012            │ Alalumieredunouveaumonde.blogspot.com │
│ 8 │ 2005            │ Allodocteurs.fr                       │
│ 9 │ 2005            │ Alterinfo.net                         │
│ … │ …               │ …                                     │
└───┴─────────────────┴───────────────────────────────────────┘

Sorting the file

xan sort -s foundation_year medias.csv | xan view -s name,foundation_year
Displaying 2 cols from 10 first rows of <stdin>
┌───┬────────────────────────────────────┬─────────────────┐
│ - │ name                               │ foundation_year │
├───┼────────────────────────────────────┼─────────────────┤
│ 0 │ Le Monde Numérique (Ouest France)  │ <empty>         │
│ 1 │ Le Figaro                          │ 1826            │
│ 2 │ Le journal de Saône-et-Loire       │ 1826            │
│ 3 │ L'Indépendant                      │ 1846            │
│ 4 │ Le Progrès                         │ 1859            │
│ 5 │ La Dépêche du Midi                 │ 1870            │
│ 6 │ Le Pélerin                         │ 1873            │
│ 7 │ Dernières Nouvelles d'Alsace (DNA) │ 1877            │
│ 8 │ La Croix                           │ 1883            │
│ 9 │ Le Chasseur Francais               │ 1885            │
│ … │ …                                  │ …               │
└───┴────────────────────────────────────┴─────────────────┘

Deduplicating the file on some column

# Some medias of our corpus have the same ids on mediacloud.org
xan dedup -s mediacloud_ids medias.csv | xan count && xan count medias.csv
457
478

Deduplicating can also be done while sorting:

xan sort -s mediacloud_ids -u medias.csv

Computing frequency tables

xan frequency -s edito medias.csv | xan view
Displaying 3 cols from 5 rows of <stdin>
┌───┬───────┬────────────┬───────┐
│ - │ field │ value      │ count │
├───┼───────┼────────────┼───────┤
│ 0 │ edito │ media      │ 423   │
│ 1 │ edito │ individu   │ 30    │
│ 2 │ edito │ plateforme │ 14    │
│ 3 │ edito │ agrégateur │ 10    │
│ 4 │ edito │ agence     │ 1     │
└───┴───────┴────────────┴───────┘

Printing a histogram

xan frequency -s edito medias.csv | xan hist
Histogram for edito (bars: 5, sum: 478, max: 423):

media      |423  88.49%|━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━|
individu   | 30   6.28%|━━━╸                                                  |
plateforme | 14   2.93%|━╸                                                    |
agrégateur | 10   2.09%|━╸                                                    |
agence     |  1   0.21%|╸                                                     |

Computing descriptive statistics

xan stats -s indegree,edito medias.csv | xan transpose | xan view -I
Displaying 2 cols from 14 rows of <stdin>
┌─────────────┬───────────────────┬────────────┐
│ field       │ indegree          │ edito      │
├─────────────┼───────────────────┼────────────┤
│ count       │ 463               │ 478        │
│ count_empty │ 15                │ 0          │
│ type        │ int               │ string     │
│ types       │ int|empty         │ string     │
│ sum         │ 25987             │ <empty>    │
│ mean        │ 56.12742980561554 │ <empty>    │
│ variance    │ 4234.530197929737 │ <empty>    │
│ stddev      │ 65.07326792108829 │ <empty>    │
│ min         │ 0                 │ <empty>    │
│ max         │ 424               │ <empty>    │
│ lex_first   │ 0                 │ agence     │
│ lex_last    │ 99                │ plateforme │
│ min_length  │ 0                 │ 5          │
│ max_length  │ 3                 │ 11         │
└─────────────┴───────────────────┴────────────┘

Evaluating an expression to filter a file

xan filter 'batch > 1' medias.csv | xan count
130

Note that the expression language distinguishes between arithmetic & string operators. Filtering on the media column which contains strings, for instance, you would rather use the eq operator than the == one that should be used for numbers:

xan filter 'edito eq "plateforme"'

This said, for this particular use-case you should often stick to xan search instead.

To access the expression language's cheatsheet, run xan help cheatsheet. To display the full list of available functions, run xan help functions.

Evaluating an expression to create a new column based on other ones

xan map 'fmt("{} ({})", name, foundation_year) as key' medias.csv | xan select key | xan slice -l 10
key
Acrimed.org (2002)
24matins.fr (2006)
Actumag.info (2013)
2012un-Nouveau-Paradigme.com (2012)
24heuresactu.com (2010)
AgoraVox (2005)
Al-Kanz.org (2008)
Alalumieredunouveaumonde.blogspot.com (2012)
Allodocteurs.fr (2005)
Alterinfo.net (2005)

To access the expression language's cheatsheet, run xan help cheatsheet. To display the full list of available functions, run xan help functions.

Transform a column by evaluating an expression

xan transform name 'split(name, ".") | first | upper' medias.csv | xan select name | xan slice -l 10
name
ACRIMED
24MATINS
ACTUMAG
2012UN-NOUVEAU-PARADIGME
24HEURESACTU
AGORAVOX
AL-KANZ
ALALUMIEREDUNOUVEAUMONDE
ALLODOCTEURS
ALTERINFO

To access the expression language's cheatsheet, run xan help cheatsheet. To display the full list of available functions, run xan help functions.

Performing custom aggregation

xan agg 'sum(indegree) as total_indegree, mean(indegree) as mean_indegree' medias.csv | xan view -I
Displaying 1 col from 1 rows of <stdin>
┌────────────────┬───────────────────┐
│ total_indegree │ mean_indegree     │
├────────────────┼───────────────────┤
│ 25987          │ 56.12742980561554 │
└────────────────┴───────────────────┘

To access the expression language's cheatsheet, run xan help cheatsheet. To display the full list of available functions, run xan help functions. Finally, to display the list of available aggregation functions, run xan help aggs.

Grouping rows and performing per-group aggregation

xan groupby edito 'sum(indegree) as indegree' medias.csv | xan view -I
Displaying 1 col from 5 rows of <stdin>
┌────────────┬──────────┐
│ edito      │ indegree │
├────────────┼──────────┤
│ agence     │ 50       │
│ agrégateur │ 459      │
│ plateforme │ 658      │
│ media      │ 24161    │
│ individu   │ 659      │
└────────────┴──────────┘

To access the expression language's cheatsheet, run xan help cheatsheet. To display the full list of available functions, run xan help functions. Finally, to display the list of available aggregation functions, run xan help aggs.

Learning

If you speak French, here is a quick rundown of the tool by our friends from CERES.

Documented use-cases

For a sense of what can be achieved with xan, see this page summarizing a variety of complex but detailed pipelines that have been used in real-life by real people to solve their problems, using the tool: PIPELINES.

Available commands

  • help: Get help regarding the expression language

Explore & visualize

  • count (c): Count rows in file
  • headers (h): Show header names
  • view (v): Preview a CSV file in a human-friendly way
  • flatten: Display a flattened version of each row of a file
  • hist: Print a histogram with rows of CSV file as bars
  • plot: Draw a scatter plot or line chart
  • heatmap: Draw a heatmap of a CSV matrix
  • spark: Draw ascii sparklines (e.g. ▇▅▄▃▂▃) from CSV data
  • progress: Display a progress bar while reading CSV data

Search & filter

  • search: Search for (or replace) patterns in CSV data
  • filter: Only keep some CSV rows based on an evaluated expression
  • head: First rows of CSV file
  • tail: Last rows of CSV file
  • slice: Slice rows of CSV file
  • top: Find top rows of a CSV file according to some column
  • sample: Randomly sample CSV data
  • bisect: Binary search on sorted CSV data

Sort & deduplicate

Aggregate

  • frequency (freq): Show frequency tables
  • groupby: Aggregate data by groups of a CSV file
  • stats: Compute basic statistics
  • agg: Aggregate data from CSV file
  • bins: Dispatch numeric columns into bins
  • window: Compute window aggregations (cumsum, rolling mean, lag etc.)

Combine multiple CSV files

  • cat: Concatenate by row or column
  • join: Join CSV files
  • merge: Merge multiple similar already sorted CSV files

Add, transform, drop and move columns

  • select: Select columns from a CSV file
  • drop: Drop columns from a CSV file
  • map: Create a new column by evaluating an expression on each CSV row
  • transform: Transform a column by evaluating an expression on each CSV row
  • enum: Enumerate CSV file by preprending an index column
  • fill: Fill empty cells
  • complete: Add missing rows in a column of contiguous values
  • blank: Blank down contiguous identical cell values
  • separate: Split a single column into multiple ones

Format, convert & recombobulate

  • behead: Drop header from CSV file
  • rename: Rename columns of a CSV file
  • input: Read unusually formatted CSV data
  • fixlengths: Makes all rows have same length
  • fmt: Format CSV output (change field delimiter)
  • explode: Explode rows based on some column separator
  • implode: Collapse consecutive identical rows based on a diverging column
  • from: Convert a variety of formats to CSV
  • to: Convert a CSV file to a variety of data formats
  • scrape: Scrape HTML into CSV data
  • reverse: Reverse rows of CSV data

Transpose & pivot

  • transpose (t): Transpose CSV file
  • pivot: Split distinct values of a column into their own columns columns
  • unpivot: Stack multiple columns into fewer

Split a CSV file into multiple

  • split: Split CSV data into chunks
  • partition: Partition CSV data based on a column value

Parallelization

Generate CSV files

  • range: Create a CSV file from a numerical range

Lexicometry & fuzzy matching

  • tokenize: Tokenize a text column
  • vocab: Build a vocabulary over tokenized documents

Matrix & network-related commands

  • matrix: Convert CSV data to matrix data
  • network: Convert CSV data to network data

Scripting

  • run: Run a xan pipeline or script
  • eval: Evaluate/debug a single expression

General flags and IO model

Getting help

If you ever feel lost, each command has a -h/--help flag that will print the related documentation.

If you need help about the expression language, check out the help command itself:

# Help about help ;)
xan help --help

Regarding input & output formats

All xan commands expect a "standard" CSV file, e.g. comma-delimited, with proper double-quote escaping. This said, xan is also perfectly able to infer the delimiter from typical file extensions such as .tsv, .tab, .psv, .ssv or .scsv.

If you need to process a file with a custom delimiter, you can either use the xan input command or use the -d/--delimiter flag available with all commands.

If you need to output a custom CSV dialect (e.g. using ; delimiters), feel free to use the xan fmt command.

If your CSV file has a varying number of columns per row, use the xan fixlengths command before piping into other commands as xan expects well-behaved CSV data where rows all have the same number of columns.

Finally, even if most xan commands won't even need to decode the file's bytes, some might still need to. In this case, xan will expect correctly formatted UTF-8 text. Please use iconv or other utils if you need to process other encodings such as latin1 ahead of xan.

Working with headless CSV file

Even if this is good practice to name your columns, some CSV file simply don't have headers. Most commands are able to deal with those file if you give the -n/--no-headers flag.

Note that this flag always relates to the input, not the output. If for some reason you want to drop a CSV output's header row, use the xan behead command.

Regarding stdin

By default, all commands will try to read from stdin when the file path is not specified. This makes piping easy and comfortable as it respects typical unix standards. Some commands may have multiple inputs (xan join, for instance), in which case stdin is usually specifiable using the - character:

# First file given to join will be read from stdin
cat file1.csv | xan join col1 - col2 file2.csv

Note that the command will also warn you when stdin cannot be read, in case you forgot to indicate the file's path.

Regarding stdout

By default, all commands will print their output to stdout (note that this output is usually buffered for performance reasons).

In addition, all commands expose a -o/--output flag that can be use to specify where to write the output. This can be useful if you do not want to or cannot use > (typically in some Windows shells). In which case, - as a output path will mean forwarding to stdout also. This can be useful when scripting sometimes.

Supported file formats

xan is able to process a large variety of CSV-adjacent data formats out-of-the box:

  • .csv files will be understood as comma-separated
  • .tsv & .tab files will be understood as tab-separated
  • .scsv & .ssv files will be understood as semicolon-separated
  • .psv files will be understood as pipe-separated
  • .cdx files (an index file format related to web archive) will be understood as space-separated and will have its magic bytes dropped
  • .ndjson & .jsonl files will be understood as tab-separated, headless, null-byte-quoted, so you can easily use them with xan commands (e.g. parsing or wrangling JSON data using the expression language to aggregate, even in parallel). If you need a more thorough conversion of newline-delimited JSON data, check out the xan from -f ndjson command instead.
  • .vcf files (Variant Call Format) from bioinformatics are supported out of the box. They will be stripped of their header data and considered as tab-delimited.
  • .gtf & .gff2 files (Gene Transfert Format) from bioinformatics are supported out of the box. They will be stripped of their header data and considered as headless & tab-delimited.
  • .sam files (Sequence Alignment Map) from bioinformatics are supported out of the box. They will be stripped of their header data and considered as headless & tab-delimited.
  • .bed files (Browser Extensible Data) from bioinformatics are supported out of the box. They will be stripped of their header data and considered as headless & tab-delimited.
  • .mtx files (Matrix Market Exchange format). They must be well formed and don't contain leading nor trailing whitespace. They will be stripped of their header & comments and considered as headless and space-delimited.

Note that more exotic delimiters can always be handled using the ubiquitous -d, --delimiter flag.

Some additional formats (e.g. .gff, .gff3) are also supported but must first be normalized using the xan input command because their cells must be trimmed or because they have comment lines to be skipped.

Note also that UTF-8 BOMs ara always stripped from the data when processed.

Regarding parquet files

xan is first and foremost a tool geared towards processing row-oriented streams of tabular data. As such it is not well aligned with the philosophy of the popular parquet file format.

This said, xan knows how to efficiently stream a parquet file as CSV data using xan from:

# `xan from` lets you stream any parquet file as the start of a pipeline:
xan from data.parquet | xan search -s title French | xan count

Then, some xan commands offer better parquet integration when they can leverage the benefits of the file format itself:

  • xan count knows how to access the number of rows of a parquet file in constant time by reading its footer.
  • xan headers will display the type of the columns along with their names.

Compressed files

xan is able to read gzipped files (having a .gz extension). It is also able to leverage .gzi indices (usually created through bgzip) when seeking is necessary (constant time reversing, parallelization etc.).

xan is also able to read files compressed with Zstdandard (having a .zst extension).

Regarding color

Some xan commands print ANSI colors in the terminal by default, typically view, flatten, etc.

All those commands have a standard --color=(auto|always|never) flag to tweak the colouring behavior if you need it (note that colors are not printed when commands are piped, by default).

They also respect typical environment variables related to ANSI colouring, such as NO_COLOR, CLICOLOR & CLICOLOR_FORCE, as documented here.

Also, note that some xan commands (xan heatmap & xan spark notably) require a terminal able to display truecolor (24bits) ANSI colors (at least if you want them to be able to print continuous color gradients).

Sometimes you might want to explicitly set the COLORTERM env variable to truecolor, if you know your terminal supports them but your shell does not know it (e.g. sometimes when using screen, tmux or ssh).

Expression language reference

News

For news about the tool's evolutions feel free to read:

  1. the changelog
  2. the xan zines
  3. the roadmap

See also blog posts related to the tool:

How to cite?

xan is published on Zenodo as 10.5281/zenodo.15310200.

You can cite it thusly:

Guillaume Plique, Béatrice Mazoyer, Laura Miguel, César Pichon, Anna Charles, & Julien Pontoire. (2025). xan, the CSV magician. (0.50.0). Zenodo. https://doi.org/10.5281/zenodo.15310200

Frequently Asked Questions

How to display a vertical bar chart?

Rotate your screen ;)

View on GitHub

Recent activity

commits and pull requests

Recent open issues

view all

Discussions

all 2

Releases and announcements

40 total
  1. v0.61.00.61.0Sep 11, 20261.5K downloads

    *Features* * Support for `.mtx` (Matrix Market) files. * Adding `geometric_mean` & `harmonic_mean` aggregation functions. *Fixes* * Fixing `xan rename` with non-comma delimiters. * Fixing `xan from -f=parquet` not converting timestamp columns. * Fixing open-ended moonblade slicing. * Fixing `xan parallel (cat|map)` not working with `-R/--run`. * Fixing `xan parallel -R/--run` not spawning checker thread. * Fixing `xan cat rows (-I|-U) -S/--source-column`. *Performance* * Improving performance of `xan freq` & `xan p freq`. *Quality of Life* * Better moonblade error messages when values are not yet materialized. * Better `xan count -H/--human-readable`.

  2. v0.60.00.60.0Jul 10, 20263.4K downloads

    *Breaking* * Renaming `xan from --path` to `--root`. * Renaming `xan separate -T/--txt` to `-L/--lines`. *Features* * Adding `xan count -c/--check-alignment & -H/--human-readable`. * Adding `xan sort -e -z/--compress`. * Adding `xan sample -g -S/--sorted`. * Adding `xan from -f=(json|ndjson) --model`. * Adding `xan cat rows -I/--intersection & -U/--union`. * Adding `xan top -g -S/--sorted`. * Adding the `sort`, `dedup`, `flatten` & `flat_map` moonblade function. * Adding support for `list` & `map` columns when using `xan from -f=parquet`. *Fixes* * Fixing text wrapping across tool, especially `xan flatten -w` & `xan flatten -F`. * Fixing `xan select -e` & `xan map` plural clause flattening given list. * Fixing `xan from -f=parquet` not emitting correct column names for list & map columns. *Performance* * Introducing a fast path for `xan sort -e` when input fits in a single chunk. * Faster `xan from -f=ndjson & -f=parquet`. * Amortizing `xan sample` allocations. * Improving performance of `xan freq` & `xan p freq`. *Quality of Life* * Better record size estimation for `xan sort -e`. * Better `xan flatten -c` when string width cannot be computed correctly (because of emojis

  3. v0.60.0-rc.10.60.0-rc.1Jun 26, 2026pre-release37 downloads
  4. v0.59.00.59.0Jun 17, 20264.5K downloads

    *Breaking* * Bumping MSRV to `1.85.0` and edition 2024. * Overhauling how `xan scrape` takes its inputs. It now targets HTML files on disk by default now. * `xan plot --density-scale` now defaults to `log`. * `xan freq -X/--approx-algo` & `xan p freq -X/--approx-algo` now default to `heavy-keeper`. * Dropping `xan eval -S/--serialize`. The default behavior of the command is now to output the serialized value. *Features* * Adding `xan search -x/--pattern-file`. * Adding `xan cat --glob`, `xan merge --glob`, `xan parallel --glob`. * Adding the `hostname` moonblade function. * Adding `xan scrape --paths, --path-column, --docs, --docs-column, -D/--stdin-doc & --glob`. * Adding `xan from -f=(json|ndjson) --path <path>`. * Adding `xan from -f toml` & `-f raw`. * Adding `xan spark --hide-all & --repeat-x-axis`. *Fixes* * Fixing moonblade string with bstring equality. * Fixing percentages shown by `xan spark -P`. * Fixing `xan complete` correctness in presence of duplicate values. * Fixing `xan spark -c` discretization & legend. *Performance* * Improving performance of `xan scrape`. * Improving performance of `xan from -f ndjson`. *Quality of Life* * Better legends & axis for `xan

  5. v0.59.0-rc.10.59.0-rc.1Jun 16, 2026pre-release33 downloads

Code frequency

additions and deletions
+6.6K-6.6KWeek of 2025-09-21: +95 linesWeek of 2025-09-21: -20 linesWeek of 2025-09-28: +192 linesWeek of 2025-09-28: -67 linesWeek of 2025-10-05: +340 linesWeek of 2025-10-05: -243 linesWeek of 2025-10-12: +2,065 linesWeek of 2025-10-12: -1,185 linesWeek of 2025-10-19: +2,556 linesWeek of 2025-10-19: -1,081 linesWeek of 2025-10-26: +1,399 linesWeek of 2025-10-26: -823 linesWeek of 2025-11-02: +416 linesWeek of 2025-11-02: -930 linesWeek of 2025-11-09: +2,604 linesWeek of 2025-11-09: -611 linesWeek of 2025-11-16: +477 linesWeek of 2025-11-16: -256 linesWeek of 2025-11-23: +694 linesWeek of 2025-11-23: -299 linesWeek of 2025-11-30: +0 linesWeek of 2025-11-30: -0 linesWeek of 2025-12-07: +0 linesWeek of 2025-12-07: -0 linesWeek of 2025-12-14: +325 linesWeek of 2025-12-14: -198 linesWeek of 2025-12-21: +103 linesWeek of 2025-12-21: -1 linesWeek of 2025-12-28: +0 linesWeek of 2025-12-28: -0 linesWeek of 2026-01-04: +0 linesWeek of 2026-01-04: -0 linesWeek of 2026-01-11: +0 linesWeek of 2026-01-11: -0 linesWeek of 2026-01-18: +0 linesWeek of 2026-01-18: -0 linesWeek of 2026-01-25: +11 linesWeek of 2026-01-25: -11 linesWeek of 2026-02-01: +2,699 linesWeek of 2026-02-01: -262 linesWeek of 2026-02-08: +1,040 linesWeek of 2026-02-08: -487 linesWeek of 2026-02-15: +1,434 linesWeek of 2026-02-15: -494 linesWeek of 2026-02-22: +68 linesWeek of 2026-02-22: -199 linesWeek of 2026-03-01: +37 linesWeek of 2026-03-01: -2 linesWeek of 2026-03-08: +0 linesWeek of 2026-03-08: -0 linesWeek of 2026-03-15: +1,128 linesWeek of 2026-03-15: -414 linesWeek of 2026-03-22: +6,631 linesWeek of 2026-03-22: -4,874 linesWeek of 2026-03-29: +5,717 linesWeek of 2026-03-29: -4,338 linesWeek of 2026-04-05: +981 linesWeek of 2026-04-05: -556 linesWeek of 2026-04-12: +341 linesWeek of 2026-04-12: -126 linesWeek of 2026-04-19: +3,465 linesWeek of 2026-04-19: -3,021 linesWeek of 2026-04-26: +3,967 linesWeek of 2026-04-26: -1,915 linesWeek of 2026-05-03: +4,863 linesWeek of 2026-05-03: -3,509 linesWeek of 2026-05-10: +2,555 linesWeek of 2026-05-10: -902 linesWeek of 2026-05-17: +1,227 linesWeek of 2026-05-17: -446 linesWeek of 2026-05-24: +761 linesWeek of 2026-05-24: -198 linesWeek of 2026-05-31: +1,455 linesWeek of 2026-05-31: -527 linesWeek of 2026-06-07: +2,892 linesWeek of 2026-06-07: -1,034 linesWeek of 2026-06-14: +1,506 linesWeek of 2026-06-14: -1,082 linesWeek of 2026-06-21: +2 linesWeek of 2026-06-21: -2 linesWeek of 2026-06-28: +1,375 linesWeek of 2026-06-28: -434 linesWeek of 2026-07-05: +311 linesWeek of 2026-07-05: -73 linesWeek of 2026-07-12: +0 linesWeek of 2026-07-12: -0 linesWeek of 2026-07-19: +7 linesWeek of 2026-07-19: -0 linesWeek of 2026-07-26: +35 linesWeek of 2026-07-26: -13 linesWeek of 2026-08-02: +0 linesWeek of 2026-08-02: -0 linesWeek of 2026-08-09: +0 linesWeek of 2026-08-09: -0 linesWeek of 2026-08-16: +0 linesWeek of 2026-08-16: -0 linesWeek of 2026-08-23: +0 linesWeek of 2026-08-23: -0 linesWeek of 2026-08-30: +341 linesWeek of 2026-08-30: -44 linesWeek of 2026-09-06: +79 linesWeek of 2026-09-06: -102 linesWeek of 2026-09-13: +0 linesWeek of 2026-09-13: -0 linesSep 21, 2025Sep 13, 2026
+56.2K lines added, -30.8K removed over the last year.

Commits per week

last 52 weeks
800Week of 2025-10-05: 11 commitsWeek of 2025-10-12: 31 commitsWeek of 2025-10-19: 48 commitsWeek of 2025-10-26: 41 commitsWeek of 2025-11-02: 17 commitsWeek of 2025-11-09: 20 commitsWeek of 2025-11-16: 11 commitsWeek of 2025-11-23: 14 commitsWeek of 2025-11-30: 0 commitsWeek of 2025-12-07: 0 commitsWeek of 2025-12-14: 9 commitsWeek of 2025-12-21: 2 commitsWeek of 2025-12-28: 0 commitsWeek of 2026-01-04: 0 commitsWeek of 2026-01-11: 0 commitsWeek of 2026-01-18: 0 commitsWeek of 2026-01-25: 2 commitsWeek of 2026-02-01: 22 commitsWeek of 2026-02-08: 22 commitsWeek of 2026-02-15: 25 commitsWeek of 2026-02-22: 4 commitsWeek of 2026-03-01: 2 commitsWeek of 2026-03-08: 0 commitsWeek of 2026-03-15: 23 commitsWeek of 2026-03-22: 48 commitsWeek of 2026-03-29: 61 commitsWeek of 2026-04-05: 17 commitsWeek of 2026-04-12: 16 commitsWeek of 2026-04-19: 43 commitsWeek of 2026-04-26: 59 commitsWeek of 2026-05-03: 56 commitsWeek of 2026-05-10: 80 commitsWeek of 2026-05-17: 29 commitsWeek of 2026-05-24: 22 commitsWeek of 2026-05-31: 17 commitsWeek of 2026-06-07: 39 commitsWeek of 2026-06-14: 30 commitsWeek of 2026-06-21: 1 commitsWeek of 2026-06-28: 20 commitsWeek of 2026-07-05: 11 commitsWeek of 2026-07-12: 0 commitsWeek of 2026-07-19: 1 commitsWeek of 2026-07-26: 4 commitsWeek of 2026-08-02: 0 commitsWeek of 2026-08-09: 0 commitsWeek of 2026-08-16: 0 commitsWeek of 2026-08-23: 0 commitsWeek of 2026-08-30: 6 commitsWeek of 2026-09-06: 4 commitsWeek of 2026-09-13: 18 commitsWeek of 2026-09-20: 7 commitsWeek of 2026-09-27: 0 commitsOct 5, 2025Sep 27, 2026
893 commits in the last 52 weeks.

When work happens

weekday and hour
SunMonTueWedThuFriSat036912151821Sun 0:00 — 14 commitsSun 1:00 — 8 commitsSun 2:00 — 0 commitsSun 3:00 — 0 commitsSun 4:00 — 0 commitsSun 5:00 — 0 commitsSun 6:00 — 0 commitsSun 7:00 — 0 commitsSun 8:00 — 2 commitsSun 9:00 — 11 commitsSun 10:00 — 8 commitsSun 11:00 — 14 commitsSun 12:00 — 13 commitsSun 13:00 — 20 commitsSun 14:00 — 13 commitsSun 15:00 — 24 commitsSun 16:00 — 13 commitsSun 17:00 — 7 commitsSun 18:00 — 3 commitsSun 19:00 — 5 commitsSun 20:00 — 18 commitsSun 21:00 — 17 commitsSun 22:00 — 3 commitsSun 23:00 — 0 commitsMon 0:00 — 0 commitsMon 1:00 — 0 commitsMon 2:00 — 0 commitsMon 3:00 — 0 commitsMon 4:00 — 0 commitsMon 5:00 — 0 commitsMon 6:00 — 0 commitsMon 7:00 — 0 commitsMon 8:00 — 0 commitsMon 9:00 — 3 commitsMon 10:00 — 39 commitsMon 11:00 — 64 commitsMon 12:00 — 10 commitsMon 13:00 — 36 commitsMon 14:00 — 73 commitsMon 15:00 — 55 commitsMon 16:00 — 61 commitsMon 17:00 — 73 commitsMon 18:00 — 24 commitsMon 19:00 — 16 commitsMon 20:00 — 21 commitsMon 21:00 — 30 commitsMon 22:00 — 23 commitsMon 23:00 — 1 commitsTue 0:00 — 2 commitsTue 1:00 — 0 commitsTue 2:00 — 1 commitsTue 3:00 — 0 commitsTue 4:00 — 1 commitsTue 5:00 — 0 commitsTue 6:00 — 1 commitsTue 7:00 — 0 commitsTue 8:00 — 0 commitsTue 9:00 — 7 commitsTue 10:00 — 23 commitsTue 11:00 — 64 commitsTue 12:00 — 13 commitsTue 13:00 — 17 commitsTue 14:00 — 56 commitsTue 15:00 — 57 commitsTue 16:00 — 77 commitsTue 17:00 — 114 commitsTue 18:00 — 23 commitsTue 19:00 — 7 commitsTue 20:00 — 17 commitsTue 21:00 — 19 commitsTue 22:00 — 18 commitsTue 23:00 — 4 commitsWed 0:00 — 0 commitsWed 1:00 — 0 commitsWed 2:00 — 0 commitsWed 3:00 — 0 commitsWed 4:00 — 1 commitsWed 5:00 — 0 commitsWed 6:00 — 0 commitsWed 7:00 — 1 commitsWed 8:00 — 0 commitsWed 9:00 — 6 commitsWed 10:00 — 53 commitsWed 11:00 — 98 commitsWed 12:00 — 27 commitsWed 13:00 — 56 commitsWed 14:00 — 35 commitsWed 15:00 — 61 commitsWed 16:00 — 86 commitsWed 17:00 — 124 commitsWed 18:00 — 33 commitsWed 19:00 — 7 commitsWed 20:00 — 5 commitsWed 21:00 — 16 commitsWed 22:00 — 20 commitsWed 23:00 — 3 commitsThu 0:00 — 0 commitsThu 1:00 — 0 commitsThu 2:00 — 0 commitsThu 3:00 — 0 commitsThu 4:00 — 2 commitsThu 5:00 — 0 commitsThu 6:00 — 1 commitsThu 7:00 — 1 commitsThu 8:00 — 7 commitsThu 9:00 — 19 commitsThu 10:00 — 51 commitsThu 11:00 — 58 commitsThu 12:00 — 27 commitsThu 13:00 — 41 commitsThu 14:00 — 88 commitsThu 15:00 — 66 commitsThu 16:00 — 85 commitsThu 17:00 — 67 commitsThu 18:00 — 37 commitsThu 19:00 — 17 commitsThu 20:00 — 21 commitsThu 21:00 — 23 commitsThu 22:00 — 16 commitsThu 23:00 — 6 commitsFri 0:00 — 8 commitsFri 1:00 — 1 commitsFri 2:00 — 1 commitsFri 3:00 — 0 commitsFri 4:00 — 0 commitsFri 5:00 — 1 commitsFri 6:00 — 0 commitsFri 7:00 — 0 commitsFri 8:00 — 2 commitsFri 9:00 — 14 commitsFri 10:00 — 58 commitsFri 11:00 — 88 commitsFri 12:00 — 34 commitsFri 13:00 — 30 commitsFri 14:00 — 73 commitsFri 15:00 — 82 commitsFri 16:00 — 83 commitsFri 17:00 — 82 commitsFri 18:00 — 34 commitsFri 19:00 — 5 commitsFri 20:00 — 10 commitsFri 21:00 — 17 commitsFri 22:00 — 12 commitsFri 23:00 — 10 commitsSat 0:00 — 3 commitsSat 1:00 — 1 commitsSat 2:00 — 0 commitsSat 3:00 — 0 commitsSat 4:00 — 0 commitsSat 5:00 — 0 commitsSat 6:00 — 1 commitsSat 7:00 — 0 commitsSat 8:00 — 1 commitsSat 9:00 — 4 commitsSat 10:00 — 13 commitsSat 11:00 — 10 commitsSat 12:00 — 9 commitsSat 13:00 — 14 commitsSat 14:00 — 18 commitsSat 15:00 — 21 commitsSat 16:00 — 21 commitsSat 17:00 — 9 commitsSat 18:00 — 5 commitsSat 19:00 — 2 commitsSat 20:00 — 11 commitsSat 21:00 — 20 commitsSat 22:00 — 19 commitsSat 23:00 — 5 commits
Commit volume by weekday and hour (UTC). Larger dots mean more commits.
DateListRankStars gained
Jul 11, 2026daily#16+2
  • n8n-io/n8n

    Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.

    206.7K stars · TypeScript

  • yt-dlp/yt-dlp

    A feature-rich command-line audio/video downloader

    195.5K stars · Python

  • ultraworkers/claw-code

    An agent-managed museum exhibit, built in Rust with Gajae-Code / LazyCodex — developed and maintained with no human intervention.

    195.2K stars · Rust

  • farion1231/cc-switch

    A cross-platform desktop All-in-One assistant for Claude Code, Codex, OpenCode, OpenClaw, Grok Build & Hermes Agent. Only official website: ccswitch.io

    140K stars · Rust

  • openai/codex

    Lightweight coding agent that runs in your terminal

    127.8K stars · Rust

  • denoland/deno

    A modern runtime for JavaScript and TypeScript.

    108.6K stars · Rust