Skip to the content.

XLBench β€” .NET Excel Library Benchmarks

Independent read/write performance and memory benchmarks comparing popular .NET Excel libraries, all consumed via NuGet and run on .NET 10 with BenchmarkDotNet.

πŸ“Š Latest results (tables + static charts) β†’

πŸ“ˆ Interactive charts β†’

πŸ€– CI results (indicative) β†’

Libraries under test

Library Package Version
ClosedXML ClosedXML 0.105.1
EPPlus EPPlus 8.6.3
OpenXML SDK DocumentFormat.OpenXml 3.5.1
NPOI NPOI 2.8.0
MiniExcel MiniExcel 1.45.0
XLibur XLibur.Bundle 0.300.0
IronXL IronXL.Excel 2026.8.1

Library links point at each project’s source repository, except IronXL, which is closed source β€” that one goes to the product page.

Scenarios

Report scenario β€” capability matrix

Not every library can express this scenario; a library that skips a feature is doing strictly less work, so read its timing against this table.

Library Import + grid Conditional formatting Auto-fit column Chart
ClosedXML βœ… βœ… βœ… ❌ no public API
EPPlus βœ… βœ… βœ… βœ…
OpenXML SDK βœ… ⚠️ hand-authored ⚠️ estimated width ⚠️ hand-authored
NPOI βœ… βœ… βœ… ⚠️ titled, invalid XML
MiniExcel βœ… ❌ ❌ ❌ (not benchmarked)
XLibur βœ… βœ… βœ… βœ…
IronXL βœ… ⚠️ font colour only βœ… βœ…

Edit scenario β€” capability matrix

Library Open + edit in place Delete row (shift + reference fixup) Calculation engine
ClosedXML βœ… βœ… IXLRow.Delete() βœ…
EPPlus βœ… βœ… DeleteRow() βœ…
OpenXML SDK ⚠️ hand-authored ⚠️ hand-authored ❌ sums computed by the benchmark
NPOI βœ… ⚠️ RemoveRow + ShiftRows βœ…
MiniExcel ❌ ❌ ❌ (not benchmarked)
XLibur βœ… βœ… IXLRow.Delete() βœ…
IronXL βœ… βœ… RemoveRow() βœ…

Insert scenario β€” capability matrix

Library Open + edit in place Insert columns (shift + reference fixup) Calculation engine
ClosedXML βœ… βœ… IXLColumn.InsertColumnsBefore() βœ…
EPPlus βœ… βœ… InsertColumn(from, count) βœ…
OpenXML SDK ⚠️ hand-authored ⚠️ hand-authored ❌ sums computed by the benchmark
NPOI βœ… βœ… XSSFSheet.ShiftColumns() βœ…
MiniExcel ❌ ❌ ❌ (not benchmarked)
XLibur βœ… βœ… IXLColumn.InsertColumnsBefore() βœ…
IronXL βœ… βœ… InsertColumns(index, count) βœ…

All 500 row totals in every saved artifact are checked against the source CSV on each dotnet run -- insert, read out of the package XML rather than through a library.

Caveats

Results are produced by running the suite locally and committing the generated markdown β€” see the repository README for how to reproduce.