Skip to footer content
USING IRONXL

How to Export DataTable to Excel C# Using Interop vs IronXL

Introduction to Exporting Data to Excel File

Exporting data from a database or application to an Excel file is a fundamental requirement for organizations that need to analyze, visualize, and share information efficiently. Excel files are widely recognized for their user-friendly interface, making it easy for users to interact with and interpret data. By converting datasets into the .XLSX format, developers ensure that the data remains accessible and structured, regardless of the user’s technical background. This process not only preserves the integrity of the original dataset but also enables seamless data transfer between systems. To facilitate this, developers can leverage a variety of Excel libraries—such as IronXL, EPPlus, NPOI, and ClosedXML—that allow them to create, read, and manipulate Excel files programmatically, all without the need for Microsoft Excel to be installed on the server or client machine. These libraries empower users to generate professional reports and data exports in Excel format, supporting a wide range of business and analytical needs.

What Are the Key Differences Between Interop and IronXL?

Before diving into code, understanding the fundamental differences between these two approaches helps inform the right choice for any project. The comparison spans technical architecture, deployment requirements, and practical development experience when working with DataTable to Excel export scenarios.

FeatureMicrosoft Office InteropIronXL
Office Installation RequiredYes – Microsoft Excel must be installedNo – standalone library
Server-Side SupportNot recommended by MicrosoftFully supported
Platform SupportWindows onlyWindows, Linux, macOS, Azure
.NET Core/.NET 5+ SupportLimitedFull support (.NET 6, 7, 8, 9, 10)
Resource ManagementRequires COM object cleanupStandard .NET disposal
Installation MethodCOM reference + Office installInstall-Package via NuGet
Threading ModelSingle-threaded apartment (STA)Thread-safe operations
Large DatasetsMemory-intensive processEfficient file-based approach
File FormatsXLSX, XLS, CSVXLSX, XLS, CSV, JSON, XML
LicensingRequires Office licenseCommercial license available

The architectural difference is fundamental: Excel Interop automates the Microsoft Excel application itself through COM, while IronXL reads and writes Excel file formats directly without launching any external process. This distinction affects everything from memory usage to deployment complexity.

How to Export DataTable to Excel C# Using Interop?

The traditional approach uses the Microsoft.Office.Interop.Excel namespace to automate Excel directly. This method requires Microsoft Excel to be installed on the machine where the code runs.

Prerequisites

Before using Interop, ensure:

  1. Microsoft Excel is installed on the development and deployment machines
  2. Add a COM reference to "Microsoft Excel Object Library" in Visual Studio
  3. Include the Microsoft.Office.Interop.Excel namespace

Interop Code Example

The following code demonstrates how to export a DataTable to an Excel file using Microsoft Office Interop:

using Microsoft.Office.Interop.Excel;
using System.Data;
using System.Runtime.InteropServices;

// Create a sample DataTable with employee data
DataTable dt = new DataTable("Employees");
dt.Columns.Add("EmployeeID", typeof(int));
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Department", typeof(string));
dt.Columns.Add("Salary", typeof(decimal));

// Fill the DataTable with sample rows
dt.Rows.Add(1, "John Smith", "Engineering", 75000);
dt.Rows.Add(2, "Sarah Johnson", "Marketing", 65000);
dt.Rows.Add(3, "Michael Chen", "Finance", 70000);
dt.Rows.Add(4, "Emily Davis", "Engineering", 80000);

// Initialize Excel Application object
Application excelApp = new Application
{
    Visible = false,
    DisplayAlerts = false
};

// Create new Workbook and get the active Worksheet
Workbook workbook = excelApp.Workbooks.Add();
Worksheet worksheet = (Worksheet)workbook.ActiveSheet;

