OfficeIMO.Excel 3.6.0

Prefix Reserved
There is a newer version of this package available.
See the version list below for details.
dotnet add package OfficeIMO.Excel --version 3.6.0
                    
NuGet\Install-Package OfficeIMO.Excel -Version 3.6.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="OfficeIMO.Excel" Version="3.6.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="OfficeIMO.Excel" Version="3.6.0" />
                    
Directory.Packages.props
<PackageReference Include="OfficeIMO.Excel" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add OfficeIMO.Excel --version 3.6.0
                    
#r "nuget: OfficeIMO.Excel, 3.6.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package OfficeIMO.Excel@3.6.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=OfficeIMO.Excel&version=3.6.0
                    
Install as a Cake Addin
#tool nuget:?package=OfficeIMO.Excel&version=3.6.0
                    
Install as a Cake Tool

OfficeIMO.Excel

nuget version nuget downloads

Create, edit, read and save Excel workbooks (.xlsx, and the supported subsets of .xlsb and Excel 97–2003 .xls) in .NET, without Microsoft Excel or COM. Tables, charts and cell styles follow the workbook's theme; very large exports stream rows with bounded memory.

Returned authoring objects

range.ConditionalFormat() adds rules; each call returns the attached ExcelConditionalFormattingInfo, the same editable model used by AddConditionalFormattingRule. Edit the returned model and call sheet.UpdateConditionalFormattingRule(rule) to apply it, or pass it to RemoveConditionalFormattingRule to remove that exact rule. Pivot conditional formats use the pivot's output range: sheet.Range(sheet.GetPivotTableRange(name)).ConditionalFormat().

range.AutoFilter() returns the ExcelAutoFilter on that range. Column(header) or Column(offset) sets criteria, Clear() removes the filter and Inspect() reads current criteria and table ownership. Creating the handle preserves deferred workbook exports. AddTableOfContents returns the sheet it creates, and AddPivotManualGrouping returns the created ExcelPivotGroupingInfo.

CustomProperties.Add returns the attached ExcelCustomProperty, so edits to the returned value are saved with the workbook. The collection also implements IDictionary<string, ExcelCustomProperty> and ICollection<KeyValuePair<string, ExcelCustomProperty>>.

AddManualRowPageBreak and AddManualColumnPageBreak return an attached ExcelPageBreak with its worksheet, index, orientation and Remove() method. AddMacro returns the attached ExcelMacroProject, which can read, save or remove the VBA payload. Removed or replaced handles reject further operations. AddIgnoredErrorRegion returns the created ExcelIgnoredErrorRegionInfo. AddBackLinksToToc returns hyperlink metadata keyed by the worksheets receiving links. Use AddImage to create an image and receive its ExcelImage. Image dimensions and anchor offsets use OfficeLength: image.Width, image.Height, image.OffsetX and image.OffsetY retain whole EMUs. Two-cell ending offsets use ToOffsetX and ToOffsetY. For example, replace widthPixels: 96 with new ExcelImageOptions { Width = OfficeLength.Pixels(96) }. SetSize, MoveTo, SetTwoCellEndingMarker and TryGetAbsoluteAnchorBounds use the same length contract. Cell and ending-marker offsets on existing XML remain inspectable when signed; SetTwoCellEndingMarker requires non-negative ending offsets; the absolute-position AddImage(x, y, ...) overload requires non-negative authored positions. HTML round trips preserve signed positions and offsets read from existing native drawings. Omitted byte-image sizes remain 96 by 32 pixels at 96 DPI, while file/scaled placement retains its source-dimension defaults. Remote insertion also uses detected source dimensions when width, height and scale are omitted; use explicit lengths to request a fixed 96 by 32 pixel image. Raster export applies its pixel rounding and safety limits when rendering. GetRangeSize returns Width and Height as lengths; worksheet reports insert images through sheet.Report().AddImage(...).

Use AddImage with a path, stream or native byte array. AddImageAsync reads files and streams asynchronously or loads an HTTP or HTTPS Uri. Geometry, metadata, network policy and stream ownership belong to ExcelImageOptions:

