IRONSOFTWAREHOME
USING IRONXL

How to Export Excel Files in Blazor Using IronXL

Curtis Chau
Curtis Chau
Updated: August 1, 2026

Exporting data to Excel is something almost every Blazor web application needs -- whether you are generating sales reports, inventory lists, or customer invoices. In a Blazor Server application, accomplishing this reliably without requiring Microsoft Office can feel daunting. IronXL makes it straightforward: you can create, format, and download Excel files directly from the server, with no Office installation required. This guide walks you through building a production-ready Excel export feature in Blazor using IronXL -- from project setup and service design to advanced formatting and multi-sheet reports.

How Do You Set Up IronXL in a Blazor Server Project?

Before writing any export logic, you need to add IronXL to a Blazor Server project and configure a browser-side download helper.

Creating the Blazor Server Project

Start by creating a new Blazor Server project in Visual Studio 2022 or later, targeting .NET 10. Once the project is ready, install IronXL through the NuGet Package Manager Console:

PM > Install-Package IronXL.Excel

IronXL works with .NET 6 and later, so existing Blazor projects can adopt it without upgrading the framework. For alternative installation methods -- such as the NuGet UI or CLI -- see the IronXL installation guide.

Adding the JavaScript Download Helper

Blazor Server runs on the server side, so triggering a file download requires a small JavaScript bridge. In your wwwroot folder, add a file called excelExport.js:

window.downloadFileFromStream = async (fileName, contentStreamReference) => {
    const arrayBuffer = await contentStreamReference.arrayBuffer();
    const blob = new Blob([arrayBuffer]);
    const url = URL.createObjectURL(blob);
    const anchorElement = document.createElement('a');
    anchorElement.href = url;
    anchorElement.download = fileName ?? 'export.xlsx';
    anchorElement.click();
    anchorElement.remove();
    URL.revokeObjectURL(url);
}
JavaScript

Include this script in your _Host.cshtml file (or App.razor in .NET 8+):

<script src="~/excelExport.js"></script>
HTML

This function converts the byte stream from Blazor into a temporary blob URL, triggers the browser download, then cleans up the URL object to prevent memory leaks. It is intentionally minimal -- the heavy lifting happens in C# on the server.

First Step:
arrow pointer

How Do You Create an Excel Export Service in C#?

Separating Excel generation from your Razor components keeps the code testable and reusable across multiple pages. The pattern below wraps IronXL inside a dedicated service class.

Building the ExcelExportService

Create a new file Services/ExcelExportService.cs:

using IronXL;
using System.IO;
using ExportExcel.Models;

public class ExcelExportService
{
    public byte[] GenerateSalesReport(List<SalesData> salesData)
    {
        var workbook = WorkBook.Create(ExcelFileFormat.XLSX);
        workbook.Metadata.Author = "Sales Department";

        var worksheet = workbook.CreateWorkSheet("Monthly Sales");

        // Add column headers
        worksheet["A1"].Value = "Date";
        worksheet["B1"].Value = "Product";
        worksheet["C1"].Value = "Quantity";
        worksheet["D1"].Value = "Revenue";
        worksheet["E1"].Value = "Profit Margin";

        // Style the header row
        var headerRange = worksheet["A1:E1"];
        headerRange.Style.Font.Bold = true;
        headerRange.Style.BackgroundColor = "#4472C4";
        headerRange.Style.Font.Color = "#FFFFFF";

        // Populate data rows
        int row = 2;
        foreach (var sale in salesData)
        {
            worksheet[$"A{row}"].Value = sale.Date.ToString("yyyy-MM-dd");
            worksheet[$"B{row}"].Value = sale.Product ?? "Unknown";
            worksheet[$"C{row}"].Value = sale.Quantity;
            worksheet[$"D{row}"].Value = sale.Revenue;
            worksheet[$"E{row}"].Value = $"=D{row}*0.15";
            row++;
        }

        worksheet.AutoSizeColumn(0, true);

        using var ms = workbook.ToStream();
        return ms.ToArray();
    }
}

Registering the Service

Add the service to the DI container in Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddScoped<ExcelExportService>();

var app = builder.Build();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.Run();