try
{
    // Write column headers to the first row
    for (int i = 0; i < dt.Columns.Count; i++)
    {
        worksheet.Cells[1, i + 1] = dt.Columns[i].ColumnName;
    }
    // Write data rows starting from row 2
    for (int i = 0; i < dt.Rows.Count; i++)
    {
        for (int j = 0; j < dt.Columns.Count; j++)
        {
            worksheet.Cells[i + 2, j + 1] = dt.Rows[i][j].ToString();
        }
    }
    // Define file path and save the Excel file
    string filePath = @"C:\Reports\EmployeeReport_Interop.xlsx";
    workbook.SaveAs(filePath);
    Console.WriteLine("Excel file created successfully using Interop.");
}
catch (Exception ex)
{
    Console.WriteLine("Error exporting data to Excel: " + ex.Message);
}
finally
{
    // Close workbook and quit Excel application
    workbook.Close();
    excelApp.Quit();
    // Critical: Release COM objects to prevent memory leaks
    Marshal.ReleaseComObject(worksheet);
    Marshal.ReleaseComObject(workbook);
    Marshal.ReleaseComObject(excelApp);
}
using Microsoft.Office.Interop.Excel;
using System.Data;
using System.Runtime.InteropServices;

// Create a sample DataTable with employee data
DataTable dt = new DataTable("Employees");
dt.Columns.Add("EmployeeID", typeof(int));
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Department", typeof(string));
dt.Columns.Add("Salary", typeof(decimal));

// Fill the DataTable with sample rows
dt.Rows.Add(1, "John Smith", "Engineering", 75000);
dt.Rows.Add(2, "Sarah Johnson", "Marketing", 65000);
dt.Rows.Add(3, "Michael Chen", "Finance", 70000);
dt.Rows.Add(4, "Emily Davis", "Engineering", 80000);

// Initialize Excel Application object
Application excelApp = new Application
{
    Visible = false,
    DisplayAlerts = false
};

// Create new Workbook and get the active Worksheet
Workbook workbook = excelApp.Workbooks.Add();
Worksheet worksheet = (Worksheet)workbook.ActiveSheet;

try
{
    // Write column headers to the first row
    for (int i = 0; i < dt.Columns.Count; i++)
    {
        worksheet.Cells[1, i + 1] = dt.Columns[i].ColumnName;
    }
    // Write data rows starting from row 2
    for (int i = 0; i < dt.Rows.Count; i++)
    {
        for (int j = 0; j < dt.Columns.Count; j++)
        {
            worksheet.Cells[i + 2, j + 1] = dt.Rows[i][j].ToString();
        }
    }
    // Define file path and save the Excel file
    string filePath = @"C:\Reports\EmployeeReport_Interop.xlsx";
    workbook.SaveAs(filePath);
    Console.WriteLine("Excel file created successfully using Interop.");
}
catch (Exception ex)
{
    Console.WriteLine("Error exporting data to Excel: " + ex.Message);
}
finally
{
    // Close workbook and quit Excel application
    workbook.Close();
    excelApp.Quit();
    // Critical: Release COM objects to prevent memory leaks
    Marshal.ReleaseComObject(worksheet);
    Marshal.ReleaseComObject(workbook);
    Marshal.ReleaseComObject(excelApp);
}
$vbLabelText   $csharpLabel

This code demonstrates the complete workflow for exporting a DataTable to an Excel file using Microsoft Interop. The process begins by creating a new DataTable named dt with employee information—four columns representing ID, name, department, and salary data types that are common in business applications.

The Application object represents the Excel process itself. Setting Visible = false prevents the Excel application from appearing on screen during processing, which is essential for background operations. The DisplayAlerts = false setting suppresses dialog boxes that would otherwise interrupt automated workflows when users run the export.

The Workbook and Worksheet objects correspond directly to Excel's file structure. A workbook is the Excel file itself (.XLSX or .XLS format), while worksheets are the individual sheet tabs within that file. The code uses workbook.ActiveSheet to get a reference to the default sheet created with every new workbook.

How to Export a DataTable to Excel Using IronXL?

IronXL provides a modern alternative that works without Office installation. The library reads and writes Excel files directly, making it suitable for server environments, cloud deployments, and cross-platform applications.

Prerequisites

Install IronXL via NuGet Package Manager Console:

