> ## Documentation Index
> Fetch the complete documentation index at: https://jetxl.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrating from other libraries

> Map openpyxl, XlsxWriter and polars.write_excel calls onto Jetxl

The mapping is mostly mechanical. Jetxl has no reader, so if your script also opens or edits workbooks, keep your existing library for that half and use Jetxl only for writing.

## From openpyxl

openpyxl builds a workbook cell by cell. Jetxl takes the whole frame plus a description of how it should look.

<CodeGroup>
  ```python Before theme={null}
  from openpyxl import Workbook
  from openpyxl.styles import Font

  wb = Workbook()
  ws = wb.active
  ws.title = 'Employees'
  ws.append(['Name', 'Salary'])

  for row in rows:
      ws.append(row)

  ws.freeze_panes = 'A2'
  for cell in ws[1]:
      cell.font = Font(bold=True)

  wb.save('out.xlsx')
  ```

  ```python After theme={null}
  import jetxl as jet

  jet.write_sheet_arrow(
      df.to_arrow(),
      'out.xlsx',
      sheet_name='Employees',
      freeze_rows=1,
      styled_headers=True,
  )
  ```
</CodeGroup>

| openpyxl                          | Jetxl                              |
| --------------------------------- | ---------------------------------- |
| `ws.title`                        | `sheet_name`                       |
| `ws.freeze_panes`                 | `freeze_rows`, `freeze_cols`       |
| `ws.auto_filter.ref`              | `auto_filter`                      |
| `cell.font = Font(bold=True)`     | `styled_headers`, or `cell_styles` |
| `cell.number_format`              | `column_formats`                   |
| `ws.column_dimensions[...].width` | `column_widths`                    |
| `ws.merge_cells(...)`             | `merge_cells`                      |
| `wb.create_sheet()`               | `write_sheets_arrow`               |
| `wb.save(path)`                   | the `filename` argument            |
| Reading a workbook                | Not available                      |

## From XlsxWriter

XlsxWriter is closer in spirit, since it's also write-only. The main difference is that it defines format objects up front and applies them per write, while Jetxl takes plain dictionaries.

<CodeGroup>
  ```python Before theme={null}
  import xlsxwriter

  wb = xlsxwriter.Workbook('out.xlsx')
  ws = wb.add_worksheet('Sales')

  money = wb.add_format({'num_format': '$#,##0.00'})
  bold = wb.add_format({'bold': True})

  ws.write_row(0, 0, ['Product', 'Revenue'], bold)
  ws.set_column(1, 1, 14, money)
  ws.freeze_panes(1, 0)

  wb.close()
  ```

  ```python After theme={null}
  import jetxl as jet

  jet.write_sheet_arrow(
      df.to_arrow(),
      'out.xlsx',
      sheet_name='Sales',
      styled_headers=True,
      freeze_rows=1,
      column_widths={'Revenue': 14.0},
      column_formats={'Revenue': 'currency'},
  )
  ```
</CodeGroup>

| XlsxWriter                   | Jetxl                                             |
| ---------------------------- | ------------------------------------------------- |
| `wb.add_format({...})`       | A dictionary in `cell_styles` or `column_formats` |
| `ws.set_column(...)`         | `column_widths`                                   |
| `ws.freeze_panes(...)`       | `freeze_rows`, `freeze_cols`                      |
| `ws.add_table(...)`          | `tables`                                          |
| `wb.add_chart(...)`          | `charts`                                          |
| `ws.insert_image(...)`       | `images`                                          |
| `ws.data_validation(...)`    | `data_validations`                                |
| `ws.conditional_format(...)` | `conditional_formats`                             |

## From polars.write\_excel

The closest starting point, since you already have a DataFrame.

```python theme={null}
# Before
df.write_excel('out.xlsx', table_style='TableStyleMedium9', autofit=True)

# After
jet.write_sheet_arrow(
    df.to_arrow(),
    'out.xlsx',
    auto_width=True,
    tables=[{'name': 'Data', 'start_row': 1, 'start_col': 0,
             'style': 'TableStyleMedium9'}],
)
```

<Tip>
  The published benchmark puts `polars.write_excel` at 26.6s against 0.66s for Jetxl on a million rows, with 3.13 GB peak memory against 958 MB. See [Performance](/about/performance).
</Tip>

## What to check after switching

<AccordionGroup>
  <Accordion title="Indexing" icon="table-cells">
    openpyxl and XlsxWriter are each internally consistent about row bases. Jetxl isn't: rows are 1-based for cell styles, header content and table ranges, and 0-based for chart and image positions. See [Conventions](/guides/conventions).
  </Accordion>

  <Accordion title="Percentages" icon="percent">
    If you were writing percentages as whole numbers with a plain format, the built-in percentage formats multiply them by 100. Store decimals instead.
  </Accordion>

  <Accordion title="Colors" icon="palette">
    XlsxWriter accepts named colors such as `red`. Jetxl doesn't, and drops them silently rather than raising. Convert to hex.
  </Accordion>

  <Accordion title="Header styling" icon="heading">
    `styled_headers` gives bold only, with no fill. If your openpyxl or XlsxWriter output had shaded headers, reproduce that with `cell_styles` on the header row.
  </Accordion>

  <Accordion title="Reading" icon="book-open">
    Any part of your code that opens an existing workbook has to stay on openpyxl. Jetxl only writes.
  </Accordion>
</AccordionGroup>
