Its own OOXML engine — built only on the BCL

Write real .xlsx, zero
dependencies. And it's MIT.

Dependency-free Office Open XML for .NET 10. Read, write and stream .xlsx with a clean, fluent API — styling, formulas, charts, pivots — on a small engine you can actually audit.

dotnet add package Matios.Spreadsheet
C6 fx =SUM(C2:C5)
ABC
1ProductRegionSales
2CoffeeNorth1 240
3TeaSouth 980
4CocoaEast1 530
5MateWest 760
6Total4 510
SalesDataPivot
The engine

A spreadsheet engine
you can actually own.

A small, readable OOXML (ECMA-376) engine built only on the BCL — no third-party packages, no transitive chain. Small enough to read end to end and audit line by line. You own it, and it's MIT.

0

Zero dependencies

Built only on System.IO.Compression + System.Xml. Nothing else, ever — no transitive supply chain.

⚙

Its own engine

A hand-written OOXML (ECMA-376) writer/reader. Small enough to read end to end and audit line by line.

✓

Opens clean

Every feature is validated by opening the file in a real spreadsheet app — no "we found a problem / repair" prompt.

Quick start

An API you already know

Package → worksheet → cells. Style, compute formulas in memory, stream a million rows, read it back.

using var pkg = new SpreadsheetPackage();
var sheet = pkg.Workbook.Worksheets.Add("Contacts");

sheet["A1"].Value = "Name";
sheet["B1"].Value = "Age";
sheet["C1"].Value = "City";

sheet["A2"].Value = "Anna";
sheet["B2"].Value = 28;
sheet["C2"].Value = "Springfield";

sheet.Column(1).Width = 16;
pkg.SaveAs("contacts.xlsx");
using Matios.Spreadsheet.Styling;

var s = pkg.Workbook.Worksheets.Add("Styled");
s["A1"].Value = "Title";
s["A1"].Style.Font.Bold = true;
s["A1"].Style.Font.Size = 14;
s["A1"].Style.Font.Color = Colors.White;
s["A1"].Style.Fill.BackgroundColor = Colors.Navy;
s["A1"].Style.Border.SetAll(BorderStyle.Thin, Colors.Black);
s["A1"].Style.HorizontalAlignment = HorizontalAlignment.Center;

s["B2"].Value = new DateTime(2026, 7, 8);
s["B2"].Style.NumberFormat.Format = "dd/MM/yyyy";
s["C2"].Value = 0.1537;
s["C2"].Style.NumberFormat.Format = "0.0%";
var s = pkg.Workbook.Worksheets.Add("Calc");
double[] values = { 10, 25, 40, 15, 30 };
for (int i = 0; i < values.Length; i++) s[i + 1, 1].Value = values[i];

s["C1"].Formula = "SUM(A1:A5)";
s["C2"].Formula = "AVERAGE(A1:A5)";
s["C3"].Formula = "MAX(A1:A5)-MIN(A1:A5)";
s["C4"].Formula = "IF(SUM(A1:A5)>100,\"over\",\"under\")";

pkg.Calculate();                // compute in memory — no spreadsheet app needed
Console.WriteLine(s["C1"].Value);
// Constant memory — a million rows without holding them all in RAM.
using (var wb = StreamingWorkbook.Create("big.xlsx"))
{
    var header = wb.CreateStyle(st =>
    {
        st.Font.Bold = true;
        st.Font.Color = Colors.White;
        st.Fill.BackgroundColor = Colors.Navy;
    });

    var s = wb.AddSheet("Transactions");
    s.AddRow(
        StreamingWorkbook.Cell("Product", header),
        StreamingWorkbook.Cell("Date", header),
        StreamingWorkbook.Cell("Amount", header));

    for (int i = 1; i <= 1_000_000; i++)
        s.AddRow($"Product {i}", baseDate.AddDays(i % 30), i * 100.0);
}
using var loaded = SpreadsheetPackage.Load("sales.xlsx");   // path, Stream, byte[] or FileInfo
var sheet = loaded.Workbook.Worksheets[0];

Console.WriteLine(sheet["A2"].Value);      // "Coffee"
Console.WriteLine(sheet["B4"].Formula);    // "SUM(B2:B3)"
Console.WriteLine(sheet["B4"].Value);      // cached result left behind
Performance

Streaming, measured on a million cells

The streaming path writes each row straight to the archive in constant memory — far faster and lighter than building the whole model first.

~3.2×
faster at 1M cells
(631 ms vs 2,045 ms)
~3.2×
less memory allocated
(272 MB vs 877 MB)
1.58M
cells / second
streaming throughput
Write path 200k cells 1M cells Memory (1M)
DOM (in-memory) ~535 ms ~2,045 ms ~877 MB
Streaming ~175 ms ~631 ms ~272 MB

Measured with the project's BenchmarkDotNet suite on .NET 10 Release, one machine. Hardware-dependent — treat as a relative reference (DOM vs streaming), not absolute.

What's in the box

A full worksheet, not just a grid of strings

✓
StylingFonts, fills, 4-side borders, alignment, wrap, custom & built-in number formats.
✓
Built-in formula evaluatorSUM · AVERAGE · MIN · MAX · COUNT · IF · ROUND · ABS · CONCAT and more — computed in memory.
✓
ChartsColumn, bar, line, area, pie and scatter — multi-series, titles, axes, legend.
✓
Tables & pivotsNative tables with banded styles, plus basic pivot tables (row field + SUM).
✓
Conditional formatting & validationcellIs rules, color scales, data bars; list / numeric / date validation with prompts.
✓
Merged cells, freeze panes, auto-filterColumn width, row height, grouping, hyperlinks, comments, print area, sheet protection.
✓
ImagesPNG / JPEG, dedup by hash, one-cell and two-cell anchors.
✓
Round-trip passthroughThemes, macros and other parts you didn't touch are captured on load and re-emitted verbatim on save.
Status & roadmap

Available now — and evolving

The engine is feature-complete, green, and published on NuGet.

v1.0 · now
Read + write + stream — on NuGetStyling, formulas, charts, pivots, streaming and round-trip — 94 tests green, every feature validated in a real spreadsheet app. dotnet add package Matios.Spreadsheet.
More formulas & pivotsGrowing the in-memory function set and multi-field pivots. Issues and feedback welcome on GitHub.

Add it to your project

Open source · MIT · .NET 10 · zero dependencies

dotnet add package Matios.Spreadsheet