Install-Package IronXL.Excel
Install-Package IronXL.Excel
SHELL

Or use the .NET CLI:

dotnet add package IronXL.Excel
dotnet add package IronXL.Excel
SHELL

No additional software, Office installation, or system configuration is required. The library works immediately after installation on Windows, Linux, and macOS. For Azure deployments, IronXL runs in App Services, Functions, and container instances without special configuration. The library supports .NET Framework 4.6.2+ and all modern .NET versions including .NET 6, 7, 8, 9, and 10.

IronXL Code Example

The following code shows how to convert a DataTable to Excel using the IronXL library:

using IronXL;
using System.Data;

// Create a sample DataTable
DataTable dt = new DataTable("Employees");
dt.Columns.Add("EmployeeID", typeof(int));
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Department", typeof(string));
dt.Columns.Add("Salary", typeof(decimal));

// Fill DataTable with rows of data
dt.Rows.Add(1, "John Smith", "Engineering", 75000);
dt.Rows.Add(2, "Sarah Johnson", "Marketing", 65000);
dt.Rows.Add(3, "Michael Chen", "Finance", 70000);
dt.Rows.Add(4, "Emily Davis", "Engineering", 80000);

// Create a new Excel workbook and worksheet
WorkBook workbook = WorkBook.Create(ExcelFileFormat.XLSX);
WorkSheet sheet = workbook.CreateWorkSheet("Employees");

// Write column names to the first row as headers
for (int i = 0; i < dt.Columns.Count; i++)
{
    sheet.SetCellValue(0, i, dt.Columns[i].ColumnName);
}

// Export DataTable rows to Excel cells
for (int i = 0; i < dt.Rows.Count; i++)
{
    for (int j = 0; j < dt.Columns.Count; j++)
    {
        sheet.SetCellValue(i + 1, j, dt.Rows[i][j]);
    }
}

// Save to file path as xlsx format
string filePath = @"C:\Reports\EmployeeReport_IronXL.xlsx";
workbook.SaveAs(filePath);
Console.WriteLine("Excel file created successfully using IronXL.");
using IronXL;
using System.Data;

// Create a sample DataTable
DataTable dt = new DataTable("Employees");
dt.Columns.Add("EmployeeID", typeof(int));
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Department", typeof(string));
dt.Columns.Add("Salary", typeof(decimal));

// Fill DataTable with rows of data
dt.Rows.Add(1, "John Smith", "Engineering", 75000);
dt.Rows.Add(2, "Sarah Johnson", "Marketing", 65000);
dt.Rows.Add(3, "Michael Chen", "Finance", 70000);
dt.Rows.Add(4, "Emily Davis", "Engineering", 80000);

// Create a new Excel workbook and worksheet
WorkBook workbook = WorkBook.Create(ExcelFileFormat.XLSX);
WorkSheet sheet = workbook.CreateWorkSheet("Employees");

// Write column names to the first row as headers
for (int i = 0; i < dt.Columns.Count; i++)
{
    sheet.SetCellValue(0, i, dt.Columns[i].ColumnName);
}

// Export DataTable rows to Excel cells
for (int i = 0; i < dt.Rows.Count; i++)
{
    for (int j = 0; j < dt.Columns.Count; j++)
    {
        sheet.SetCellValue(i + 1, j, dt.Rows[i][j]);
    }
}

// Save to file path as xlsx format
string filePath = @"C:\Reports\EmployeeReport_IronXL.xlsx";
workbook.SaveAs(filePath);
Console.WriteLine("Excel file created successfully using IronXL.");
$vbLabelText   $csharpLabel

The IronXL approach follows a similar logical structure but with cleaner syntax and no COM complexity. This Excel library enables developers to create, read, and write spreadsheet files without any Microsoft Office dependency. The WorkBook.Create method initializes a new workbook in the specified format—ExcelFileFormat.XLSX produces modern Office Open XML files compatible with Excel 2007 and later, while the library also supports XLS format for legacy systems.

Output

How to Export DataTable to Excel C# Using Interop vs IronXL: Image 1 - Excel Output

