SimpleExcelExporter 1.5.0
dotnet add package SimpleExcelExporter --version 1.5.0
NuGet\Install-Package SimpleExcelExporter -Version 1.5.0
<PackageReference Include="SimpleExcelExporter" Version="1.5.0" />
<PackageVersion Include="SimpleExcelExporter" Version="1.5.0" />
<PackageReference Include="SimpleExcelExporter" />
paket add SimpleExcelExporter --version 1.5.0
#r "nuget: SimpleExcelExporter, 1.5.0"
#:package SimpleExcelExporter@1.5.0
#addin nuget:?package=SimpleExcelExporter&version=1.5.0
#tool nuget:?package=SimpleExcelExporter&version=1.5.0
SimpleExcelExporter
Small focused C# library for exporting .NET objects to .xlsx files. Built on top of DocumentFormat.OpenXml, it trades the SDK's full flexibility for a much simpler API aimed at one specific use case: turning a list of annotated POCOs into a spreadsheet.
The generated files open in:
- Microsoft Excel (Windows + macOS)
- LibreOffice Calc
- Google Sheets (up to its 10 M-cell quota)
- Apple Numbers — since
1.5.0the output is strict ECMA-376 compliant
Installation
dotnet add package SimpleExcelExporter
Target framework: .NET 8.
Two ways to use it
1. Annotated POCOs (recommended for most use cases)
Annotate your model classes with attributes from SimpleExcelExporter.Annotations, then let the exporter discover the structure via reflection.
using SimpleExcelExporter;
using SimpleExcelExporter.Annotations;
using SimpleExcelExporter.Definitions;
public class Player
{
[CellDefinition(CellDataType.String)]
[Header(typeof(TeamRes), "PlayerNameColumnName")]
[Index(1)]
public string? PlayerName { get; set; }
[CellDefinition(CellDataType.Date)]
[Header(typeof(TeamRes), "DateOfBirthColumnName")]
[Index(2)]
public DateTime? DateOfBirth { get; set; }
[CellDefinition(CellDataType.Number)]
[Header(typeof(TeamRes), "NumberOfVictoryColumnName")]
[Index(3)]
public int? NumberOfVictory { get; set; }
}
public class Team
{
private ICollection<Player>? _players;
[SheetName(typeof(TeamRes), "SheetName")]
[EmptyResultMessage(typeof(TeamRes), "EmptyResultMessage")]
public ICollection<Player> Players => _players ??= new HashSet<Player>();
}
// …and then:
var team = new Team { Players = { /* … */ } };
using var stream = new FileStream("team.xlsx", FileMode.Create);
new SpreadsheetWriter(stream, team).Write();
Header labels come from a resource file (TeamRes.resx) so the same workbook can be exported in several languages.
See the full worked example at SimpleExcelExporterExample.
2. WorkbookDfn — explicit, attribute-free
If annotating your domain classes is not an option, build a WorkbookDfn by hand and pass that to the writer. You keep full control of sheet names, column ordering, cell types, and data.
var workbook = new WorkbookDfn();
var sheet = new WorksheetDfn("Players");
workbook.Worksheets.Add(sheet);
sheet.ColumnHeadings.Cells.Add(new CellDfn("Name"));
sheet.ColumnHeadings.Cells.Add(new CellDfn("Date of birth"));
var row = new RowDfn();
row.Cells.Add(new CellDfn("Alexandre", cellDataType: CellDataType.String));
row.Cells.Add(new CellDfn(new DateTime(1974, 2, 1), cellDataType: CellDataType.Date));
sheet.Rows.Add(row);
using var stream = new FileStream("players.xlsx", FileMode.Create);
new SpreadsheetWriter(stream, workbook).Write();
A more complete example is in src/ConsoleApp/Program.cs.
Supported attributes
| Attribute | Applied on | Purpose |
|---|---|---|
[SheetName] |
property returning IEnumerable<T> |
Localised sheet name from a resource file |
[EmptyResultMessage] |
idem | Message shown in the sheet when the collection is empty |
[Header] |
property | Localised column header |
[Index] |
property | Column order within a sheet (1-indexed) |
[CellDefinition] |
property | Cell data type (Date, Number, Boolean, Percentage, Time, String) |
[MultiColumn] |
property of collection type | Expands a sub-collection into repeating columns |
[IgnoreFromSpreadSheet] |
property | Skip this property during export |
What's in the generated XLSX?
Output conforms to ECMA-376 strict mode since 1.5.0:
- Every
<c>carriesr="A1"-style references (Apple Numbers requires it). - Non-empty string cells route through
xl/sharedStrings.xml(deduplicated). - Empty cells are omitted from the sheet XML — readers infer the position (matches Excel's native output).
- Default style attributes (
s="0",t="n") are omitted to keep files compact. docProps/core.xmlis populated withdc:creator,dcterms:created,dcterms:modified.- Deterministic writes when running under CI (
ContinuousIntegrationBuild=true), plus a companion.snupkgwith Source Link for step-into-source debugging.
Performance and file-size characteristics
On a 1 M-row annotated fixture (see BENCHMARK_RESULTS.md for the full table and methodology):
- Runtime is dominated by the reflection walk of annotated objects (~60 % of total) rather than the XML write.
- Files sit ~100 % larger than the pre-
1.5.0output — the price of the mandatoryr="A1"attribute on every cell. Three spec-conformant optimisations (skip empty cells, omit defaults="0", omit defaultt="n") partially offset this and keep a 1 M × 20 fixture under Google Sheets' 100 MB upload limit.
A reproducible benchmark harness is at scripts/benchmark.sh.
Repository layout
src/
SimpleExcelExporter/ the library (published as the NuGet package)
ConsoleApp/ runnable harness used for manual + perf checks
test/
SimpleExcelExporterTests/ 48 NUnit tests (unit + OOXML compliance + behaviour)
scripts/
benchmark.sh perf & file-size benchmark across library versions
.github/
workflows/ CI (on push/PR) and Release (on tag)
dependabot.yml weekly NuGet + Actions dependency scans
Releasing
Version bumps, NuGet publication, and GitHub Releases are driven entirely by pushing a v* tag that matches <Version> in the csproj. See RELEASING.md for the step-by-step flow, SemVer guidance, and troubleshooting.
License
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- DocumentFormat.OpenXml (>= 3.5.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.5.0 | 100 | 4/21/2026 |
| 1.5.0-alpha.3 | 52 | 4/21/2026 |
| 1.5.0-alpha.2 | 46 | 4/21/2026 |
| 1.5.0-alpha.1 | 53 | 4/21/2026 |
| 1.4.4 | 1,861 | 11/26/2024 |
| 1.4.3 | 2,068 | 9/23/2024 |
| 1.4.3-alpha | 135 | 9/23/2024 |
| 1.4.2 | 254 | 8/27/2024 |
| 1.4.2-alpha.1 | 110 | 8/27/2024 |
| 1.4.2-alpha | 177 | 8/21/2024 |
| 1.4.1 | 275 | 6/7/2024 |
| 1.4.1-alpha.2 | 106 | 6/7/2024 |
| 1.4.1-alpha.1 | 120 | 6/6/2024 |
| 1.4.1-alpha | 158 | 6/6/2024 |
| 1.4.0 | 501 | 6/3/2024 |
| 1.4.0-alpha | 173 | 6/3/2024 |
| 1.3.1 | 317 | 8/29/2023 |
| 1.3.0 | 278 | 8/28/2023 |
| 1.2.3 | 407 | 3/9/2023 |
| 1.2.2 | 409 | 3/8/2023 |