# Excel Import and Export Libraries
URL: https://pro.rv-grid.com/guides/excel-export/excel-import-export-libraries/
Source: src/content/docs/guides/excel-export/excel-import-export-libraries.mdx
Description: Compare SheetJS, ExcelJS, read-excel-file, and write-excel-file for XLSX import/export workflows with RevoGrid.
RevoGrid Pro includes an Excel export plugin, but most production apps still need to choose how uploaded workbook files are parsed, validated, normalized, and streamed into the grid.

Use this guide when your workflow is:

1. User uploads an Excel file.
2. Your app parses `.xlsx` data.
3. Your app converts the first sheet, selected sheet, or validated sheet into JSON.
4. RevoGrid receives normalized `columns` and `source` data.

The bundled `ExportExcelPlugin` exports `.xlsx` files through `write-excel-file` and imports CSV files by default. XLSX import is app-owned: install the parser you want, parse the workbook, then assign normalized rows to RevoGrid. For plugin options, see the [Excel export guide](/guides/excel-export/).

## Quick Recommendation

| Goal | Recommended library | Why |
| --- | --- | --- |
| Fast `.xlsx` upload to grid JSON | SheetJS | Broad format support, direct `sheet_to_json()` conversion, strong compatibility with real-world workbooks. |
| Full workbook editing or styled report generation | ExcelJS | Good API for worksheets, rows, formatting, formulas, tables, merged cells, and generated reports. |
| Simple validated upload forms | read-excel-file | Small API surface with schema-based parsing and validation. |
| Default RevoGrid Pro `.xlsx` export | write-excel-file | Lightweight writer used by the bundled export provider. |
| Huge browser imports | SheetJS or read-excel-file in a Web Worker | Keep parse work away from the UI thread and load rows into RevoGrid incrementally. |
| Backend import/export processing | SheetJS or ExcelJS | Pick SheetJS for broad import compatibility; pick ExcelJS when workbook editing and formatting matter more. |

## SheetJS