How to Export DataTable to Excel C# Using Interop vs IronXL: Image 2 - Console Output

The CreateWorkSheet method adds a new worksheet to the workbook with the specified table name. Unlike Interop where you work with the application object first, IronXL works directly with file structures. The sheet name appears on the tab at the bottom of Excel when users open the file.

Cell population uses SetCellValue, which accepts row index, column index, and the value to write. Unlike Excel Interop's 1-based indexing, IronXL uses 0-based indices matching standard .NET Framework conventions—row 0 is the first row, column 0 is the first column. This consistency with other .NET collections and DataTable columns reduces cognitive load and eliminates off-by-one errors that often occur when converting between indexing systems.

The method handles type conversion automatically and intelligently. Integer, string, decimal, and DateTime values are written with appropriate Excel cell formatting. A decimal value appears as a number that can participate in formulas, while date values can be formatted as dd/mm/yyyy or other regional formats. The library properly handles null values and missing data without throwing exceptions.

Notice the complete absence of cleanup code. IronXL objects are standard .NET managed objects that the garbage collector handles automatically. There's no risk of orphaned processes, no COM reference counting to manage, and no memory leaks from improper disposal patterns. This simplification alone removes an entire category of bugs that plague Excel Interop solutions.

For more details on IronXL's Excel creation capabilities, see the creating spreadsheets documentation.

How Can You Create a Reusable Export Method?

Production applications often need a reusable method that can export any DataTable to an Excel file. The following code example demonstrates a helper class that encapsulates the export logic and can be called from event handlers like button clicks with object sender parameters.

Reusable IronXL Export Helper