ExcelImage logo = sheet.AddImage(2, 3, "logo.png", new ExcelImageOptions {
    ScalePercent = 20,
    Description = "Company logo",
    Title = "Logo"
});
sheet.AddImage("A1:C15", File.ReadAllBytes("header.png"), new ExcelImageOptions {
    Placement = ExcelImagePlacement.MoveAndSize
});
await sheet.AddImageAsync(4, 2, new Uri("https://example.org/logo.png"));

A single A1 reference uses a one-cell anchor; a colon-delimited range, including A1:A1, uses a two-cell anchor. AddImage(x, y, source, options) uses an absolute anchor. Range anchors determine their own size and reject explicit dimensions or scale. LockAspectRatio sets Excel's picture lock; it does not calculate an omitted dimension. Streams stay open by default and retain their seekable position; LeaveOpen = false closes them on success, failure or cancellation. Image bytes are embedded without re-encoding. Deduplicate = true shares identical native payloads within the worksheet drawing while each picture keeps its own metadata; the default creates separate image parts. sheet.Report() uses the same options and returns the worksheet's attached image.

Install

dotnet add package OfficeIMO.Excel
dotnet add package OfficeIMO.Excel.Pdf   # only for SaveAsPdf

Targets netstandard2.0, net8.0 and net10.0, plus net472 on Windows.

A table and a chart from your data

using OfficeIMO;
using OfficeIMO.Excel;

Order[] orders = [
    new("Contoso", "North", 12_400m, 0.21),
    new("Fabrikam", "South", 8_900m, 0.17),
    new("Northwind", "North", 15_100m, 0.24),
    new("Tailspin", "West", 6_300m, 0.12)
];

using var book = ExcelDocument.Create("Orders.xlsx", new ExcelCreateOptions { Theme = OfficeTheme.Modern });
ExcelSheet sheet = book.AddSheet("Orders");

ExcelTable table = sheet.AddTable(orders, new OfficeTableOptions { Name = "Orders" });
sheet.AddChart(OfficeChartType.Column, orders, nameof(Order.Customer),
    new ExcelChartOptions { Title = "Revenue by customer", Row = 2, Column = 7 }, nameof(Order.Total));

book.Save();

record Order(string Customer, string Region, decimal Total, double Margin);

AddTable writes a native Excel table: a header row from the property names, typed cells and the theme's table style. It returns the ExcelTable, and AddChart returns the ExcelChart, for further changes. ExcelChartOptions.Row and Column anchor the chart; Width and Height take an OfficeLength.

Cells, formulas and formatting

using OfficeIMO;
using OfficeIMO.Excel;

using var book = ExcelDocument.Create("Budget.xlsx");
ExcelSheet sheet = book.AddSheet("Budget");

sheet.Range("A1:B3").SetValues(new object?[,] {
    { "Item", "Cost" },
    { "Laptops", 18_500m },
    { "Licenses", 7_250m },
});
sheet.Cell("A4").SetValue("Total").SetBold();
sheet.Cell("B4").SetFormula("SUM(B2:B3)");

sheet.Range("A1:B1").SetBold().SetFillColor(OfficeColor.Parse("D9EAF7"));
sheet.Range("B2:B4").SetNumberFormat("#,##0.00");
sheet.Range("B2:B3").ConditionalFormat().DataBar(OfficeColor.Accent1);
sheet.View.Freeze(topRows: 1);
sheet.AutoFitColumns();

book.Save();

Rows and columns are 1-based, as in Excel. sheet.Cell(row, column) and sheet.Cell("B4") return a lightweight ExcelCell handle (a struct, so a loop over cells allocates nothing); sheet.Range("A1:V1") returns an ExcelRange. Format a block through its range rather than cell by cell: one range call applies the style under one lock and saves the stylesheet once. sheet.UsedRange returns the range in use, and book.GetNamedRange("Total")?.FirstCell writes through a defined name without parsing its address.

Cells created in a formatted row or column start with that row's or column's style, so values written into a template keep its number formats and fonts. A date written into a cell that already has a date format keeps it.

