Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,11 @@ jobs:
- name: Generate SBOM
run: |
dotnet tool install --global Microsoft.Sbom.DotNetTool --version 4.1.13
sbom-tool generate -b artifacts -bc . -m sbom -pn SheetStream -pv "${GITHUB_REF_NAME#v}" -ps "P4 Software" -nsb https://p4.software/sbom -V Warning
cp sbom/_manifest/spdx_2.2/manifest.spdx.json "artifacts/SheetStream-${GITHUB_REF_NAME#v}.spdx.json"
sbom-tool generate -b artifacts -bc . -m sbom -pn SheetStream.NET -pv "${GITHUB_REF_NAME#v}" -ps "P4 Software" -nsb https://p4.software/sbom -V Warning
cp sbom/_manifest/spdx_2.2/manifest.spdx.json "artifacts/SheetStream.NET-${GITHUB_REF_NAME#v}.spdx.json"

# Signed statement that these exact package files were produced by this workflow from this commit.
# Anyone can verify it with `gh attestation verify SheetStream.x.y.z.nupkg --owner P4Software`.
# Anyone can verify it with `gh attestation verify SheetStream.NET.x.y.z.nupkg --owner P4Software`.
- name: Attest build provenance
id: attest
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2
Expand All @@ -97,7 +97,7 @@ jobs:
# The same signed provenance, attached to the release as a Sigstore bundle so it can be checked
# offline (and so scanners that look for a signature file next to the assets find one).
- name: Attach the provenance bundle to the release assets
run: cp "${{ steps.attest.outputs.bundle-path }}" "artifacts/SheetStream-${GITHUB_REF_NAME#v}.intoto.jsonl"
run: cp "${{ steps.attest.outputs.bundle-path }}" "artifacts/SheetStream.NET-${GITHUB_REF_NAME#v}.intoto.jsonl"

- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# OpenSSF Scorecard: an automated review of the repository's security practices (pinned dependencies,
# branch protection, token permissions, dependency updates, SAST...). Results are published to
# https://scorecard.dev/viewer/?uri=github.com/P4Software/SheetStream and shown as a README badge, so
# https://scorecard.dev/viewer/?uri=github.com/P4Software/SheetStream.NET and shown as a README badge, so
# anyone evaluating SheetStream for production can see the score without trusting our word for it.
name: Scorecard