using IronXL;
using System.Data;
using System.IO;
using System;
public class ExcelExporter
{
    /// <summary>
    /// Export a DataTable to Excel file at the specified path
    /// </summary>
    public static bool ExportToExcel(DataTable dt, string filePath)
    {
        if (dt == null || dt.Rows.Count == 0)
            return false;
        try
        {
            // Create new workbook and worksheet
            WorkBook workbook = WorkBook.Create(ExcelFileFormat.XLSX);
            WorkSheet sheet = workbook.CreateWorkSheet(dt.TableName ?? "Sheet1");
            // Write column names as headers in the first row
            for (int i = 0; i < dt.Columns.Count; i++)
            {
                var cell = sheet.GetCellAt(0, i);
                cell.Value = dt.Columns[i].ColumnName;
                cell.Style.Font.Bold = true;
            }
            // Fill cells with data values from each row
            for (int i = 0; i < dt.Rows.Count; i++)
            {
                for (int j = 0; j < dt.Columns.Count; j++)
                {
                    var value = dt.Rows[i][j];
                    // Handle missing or null values
                    if (value == DBNull.Value || value == null)
                        sheet.SetCellValue(i + 1, j, "");
                    else
                        sheet.SetCellValue(i + 1, j, value);
                }
            }
            // Validate file path and save
            FileInfo fileInfo = new FileInfo(filePath);
            if (!fileInfo.Directory.Exists)
                fileInfo.Directory.Create();
            workbook.SaveAs(filePath);
            return true;
        }
        catch (Exception ex)
        {
            Console.WriteLine("Export failed: " + ex.Message);
            return false;
        }
    }
    /// <summary>
    /// Query a DataTable and export filtered results
    /// </summary>
    public static DataTable FilterAndExport(DataTable dt, string filterExpression, string filePath)
    {
        if (dt == null)
            return dt;
        // Create filtered view and export
        DataRow[] filteredRows = dt.Select(filterExpression);
        DataTable filteredTable = dt.Clone();
        foreach (DataRow row in filteredRows)
        {
            filteredTable.ImportRow(row);
        }
        ExportToExcel(filteredTable, filePath);
        return filteredTable;
    }
    /// <summary>
    /// Export DataTable to CSV file as an alternative format
    /// </summary>
    public static string ExportToCsv(DataTable dt)
    {
        StringBuilder sb = new StringBuilder();
        // Write column headers
        string[] columnNames = dt.Columns.Cast<DataColumn>().Select(column => column.ColumnName).ToArray();
        sb.AppendLine(string.Join(",", columnNames));
        // Write data rows
        foreach (DataRow row in dt.Rows)
        {
            string[] values = row.ItemArray.Select(field => field?.ToString() ?? "").ToArray();
            sb.AppendLine(string.Join(",", values));
        }
        return sb.ToString();
    }
}
// Usage example in Windows Forms or WPF event handler
public void ExportButton_Click(object sender, EventArgs e)
{
    DataTable dt = GetEmployeeData(); // Your data source
    string filePath = @"C:\Reports\Export.xlsx";
    bool success = ExcelExporter.ExportToExcel(dt, filePath);
    if (success)
        Console.WriteLine("Export completed successfully");
}
using IronXL;
using System.Data;
using System.IO;
using System;
public class ExcelExporter
{
    /// <summary>
    /// Export a DataTable to Excel file at the specified path
    /// </summary>
    public static bool ExportToExcel(DataTable dt, string filePath)
    {
        if (dt == null || dt.Rows.Count == 0)
            return false;
        try
        {
            // Create new workbook and worksheet
            WorkBook workbook = WorkBook.Create(ExcelFileFormat.XLSX);
            WorkSheet sheet = workbook.CreateWorkSheet(dt.TableName ?? "Sheet1");
            // Write column names as headers in the first row
            for (int i = 0; i < dt.Columns.Count; i++)
            {
                var cell = sheet.GetCellAt(0, i);
                cell.Value = dt.Columns[i].ColumnName;
                cell.Style.Font.Bold = true;
            }
            // Fill cells with data values from each row
            for (int i = 0; i < dt.Rows.Count; i++)
            {
                for (int j = 0; j < dt.Columns.Count; j++)
                {
                    var value = dt.Rows[i][j];
                    // Handle missing or null values
                    if (value == DBNull.Value || value == null)
                        sheet.SetCellValue(i + 1, j, "");
                    else
                        sheet.SetCellValue(i + 1, j, value);
                }
            }
            // Validate file path and save
            FileInfo fileInfo = new FileInfo(filePath);
            if (!fileInfo.Directory.Exists)
                fileInfo.Directory.Create();
            workbook.SaveAs(filePath);
            return true;
        }
        catch (Exception ex)
        {
            Console.WriteLine("Export failed: " + ex.Message);
            return false;
        }
    }
    /// <summary>
    /// Query a DataTable and export filtered results
    /// </summary>
    public static DataTable FilterAndExport(DataTable dt, string filterExpression, string filePath)
    {
        if (dt == null)
            return dt;
        // Create filtered view and export
        DataRow[] filteredRows = dt.Select(filterExpression);
        DataTable filteredTable = dt.Clone();
        foreach (DataRow row in filteredRows)
        {
            filteredTable.ImportRow(row);
        }
        ExportToExcel(filteredTable, filePath);
        return filteredTable;
    }
    /// <summary>
    /// Export DataTable to CSV file as an alternative format
    /// </summary>
    public static string ExportToCsv(DataTable dt)
    {
        StringBuilder sb = new StringBuilder();
        // Write column headers
        string[] columnNames = dt.Columns.Cast<DataColumn>().Select(column => column.ColumnName).ToArray();
        sb.AppendLine(string.Join(",", columnNames));
        // Write data rows
        foreach (DataRow row in dt.Rows)
        {
            string[] values = row.ItemArray.Select(field => field?.ToString() ?? "").ToArray();
            sb.AppendLine(string.Join(",", values));
        }
        return sb.ToString();
    }
}
// Usage example in Windows Forms or WPF event handler
public void ExportButton_Click(object sender, EventArgs e)
{
    DataTable dt = GetEmployeeData(); // Your data source
    string filePath = @"C:\Reports\Export.xlsx";
    bool success = ExcelExporter.ExportToExcel(dt, filePath);
    if (success)
        Console.WriteLine("Export completed successfully");
}
$vbLabelText   $csharpLabel