Native roles such as OfficeColor.Accent1 stay linked to the workbook theme. Success, Warning and Danger use the shared palette selected at creation or through book.ApplyTheme(theme). Loading a file or replacing raw theme XML does not infer these status roles, because Excel's native theme has no slots for them. In that case, pass color.Resolve(theme) as a literal color, or call book.ApplyTheme(theme) before authoring with status roles.

Read rows back as objects

using OfficeIMO.Excel;

using var book = ExcelDocument.Load("Orders.xlsx");
foreach (Order order in book["Orders"].RowsAs<Order>()) {
    Console.WriteLine($"{order.Customer}: {order.Total:N0}");
}

record Order(string Customer, string Region, decimal Total, double Margin);

Columns map to properties or constructor parameters by header name. RowsAs also accepts a factory or an explicit column mapping. For files from outside your organization, load with ExcelLoadOptions.UntrustedDefaults.

For a forward-only read, OpenReader(pathOrStream, options) returns an ExcelWorkbookDataReader derived from DbDataReader. The shared OfficeIMO.Data mappings also work on loaded documents:

using OfficeIMO.Data;
using OfficeIMO.Excel;

using ExcelWorkbookDataReader reader = ExcelDocument.OpenReader("Orders.xlsx",
    new ExcelReaderOptions { SheetName = "Orders" });
List<Order> streamed = reader.RowsAs<Order>().ToList();

using var book = ExcelDocument.Load("Orders.xlsx");
List<Order> loaded = book.RowsAs<Order>(
    options: new ExcelReaderOptions { SheetName = "Orders" }).ToList();

Loaded-document RowsAs overloads support automatic, configured RowMapper<T> and factory mapping, with ExcelReaderOptions and cancellation. Their RowsAsParallel counterparts take parallelOptions, format options, then cancellationToken and preserve source order. OpenReaderAsync returns Task<ExcelWorkbookDataReader> on .NET 8 and later.

XML Spreadsheet import also limits defined names (10,000 by default). Set ExcelSpreadsheetXmlOptions.MaxNames for a larger trusted workbook.

Large exports

The object model keeps the whole workbook editable until Save(). For hundreds of thousands of rows, the XLSX and XLSB streaming writers write each row as it arrives with bounded row memory:

using OfficeIMO;
using OfficeIMO.Excel;

IEnumerable<LogEvent> events = Enumerable.Range(1, 200_000)
    .Select(i => new LogEvent(DateTime.UtcNow.AddSeconds(-i), i % 7 == 0 ? "Warning" : "Info", $"Event {i}"));

using (ExcelWorkbookWriter writer = ExcelDocument.CreateWriter("Events.xlsx", theme: OfficeTheme.Modern)) {
    writer.WriteTable("Events", events);
}

record LogEvent(DateTime Time, string Level, string Message);

WriteTable also takes an IAsyncEnumerable<T>, a DataTable or an IDataReader. The file is published when the writer is disposed.

The same writer supports binary formats with an explicit format argument. A typed callback writes scalar values directly to native records:

using (var writer = ExcelDocument.CreateWriter(ExcelFileFormat.Xlsb, "Events.xlsb")) {
    writer.WriteTable("Events", events, new[] { "Time", "Level", "Message" },
        static (row, item) => row.Write(item.Time).Write(item.Level).Write(item.Message));
}

Use ExcelFileFormat.Xls for BIFF8 output, within its limit of 65,536 rows (including headers) and 256 columns. XLS stages native records and its required shared-string table; RequireStreaming=true rejects that format. Binary row writers create plain worksheets and reject tables, AutoFit, freeze panes and declared styles. Existing CreateWriter(path) and CreateWriter(stream) calls select XLSX. WriteData retains its selector and buffering behavior.

XLS and XLSB numeric cells use IEEE-754 double precision, including when a callback supplies a decimal, long or ulong. Large integers and high-precision decimals may lose digits. Write identifiers or exact decimal text as strings when every digit matters.

Report sheets

sheet.Report() lays out titled sections, KPI rows, paragraphs and tables on a sheet, for workbooks that people read rather than filter:

using OfficeIMO;
using OfficeIMO.Excel;

