Quick wins, real benchmarks, and when to trade developer joy for raw speed.#
In a recent project we needed to take form data and inject it into an existing Excel template — replacing placeholder variables and producing filled spreadsheets automatically. We evaluated the available .NET libraries (looking at maintenance, maturity and community support) and found only two relevant contenders for this scenario:
| |
We compared both ergonomics (how easy is it to open and manipulate an Excel file?) and performance (measured with BenchmarkDotNet). Below is a pragmatic walkthrough of what we did, the demo code we used, the benchmark results, and a recommendation you can reuse.
TL;DR#
- OpenXmlSdk = lower-level, faster, less memory allocation → best for high-throughput, server-side processing.
- ClosedXML = higher-level, developer-friendly, faster to implement → great for prototyping and templates with formatting.
- Benchmarks show OpenXmlSdk is ~2.9–3.5× faster and uses ~1/3 of the allocations compared to ClosedXML in our tests.
A quick note about my background#
I already had some experience with OpenXmlSdk — it’s powerful, but you end up “sliding through rows and columns” more compared to ClosedXML’s niceties. That background helped when we needed to optimize for performance, but it also showed why ClosedXML is so popular for day-to-day work.
What the demo does#
- Ensures a template exists (
Assets/Template.xlsx). - Prompts the user for a set of variables (e.g.
vehicleRegistration,revenueQ1,status_A,budget_A). - Copies the template into two files and performs token replacement using:
- a low-level OpenXmlSdk approach (replacing text inside the shared string table), and
- a high-level ClosedXML approach (iterating used cells and replacing values).
Both demo methods replace tokens like ##Revenue_Q1## etc. with provided values (or defaults).
Demo entry point (RunDemo)#
| |
Open XML SDK approach (low-level, precise)#
This approach opens the XLSX package, iterates the shared string table and replaces placeholders directly in SharedStringItem s:
| |
Why choose it: efficient, minimal allocations, fine-grained control.
Downside: more verbose and more code to maintain.
ClosedXML approach (high-level, ergonomic)#
This approach opens the workbook with ClosedXML, iterates used cells and replaces values:
| |
Why choose it: readable code, fast to implement, great for formatting and formulas.
Downside: higher memory allocations and lower throughput for bulk processing.
Benchmarks (real runs)#
We ran BenchmarkDotNet for both methods. Here are the trimmed results relevant to decision-making:
| Method | Environment | Mean | Gen0 | Allocated | Alloc Ratio |
|---|---|---|---|---|---|
| OpenXmlSdk | Job-YETQRT | 3.101 ms | 46.8750 | 317.09 KB | 1.00 âś“ |
| ClosedXml | Job-YETQRT | 4.733 ms | 171.8750 | 1098.7 KB | 3.46Ă— slower |
| OpenXmlSdk | .NET 9.0 | 1.057 ms | 50.7813 | 316.62 KB | 1.00 âś“ |
| ClosedXml | .NET 9.0 | 3.264 ms | 171.8750 | 1099.18 KB | 3.47Ă— slower |
Conclusion from benchmarks: OpenXmlSdk is notably faster and uses far fewer allocations. For many-file generation scenarios, that difference matters.
âś… Recommendation (practical)#
Choose Open XML SDK when:
- You need the best performance and minimal allocations.
- You generate many files concurrently or work at scale.
- You don’t mind more detailed code and extra boilerplate.
Choose ClosedXML when:
- Developer speed matters and you want readable, maintainable code.
- Templates include complicated formatting / ranges you want to manipulate easily.
- Throughput demands are moderate.