This helper class demonstrates several production-ready patterns. The ExportToExcel method accepts any DataTable and a file path string, returning false if the export fails or the table is empty. The method handles missing values gracefully by checking for DBNull.Value before writing to cells.

The FilterAndExport method shows how to query a DataTable using filter expressions before export—useful when users need to export only specific records. The method returns the filtered DataTable so calling code can use it for additional processing.

The ExportToCsv method uses a StringBuilder to efficiently build CSV output as an alternative to Excel format. While IronXL handles CSV export natively, this example shows the manual approach for educational purposes.

The event handler example shows how these methods integrate with Windows Forms or WPF applications where object sender and EventArgs are standard parameters. Some developers familiar with ClosedXML might recognize similar patterns using new XLWorkbook(), but IronXL's API provides equivalent functionality with additional format support.

How Do Both Approaches Handle Cell Formatting?

Professional Excel exports often require formatting: bold headers, colored cells, borders, and number formats. Both libraries support styling, but the implementation differs significantly.

Formatting with Interop

using Microsoft.Office.Interop.Excel;
using System.Data;
using System.Runtime.InteropServices;
DataTable dt = new DataTable("Sales");
dt.Columns.Add("Product", typeof(string));
dt.Columns.Add("Revenue", typeof(decimal));
dt.Rows.Add("Widget A", 15000.50m);
dt.Rows.Add("Widget B", 22500.75m);
Application excelApp = new Application();
Workbook workbook = excelApp.Workbooks.Add();
Worksheet worksheet = (Worksheet)workbook.ActiveSheet;
// Write column headers with formatting to first row
for (int i = 0; i < dt.Columns.Count; i++)
{
    Range headerCell = worksheet.Cells[1, i + 1];
    headerCell.Value = dt.Columns[i].ColumnName;
    headerCell.Font.Bold = true;
    headerCell.Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.LightBlue);
    headerCell.Borders.LineStyle = XlLineStyle.xlContinuous;
}
// Write data values to cells
for (int i = 0; i < dt.Rows.Count; i++)
{
    for (int j = 0; j < dt.Columns.Count; j++)
    {
        worksheet.Cells[i + 2, j + 1] = dt.Rows[i][j];
    }
}
string filePath = @"C:\Reports\FormattedReport_Interop.xlsx";
workbook.SaveAs(filePath);
workbook.Close();
excelApp.Quit();
Marshal.ReleaseComObject(worksheet);
Marshal.ReleaseComObject(workbook);
Marshal.ReleaseComObject(excelApp);
using Microsoft.Office.Interop.Excel;
using System.Data;
using System.Runtime.InteropServices;
DataTable dt = new DataTable("Sales");
dt.Columns.Add("Product", typeof(string));
dt.Columns.Add("Revenue", typeof(decimal));
dt.Rows.Add("Widget A", 15000.50m);
dt.Rows.Add("Widget B", 22500.75m);
Application excelApp = new Application();
Workbook workbook = excelApp.Workbooks.Add();
Worksheet worksheet = (Worksheet)workbook.ActiveSheet;
// Write column headers with formatting to first row
for (int i = 0; i < dt.Columns.Count; i++)
{
    Range headerCell = worksheet.Cells[1, i + 1];
    headerCell.Value = dt.Columns[i].ColumnName;
    headerCell.Font.Bold = true;
    headerCell.Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.LightBlue);
    headerCell.Borders.LineStyle = XlLineStyle.xlContinuous;
}
// Write data values to cells
for (int i = 0; i < dt.Rows.Count; i++)
{
    for (int j = 0; j < dt.Columns.Count; j++)
    {
        worksheet.Cells[i + 2, j + 1] = dt.Rows[i][j];
    }
}
string filePath = @"C:\Reports\FormattedReport_Interop.xlsx";
workbook.SaveAs(filePath);
workbook.Close();
excelApp.Quit();
Marshal.ReleaseComObject(worksheet);
Marshal.ReleaseComObject(workbook);
Marshal.ReleaseComObject(excelApp);
$vbLabelText   $csharpLabel

