csvlite vs Polars · measured 29 September 2026

Faster than Polars.
Without writing Polars.

Same files, same laptop, CSV to answer. Median of 5 runs.

typical2.2× fastermedian of 35 measured queries
best case5.6× fasterDate range, 1 GB
1 GB2.0–5.6×faster on every query
10 GB · 9 queries9 of 9answered in 8 GB; Polars ran out of memory on 1

Every query

10 MB

53,596 rows · 15 columns · File in page cache

10 MB: median time from CSV to answer
QuerycsvlitePolarsBarsvs Polars
Text matchregion = north10 ms19 ms1.9× faster
Regex searchdescription has the word café14 ms21 ms1.4× faster
Number rangeamount 25,000–75,00010 ms18 ms1.9× faster
Date rangeoccurred_at in a range10 ms21 ms2.2× faster
Sort textevery row by region10 ms21 ms2.2× faster
Sort numbersevery row by amount10 ms20 ms2.0× faster
Sort datesevery row by occurred_at12 ms23 ms1.9× faster
Group + sumcount, sum(amount) by region, status12 ms20 ms1.7× faster
Group + distinct…plus distinct descriptions12 ms22 ms1.8× faster
Open once, keep askingTotal time as queries pile up. Polars re-reads the CSV per query; grey loads it into Polars first.
Total time after 9 queries, 10 MB: csvlite 40 ms, Polars 184 ms, Polars, read_csv first 44 ms0 ms50 ms100 ms150 ms200 msopen123456789queries answered184 msPolars44 msPolars, read_csv first40 mscsvlite
Chart data
AftercsvlitePolarsPolars, read_csv first
Open10 ms0.0 ms7.8 ms
Text match12 ms19 ms9.4 ms
Regex search18 ms39 ms13 ms
Number range20 ms57 ms16 ms
Date range23 ms78 ms22 ms
Sort text25 ms99 ms25 ms
Sort numbers27 ms119 ms28 ms
Sort dates30 ms142 ms34 ms
Group + sum34 ms162 ms39 ms
Group + distinct40 ms184 ms44 ms

100 MB

532,923 rows · 15 columns · File in page cache

100 MB: median time from CSV to answer
QuerycsvlitePolarsBarsvs Polars
Text matchregion = north15 ms64 ms4.4× faster
Regex searchdescription has the word café32 ms88 ms2.7× faster
Number rangeamount 25,000–75,00021 ms79 ms3.8× faster
Date rangeoccurred_at in a range19 ms90 ms4.7× faster
Sort textevery row by region29 ms80 ms2.7× faster
Sort numbersevery row by amount26 ms76 ms2.9× faster
Sort datesevery row by occurred_at27 ms90 ms3.4× faster
Group + sumcount, sum(amount) by region, status29 ms86 ms3.0× faster
Group + distinct…plus distinct descriptions39 ms95 ms2.5× faster
Open once, keep askingTotal time as queries pile up. Polars re-reads the CSV per query; grey loads it into Polars first.
Total time after 9 queries, 100 MB: csvlite 140 ms, Polars 746 ms, Polars, read_csv first 236 ms0 ms200 ms400 ms600 ms800 msopen123456789queries answered746 msPolars236 msPolars, read_csv first140 mscsvlite
Chart data
AftercsvlitePolarsPolars, read_csv first
Open11 ms0.0 ms34 ms
Text match14 ms64 ms37 ms
Regex search35 ms152 ms62 ms
Number range45 ms230 ms75 ms
Date range53 ms320 ms104 ms
Sort text69 ms400 ms121 ms
Sort numbers83 ms475 ms140 ms
Sort dates97 ms565 ms172 ms
Group + sum114 ms651 ms204 ms
Group + distinct140 ms746 ms236 ms

1 GB

5,300,205 rows · 15 columns · File in page cache

