ExcelMapper: reading and writing Excel files from POCOs
An Excel to object mapper. Maps POCOs to and from Excel. Configuration via convention, attributes, or fluent methods.
At a glance
- What is it?
- ExcelMapper is a .NET library that maps plain C# objects to Excel worksheets and back, using NPOI rather than the Jet engine, with configuration by convention, attributes or method calls. It suits .NET teams that need to import or export spreadsheets without hand-rolling a reader.
- Who is it for?
- ExcelMapper is a good fit for a .NET team that has to read a spreadsheet into typed objects or write typed objects into one, and that wants the mapping rules to live on the model rather than in the import code.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 9 days ago.
- What is it written in?
- Mainly C#, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The zero configuration path, and when it breaks
The library is a mapper between plain old CLR objects and Excel files, and the simplest possible use of it is a single line:
var products = new ExcelMapper("products.xlsx").Fetch<Product>();The rules for that line are stated plainly and they are what makes the library usable without configuration in the common case. The Excel file is expected to contain a header row with the column names, objects are read from the first worksheet, and if the column names equal the property names, ignoring case, no other configuration is necessary. The file format, whether xlsx or xls, is autodetected. The zero configuration path is a real advantage for the common case where a spreadsheet was designed by a person with a header row and a domain that matches your class names. Where it breaks is obvious in hindsight: a column called Number that maps to a property called NumberInStock, a sheet with a title row above the headers, or a workbook with several sheets where the data is not in the first one. Each of those needs one of the explicit mapping routes, and the library offers three.
Three ways to map a column, and the one that catches people out
The three routes are attributes, method calls, and plain convention, and the readme is clear about when each applies. An attribute is the most declarative. Mapping to a specific column name is a Column attribute with the name in it, and mapping to a column index uses the numeric overload, where column indexes start at 1, or a letter form. The rule for index mapping is strict: every property needs to be explicitly mapped through the attribute or the AddMapping method, and the indexes do not need to be consecutive. Indexes can also be combined with names to specify an explicit column order while still using a header row, which is the case where a spreadsheet has a fixed template with an unusual column sequence. Method calls are the runtime alternative, and there are four overloads shown, taking a type parameter or an expression, with a column name or an index, and the index overload can be built from a letter using a helper on the mapper. What catches people out is the multiple mapping case. You can map a single column to several properties, but then you have to say which one is written back to Excel, and the mechanism is the MappingDirections.ExcelToObject marker on the Column attribute of the other properties, or the FromExcelOnly method on a method-call mapping. Without that marker, the write direction is ambiguous, and that is a data corruption risk rather than a compile error.
Attribute inheritance, and the switch that turns it off
There is a subtlety in how attributes behave in a class hierarchy, and the documentation treats it as something you need to know about rather than something it handles for you. Column attributes are inherited by default, which results in multiple mappings for a single overridden property if you add a Column attribute to the property in both the base and the derived classes. The fix is to set the Inherit property to false on the Column attribute in the base class. This is a common shape in .NET code, where a base class defines the domain and a derived class adds validation or behaviour, and the default behaviour produces a mapper that quietly maps one property twice. Whether the duplicated mapping is harmless or a bug depends on what the two columns mean, and in most spreadsheets it is a bug. The related piece of machinery is the Ignore attribute and its method-call equivalent, which removes a property from the mapping entirely, and that is the tool for computed or derived properties that should never be written to a column.
Preserving a template while filling it with data
The saving side has a behaviour that is more useful than it first appears. Saving objects takes a file name, a collection, and a worksheet name:
new ExcelMapper().Save("products.xlsx", products, "Products");The important part is what happens when the same mapper instance has already read from a file. In that case the style of the workbook is preserved, which allows the use case where an Excel template is filled with computed data. That is a different capability from writing a fresh spreadsheet, because it means the layout, the number formats, the column widths and the styling of a workbook designed by a human survive the round trip, while the data is replaced. The feature list calls this preserving formatting when saving back files, and it is the reason to use this library rather than writing values cell by cell with NPOI. The related feature of optionally letting the mapper track objects is what makes the edit-and-save-back workflow possible, so that when you change a property on an object you fetched, the mapper knows which cell to write.
Dynamic rows, nested objects and JSON
Beyond typed mapping there is a set of features for the cases where the schema is not known in advance. Dynamic mapping lets you fetch a collection of dynamic objects without specifying a mapping, and the returned objects are ExpandoObject instances with an extra property called __indexes__ holding a dictionary from property names to column indexes, which is how you find out where a value came from. With the HeaderRow property set to false, the property names of the dynamic objects match the Excel letter column names, so A for column 1. There is also the option of mapping JSON, fetching and saving dynamic objects, and using records rather than classes, plus the ability to provide custom object factories for when the type needs constructing in a particular way. Nested objects, parent and child objects, are supported, which is the feature that makes the library usable for an order with line items rather than only for a flat table. Other options include optionally skipping blank lines when reading, using custom or builtin data formats for numeric and DateTime columns, and mapping formulas or formula results depending on the property type, where a string property receives the formula text such as A1+B1 and other types receive the computed result.
NPOI instead of Jet, and two target frameworks
The implementation choice that matters operationally is stated in the feature list. The library uses the pure managed NPOI library instead of the Jet database engine, and that single decision removes the platform dependency that used to make Excel automation in .NET painful. Jet is a Windows COM component, so a library built on it cannot run on Linux or in a container and often needs the Office bit installed, whereas NPOI is pure managed code and works anywhere the runtime does. The target frameworks in the readme badges are netstandard2.0 and net462, which tells you the library is consumable from .NET Framework 4.6.2 as well as from modern .NET, and the package is on NuGet as ExcelMapper. The build runs on AppVeyor and coverage is reported to codecov, and the repository is laid out as a solution with a library project and a separate test project. The licence field on the repository says MIT, and the release history is a stream of patch versions, with v6.0.712 from 2026-09-24, v6.0.641 from 2026-04-27 and v6.0.615 from 2025-12-22, and the last push on 2026-10-14.
Editorial conclusion
ExcelMapper is a good fit for a .NET team that has to read a spreadsheet into typed objects or write typed objects into one, and that wants the mapping rules to live on the model rather than in the import code. It is the wrong tool if your requirement is Excel fidelity at the workbook level, since the formatting it preserves is a template, not a full round trip, and it is the wrong tool for a data pipeline where the interchange format should be CSV or JSON rather than a spreadsheet. It is also the wrong tool if you need to work with a workbook format other than xlsx or xls, since the reader autodetects those two and is built on NPOI. Before adopting it, decide how you want column mapping configured, because the three routes have different costs, and check the multiple mapping behaviour, since one column can feed several properties and the write direction needs the ExcelToObject marker to avoid writing the same value twice. The project is MIT licensed, the last push was on 2026-10-14, and the latest release is v6.0.712 from 2026-09-24.
Frequently asked questions
How do I read Excel rows into objects with ExcelMapper?
Create an ExcelMapper for the file and call Fetch with your type, as in new ExcelMapper("products.xlsx").Fetch<Product>(). It expects a header row of column names, reads the first worksheet, matches column names to property names ignoring case, and autodetects whether the file is xlsx or xls.
How do I map a column to a property with a different name?
With a Column attribute on the property, such as a Column attribute carrying the name Number, which maps the column Number to a property called NumberInStock. You can also use method calls with AddMapping, or map by column index where indexes start at 1 and every property must be mapped explicitly.
What happens if one Excel column maps to several properties?
You have to say which property should be written back to Excel, by adding the MappingDirections.ExcelToObject direction to the Column attribute of the other properties, or by calling the FromExcelOnly method on a method-call mapping. Without that marker the write direction is ambiguous.
Can ExcelMapper preserve the formatting of an existing workbook?
Yes. If you save objects after having previously read from an Excel file using the same mapper instance, the style of the workbook is preserved, which allows a case where an Excel template is filled with computed data. The optional object tracking feature lets you change a fetched object and save it back.
Does ExcelMapper need Excel or Windows installed?
No. The library uses the pure managed NPOI library instead of the Jet database engine, so it does not depend on the Office installation or on the Windows COM components. The package targets netstandard2.0 and net462 and is published on NuGet as ExcelMapper.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/mganss-excelmapper)Was this useful?