This service demonstrates several key IronXL capabilities. You can create new workbooks and worksheets with a single method call, apply styled headers, populate rows from any data source, and embed Excel formulas such as =D2*0.15. The AutoSizeColumn call ensures columns are wide enough to display their content correctly, regardless of data length. For further formatting options, see the cell styling guide.

How Do You Trigger an Excel Download from a Blazor Component?

Once the service is in place, you need a Razor component that calls it and passes the resulting bytes to the browser.

Writing the Razor Component

Create a page at Pages/ExcelExportDashboard.razor:

@page "/excel-export"
@using ExportExcel.Models
@inject ExcelExportService ExcelService
@inject IJSRuntime JS

<h3>Excel Export Dashboard</h3>

<div class="export-section">
    <button class="btn btn-primary" @onclick="ExportSalesReport" disabled="@isExporting">
        @if (isExporting)
        {
            <span>Generating...</span>
        }
        else
        {
            <span>Export Sales Report</span>
        }
    </button>

    @if (!string.IsNullOrEmpty(errorMessage))
    {
        <div class="alert alert-danger mt-2">@errorMessage</div>
    }
</div>

@code {
    private bool isExporting = false;
    private string errorMessage = "";

    private async Task ExportSalesReport()
    {
        try
        {
            isExporting = true;
            errorMessage = "";

            var salesData = GetSalesData();
            var fileBytes = ExcelService.GenerateSalesReport(salesData);

            using var stream = new MemoryStream(fileBytes);
            using var streamRef = new DotNetStreamReference(stream);
            await JS.InvokeVoidAsync(
                "downloadFileFromStream",
                $"SalesReport_{DateTime.Now:yyyyMMdd}.xlsx",
                streamRef
            );
        }
        catch (Exception)
        {
            errorMessage = "Export failed. Please try again.";
        }
        finally
        {
            isExporting = false;
        }
    }

    private List<SalesData> GetSalesData()
    {
        return new List<SalesData>
        {
            new() { Date = DateTime.Now, Product = "Widget A", Quantity = 100, Revenue = 5000 },
            new() { Date = DateTime.Now.AddDays(-1), Product = "Widget B", Quantity = 75, Revenue = 3750 }
        };
    }
}

What the Component Does

The isExporting flag disables the button during generation, preventing duplicate requests. The DotNetStreamReference wrapper handles efficient binary streaming from the .NET memory stream to the JavaScript function -- avoiding large base64 strings that would inflate payload size. Timestamped filenames such as SalesReport_20260228.xlsx keep downloads organized without additional configuration.

When you navigate to /excel-export in the browser, the dashboard page loads with an export button:

Blazor Export to Excel: Complete Guide Using IronXL in C#: Image 1 - Sample Blazor page

Clicking the button generates the spreadsheet and the browser automatically downloads the file:

Blazor Export to Excel: Complete Guide Using IronXL in C#: Image 2 - Data exported to an Excel file

What Advanced Formatting Can You Apply to Excel Exports?

Basic data exports satisfy many use cases, but production applications often need conditional formatting, multiple worksheets, or data validation. IronXL supports all of these natively.

Conditional Formatting for Inventory Reports

The following service highlights low-stock items in red -- a common requirement for warehouse or inventory management applications:

using IronXL;
using ExportExcel.Models;
using System.IO;

public class InventoryExportService
{
    public byte[] GenerateInventoryReport(List<InventoryItem> items)
    {
        var workbook = WorkBook.Create();
        var details = workbook.CreateWorkSheet("Inventory Details");

        // Column headers
        details["A1"].Value = "SKU";
        details["B1"].Value = "Name";
        details["C1"].Value = "Quantity";
        details["D1"].Value = "Reorder Level";
        details["E1"].Value = "Status";

        var headerRange = details["A1:E1"];
        headerRange.Style.Font.Bold = true;
        headerRange.Style.BackgroundColor = "#2E75B6";
        headerRange.Style.Font.Color = "#FFFFFF";

        for (int i = 0; i < items.Count; i++)
        {
            int row = i + 2;
            var item = items[i];

            details[$"A{row}"].Value = item.SKU;
            details[$"B{row}"].Value = item.Name;
            details[$"C{row}"].Value = item.Quantity;
            details[$"D{row}"].Value = item.ReorderLevel;
            details[$"E{row}"].Value = item.Quantity < item.ReorderLevel
                ? "Reorder Required"
                : "OK";

            if (item.Quantity < item.ReorderLevel)
            {
                // Highlight the entire row for low-stock items
                details[$"A{row}:E{row}"].Style.BackgroundColor = "#FFB6B6";
                details[$"C{row}"].Style.Font.Bold = true;
            }
        }

        details.AutoSizeColumn(0, true);
        details.AutoSizeColumn(1, true);

        using var stream = workbook.ToStream();
        return stream.ToArray();
    }
}