[SheetJS](https://docs.sheetjs.com/) is the strongest general-purpose choice for Excel upload workflows. It works in the browser and Node.js, reads workbook bytes from an `ArrayBuffer`, supports common spreadsheet formats, and converts worksheets directly into JSON.

Use it when the import goal is "Excel file in, JSON rows out".

```sh
pnpm add xlsx
```

```ts
import * as XLSX from 'xlsx';
import type { ColumnRegular, DataType } from '@revolist/revogrid';

export async function parseSheetJsFile(file: File): Promise<{
  columns: ColumnRegular[];
  rows: DataType[];
}> {
  const data = await file.arrayBuffer();
  const workbook = XLSX.read(data, { cellDates: true });
  const worksheet = workbook.Sheets[workbook.SheetNames[0]];
  const rows = XLSX.utils.sheet_to_json<Record<string, unknown>>(worksheet, {
    defval: '',
  });

  const columns = Object.keys(rows[0] ?? {}).map((key) => ({
    prop: key,
    name: key,
  }));

  return { columns, rows };
}
```

```ts
const { columns, rows } = await parseSheetJsFile(file);

grid.columns = columns;
grid.source = rows;
```

SheetJS is usually the best RevoGrid import fit for admin panels, ERP screens, analytics tools, and customer-provided enterprise spreadsheets where file shape is not perfectly controlled.

The tradeoff is that parsing large files on the main browser thread can freeze the UI. For large files, parse in a Web Worker and only send normalized data back to the page.

```ts title="xlsx-import.worker.ts"
import * as XLSX from 'xlsx';

self.onmessage = async (event: MessageEvent<File>) => {
  const workbook = XLSX.read(await event.data.arrayBuffer(), { cellDates: true });
  const worksheet = workbook.Sheets[workbook.SheetNames[0]];
  const rows = XLSX.utils.sheet_to_json<Record<string, unknown>>(worksheet, {
    defval: '',
  });
  const columns = Object.keys(rows[0] ?? {}).map((key) => ({
    prop: key,
    name: key,
  }));

  self.postMessage({ columns, rows });
};
```

```ts title="import-ui.ts"
const worker = new Worker(new URL('./xlsx-import.worker.ts', import.meta.url), {
  type: 'module',
});

worker.onmessage = ({ data }) => {
  grid.columns = data.columns;
  grid.source = data.rows;
};

worker.postMessage(file);
```

## ExcelJS

[ExcelJS](https://github.com/exceljs/exceljs) is better when you need to read, edit, preserve, or generate richer workbook structures. It is a good fit for financial reports, styled exports, workbook templates, formulas, tables, and merged-cell workflows.

Use it when the app needs workbook manipulation, not only raw import speed.

```sh
pnpm add exceljs
```

```ts
import ExcelJS from 'exceljs';
import type { ColumnRegular, DataType } from '@revolist/revogrid';

export async function parseExcelJsFile(file: File): Promise<{
  columns: ColumnRegular[];
  rows: DataType[];
}> {
  const workbook = new ExcelJS.Workbook();
  await workbook.xlsx.load(await file.arrayBuffer());

  const worksheet = workbook.worksheets[0];
  const headerRow = worksheet.getRow(1);
  const headerValues = Array.isArray(headerRow.values)
    ? headerRow.values.slice(1)
    : Object.values(headerRow.values);
  const headers = headerValues
    .map((value) => String(value ?? '').trim())
    .filter(Boolean);

  const columns = headers.map((header) => ({
    prop: header,
    name: header,
  }));

  const rows: DataType[] = [];
  worksheet.eachRow((row, rowNumber) => {
    if (rowNumber === 1) {
      return;
    }

    const model: DataType = {};
    headers.forEach((header, index) => {
      model[header] = row.getCell(index + 1).value ?? '';
    });
    rows.push(model);
  });

  return { columns, rows };
}
```

ExcelJS can also be used as an optional RevoGrid export provider when you need workbook features beyond the bundled provider.

```ts
import ExcelJS from 'exceljs';
import { createExcelJsExcelExportProvider } from '@revolist/revogrid-pro';

grid.exportExcel = {
  exportProvider: createExcelJsExcelExportProvider(ExcelJS),
};
```

The tradeoff is size and speed. ExcelJS is usually heavier than SheetJS for pure "parse and convert to JSON" imports.

## read-excel-file

[read-excel-file](https://www.npmjs.com/package/read-excel-file) is the best fit when uploads are simple and validation matters more than workbook feature coverage. It reads `.xlsx` files in the browser or Node.js and can map columns into typed JSON with a schema.

```sh
pnpm add read-excel-file
```

```ts
import readXlsxFile from 'read-excel-file';

const schema = {
  name: {
    column: 'Name',
    type: String,
    required: true,
  },
  age: {
    column: 'Age',
    type: Number,
  },
};

const { rows, errors } = await readXlsxFile(file, { schema });

if (errors.length) {
  throw new Error(`Invalid spreadsheet: ${errors[0].error}`);
}

grid.columns = [
  { prop: 'name', name: 'Name' },
  { prop: 'age', name: 'Age' },
];
grid.source = rows;
```

This is a strong choice for import forms, onboarding flows, and ETL-style screens where the workbook is really a typed table.

The tradeoff is that it is not intended to be a full workbook manipulation layer. If users upload complex workbooks with formulas, styles, merged headers, comments, or multiple business sheets, use SheetJS or ExcelJS instead.

## write-excel-file

[write-excel-file](https://www.npmjs.com/package/write-excel-file) is a lightweight `.xlsx` writer for browser and Node.js. It is also the default writer behind RevoGrid Pro's bundled Excel export provider.

For most RevoGrid exports, use `ExportExcelPlugin` directly:

```ts
import { ExportExcelPlugin } from '@revolist/revogrid-pro';

grid.plugins = [ExportExcelPlugin];

const plugins = await grid.getPlugins();
await plugins.find((plugin) => plugin instanceof ExportExcelPlugin)?.export({
  workbookName: 'orders.xlsx',
  sheetName: 'Orders',
});
```

Use `write-excel-file` directly when you are exporting app data that does not need the grid export pipeline.

```sh
pnpm add write-excel-file
```

```ts
import writeXlsxFile from 'write-excel-file';

await writeXlsxFile(
  [
    [
      { value: 'Name', fontWeight: 'bold' },
      { value: 'Revenue', fontWeight: 'bold' },
    ],
    [
      { value: 'North', type: String },
      { value: 12000, type: Number, format: '$#,##0' },
    ],
  ],
  {
    fileName: 'summary.xlsx',
    sheet: 'Summary',
  },
);
```

The tradeoff is intentional simplicity. If export needs template workbooks, charts, complex formulas, images, or heavy workbook editing, use ExcelJS or a custom provider.

## RevoGrid Import Pipeline

For RevoGrid imports, keep the parser separate from the grid:

1. Read the uploaded file.
2. Parse workbook data with the selected library.
3. Normalize headers into stable `ColumnRegular` objects.
4. Normalize each row into a plain object keyed by `column.prop`.
5. Validate and coerce values before assigning them to the grid.
6. Assign `grid.columns` before `grid.source`.

```ts
type ImportedTable = {
  columns: { prop: string; name: string }[];
  rows: Record<string, unknown>[];
};

async function importWorkbook(file: File): Promise<ImportedTable> {
  return parseSheetJsFile(file);
}

const imported = await importWorkbook(file);

grid.columns = imported.columns;
grid.source = imported.rows;
```

Avoid putting the raw workbook object into reactive application state. Workbooks can be large and contain circular or library-specific objects. Store the normalized rows, validation errors, and lightweight import metadata instead.

## Performance Notes

Browser-side Excel parsing becomes visible to users once files are large enough. The exact threshold depends on column count, formulas, styles, browser, device, and parser options, but imports around `100k+` rows are where main-thread parsing commonly starts to feel expensive.

For larger files:

- Parse inside a Web Worker.
- Limit the first preview to a small row count.
- Normalize rows in chunks.
- Keep the original workbook out of framework state.
- Show validation errors separately from accepted rows.
- Let RevoGrid render the normalized dataset with virtualization.

For very large or regulated imports, parse on the backend and send RevoGrid paged or streamed JSON instead of asking the browser to own the whole workbook lifecycle.

## Practical Choice

For most RevoGrid apps:

- Use `ExportExcelPlugin` with the bundled `write-excel-file` provider for grid export.
- Use SheetJS for flexible `.xlsx` upload and header inference.
- Use `read-excel-file` for small validated upload forms.
- Use ExcelJS when the workbook itself is the product: formatted reports, templates, formulas, tables, and workbook editing.

That gives the fastest path for common XLSX-to-grid imports while keeping advanced export and workbook-editing cases open through RevoGrid's custom provider contract.