The Interop formatting code accesses individual Range objects and sets properties like Font.Bold, Interior.Color, and Borders.LineStyle. Each property access is a COM interprocess call, which adds overhead and increases the chance of exceptions if Excel becomes unresponsive.

Formatting with IronXL

using IronXL;
using IronXL.Styles;
using System.Data;
DataTable dt = new DataTable("Sales");
dt.Columns.Add("Product", typeof(string));
dt.Columns.Add("Revenue", typeof(decimal));
dt.Rows.Add("Widget A", 15000.50m);
dt.Rows.Add("Widget B", 22500.75m);
WorkBook workbook = WorkBook.Create(ExcelFileFormat.XLSX);
WorkSheet sheet = workbook.CreateWorkSheet("Sales");
// Write column headers with formatting to first row
for (int i = 0; i < dt.Columns.Count; i++)
{
    sheet.SetCellValue(0, i, dt.Columns[i].ColumnName);
    var cell = sheet.GetCellAt(0, i);
    cell.Value = dt.Columns[i].ColumnName;
    cell.Style.Font.Bold = true;
    cell.Style.SetBackgroundColor("#ADD8E6");
    cell.Style.BottomBorder.SetColor("#000000");
    cell.Style.BottomBorder.Type = BorderType.Thin;
}
// Write data rows with values from DataTable
for (int i = 0; i < dt.Rows.Count; i++)
{
    for (int j = 0; j < dt.Columns.Count; j++)
    {
        sheet.SetCellValue(i + 1, j, dt.Rows[i][j]);
    }
}
string filePath = @"C:\Reports\FormattedReport_IronXL.xlsx";
workbook.SaveAs(filePath);
using IronXL;
using IronXL.Styles;
using System.Data;
DataTable dt = new DataTable("Sales");
dt.Columns.Add("Product", typeof(string));
dt.Columns.Add("Revenue", typeof(decimal));
dt.Rows.Add("Widget A", 15000.50m);
dt.Rows.Add("Widget B", 22500.75m);
WorkBook workbook = WorkBook.Create(ExcelFileFormat.XLSX);
WorkSheet sheet = workbook.CreateWorkSheet("Sales");
// Write column headers with formatting to first row
for (int i = 0; i < dt.Columns.Count; i++)
{
    sheet.SetCellValue(0, i, dt.Columns[i].ColumnName);
    var cell = sheet.GetCellAt(0, i);
    cell.Value = dt.Columns[i].ColumnName;
    cell.Style.Font.Bold = true;
    cell.Style.SetBackgroundColor("#ADD8E6");
    cell.Style.BottomBorder.SetColor("#000000");
    cell.Style.BottomBorder.Type = BorderType.Thin;
}
// Write data rows with values from DataTable
for (int i = 0; i < dt.Rows.Count; i++)
{
    for (int j = 0; j < dt.Columns.Count; j++)
    {
        sheet.SetCellValue(i + 1, j, dt.Rows[i][j]);
    }
}
string filePath = @"C:\Reports\FormattedReport_IronXL.xlsx";
workbook.SaveAs(filePath);
$vbLabelText   $csharpLabel

IronXL's styling API uses a fluent, intuitive syntax that .NET developers will find familiar. The Style property provides access to font settings, background colors, and borders through a clean object model. Color values accept standard hex codes like #ADD8E6 (light blue), making it easy to match corporate branding or design specifications without converting between color systems.

Output

How to Export DataTable to Excel C# Using Interop vs IronXL: Image 3 - Formatting with IronXL Output

The cell accessor syntax sheet[row, col] provides direct access to individual cells without creating additional objects or range references. This approach reduces code verbosity and eliminates the ceremony required by COM-based APIs. Setting multiple style properties on the same cell is straightforward—each property assignment modifies the cell's appearance directly.

