FormulaEngineer 3.0.1

dotnet add package FormulaEngineer --version 3.0.1
                    
NuGet\Install-Package FormulaEngineer -Version 3.0.1
                    
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="FormulaEngineer" Version="3.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="FormulaEngineer" Version="3.0.1" />
                    
Directory.Packages.props
<PackageReference Include="FormulaEngineer" />
                    
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 FormulaEngineer --version 3.0.1
                    
#r "nuget: FormulaEngineer, 3.0.1"
                    
#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 FormulaEngineer@3.0.1
                    
#: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=FormulaEngineer&version=3.0.1
                    
Install as a Cake Addin
#tool nuget:?package=FormulaEngineer&version=3.0.1
                    
Install as a Cake Tool

FormulaEngineer

A complete .NET Excel solution for high-performance XLSX creation, streaming reading, formula evaluation, and advanced workbook presentation — styling, tables, comments, images, shapes, charts, sparklines, and auto-fit — without Excel or COM.

NuGet Downloads Website


What FormulaEngineer does

FormulaEngineer brings together a production-grade Excel formula engine, high-performance streaming workbook I/O, and advanced XLSX presentation features in one .NET package.

Most .NET Excel libraries can open and create .xlsx files. Very few can evaluate the formulas inside them correctly. FormulaEngineer is built around that gap: a from-scratch formula engine that matches Excel's output to last-bit floating-point precision.

  • Accurate formula evaluation — verified against hundreds of real-world formulas; where Excel's cached values exist in the source workbooks, results match bit-for-bit
  • 435 Excel-compatible functions — including lookup, financial, statistical, math, text, date/time, logical, information, database, dynamic-array, and lambda-helper functions such as LET, LAMBDA, MAP, REDUCE, SCAN, BYROW, BYCOL, MAKEARRAY, and ISOMITTED
  • Handles the hard cases — dynamic arrays, structured table references, cross-sheet INDIRECT, spill semantics (#SPILL! / #CALC!), full error propagation
  • Reads and writes formulas — write formulas into cells, then read them back and evaluate them with no Excel involved
  • Ultra-fast streaming reader and writer — forward-only, single-enumeration, flat memory profile regardless of file size
  • Create professionally styled spreadsheets — fonts, fills, borders, number formats, alignment, layout, protection, and auto-fit
  • Build advanced reports — conditional formatting, rich text, named styles, themes, and Excel tables
  • Add workbook presentation objects — notes, threaded comments, images, shapes, charts, and sparklines
  • Cross-platform — pure managed code for .NET 6 and later; Windows, Linux, macOS. No Excel installation, no COM interop.

Install

dotnet add package FormulaEngineer

Targets net6.0 and later.


A note on formula strings

When you create a formula with ExcelFormula.From(...), pass the formula without a leading =. Write SUM(A1:A3), not =SUM(A1:A3).


Activating a license

During the 7-day trial period, there is no need to call LicenseManager.ActivateFromFile("license.lic");.

For paid Pro or Enterprise licenses, activate your .lic file like this:

using FormulaEngineer.Licensing;

LicenseManager.ActivateFromFile("license.lic");

Writing formulas

Pass an ExcelFormula into WriteRow to write a formula cell. Each example below writes a workbook; the matching example in the next section reads it back and evaluates it.

Example 1 — SUM

Writes three numbers and a SUM formula over them.

using FormulaEngineer.Api;
using FormulaEngineer.Licensing;

LicenseManager.ActivateFromFile("license.lic");

using (var writer = new ExcelWriter("sum.xlsx"))
{
    using (var sheet = writer.CreateWorksheet("Data"))
    {
        sheet.WriteRow(10);                              // A1
        sheet.WriteRow(20);                              // A2
        sheet.WriteRow(30);                              // A3
        sheet.WriteRow(ExcelFormula.From("SUM(A1:A3)")); // A4 — the formula
    }

    writer.Close();
}

The formula cell is in row 4, column 1. It sums 10 + 20 + 30.

Example 2 — Cell arithmetic

Writes two numbers and a formula that multiplies them.

using FormulaEngineer.Api;
using FormulaEngineer.Licensing;

LicenseManager.ActivateFromFile("license.lic");

using (var writer = new ExcelWriter("multiply.xlsx"))
{
    using (var sheet = writer.CreateWorksheet("Data"))
    {
        // A1 = 7, B1 = 6, C1 = the formula
        sheet.WriteRow(7, 6, ExcelFormula.From("A1*B1"));
    }

    writer.Close();
}

The formula cell is in row 1, column 3. It multiplies 7 * 6.

Example 3 — Conditional logic (medium)

Writes a header row, a score, and an IF formula that returns text.

using FormulaEngineer.Api;
using FormulaEngineer.Licensing;

LicenseManager.ActivateFromFile("license.lic");

using (var writer = new ExcelWriter("conditional.xlsx"))
{
    using (var sheet = writer.CreateWorksheet("Scores"))
    {
        sheet.WriteRow("Score", "Result");                                      // A1, B1
        sheet.WriteRow(135, ExcelFormula.From("IF(A2>100, \"High\", \"Low\")")); // A2 = 135, B2 = formula
    }

    writer.Close();
}

The formula cell is in row 2, column 2. Since 135 > 100, it returns the text "High".

Example 4 — VLOOKUP over a table (difficult)

Writes a three-row lookup table and a VLOOKUP formula against it.

using FormulaEngineer.Api;
using FormulaEngineer.Licensing;

LicenseManager.ActivateFromFile("license.lic");

using (var writer = new ExcelWriter("lookup.xlsx"))
{
    using (var sheet = writer.CreateWorksheet("Regions"))
    {
        sheet.WriteRow("EMEA", 1_240_000);  // A1, B1
        sheet.WriteRow("APAC", 2_180_000);  // A2, B2
        sheet.WriteRow("AMER", 3_950_000);  // A3, B3
        sheet.WriteRow(ExcelFormula.From("VLOOKUP(\"APAC\", A1:B3, 2, FALSE)")); // A4 — the formula
    }

    writer.Close();
}

The formula cell is in row 4, column 1. It looks up "APAC" in the table and returns the value from the second column.

Example 5 — Multiple formulas in one sheet (advanced)

Writes an invoice sheet where formulas work together — line totals feed a subtotal, which feeds the tax and total, which the status formula tests.

using FormulaEngineer.Api;
using FormulaEngineer.Licensing;

LicenseManager.ActivateFromFile("license.lic");

using (var writer = new ExcelWriter("invoice.xlsx"))
{
    using (var sheet = writer.CreateWorksheet("Invoice"))
    {
        sheet.WriteRow("Item", "Qty", "Unit Price", "Line Total");      // row 1 — header
        sheet.WriteRow("Widget", 4, 25.00, ExcelFormula.From("B2*C2")); // row 2
        sheet.WriteRow("Gadget", 2, 80.00, ExcelFormula.From("B3*C3")); // row 3
        sheet.WriteRow("Cable",  10, 3.50, ExcelFormula.From("B4*C4")); // row 4
        sheet.WriteRow("Subtotal", "", "", ExcelFormula.From("SUM(D2:D4)"));                              // row 5
        sheet.WriteRow("Tax (8%)", "", "", ExcelFormula.From("D5*0.08"));                                 // row 6
        sheet.WriteRow("Total",    "", "", ExcelFormula.From("D5+D6"));                                   // row 7
        sheet.WriteRow("Status",   "", "", ExcelFormula.From("IF(D7>200,\"Large order\",\"Standard\")")); // row 8
    }

    writer.Close();
}

The line totals (B*C) feed the subtotal (SUM), which feeds the tax line and the total, which the status formula then tests. The formula cells are all in column 4, rows 2 through 8.


Reading and evaluating formulas

Each example opens the workbook written above, reads the formula cell to get its formula text, then evaluates it — printing both. The formula text is read first with one worksheet reader; the evaluation uses a separate reader afterwards.

Example 1 — SUM

using FormulaEngineer.Api;
using FormulaEngineer.Licensing;

LicenseManager.ActivateFromFile("license.lic");

using var reader    = new ExcelReader("sum.xlsx");
using var evaluator = new ExcelFormulaEvaluator();

// Read the formula text (row 4, column 1)
string formulaText;
using (var sheet = reader.OpenWorksheet("Data"))
    formulaText = ((ExcelFormula)sheet.ReadRows().Last()[0]!).FormulaText;

// Evaluate it
object? result;
using (var sheet = reader.OpenWorksheet("Data"))
    result = evaluator.EvaluateCell(sheet, row: 4, col: 1);

Console.WriteLine($"Formula:  {formulaText}");   // SUM(A1:A3)
Console.WriteLine($"Result:   {result}");        // 60

Example 2 — Cell arithmetic

using FormulaEngineer.Api;
using FormulaEngineer.Licensing;

LicenseManager.ActivateFromFile("license.lic");

using var reader    = new ExcelReader("multiply.xlsx");
using var evaluator = new ExcelFormulaEvaluator();

// Read the formula text (row 1, column 3)
string formulaText;
using (var sheet = reader.OpenWorksheet("Data"))
    formulaText = ((ExcelFormula)sheet.ReadRows().First()[2]!).FormulaText;

// Evaluate it
object? result;
using (var sheet = reader.OpenWorksheet("Data"))
    result = evaluator.EvaluateCell(sheet, row: 1, col: 3);

Console.WriteLine($"Formula:  {formulaText}");   // A1*B1
Console.WriteLine($"Result:   {result}");        // 42

Example 3 — Conditional logic (medium)

using FormulaEngineer.Api;
using FormulaEngineer.Licensing;

LicenseManager.ActivateFromFile("license.lic");

using var reader    = new ExcelReader("conditional.xlsx");
using var evaluator = new ExcelFormulaEvaluator();

// Read the formula text (row 2, column 2)
string formulaText;
using (var sheet = reader.OpenWorksheet("Scores"))
    formulaText = ((ExcelFormula)sheet.ReadRows().Last()[1]!).FormulaText;

// Evaluate it
object? result;
using (var sheet = reader.OpenWorksheet("Scores"))
    result = evaluator.EvaluateCell(sheet, row: 2, col: 2);

Console.WriteLine($"Formula:  {formulaText}");   // IF(A2>100, "High", "Low")
Console.WriteLine($"Result:   {result}");        // High

Example 4 — VLOOKUP over a table (difficult)

using FormulaEngineer.Api;
using FormulaEngineer.Licensing;

LicenseManager.ActivateFromFile("license.lic");

using var reader    = new ExcelReader("lookup.xlsx");
using var evaluator = new ExcelFormulaEvaluator();

// Read the formula text (row 4, column 1)
string formulaText;
using (var sheet = reader.OpenWorksheet("Regions"))
    formulaText = ((ExcelFormula)sheet.ReadRows().Last()[0]!).FormulaText;

// Evaluate it
object? result;
using (var sheet = reader.OpenWorksheet("Regions"))
    result = evaluator.EvaluateCell(sheet, row: 4, col: 1);

Console.WriteLine($"Formula:  {formulaText}");   // VLOOKUP("APAC", A1:B3, 2, FALSE)
Console.WriteLine($"Result:   {result}");        // 2180000

Example 5 — Multiple formulas in one sheet (advanced)

using FormulaEngineer.Api;
using FormulaEngineer.Licensing;

LicenseManager.ActivateFromFile("license.lic");

using var reader    = new ExcelReader("invoice.xlsx");
using var evaluator = new ExcelFormulaEvaluator();

// Read the formula text from every row (formula cells are in column 4)
List<string> formulaTexts;
using (var sheet = reader.OpenWorksheet("Invoice"))
    formulaTexts = sheet.ReadRows()
        .Where(row => row.Length > 3 && row[3] is ExcelFormula)
        .Select(row => ((ExcelFormula)row[3]!).FormulaText)
        .ToList();

// Evaluate the formula cell in each row (rows 2 through 8, column 4)
List<object?> results;
using (var sheet = reader.OpenWorksheet("Invoice"))
    results = Enumerable.Range(2, 7)
        .Select(rowNum => evaluator.EvaluateCell(sheet, row: rowNum, col: 4))
        .ToList();

for (int i = 0; i < formulaTexts.Count; i++)
    Console.WriteLine($"Formula:  {formulaTexts[i],-40}  Result:  {results[i]}");

// Formula:  B2*C2                                     Result:  100
// Formula:  B3*C3                                     Result:  160
// Formula:  B4*C4                                     Result:  35
// Formula:  SUM(D2:D4)                                Result:  295
// Formula:  D5*0.08                                   Result:  23.6
// Formula:  D5+D6                                     Result:  318.6
// Formula:  IF(D7>200,"Large order","Standard")       Result:  Large order

You can also evaluate an entire sheet at once with evaluator.EvaluateSheet(sheet), which returns each row with formula cells replaced by their computed values.


The formula engine

The engine has been verified against hundreds of formulas drawn from production-style workbooks — covering the lookup, financial, statistical, aggregate, date/time, text, logical, and information families. Where Excel's cached values exist in the source files, the evaluator matches them bit-for-bit. Floating-point arithmetic follows IEEE 754 exactly, including the canonical edge cases Excel itself produces.

Function families

  • LookupLOOKUP, VLOOKUP, HLOOKUP, XLOOKUP, INDEX, MATCH — including wildcards, case-sensitive matching, reverse search, multi-criteria, and structured table references
  • Dynamic arraysFILTER, SEQUENCE, TRANSPOSE, SORT, UNIQUE, spill semantics, array-to-array concatenation, boolean-to-numeric coercion
  • Lambda helpers and special formsLET, LAMBDA, MAP, REDUCE, SCAN, BYROW, BYCOL, MAKEARRAY, and ISOMITTED, with support for nested lambda evaluation and dynamic-array behavior
  • FinancialPMT, IPMT, PPMT, IRR, XIRR, MIRR, NPV, XNPV, PV, FV, RATE, NPER, and more — verified to last-ULP precision across every compounding frequency
  • Date and timeDATE, EDATE, EOMONTH, YEAR, MONTH, DAY, TODAY, NOW, WORKDAY, NETWORKDAYS, YEARFRAC — with correct leap-year handling and end-of-month clamping
  • AggregateSUM, AVERAGE, COUNT, COUNTA, COUNTIF, COUNTIFS, SUMIF, SUMIFS, AVERAGEIF, AVERAGEIFS, SUMPRODUCT, AGGREGATE, SUBTOTAL
  • Logical and informationIF, IFS, AND, OR, NOT, XOR, IFERROR, IFNA, SWITCH, ISBLANK, ISERR, ISNA, ISNUMBER, ISEVEN, ISODD, TYPE, ERROR.TYPE, CELL
  • TextCONCAT, CONCATENATE, TEXTJOIN, TEXT, LEFT, MID, RIGHT, LEN, SEARCH, FIND, SUBSTITUTE, REPLACE, EXACT, VALUE
  • Reference — named ranges (workbook- and sheet-scoped), cross-sheet references, structured table references (Table[Col], Table[#Headers], Table[]), INDIRECT with scalar or array arguments, OFFSET
  • DatabaseDSUM, DCOUNT, DAVERAGE, DMAX, DMIN, DGET, and the rest of the D-function family

FormulaEngineer also handles the patterns that break most non-Microsoft formula engines — INDIRECT fed an array of sheet names, header-driven nested XLOOKUP that returns an entire column dynamically, FILTER + SEQUENCE for Nth-occurrence lookups, the CHOOSE-virtual-table case-sensitive VLOOKUP trick, and matrix lookups with composite headers — all evaluated correctly against real workbooks.


Reading and writing plain workbooks

FormulaEngineer is also a fast streaming reader and writer for ordinary (non-formula) spreadsheets.

Writing a workbook

using FormulaEngineer.Api;
using FormulaEngineer.Licensing;

LicenseManager.ActivateFromFile("license.lic");

using (var writer = new ExcelWriter("report.xlsx"))
{
    using (var sheet = writer.CreateWorksheet("Q4"))
    {
        sheet.WriteRow("Region", "Revenue", "Growth");
        sheet.WriteRow("EMEA", 1_240_000, 0.18);
        sheet.WriteRow("APAC", 2_180_000, 0.32);
        sheet.WriteRow("AMER", 3_950_000, 0.14);
    }

    writer.Close();
}

Forward-only, one active worksheet at a time. WriteRows, SkipRows, SkipColumns, MergeCells, and named ranges are all supported.

Reading a workbook

using FormulaEngineer.Api;
using FormulaEngineer.Licensing;

LicenseManager.ActivateFromFile("license.lic");

using var reader = new ExcelReader("report.xlsx");

foreach (var sheetName in reader.WorksheetNames)
{
    using var sheet = reader.OpenWorksheet(sheetName);

    foreach (object?[] row in sheet.ReadRows())
    {
        for (int i = 0; i < row.Length; i++)
            Console.WriteLine(row[i]);
    }
}

Worksheets are single-enumeration — read top to bottom, once. The reader streams; memory stays flat regardless of file size.


Practical Excel solution examples

These examples show FormulaEngineer as a complete XLSX creation and presentation API, not only a formula evaluator. Each example writes a real .xlsx file without Microsoft Excel or COM interop.

Bonus example — Simple financial dashboard

This compact example creates a styled dashboard with a merged title, formatted input columns, formula cells, currency totals, and worksheet layout.

using FormulaEngineer.Api;
using FormulaEngineer.Api.Styling;

var title =
    ExcelStyle.Default.With(
        font: ExcelFontStyle.Default.With(bold: true, size: 16d, color: ExcelColor.FromRgb(255, 255, 255)),
        fill: ExcelFillStyle.Solid(ExcelColor.FromRgb(0, 112, 160)),
        alignment: ExcelAlignmentStyle.Default.With(horizontal: ExcelHorizontalAlignment.Center));

var header =
    ExcelStyle.Default.With(
        font: ExcelFontStyle.Default.With(bold: true, color: ExcelColor.FromRgb(255, 255, 255)),
        fill: ExcelFillStyle.Solid(ExcelColor.FromRgb(31, 78, 121)),
        alignment: ExcelAlignmentStyle.Default.With(horizontal: ExcelHorizontalAlignment.Center));

var input = ExcelStyle.Default.With(fill: ExcelFillStyle.Solid(ExcelColor.FromRgb(255, 242, 204)));
var money = ExcelStyle.Default.With(numberFormat: ExcelNumberFormatStyle.Custom("$#,##0.00"));
var total = money.With(fill: ExcelFillStyle.Solid(ExcelColor.FromRgb(189, 215, 238)));

using (var writer = new ExcelStyledWriter("simple-dashboard.xlsx"))
{
    using (var sheet = writer.CreateWorksheet("Dashboard"))
    {
        sheet.MergeCells(1, 1, 1, 6);
        sheet.SetColumnStyle(1, ExcelColumnStyle.Default.With(width: 12d));
        sheet.SetColumnStyle(2, ExcelColumnStyle.Default.With(width: 28d));
        sheet.SetColumnStyle(3, ExcelColumnStyle.Default.With(width: 10d));
        sheet.SetColumnStyle(4, ExcelColumnStyle.Default.With(width: 14d));
        sheet.SetColumnStyle(5, ExcelColumnStyle.Default.With(width: 14d));
        sheet.SetColumnStyle(6, ExcelColumnStyle.Default.With(width: 14d));

        sheet.WriteRow(new object?[] { "Integrated financial dashboard" }, title);
        sheet.WriteRow();
        sheet.WriteRow(new object?[] { "ID", "Item", "Qty", "Unit price", "Net", "Tax" }, header);

        sheet.WriteRow(new object?[] { "P-100", "Formula Engine license", 2, 499m, ExcelFormula.From("C4*D4"), ExcelFormula.From("E4*18%") },
            new ExcelStyle?[] { null, null, input, input, money, money });

        sheet.WriteRow(new object?[] { "P-200", "Streaming XLSX support", 3, 275.5m, ExcelFormula.From("C5*D5"), ExcelFormula.From("E5*18%") },
            new ExcelStyle?[] { null, null, input, input, money, money });

        sheet.WriteRow(new object?[] { "P-300", "Dynamic-array module", 1, 750m, ExcelFormula.From("C6*D6"), ExcelFormula.From("E6*18%") },
            new ExcelStyle?[] { null, null, input, input, money, money });

        sheet.WriteRow(new object?[] { "", "TOTAL", "", "", ExcelFormula.From("SUM(E4:E6)"), ExcelFormula.From("SUM(F4:F6)") },
            new ExcelStyle?[] { null, null, null, null, total, total });
    }

    writer.Close();
}

1 - Core styling

Example 1 — Styled report title and header row
using FormulaEngineer.Api;
using FormulaEngineer.Api.Styling;

var titleStyle =
    ExcelStyle.Default.With(
        font: ExcelFontStyle.Default.With(
            bold: true,
            size: 16d,
            color: ExcelColor.FromRgb(255, 255, 255)),
        fill: ExcelFillStyle.Solid(
            ExcelColor.FromRgb(31, 78, 121)),
        alignment: ExcelAlignmentStyle.Default.With(
            horizontal: ExcelHorizontalAlignment.Center,
            vertical: ExcelVerticalAlignment.Center));

var headerStyle =
    ExcelStyle.Default.With(
        font: ExcelFontStyle.Default.With(
            bold: true,
            color: ExcelColor.FromRgb(255, 255, 255)),
        fill: ExcelFillStyle.Solid(
            ExcelColor.FromRgb(68, 114, 196)),
        alignment: ExcelAlignmentStyle.Default.With(
            horizontal: ExcelHorizontalAlignment.Center));

using (var writer = new ExcelStyledWriter("core-styling-title.xlsx"))
{
    using (var sheet = writer.CreateWorksheet("Report"))
    {
        sheet.MergeCells(1, 1, 1, 3);

        sheet.WriteRow(
            new object?[] { "Quarterly Sales Report" },
            titleStyle);

        sheet.WriteRow(
            new object?[] { "Region", "Revenue", "Growth" },
            headerStyle);

        sheet.WriteRow("North", 125000, 0.18);
        sheet.WriteRow("South", 98000, 0.11);
    }

    writer.Close();
}
Example 2 — Currency and percentage number formats
using FormulaEngineer.Api;
using FormulaEngineer.Api.Styling;

var headerStyle =
    ExcelStyle.Default.With(
        font: ExcelFontStyle.Bold);

var currencyStyle =
    ExcelStyle.Default.With(
        numberFormat: ExcelNumberFormatStyle.Custom("$#,##0.00"));

var percentStyle =
    ExcelStyle.Default.With(
        numberFormat: ExcelNumberFormatStyle.Custom("0.00%"));

using (var writer = new ExcelStyledWriter("core-styling-number-formats.xlsx"))
{
    using (var sheet = writer.CreateWorksheet("Numbers"))
    {
        sheet.WriteRow(
            new object?[] { "Region", "Revenue", "Growth" },
            headerStyle);

        sheet.WriteRow(
            new object?[] { "North", 125000.50m, 0.184 },
            new ExcelStyle?[] { null, currencyStyle, percentStyle });

        sheet.WriteRow(
            new object?[] { "South", 98000.25m, 0.112 },
            new ExcelStyle?[] { null, currencyStyle, percentStyle });
    }

    writer.Close();
}

2 - Layout and streaming auto-fit

Example 3 — Fixed columns plus streaming auto-fit
using FormulaEngineer.Api;
using FormulaEngineer.Api.Styling;

using (var writer = new ExcelStyledWriter("layout-autofit.xlsx"))
{
    using (var sheet = writer.CreateWorksheet("AutoFit"))
    {
        sheet.SetColumnStyle(
            1,
            ExcelColumnStyle.Default.With(width: 14d));

        sheet.SetColumnStyle(
            2,
            ExcelColumnStyle.Default.With(
                width: 12d,
                autoFit: true));

        sheet.WriteRow("Code", "Description");
        sheet.WriteRow("A100", "Short");
        sheet.WriteRow("B200", "This longer text expands the auto-fit column");
    }

    writer.Close();
}
Example 4 — Wrapped text with a taller row
using FormulaEngineer.Api;
using FormulaEngineer.Api.Styling;

var wrappedStyle =
    ExcelStyle.Default.With(
        alignment: ExcelAlignmentStyle.Default.With(
            wrapText: true,
            vertical: ExcelVerticalAlignment.Top));

using (var writer = new ExcelStyledWriter("layout-wrapped-row.xlsx"))
{
    using (var sheet = writer.CreateWorksheet("Wrapped"))
    {
        sheet.SetColumnStyle(
            1,
            ExcelColumnStyle.Default.With(width: 35d));

        sheet.WriteRowWithLayout(
            new object?[]
            {
                "This cell is wrapped and the row is made taller so the text remains readable."
            },
            ExcelRowStyle.Default.With(height: 45d),
            new ExcelStyle?[] { wrappedStyle });
    }

    writer.Close();
}

3 - Conditional formatting and rich text

Example 5 — Highlight values above a threshold
using FormulaEngineer.Api;
using FormulaEngineer.Api.Styling;

var stylingOptions =
    new ExcelStylingOptions
    {
        EnableConditionalFormatting = true
    };

var highlightStyle =
    ExcelStyle.Default.With(
        font: ExcelFontStyle.Default.With(bold: true),
        fill: ExcelFillStyle.Solid(
            ExcelColor.FromRgb(226, 239, 218)));

using (var writer = new ExcelStyledWriter(
    "conditional-formatting.xlsx",
    null,
    stylingOptions))
{
    using (var sheet = writer.CreateWorksheet("Scores"))
    {
        sheet.WriteRow("Region", "Score");
        sheet.WriteRow("North", 120);
        sheet.WriteRow("South", 80);
        sheet.WriteRow("West", 135);

        sheet.AddConditionalFormat(
            "B2:B4",
            ExcelConditionalFormat.CellValue(
                ExcelConditionalFormatOperator.GreaterThan,
                "100",
                style: highlightStyle));
    }

    writer.Close();
}
Example 6 — Multi-run rich text in one cell
using FormulaEngineer.Api;
using FormulaEngineer.Api.Styling;

var stylingOptions =
    new ExcelStylingOptions
    {
        EnableRichText = true
    };

var richText =
    ExcelRichText.From(
        new ExcelRichTextRun("Status: "),
        new ExcelRichTextRun(
            "Approved",
            ExcelFontStyle.Default.With(
                bold: true,
                color: ExcelColor.FromRgb(0, 128, 0))));

using (var writer = new ExcelStyledWriter(
    "rich-text.xlsx",
    null,
    stylingOptions))
{
    using (var sheet = writer.CreateWorksheet("Status"))
    {
        sheet.WriteRow(richText);
    }

    writer.Close();
}

4 - Tables and notes

Example 7 — Register an Excel table over streamed rows
using FormulaEngineer.Api;
using FormulaEngineer.Api.Styling;

var stylingOptions =
    new ExcelStylingOptions
    {
        EnableTables = true
    };

using (var writer = new ExcelStyledWriter(
    "excel-table.xlsx",
    null,
    stylingOptions))
{
    using (var sheet = writer.CreateWorksheet("Sales"))
    {
        sheet.WriteRow("Product", "Quantity", "Revenue");
        sheet.WriteRow("Laptop", 5, 6250);
        sheet.WriteRow("Monitor", 9, 3150);
        sheet.WriteRow("Keyboard", 14, 980);

        sheet.AddTable(
            ExcelTable.Create(
                "SalesTable",
                "A1:C4",
                new[]
                {
                    ExcelTableColumn.Create("Product"),
                    ExcelTableColumn.Create("Quantity"),
                    ExcelTableColumn.Create("Revenue")
                },
                ExcelTableStyle.Create("TableStyleMedium2")));
    }

    writer.Close();
}
Example 8 — Add a traditional Excel note
using FormulaEngineer.Api;
using FormulaEngineer.Api.Styling;

var stylingOptions =
    new ExcelStylingOptions
    {
        EnableComments = true
    };

using (var writer = new ExcelStyledWriter(
    "excel-note.xlsx",
    null,
    stylingOptions))
{
    using (var sheet = writer.CreateWorksheet("Notes"))
    {
        sheet.WriteRow("Region", "Revenue");
        sheet.WriteRow("North", 125000);

        sheet.AddNote(
            "A1",
            ExcelNote.Create(
                "This is a traditional Excel note.",
                "John"));
    }

    writer.Close();
}

5 - Images, charts, Sparklines

Example 9 — Embed a PNG image
using FormulaEngineer.Api;
using FormulaEngineer.Api.Styling;
using System.IO;

var stylingOptions =
    new ExcelStylingOptions
    {
        EnableImages = true
    };

byte[] logoBytes = File.ReadAllBytes("logo.png");

using (var writer = new ExcelStyledWriter(
    "image-example.xlsx",
    null,
    stylingOptions))
{
    using (var sheet = writer.CreateWorksheet("Images"))
    {
        sheet.WriteRow("Company report");

        sheet.AddImage(
            ExcelImage.Create(
                logoBytes,
                ExcelImageFormat.Png,
                ExcelDrawingAnchor.OneCell(
                    column: 3,
                    row: 2,
                    widthPixels: 180d,
                    heightPixels: 80d),
                name: "Company logo"));
    }

    writer.Close();
}
Example 10 — Add sparklines and a column chart
using FormulaEngineer.Api;
using FormulaEngineer.Api.Styling;

var stylingOptions =
    new ExcelStylingOptions
    {
        EnableCharts = true,
        EnableSparklines = true
    };

using (var writer = new ExcelStyledWriter(
    "charts-and-sparklines.xlsx",
    null,
    stylingOptions))
{
    using (var sheet = writer.CreateWorksheet("Trends"))
    {
        sheet.AddSparklineGroup(
            ExcelSparklineGroup.Create(
                new[]
                {
                    ExcelSparkline.Create("'Trends'!$B$2:$D$2", 2, 5),
                    ExcelSparkline.Create("'Trends'!$B$3:$D$3", 3, 5)
                },
                type: ExcelSparklineType.Line,
                showMarkers: true,
                showHighPoint: true,
                showLowPoint: true));

        sheet.WriteRow("Region", "Jan", "Feb", "Mar", "Trend");
        sheet.WriteRow("North", 10, 14, 18, null);
        sheet.WriteRow("South", 8, 9, 12, null);

        sheet.AddChart(
            ExcelChart.Create(
                ExcelChartKind.ColumnClustered,
                ExcelDrawingAnchor.OneCell(
                    column: 7,
                    row: 2,
                    widthPixels: 420d,
                    heightPixels: 240d),
                new[]
                {
                    ExcelChartSeries.Create(
                        "North",
                        "'Trends'!$B$1:$D$1",
                        "'Trends'!$B$2:$D$2")
                },
                title: "North trend"));
    }

    writer.Close();
}

Licensing

FormulaEngineer includes a built-in 7-day trial. No license required to evaluate.

Tier Use case
Trial 7 days, full API, throttled request counts per capability
Pro Production use
Enterprise Production use with extended terms

Above the trial caps, each subsequent request incurs a short delay. Paid licenses bypass throttling entirely.

To purchase a Pro or Enterprise license, visit nasvelocityexcel.com/pricing.

Getting a license

Each license is bound to a machine fingerprint. To obtain yours, visit nasvelocityexcel.com and use the machine hash calculator, then include the hash with your purchase. Your .lic file is issued for that machine.

Activation

using FormulaEngineer.Licensing;

// Activate from a .lic file
LicenseManager.ActivateFromFile("license.lic");

// Check licensing state
if (!LicenseManager.IsLicensed())
{
    int trialDays = LicenseManager.GetRemainingTrialDays();
    Console.WriteLine($"Not licensed. Trial days remaining: {trialDays}");
}

Requirements

  • .NET 6 or later
  • Network access for trial registration and license validation

License

FormulaEngineer is proprietary software. Refer to the LICENSE file for full terms.



© 2026 Mohd Nasrullah Kazmi. All rights reserved.

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  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 was computed.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
3.0.1 42 7/24/2026
3.0.0 83 7/21/2026
2.0.3 118 7/6/2026
2.0.2 116 6/20/2026
2.0.1 132 6/14/2026 2.0.1 is deprecated because it is no longer maintained and has critical bugs.
2.0.0 144 6/7/2026 2.0.0 is deprecated because it is no longer maintained and has critical bugs.
1.0.1 130 5/26/2026
1.0.0 133 5/15/2026

Version 3.0.1 expands FormulaEngineer from a formula engine and streaming XLSX reader/writer into a complete .NET Excel solution.

New capabilities include:
- Core styling: fonts, fills, borders, number formats, alignment, and protection
- Layout and streaming auto-fit: row layout, column layout, default styles, and deterministic auto-fit
- Advanced reporting: conditional formatting, rich text, named styles, themes, and Excel tables
- Workbook collaboration objects: traditional notes and modern threaded comments
- Workbook presentation objects: images, shapes, charts, and sparklines
- Continued high-performance streaming workbook creation and formula evaluation without Excel or COM

The existing ExcelWriter, ExcelReader, and formula evaluation APIs remain supported.