Ballerina XLSX Library
June 24, 2026 · View on GitHub
The Ballerina XLSX library provides functionality to read and write Microsoft Excel files in the XLSX format with type-safe data binding to Ballerina records. It exposes a simple file-based API (parseSheet / writeSheet) for single-sheet ETL and an object-based Workbook API for multi-sheet operations, byte-array I/O, and Excel Tables.
All processing is done locally with no external service dependencies.
Quickstart
To use the xlsx library in your Ballerina application, modify the .bal file as follows:
Step 1: Import the module
Import the xlsx module.
import ballerina/xlsx;
Step 2: Invoke module functions
Parse an XLSX file into typed records
type Employee record {|
string name;
int age;
string department;
|};
Employee[] employees = check xlsx:parseSheet("employees.xlsx");
Write records to an XLSX file
Employee[] employees = [
{name: "John", age: 30, department: "IT"},
{name: "Jane", age: 28, department: "HR"}
];
check xlsx:writeSheet(employees, "output.xlsx", "Employees");
Writing to an existing file preserves every other sheet — only the named sheet is affected. The write fails by default if that sheet already exists; pass sheetWriteMode = xlsx:REPLACE to overwrite it, or xlsx:APPEND to add rows below the existing data. The write is atomic — on failure the original file is preserved.
Map non-matching headers with @xlsx:Name
type Employee record {|
@xlsx:Name {value: "Employee Name"}
string name;
@xlsx:Name {value: "Years of Service"}
int tenure;
|};
Employee[] employees = check xlsx:parseSheet("employees.xlsx");
Work with multiple sheets via the Workbook API
xlsx:Workbook wb = check xlsx:fromFile("report.xlsx");
xlsx:Sheet sales = check wb.getSheet("Sales");
Employee[] salesRows = check sales.getRows();
xlsx:Sheet summary = check wb.createSheet("Summary");
check summary.putRows(salesRows);
check wb.save();
check wb.close();
Read and write Excel Tables
For one-shot table-by-name flows, the tier 1 functions are simplest (tables are unique across the workbook, so no sheet specifier is needed):
Employee[] employees = check xlsx:parseTable("sales.xlsx", "EmployeeTable");
Employee[] additions = [{name: "Alice", age: 31, department: "Eng"}];
check xlsx:writeTable([...employees, ...additions], "sales.xlsx", "EmployeeTable");
// writeTable resizes the table's data range to fit the data (grows or shrinks)
For totals rows, rename, resize, or coordination with other workbook operations, go through the Workbook API:
xlsx:Workbook wb = check xlsx:fromFile("sales.xlsx");
xlsx:Table empTable = check wb.getTable("EmployeeTable");
Employee[] employees = check empTable.getRows();
if check empTable.hasTotalRow() {
map<xlsx:CellValue> totals = check empTable.getTotalRow();
// ...
}
check wb.save();
check wb.close();
Bind dates and times to time:Civil, time:Date, or time:TimeOfDay
Declare the field's type to control the shape — typed time records, or ISO 8601 strings:
import ballerina/time;
type Transaction record {|
int id;
time:Civil timestamp; // date-time cell → time:Civil
time:Date settledOn; // date-only cell → time:Date
decimal amount;
|};
Transaction[] txns = check xlsx:parseSheet("transactions.xlsx");
Read from bytes, write to bytes
byte[] inputBytes = check sftp->get("/in/report.xlsx");
xlsx:Workbook wb = check xlsx:fromBytes(inputBytes);
// ...read, modify...
byte[] outputBytes = check wb.toBytes();
check sftp->put("/out/report.xlsx", outputBytes);
check wb.close();
Step 3: Run the Ballerina application
bal run
Examples
The xlsx library provides practical examples illustrating usage in various scenarios. Explore these examples, progressing from the simplest Tier 1 read/write loop through multi-sheet workbooks, validation, and in-memory byte pipelines to database and enrichment flows.
- Process Employee Data — Tier 1 quickstart. Write employee records, read them back into typed records, filter, write the filtered subset. Demonstrates
parseSheet,writeSheet, and@xlsx:Namecolumn mapping. - Monthly Sales Report — Build a multi-sheet workbook with an embedded Excel Table and
time:Datecolumns; reopen and query it through the Workbook + Table APIs. - Validated Bulk Import — Parse a partner file with
@constraintvalidation and fail-safe error logging — clean rows flow downstream; rejected rows are logged with their raw values and reason. - In-Memory Pipeline — Process XLSX bytes end-to-end without disk I/O. Demonstrates
xlsx:fromBytesandWorkbook.toBytes()— the shape an HTTP service or queue consumer would use. - Database to Excel — Read rows from a database (in-memory H2, no server to configure), map them onto a consumer's column layout with
@xlsx:Name, build the workbook with the Workbook API, and serialise it to bytes withWorkbook.toBytes(). - Standardize and Enrich — Parse an Excel file's bytes with
xlsx:fromBytes, map its layout onto a standard schema, enrich each row (region lookup, computed total, customer tier,time:Datestamp), and write the result withwriteSheet.
Issues and projects
Issues and Projects tabs are disabled for this repository as this is part of the Ballerina library. To report bugs, request new features, start new discussions, view project boards, etc., visit the Ballerina library parent repository.
This repository only contains the source code for the package.
Build from the source
Setting up the prerequisites
-
Download and install Java SE Development Kit (JDK) version 21. You can download it from either of the following sources:
Note: After installation, remember to set the
JAVA_HOMEenvironment variable to the directory where JDK was installed. -
Download and install Ballerina Swan Lake.
-
Download and install Docker.
Note: Ensure that the Docker daemon is running before executing any tests.
-
Export Github Personal access token with read package permissions as follows,
export packageUser=<Username> export packagePAT=<Personal access token>
Build options
Execute the commands below to build from the source.
-
To build the package:
./gradlew clean build -
To run the tests:
./gradlew clean test -
To build the without the tests:
./gradlew clean build -x test -
To run tests against different environments:
./gradlew clean test -Pgroups=<Comma separated groups/test cases> -
To debug the package with a remote debugger:
./gradlew clean build -Pdebug=<port> -
To debug with the Ballerina language:
./gradlew clean build -PbalJavaDebug=<port> -
Publish the generated artifacts to the local Ballerina Central repository:
./gradlew clean build -PpublishToLocalCentral=true -
Publish the generated artifacts to the Ballerina Central repository:
./gradlew clean build -PpublishToCentral=true
Contribute to Ballerina
As an open-source project, Ballerina welcomes contributions from the community.
For more information, go to the contribution guidelines.
Code of conduct
All the contributors are encouraged to read the Ballerina Code of Conduct.
Useful links
- For more information go to the
xlsxpackage. - For example demonstrations of the usage, go to Ballerina By Examples.
- Chat live with us via our Discord server.
- Post all technical questions on Stack Overflow with the #ballerina tag.