1 GB: median time from CSV to answer
QuerycsvlitePolarsBarsvs Polars
Text matchregion = north90 ms376 ms4.2× faster
Regex searchdescription has the word café264 ms613 ms2.3× faster
Number rangeamount 25,000–75,000172 ms473 ms2.7× faster
Date rangeoccurred_at in a range139 ms779 ms5.6× faster
Sort textevery row by region226 ms535 ms2.4× faster
Sort numbersevery row by amount197 ms551 ms2.8× faster
Sort datesevery row by occurred_at191 ms766 ms4.0× faster
Group + sumcount, sum(amount) by region, status236 ms620 ms2.6× faster
Group + distinct…plus distinct descriptions362 ms716 ms2.0× faster
Open once, keep askingTotal time as queries pile up. Polars re-reads the CSV per query; grey loads it into Polars first.
Total time after 9 queries, 1 GB: csvlite 1.4 s, Polars 5.4 s, Polars, read_csv first 2.7 s0 s2 s4 s6 sopen123456789queries answered5.4 sPolars2.7 sPolars, read_csv first1.4 scsvlite
Chart data
AftercsvlitePolarsPolars, read_csv first
Open69 ms0.0 ms372 ms
Text match99 ms376 ms389 ms
Regex search303 ms989 ms656 ms
Number range413 ms1.5 s775 ms
Date range491 ms2.2 s1.2 s
Sort text654 ms2.8 s1.4 s
Sort numbers791 ms3.3 s1.6 s
Sort dates920 ms4.1 s2.1 s
Group + sum1.1 s4.7 s2.4 s
Group + distinct1.4 s5.4 s2.7 s

10 GB

53,002,050 rows · 15 columns · Cold cache: evicted from memory before every run

10 GB: median time from CSV to answer
QuerycsvlitePolarsBarsvs Polars
Text matchregion = north4.6 s7.6 s1.6× faster
Regex searchdescription has the word café6.2 s10 s1.7× faster
Number rangeamount 25,000–75,0005.3 s8.6 s1.6× faster
Date rangeoccurred_at in a range5.0 s8.7 s1.7× faster
Sort textevery row by region9.1 s9.9 son par
Sort numbersevery row by amount6.4 s9.7 s1.5× faster
Sort datesevery row by occurred_at6.3 s9.1 s1.4× faster
Group + sumcount, sum(amount) by region, status5.7 s11 sout of memory in 1 of 5 runs1.9× faster
Group + distinct…plus distinct descriptions7.2 sout of memoryonly csvlite
Open once, keep askingTotal time as queries pile up. Polars re-reads the CSV per query; grey loads it into Polars first.
Total time after 9 queries, 10 GB: csvlite 31 s0 s10 s20 s30 s40 sopen123456789queries answered31 scsvlite
Chart data
AftercsvlitePolarsPolars, read_csv first
Open3.1 s——
Text match4.7 s——
Regex search7.8 s——
Number range9.9 s——
Date range12 s——
Sort text18 s——
Sort numbers21 s——
Sort dates24 s——
Group + sum27 s——
Group + distinct31 s——

The code you’d write

As benchmarked

Text matchcsvlite 90 msPolars 376 msat 1 GB
(pl.scan_csv("data.csv", infer_schema=False,
            empty_string_is_null=False)
  .select((pl.col("region") == "north").sum())
  .collect())
csvliteAdd filter · region = north
Sort numberscsvlite 197 msPolars 551 msat 1 GB
(pl.scan_csv("data.csv", infer_schema=False,
            empty_string_is_null=False)
  .select(pl.col("amount").cast(pl.Float64, strict=False)
          .arg_sort(nulls_last=True))
  .collect())
csvliteClick the amount header
Group + sumcsvlite 236 msPolars 620 msat 1 GB
(pl.scan_csv("data.csv", infer_schema=False,
            empty_string_is_null=False)
  .group_by("region", "status")
  .agg(pl.len(),
       pl.col("amount").cast(pl.Float64, strict=False).sum())
  .collect())
csvlitePivot · region, status · Sum of amount
Machine
Intel Core i7-11850H · 32 GB RAM · NVMe SSD · Linux. Every run capped at 8 GB of memory.
Versions
csvlite 1.0.0 · DuckDB 1.5.5 · Polars 1.44.2 · pandas 3.0.6. All columns read as text.
Timing
CSV to answer, fresh process per run, startup excluded. ≤1 GB warm; 10 GB cold. Out of memory: one capped attempt. Polars, read_csv first: the same queries after loading the CSV into Polars, a separate five-run cohort.
Data
Generated analytics CSV. All 1064 raw runs (plus load-first) · csvlite-only benchmarks

Try it on your own CSV

Download csvlite