IronXL applies cell-level formatting based on data values at generation time. You can also apply conditional formatting rules declaratively, or manage multiple worksheets within the same workbook -- for example, one sheet for current stock and another for historical orders.

Adding Multiple Worksheets to a Single Export

Separating data into logical sheets improves readability without requiring separate downloads:

public byte[] GenerateMultiSheetReport(
    List<SalesData> sales,
    List<InventoryItem> inventory)
{
    var workbook = WorkBook.Create(ExcelFileFormat.XLSX);

    // Sheet 1 -- Sales summary
    var salesSheet = workbook.CreateWorkSheet("Sales");
    salesSheet["A1"].Value = "Date";
    salesSheet["B1"].Value = "Revenue";
    salesSheet["A1:B1"].Style.Font.Bold = true;

    for (int i = 0; i < sales.Count; i++)
    {
        salesSheet[$"A{i + 2}"].Value = sales[i].Date.ToString("yyyy-MM-dd");
        salesSheet[$"B{i + 2}"].Value = sales[i].Revenue;
    }

    // Sheet 2 -- Inventory snapshot
    var invSheet = workbook.CreateWorkSheet("Inventory");
    invSheet["A1"].Value = "SKU";
    invSheet["B1"].Value = "Name";
    invSheet["C1"].Value = "Quantity";
    invSheet["A1:C1"].Style.Font.Bold = true;

    for (int i = 0; i < inventory.Count; i++)
    {
        invSheet[$"A{i + 2}"].Value = inventory[i].SKU;
        invSheet[$"B{i + 2}"].Value = inventory[i].Name;
        invSheet[$"C{i + 2}"].Value = inventory[i].Quantity;
    }

    using var stream = workbook.ToStream();
    return stream.ToArray();
}

For a full API reference covering workbook properties, range operations, and chart support, visit the IronXL API documentation.

Blazor Export to Excel: Complete Guide Using IronXL in C#: Image 3 - Advanced features example output

How Do You Handle Errors and Large Datasets Efficiently?

Excel export operations can fail silently or degrade performance when datasets are large. The patterns below address both concerns.

Error Handling in the Service Layer

Wrapping generation logic in the service (rather than the component) keeps error handling consistent across all callers. The recommended pattern is to let IronXL exceptions propagate, then wrap them in a domain-specific exception with context about which report failed:

Place a try/catch block around the workbook generation in GenerateSalesReport, catching Exception and rethrowing as InvalidOperationException("Failed to generate sales report", ex). In the Blazor component, catch the InvalidOperationException and display a user-friendly message without exposing internal details. Log the inner exception using ILogger<T> injected into the service constructor, so the development team can trace failures back to a specific workbook operation. Never surface raw exception messages to end users -- file paths, memory addresses, or stack traces can reveal server internals.

See error handling best practices in the official Microsoft documentation for guidance on structured error logging in Blazor. For more guidance on building testable services in .NET, the Microsoft dependency injection documentation explains how to register and resolve scoped services, which is exactly the pattern used here with ExcelExportService.

Performance Considerations for Large Datasets

For datasets exceeding a few thousand rows, consider these approaches:

Excel Export Performance Strategies
StrategyWhen to UseIronXL Support
Stream directly to responseFiles >10 MBworkbook.ToStream()
Paginate data before exportUI-driven exports with filtersApply in service before creating workbook
Background job + download linkReports taking >5 secondsCombine with SignalR or polling
Disable AutoSizeColumn on large sheetsSheets with >500 rowsSet fixed column widths instead

IronXL's ToStream() method writes directly to an output stream without loading the entire file into a byte array first, which keeps memory usage lower for large workbooks. For additional performance guidance, see reading and writing large Excel files with IronXL.

What Other Excel Features Does IronXL Support?