using var book = ExcelDocument.Create("Summary.xlsx");
book.AddSheet("Summary").Report()
    .Title("Service review", "October")
    .KpiRow([("Availability", "99.95%"), ("Incidents", 3), ("Changes", 41)])
    .Section("Highlights")
    .BulletedList(["No priority 1 incidents", "Patch compliance at 98%"]);
book.Save();

Save as PDF

using OfficeIMO;
using OfficeIMO.Excel;
using OfficeIMO.Excel.Pdf;

using var book = ExcelDocument.Load("Orders.xlsx");
OfficeConversionReport report = book.SaveAsPdf("Orders.pdf");
Console.WriteLine($"{report.ItemsWritten} pages, loss: {report.HasLoss}");

More

Dependencies: the Open XML SDK and OfficeIMO.Core. MIT licensed.

Generated capability summary

This table is generated from the package-neutral OfficeIMO operation catalog. The detailed source contracts remain authoritative for feature-level behavior and limitations.

Operation Supported Partial Preserved Rejected Unsupported Not applicable
Create 22 13 0 15 1 2
Read 34 0 17 0 0 2
Edit 11 0 39 2 1 0
Preserve 10 0 39 0 0 0
Inspect 6 0 0 0 0 0
Validate 4 0 0 0 0 2
Remove 4 0 0 0 1 0
Convert 49 41 0 8 0 0
Export 5 0 0 0 0 0

The complete rows for OfficeIMO.Excel are published in the generated operation contract.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  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 is compatible.  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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 is compatible.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (16)

Showing the top 5 NuGet packages that depend on OfficeIMO.Excel:

Package Downloads
OfficeIMO.Excel.Pdf

PDF converter for OfficeIMO.Excel - Export Excel workbooks to PDF using the first-party OfficeIMO.Pdf engine.

Ank.DocToolkit

Convert HTML to PDF and DOCX in C# without a browser - pure managed, no Chromium, no wkhtmltopdf, no native binaries, no LibreOffice, no Office interop. Also converts Markdown to DOCX and PDF; renders DOCX, XLSX and PPTX to PDF; exports DOCX to HTML/Markdown and XLSX to CSV/HTML; reads legacy Word 97-2003 .doc files; reads text out of a PDF; creates/edits DOCX, XLSX and PPTX; password-protects PDF, DOCX, XLSX and PPTX; and inspects and validates digital signatures in DOCX, XLSX and PPTX. Runs on Linux, Windows, macOS and arm64, and makes no network calls at runtime.

OfficeIMO.ChartForgeX

Optional typed bridge from ChartForgeX visual artifacts to OfficeIMO Word, Excel, PowerPoint, PDF, drawing, and editable Visio surfaces.

OfficeIMO.Reader

Unified, read-only document extraction facade for OfficeIMO (Word/Excel/PowerPoint/Markdown/PDF) intended for AI ingestion.

OfficeIMO.Reader.Excel

Excel workbook adapter for OfficeIMO.Reader.Core.

GitHub repositories (2)

Showing the top 2 popular GitHub repositories that depend on OfficeIMO.Excel:

Repository Stars
EvotecIT/EventViewerX
Windows Event Log tooling for PowerShell and .NET: typed queries, reporting, export, WEC, automation, and the PSEventViewer module.
EvotecIT/PSWriteOffice
Moved to OfficeIMO. Development, releases, issues and pull requests: https://github.com/EvotecIT/OfficeIMO
Version Downloads Last Updated
3.6.1 527 11/10/2026
3.6.0 874 11/6/2026
3.5.3 2,106 10/31/2026
3.5.2 3,342 10/24/2026
3.5.1 2,534 10/16/2026
3.4.5 2,346 10/10/2026
3.4.4 6,384 9/27/2026
3.4.3 2,841 9/12/2026
3.4.2 861 9/9/2026
3.4.1 722 9/7/2026
3.4.0 599 9/6/2026
3.3.0 713 9/2/2026
3.2.7 2,745 8/29/2026
3.2.6 4,555 8/22/2026
3.2.5 592 8/21/2026
3.2.4 2,259 8/19/2026
3.2.3 958 8/17/2026
3.2.2 3,969 8/13/2026
3.2.1 646 8/11/2026
3.2.0 4,159 8/7/2026
Loading failed