Expand Down
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to SheetStream. Versions follow [Semantic Versioning](https:

## 0.4.0 (2026-10-14)

### Changed

- **Package renamed to `SheetStream.NET`** (the repository is now `P4Software/SheetStream.NET`, the docs live at https://p4software.github.io/SheetStream.NET/). The C# namespace stays `SheetStream` and `SheetStream.AspNetCore` keeps its name, so upgrading is one package reference: `dotnet remove package SheetStream` then `dotnet add package SheetStream.NET`. The old `SheetStream` package stays on nuget.org at 0.3.0, marked as renamed.

### Added

- **Edit small existing workbooks**: `ExcelPackage.Edit(path)` (in place, atomic replace) or `Edit(input, output)`, then `Worksheets.Edit(name)` loads the sheet into `Cells[...]`: read values, change cells, add rows, `Cells.Existing`, `Cells.Dimension`, `ExcelCell.Clear()`. Untouched cells, rows, formulas (shared and array formulas included), charts, tables and other sheets are written back unchanged. Guarded by `PackageOptions.MaxEditableCells` (200,000 by default); large files keep using streaming or templates.
Expand All @@ -30,7 +34,7 @@ All notable changes to SheetStream. Versions follow [Semantic Versioning](https:
- **Template filling**: `ExcelPackage.OpenTemplate(template, output)` and `Worksheets.Open(name)` stream rows into a workbook designed in Excel. Everything not touched is copied unchanged; tables, filters, data validations and conditional formats on the first data row stretch over the new rows; template styles are reusable with `TemplateStyle("D5")`; new styles append to the template's style table; the calculation chain is dropped and the workbook recalculates on open.
- **Async loading** (.NET 8+): `Worksheet.LoadFromAsyncEnumerable(...)` streams an `IAsyncEnumerable<T>` such as an EF Core query, with cancellation.
- **SheetStream.AspNetCore** package: `ExcelResults.Excel(...)` and `Results.Extensions.Excel(...)` return a streamed download from minimal APIs and controllers, with flat memory, accurate `Content-Length`, correct non-ASCII file names and no synchronous I/O.
- **Documentation site** at https://p4software.github.io/SheetStream/ with guides and the API reference generated from the XML comments.
- **Documentation site** at https://p4software.github.io/SheetStream.NET/ with guides and the API reference generated from the XML comments.
- **Migration guide** from EPPlus, built on a real production exporter and compiled as a test.
- **Benchmarks** project comparing SheetStream with EPPlus 4.5.3.3, ClosedXML, MiniExcel and NPOI.
- Reader **fuzz tests**, code coverage in CI, `SECURITY.md` and Dependabot.
Expand Down
21 changes: 12 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# 🚀 SheetStream
# 🚀 SheetStream.NET

A fast, zero-dependency, **MIT-licensed** .NET library for creating, filling and reading Excel (`.xlsx`) files.
A fast, zero-dependency, **MIT-licensed** .NET library for creating, filling, editing and reading Excel (`.xlsx`) files. (Not related to the Node.js package of the same name.)

SheetStream streams rows straight into the file instead of building the workbook in memory, so large exports stay fast and memory stays flat. It was built at P4 Software when EPPlus moved to a commercial licence, and it covers what business reports actually use: styles, tables, charts, conditional formatting, validation, templates designed in Excel, and a streaming reader for imports.

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![NuGet](https://img.shields.io/nuget/v/SheetStream.svg)](https://www.nuget.org/packages/SheetStream)
[![Build](https://github.com/P4Software/SheetStream/actions/workflows/build.yml/badge.svg)](https://github.com/P4Software/SheetStream/actions/workflows/build.yml)
[![Docs](https://img.shields.io/badge/docs-p4software.github.io-0A5FAD)](https://p4software.github.io/SheetStream/)
[![Build](https://github.com/P4Software/SheetStream.NET/actions/workflows/build.yml/badge.svg)](https://github.com/P4Software/SheetStream.NET/actions/workflows/build.yml)
[![Docs](https://img.shields.io/badge/docs-p4software.github.io-0A5FAD)](https://p4software.github.io/SheetStream.NET/)
[![Downloads](https://img.shields.io/nuget/dt/SheetStream.svg)](https://www.nuget.org/packages/SheetStream)
[![Coverage](https://img.shields.io/endpoint?url=https%3A%2F%2Fp4software.github.io%2FSheetStream%2Fcoverage.json)](https://github.com/P4Software/SheetStream/actions/workflows/build.yml)
[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/P4Software/SheetStream/badge)](https://scorecard.dev/viewer/?uri=github.com/P4Software/SheetStream)
[![Coverage](https://img.shields.io/endpoint?url=https%3A%2F%2Fp4software.github.io%2FSheetStream%2Fcoverage.json)](https://github.com/P4Software/SheetStream.NET/actions/workflows/build.yml)
[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/P4Software/SheetStream.NET/badge)](https://scorecard.dev/viewer/?uri=github.com/P4Software/SheetStream.NET)

## ✨ Why SheetStream?

Expand All @@ -24,11 +24,13 @@ SheetStream streams rows straight into the file instead of building the workbook
## 📦 Installation

```bash
dotnet add package SheetStream
dotnet add package SheetStream.NET
dotnet add package SheetStream.AspNetCore # optional: one-line Excel downloads
```

Full documentation and API reference: **https://p4software.github.io/SheetStream/**
Upgrading from the 0.3.x `SheetStream` package: `dotnet remove package SheetStream`, then add `SheetStream.NET`. The namespace is still `SheetStream`, so no code changes.

Full documentation and API reference: **https://p4software.github.io/SheetStream.NET/**

Try it in your browser without installing anything: **[DotNetFiddle: write a styled Excel file and read it back](https://dotnetfiddle.net/BR59ju)**.

Expand Down Expand Up @@ -348,6 +350,7 @@ What the numbers say, including where SheetStream does not win:
- **Memory is SheetStream's clearest advantage.** It allocates about 13 times less than the next library and keeps the lowest peak in both the long and the wide (1,000 × 1,000) scenarios.
- **MiniExcel is faster than SheetStream's default.** SheetStream defaults to the smallest file (`CompressionLevel.Optimal`). With `Fastest` compression SheetStream is quickest in both scenarios, though on the long sheet the lead over MiniExcel is within the margin of error.
- **NPOI and EPPlus produce slightly smaller files** on the long sheet.
- **At a million rows** (1,000,000 × 10) SheetStream writes in 4.8 s with `Fastest` compression (12.8 s with the default, smaller-file setting) and allocates 275 MB with a 200 MB peak working set; MiniExcel takes 5.3 s and 3.3 GB, EPPlus 4.5.3.3 26 s and 3.9 GB with a 1.5 GB peak, ClosedXML 37 s and 11.6 GB with a 2.4 GB peak. A 1,000 × 10,000 sheet costs SheetStream the same as a 10,000 × 1,000 one.
- MiniExcel cannot bold the header, so its file carries slightly less formatting.

Full results, the wide-sheet scenario, methodology, machine details and how to rerun everything are in [benchmarks/README.md](benchmarks/README.md). EPPlus is pinned to 4.5.3.3 and NPOI to 2.7.6, their last releases under plain open-source licences. Numbers come from a developer workstation, so expect some noise; rerun them on your own hardware.
Expand Down Expand Up @@ -424,7 +427,7 @@ The `Release` workflow refuses to run if the tag and the csproj version disagree

## 🤝 Contributing

Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md), the [good first issues](https://github.com/P4Software/SheetStream/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22), and [Discussions](https://github.com/P4Software/SheetStream/discussions) for questions. Security reports go through [SECURITY.md](SECURITY.md).
Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md), the [good first issues](https://github.com/P4Software/SheetStream.NET/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22), and [Discussions](https://github.com/P4Software/SheetStream.NET/discussions) for questions. Security reports go through [SECURITY.md](SECURITY.md).

## 📄 License

Expand Down
4 changes: 2 additions & 2 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Security fixes are released for the latest minor version of SheetStream and Shee

Please do not open a public issue for security problems.

Report them privately through GitHub's private vulnerability reporting: https://github.com/P4Software/SheetStream/security/advisories/new (the **Report a vulnerability** button on the repository's **Security** tab). Include the SheetStream version, a minimal reproduction (code or a sample file), and the impact you observed.
Report them privately through GitHub's private vulnerability reporting: https://github.com/P4Software/SheetStream.NET/security/advisories/new (the **Report a vulnerability** button on the repository's **Security** tab). Include the SheetStream version, a minimal reproduction (code or a sample file), and the impact you observed.

What happens next:

Expand All @@ -20,7 +20,7 @@ Please give us that window before disclosing publicly. If you have not heard bac

## Verifying what you install

Every release is built by the public `Release` workflow in this repository. Each package carries a signed build-provenance attestation (`gh attestation verify SheetStream.<version>.nupkg --owner P4Software`), and the GitHub release includes an SPDX software bill of materials. The packages have no runtime dependencies.
Every release is built by the public `Release` workflow in this repository. Each package carries a signed build-provenance attestation (`gh attestation verify SheetStream.NET.<version>.nupkg --owner P4Software`), and the GitHub release includes an SPDX software bill of materials. The packages have no runtime dependencies.

## Scope notes

Expand Down
45 changes: 43 additions & 2 deletions benchmarks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,19 @@ Each figure is the median of 3 fresh processes. "Cold write time" is a single wr

### Million: 1,000,000 rows x 10 columns (BenchmarkDotNet)

Results pending: run `dotnet run -c Release -- --filter '*Million*'` on the benchmark machine and paste `BenchmarkDotNet.Artifacts/results/SheetStream.Benchmarks.MillionBenchmarks-report-github.md` here.
Measured on 2026-10-14. Job: `InvocationCount=1 IterationCount=3 LaunchCount=1 UnrollFactor=1 WarmupCount=1` (3 measured writes per library; the error column is wide because of that).

| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Gen1 | Gen2 | Allocated | Alloc Ratio |
|---------------------------- |---------:|-----------:|---------:|------:|--------:|-------------:|------------:|----------:|------------:|------------:|
| SheetStream | 12.825 s | 14.5478 s | 0.7974 s | 1.00 | 0.08 | 45000.0000 | - | - | 274.7 MB | 1.00 |
| 'SheetStream (Fastest zip)' | 4.753 s | 1.0805 s | 0.0592 s | 0.37 | 0.02 | 45000.0000 | - | - | 274.7 MB | 1.00 |
| 'EPPlus 4.5.3.3' | 26.228 s | 103.0873 s | 5.6506 s | 2.05 | 0.40 | 409000.0000 | 30000.0000 | 4000.0000 | 3934.59 MB | 14.32 |
| ClosedXML | 36.506 s | 9.3365 s | 0.5118 s | 2.85 | 0.16 | 1599000.0000 | 142000.0000 | 5000.0000 | 11559.78 MB | 42.08 |
| MiniExcel | 5.325 s | 0.6575 s | 0.0360 s | 0.42 | 0.02 | 553000.0000 | - | - | 3325.16 MB | 12.10 |
| 'NPOI XSSF' | 47.264 s | 17.7229 s | 0.9715 s | 3.70 | 0.22 | 1616000.0000 | 488000.0000 | 6000.0000 | 11596.94 MB | 42.22 |
| 'NPOI SXSSF' | 20.738 s | 7.1444 s | 0.3916 s | 1.62 | 0.09 | 1178000.0000 | 393000.0000 | - | 7049.39 MB | 25.66 |

At a million rows the zip compression level decides the time: SheetStream with `Fastest` is the quickest writer (4.8 s), MiniExcel is close (5.3 s), and SheetStream's default `Optimal` level costs 12.8 s for a file 17% smaller. Allocation scales linearly from the 100,000-row figures: 275 MB for SheetStream against 3.3 GB (MiniExcel), 3.9 GB (EPPlus) and 11.6 GB (ClosedXML, NPOI XSSF).

### VeryWide: 1,000 rows x 10,000 columns (BenchmarkDotNet)

Expand All @@ -195,7 +207,36 @@ Results pending: run `dotnet run -c Release -- --filter '*Read*'` on the benchma

### Peak working set for Million, VeryWide and Read (`--peak`)

Results pending: run `dotnet run -c Release -- --peak Million VeryWide Read` on the benchmark machine and paste the three tables here. For Read, the "Output size" column becomes "Input size" (the same 5,798 KB file for every reader) and "rows verified" becomes "checksum verified".
Measured on 2026-10-14 with `dotnet run -c Release -- --peak Million VeryWide Read` (the whole run took about two hours; NPOI XSSF alone needs 32 minutes per VeryWide write). Median of 3 fresh processes.

**Million: 1,000,000 rows x 10 columns**

| Library | Peak working set (MB) | Above baseline (MB) | Cold write time (ms) | Output size (KB) | Full-size rows verified |
|---|---:|---:|---:|---:|---|
| Baseline | 121.1 | - | - | - | - |
| SheetStream | 200.4 | 79.3 | 13,303 | 58,079 | yes (1,000,001 rows x 10 cells) |
| SheetStream-Fastest | 212.3 | 91.1 | 13,628 | 70,121 | yes (1,000,001 rows x 10 cells) |
| EPPlus 4.5.3.3 | 1548.1 | 1427.0 | 24,529 | 56,226 | yes (1,000,001 rows x 10 cells) |
| ClosedXML | 2378.4 | 2257.3 | 55,943 | 60,542 | yes (1,000,001 rows x 10 cells) |
| MiniExcel | 220.7 | 99.6 | 7,327 | 74,788 | yes (1,000,001 rows x 10 cells) |
| NPOI XSSF | 5025.6 | 4904.5 | 64,764 | 53,480 | yes (1,000,001 rows x 10 cells) |
| NPOI SXSSF | 225.2 | 104.1 | 29,035 | 55,180 | yes (1,000,001 rows x 10 cells) |

SheetStream's 79 MB above baseline is mostly the 58 MB output buffer: the writer itself holds a few MB. The in-memory libraries need 1.4 GB (EPPlus), 2.3 GB (ClosedXML) and 4.9 GB (NPOI XSSF) for the same file.

**VeryWide: 1,000 rows x 10,000 columns**

| Library | Peak working set (MB) | Above baseline (MB) | Cold write time (ms) | Output size (KB) | Full-size rows verified |
|---|---:|---:|---:|---:|---|
| Baseline | 100.3 | - | - | - | - |
| SheetStream | 160.1 | 59.8 | 16,680 | 45,908 | yes (1,000 rows x 10,000 cells) |
| SheetStream-Fastest | 166.0 | 65.7 | 9,942 | 52,144 | yes (1,000 rows x 10,000 cells) |
| EPPlus 4.5.3.3 | 1489.5 | 1389.2 | 72,930 | 49,690 | yes (1,000 rows x 10,000 cells) |
| ClosedXML | 1555.6 | 1455.3 | 48,753 | 48,254 | yes (1,000 rows x 10,000 cells) |
| MiniExcel | 180.4 | 80.1 | 14,691 | 49,460 | yes (1,000 rows x 10,000 cells) |
| NPOI XSSF | 4842.2 | 4741.9 | 1,918,212 | 47,748 | yes (1,000 rows x 10,000 cells) |

The NPOI SXSSF VeryWide row and the Read peak table did not survive the first run's log and are being re-measured; they will be added here.

### What each library actually wrote (`--verify`, small Long case)

Expand Down
4 changes: 2 additions & 2 deletions docs/analyzers.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ poor place to learn a rule.

The SheetStream package therefore ships a Roslyn analyzer. It runs inside the compiler and the IDE and shows the
three rules below as warnings while you type, with a message that says what to change. There is nothing to
install: `dotnet add package SheetStream` is enough, and the analyzer adds nothing to your application's output.
install: `dotnet add package SheetStream.NET` is enough, and the analyzer adds nothing to your application's output.

| Id | Title | What it catches |
|---|---|---|
Expand Down Expand Up @@ -161,4 +161,4 @@ To turn the rules into build errors, set the severity to `error` the same way, o
## Not what you expected?

If a warning fires on code that runs fine, or does not fire on code that throws, please open an issue at
<https://github.com/P4Software/SheetStream/issues> with the snippet. False positives are treated as bugs.
<https://github.com/P4Software/SheetStream.NET/issues> with the snippet. False positives are treated as bugs.
4 changes: 2 additions & 2 deletions docs/docfx.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@
"dest": "_site",
"template": [ "default", "modern" ],
"globalMetadata": {
"_appTitle": "SheetStream",
"_appTitle": "SheetStream.NET",
"_appName": "SheetStream",
"_appLogoPath": "images/logo.png",
"_appFaviconPath": "images/logo.png",
"_appFooter": "SheetStream is MIT licensed and published by P4 Software.",
"_enableSearch": true,
"_gitContribute": { "repo": "https://github.com/P4Software/SheetStream", "branch": "main" }
"_gitContribute": { "repo": "https://github.com/P4Software/SheetStream.NET", "branch": "main" }
}
}
}
6 changes: 3 additions & 3 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# SheetStream
# SheetStream.NET

A zero-dependency, MIT-licensed .NET library for creating and reading Excel (`.xlsx`) files. Rows stream straight into the file, so 10 million cells write in seconds with flat memory.

```bash
dotnet add package SheetStream
dotnet add package SheetStream.NET
dotnet add package SheetStream.AspNetCore # optional: one-line Excel downloads
```

Expand Down Expand Up @@ -37,7 +37,7 @@ package.Save();
- [Migrating from EPPlus](migrating-from-epplus.md): a real exporter converted line by line.
- [Filling templates](templates.md): design in Excel, fill from code.
- [API reference](api/SheetStream.yml): every public type, generated from the source.
- [Benchmarks](https://github.com/P4Software/SheetStream/tree/main/benchmarks): reproducible comparisons with EPPlus, ClosedXML, MiniExcel and NPOI.
- [Benchmarks](https://github.com/P4Software/SheetStream.NET/tree/main/benchmarks): reproducible comparisons with EPPlus, ClosedXML, MiniExcel and NPOI.

## Design in one paragraph

Expand Down
2 changes: 1 addition & 1 deletion samples/SheetStream.Sample.Web/wwwroot/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ <h2>Summary with charts</h2>

<footer>
Source: <code>samples/SheetStream.Sample.Web/Program.cs</code>.
SheetStream is MIT licensed, published by <a href="https://github.com/P4Software/SheetStream">P4 Software</a>.
SheetStream is MIT licensed, published by <a href="https://github.com/P4Software/SheetStream.NET">P4 Software</a>.
</footer>
</main>
</body>
Expand Down
Loading
Loading