Beyond basic export, IronXL provides a wide range of Excel features that cover real-world reporting requirements.

Formulas, Named Ranges, and Number Formatting

You can embed any Excel formula using the same syntax you would type directly into a cell. IronXL evaluates formulas at read time, so consumers of the generated file see calculated results as soon as they open the spreadsheet. Named ranges make formulas more readable and maintainable over time:

// Aggregate formulas on a summary row
worksheet["E2"].Value = "=SUM(D2:D100)";
worksheet["F2"].Value = "=AVERAGE(C2:C100)";
worksheet["G2"].Value = "=COUNTIF(B2:B100,\"Widget A\")";

// Named ranges improve formula readability
worksheet["D2:D100"].Name = "RevenueColumn";
worksheet["E2"].Value = "=SUM(RevenueColumn)";

// Number and date formatting prevents type misinterpretation
worksheet["D2"].Value = 12345.67m;
worksheet["D2"].FormatString = "#,##0.00";
worksheet["A2"].Value = DateTime.Now;
worksheet["A2"].FormatString = "dd/MM/yyyy";

To define named ranges and set the number format explicitly, IronXL exposes both as properties on the range object. This prevents Excel from treating currency values as plain text -- a common issue when exporting financial data from databases that store values as strings.

Supported Excel File Formats

IronXL can read and write multiple Excel formats including .xlsx, .xls, .csv, and .tsv. The format is determined at save time, so the same service class can support both Excel and CSV exports with a small parameter change:

// Export as CSV for systems that consume flat files
workbook.SaveAs("report.csv");

// Or stream as CSV for download
using var ms = workbook.ToStream(ExcelFileFormat.CSV);

This flexibility matters in integrations where downstream systems -- such as ERP platforms or data warehouses -- expect a specific file format. For a full feature comparison between IronXL and other Excel libraries, visit the IronXL features page.

Microsoft provides a good reference for understanding OOXML file formats if you need to understand the internal structure of .xlsx files when debugging unexpected output. The NuGet package for IronXL is also listed on NuGet.org with full version history and compatibility notes.

How Do You Get Started with IronXL for Blazor Projects?

IronXL is available under a free development license that lets you build and test without any time limit. For production applications, a deployment license is required.

You can download a free trial directly from NuGet -- no registration is needed to start. When you are ready to deploy, review the IronXL licensing options to find the plan that fits the scale of the application.

IronXL works across all major .NET application types -- Blazor Server, Blazor WebAssembly (server-rendered), ASP.NET Core MVC, console applications, and Windows desktop apps. The library targets .NET Standard 2.0, so it is compatible with every supported .NET version from .NET Framework 4.6.2 through .NET 10. If the project also requires PDF generation, IronPDF integrates alongside IronXL with no conflicts, allowing you to export data as either Excel or PDF from the same service layer.

To explore more Blazor-specific examples, see the Blazor Excel export tutorial and the ASP.NET Core export guide. For reading existing spreadsheets, the C# Excel reader tutorial covers common import scenarios. You can also review how to create a new Excel workbook from scratch for projects that need to build files programmatically rather than from templates.

Curtis Chau
Technical Writer

Curtis Chau holds a Bachelor’s degree in Computer Science (Carleton University) and specializes in front-end development with expertise in Node.js, TypeScript, JavaScript, and React. Passionate about crafting intuitive and aesthetically pleasing user interfaces, Curtis enjoys working with modern frameworks and creating well-structured, visually appealing manuals.

...
Read More

Related Articles

Key in blue circle

Get your free 30-day Trial Key instantly.

Your trial license will be sent to your email address

No limitations. 100% unlocked. No credit card.

bullet_checkedNo credit card or account creation requiredNo limitations. 100% unlocked. No credit card.
  • Logo Aetna
  • Logo NASA
  • Logo GE
  • Logo Porsche
  • Logo USDA
  • Logo Qatar
Join Millions of Engineers who’ve tried IronPDF
Book your free Live Demo
Booking Badge

Trusted by Millions of Engineers Worldwide

Iron Software's customer logos
Get Your No-Obligation Consult
Complete the form below or email sales@ironsoftware.com
Your details will always be kept confidential.
Trusted by Millions of Engineers Worldwide
Iron Software's customer logos
Get your free 30-day Trial Key instantly.
No credit card or account creation required