Border configuration demonstrates IronXL's practical design. Rather than dealing with enumeration values that require documentation lookups, developers use BorderType.Thin for standard borders or BorderType.Thick for emphasized boundaries. The SetColor method accepts hex color codes for border coloring, maintaining consistency with background color specification.

For comprehensive formatting options including number formats, conditional formatting, and advanced styling techniques, explore the cell styling documentation and border alignment guide.

Best Practices for Export

To ensure a smooth and reliable export of data to Excel, it is important to follow best practices throughout the development process. Always use a consistent file path and naming convention for the exported Excel file to make file management straightforward and predictable. Implement robust error handling by catching exceptions—such as using catch (Exception ex)—and returning false or providing meaningful feedback if an error occurs during export. For large datasets, consider using the OpenXML SDK, which offers a high-performance, memory-efficient way to write data to Excel files without the overhead of automating Microsoft Excel. Libraries like ClosedXML further simplify the export process, providing intuitive APIs that help ensure your code works efficiently and is easy to maintain. By adhering to these best practices, developers can create export routines that are both reliable and scalable, delivering accurate data to Excel files regardless of dataset size or complexity.

When Should You Choose Each Approach?

The right choice depends on the project's specific requirements, deployment environment, and long-term maintenance considerations when you need to export DataTable data to Excel files.

Choose Microsoft Office Excel Interop when:

  • Working with legacy systems that already have Office installed and depend on Interop
  • Needing advanced Excel features like macros, pivot tables, or chart automation that require the full Excel application object model
  • Building desktop applications where users have Microsoft Excel installed and the application runs interactively
  • The deployment environment is fully controlled, Windows-only, and Office licenses are already available
  • Automating existing Excel templates with complex embedded formulas or VBA code

Choose IronXL when:

  • Building web applications, REST APIs, or background services that generate Excel file exports
  • Deploying to cloud environments like Azure App Services, AWS Lambda, or Docker containers
  • Requiring cross-platform support for Windows, Linux, or macOS deployments
  • Working with .NET Framework 4.6.2+ or modern .NET versions where Interop support is limited
  • Needing reliable, predictable resource management without COM cleanup concerns
  • Avoiding Office licensing dependencies on production servers
  • Building multi-tenant applications where isolated Excel file generation is essential
  • Processing large datasets efficiently without the overhead of COM interprocess communication
  • Needing to export to multiple formats, including XLSX, XLS, CSV file, JSON, and XML

The IronXL tutorials provide additional examples covering common scenarios, including reading existing Excel files, working with formulas, and managing multiple worksheets. The library also supports working with DataSet objects when you need to export multiple related tables to different sheets.

Conclusion

Exporting a DataTable to an Excel file is a fundamental requirement for .NET applications that handle business data. Whether you need to export data from a database query, create reports from a DataSet, or convert DataTable columns to formatted Excel sheets, choosing the right library matters.

While Microsoft Office Excel Interop has served developers for years, its dependency on Office installation, COM complexity, unsupported server scenarios, and resource management challenges make it increasingly impractical for modern application development. Issues like catch (Exception ex) blocks filled with COM cleanup code and workarounds for missing references are common pain points.

IronXL offers a cleaner, more reliable alternative that addresses these limitations directly. With simple Install-Package via NuGet, cross-platform support spanning Windows, Linux, and macOS, and straightforward APIs that follow .NET Framework conventions, it eliminates the deployment headaches and resource management pitfalls that plague Excel Interop solutions. The code examples in this article demonstrate that accomplishing the same DataTable to Excel export task requires similar development effort—but IronXL delivers results without the operational overhead and maintenance burden.

Ready to simplify Excel file generation in .NET projects? Start a free trial of IronXL and experience the difference in your development workflow. For production deployment and team licensing, explore the licensing options that fit your organization's needs.

Jordi Bardia
Software Engineer
Jordi is most proficient in Python, C# and C++, when he isn’t leveraging his skills at Iron Software; he’s game programming. Sharing responsibilities for product testing, product development and research, Jordi adds immense value to continual product improvement. The varied experience keeps him challenged and engaged, and he ...
Read More