What’s Changed & Migration

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

The reference material consulted while preparing these pages is listed in the section bibliography.

Baseline date: 2026-10-09. This page was written against Apache POI 5.5.1 (the latest release on that date, published on 30 November 2025). POI 6.0.0 has not been released: the POI site lists it as in development, so everything about 6.0 below is the planned or announced scope, not shipped behaviour. Java 21 and later, Spring Boot 4.x on Spring Framework 7 and Jakarta EE 11 are assumed for the examples.

Most Apache POI code found on the web was written for 3.x or 4.x, and a lot of it no longer compiles against 5.5.x. This page is the map between the old code and the code used in the rest of this section: what each major version changed, what the 5.1 to 5.5 releases added or tightened, and what 6.0 is expected to change. It is a summary built from the official release notes (https://poi.apache.org/changes.html) and the versioning page (https://poi.apache.org/versioning.html), not a replacement for them. Where a claim could not be confirmed there, the page says so.

Version timeline

timeline title Apache POI releases that matter for Word and Excel code 2018 : 4.0.0 - Java 8 minimum, deprecated classes removed, SemVer starts 2021 : 5.0.0 - poi-ooxml-lite and poi-ooxml-full, JPMS modules, ECMA-376 5th edition schemas : 5.1.0 - log4j-api logging, DTDs refused by default 2022 : 5.2.0 - XLOOKUP and XMATCH 2024 : 5.3.0 - SXSSFWorkbook removes temp files on close 2025 : 5.4.0 - duplicate zip entries rejected : 5.5.0 - XLSB reading API : 5.5.1 - module-info restored Planned : 6.0.0 - JDK 17 minimum, DataFormatter cached values default, removed deprecations

Dates and the content of each release are those of the POI changes page: 4.0.0 on 2018-09-07, 5.0.0 on 2021-01-20, 5.1.0 on 2021-11-01, 5.2.0 on 2022-01-14, 5.3.0 on 2024-07-02, 5.4.0 on 2025-01-08, 5.5.0 on 2025-11-15 and 5.5.1 on 2025-11-30.

How POI versions its releases

Since 4.0.0 POI follows the principles of Semantic Versioning 2.0.0. Before it, the version was an X.Y pair and minor releases sometimes carried large changes. The versioning page gives the rules that matter when upgrading:

  • An API may be deprecated in one major version and removed in the next. Compile with deprecation warnings on, fix them while still on the old major, then move.

  • Minor versions may add features, deprecate APIs or fix bugs in a way that changes existing behaviour (the 5.4.0 and 6.0 notes below are examples).

  • When jumping several majors, move one major at a time and test in between.

  • 4.x and earlier are no longer supported. 5.5.x still receives critical bug fixes and security patches, and support for 5.5.x continues for a limited time after 6.0.0 is released (the length is not decided yet).

3.x to 4.0

The 4.0.0 release (2018-09-07) is the first SemVer release and the one that cleaned up the 3.x API:

  • Java 8 is the minimum. Support for Java 6 and 7 was dropped.

  • Deprecated classes were removed, as the release notes say ("Remove deprecated classes"), and the OPOIFS classes were removed, which the notes list as breaking backwards compatibility.

  • The CellType enum replaces the int constants. Before 4.0, getCellType() returned an int, compared with constants such as Cell.CELL_TYPE_STRING; the 3.17 Javadoc marks those constants as deprecated since 3.15 and due for removal in 4.0, and offers the transitional getCellTypeEnum(), which returns the enum. The 4.1 Javadoc of Cell documents the end of the transition: getCellType() returns CellType, and getCellTypeEnum() is deprecated with the note that it "will be renamed to getCellType() when we make the CellType enum transition in POI 4.0", and a removal notice for 4.2.

In 5.5.1 the Cell interface has getCellType(), getCachedFormulaResultType() and setCellType(CellType), no getCellTypeEnum() and no CELL_TYPE_* constants.

4.x to 5.0

The 5.0.0 release (2021-01-20) changed the artifacts, the module system and the XML schemas:

  • Jar renames. The release notes say "Change artifact names of poi-/ooxml-schemas to poi-ooxml-lite/full". The old ooxml-schemas artifact is now poi-ooxml-full and the old poi-ooxml-schemas is now poi-ooxml-lite. Lite is the default dependency of poi-ooxml; full is needed for the low-level CT* beans that lite does not contain. See Setup & Dependencies for the coordinates and for the NoClassDefFoundError that appears when a bean is missing from lite.

  • JPMS. POI provides JigSaw modules, and the release notes warn that "some classes moved between packages for the JDK 9+ support". Code that imported a moved class needs a new import. The module names are in the JPMS section of Setup & Dependencies.

  • ECMA-376 5th edition schemas. POI upgraded to the transitional schemas of the 5th edition of ECMA-376, with the warning "expect API breaks when using XmlBeans directly". Code that only uses the usermodel types (XSSFWorkbook, XWPFDocument) is not affected; code that touches CT* classes may be.

  • CellType everywhere. The notes list "Add some more methods to allow to use CellType everywhere".

The practical migration is to change the dependency artifacts, recompile, fix imports of moved classes and fix any CT* code against the new schemas. Do not mix POI jars of different versions.

The 5.1 to 5.5 highlights

All of these are minor releases. The table lists items from the release notes that change what a server application sees; it is a selection, not the full changelog.

Release Change (as in the release notes) What it means for your code

5.1.0 (2021-11-01)

"Internal logging in POI now uses Apache Log4J 2". POI depends only on log4j-api.

Add a log4j-api bridge or implementation to route the logs, see the logging bridge in Setup & Dependencies.

5.1.0

"By default, no DTDs will be accepted in XML files."

A file with a DOCTYPE is refused instead of being parsed, which closes the XXE door. See Security & Untrusted Files.

5.1.0

IFS and SWITCH functions supported.

Workbooks that use them can be evaluated by FormulaEvaluator.

5.1.0

ZipSecureFile.setMaxEntrySize accepts sizes above 4 GB.

The entry size limit can be raised for large legitimate files, if you accept the risk.

5.2.0 (2022-01-14)

XLOOKUP and XMATCH supported.

FormulaEvaluator can evaluate them. Check the supported functions list before relying on a newer Excel function.

5.2.0

DataFormatter.setUseCachedValuesForFormulaCells(boolean) added, default false.

Formula cells are formatted from a fresh evaluation unless you opt in to the cached value.

5.2.3 and 5.2.4

SXSSFWorkbook keeps working when no fonts are installed on the operating system.

Containers without system fonts no longer break SXSSF, which matters for column auto-sizing in slim images.

5.3.0 (2024-07-02)

"SXSSFWorkbook now removes temp files when closed - removing need for a separate dispose call".

Use try-with-resources on SXSSFWorkbook. dispose() still exists in 5.5.1.

5.3.0

allowStoredEntriesWithDataDescriptor=true supported when reading zip data.

Some zip variants that were rejected can be read.

5.4.0 (2025-01-08)

A breaking change: some invalid compressed content in OOXML files now fails parsing. Files with duplicate zip entry names throw an exception.

Some files that used to open now fail. The duplicate-entry check relates to CVE-2025-31672 (see below).

5.4.0

log4j-api 2.24.3 and a log4j-bom dependency.

Use the BOM to keep log4j versions aligned. The POI site advises against log4j-api 2.24.1 with a different log4j-core version.

5.4.1 (2025-04-06)

Custom TempFileCreationStrategy per thread. A note that JDK 24 changes locale provider behaviour.

Temp-file location can be set per thread. Formatted dates and numbers may differ on JDK 24; test formatting.

5.5.0 (2025-11-15)

New API for reading XLSB files. A fix for images in .xlsx files that could fill the disk with temporary files.

Binary workbooks can be read without converting them first. Re-test the temp directory usage of image-heavy exports.

5.5.1 (2025-11-30)

"Add back module-info classes that were omitted from the 5.5.0 jars by accident".

JPMS users should skip 5.5.0.

The POI site also announces CVE-2025-31672 (8 April 2025): a crafted OOXML file with duplicate zip entry names could make different products read different data, and from poi-ooxml 5.4.0 duplicate entries cause an exception. The recommendation is to be on 5.4.0 or later.

What 6.0 is expected to change

POI 6.0.0 is in development on the trunk branch, with no release date. According to the versioning page and the draft 6.0.0 section of the changes page, the scope that is currently listed is:

  • JDK 17 is the minimum, "was JDK 8 in POI 5.x". The Java 8 support is removed.

  • DataFormatter uses cached values for formula cells by default. The notes call it a breaking change: setUseCachedValuesForFormulaCells(boolean) now defaults to true (it was false since 5.2.0).

  • Removed deprecated APIs. The draft notes name getCodepoints and hasOOXMLHeader (OOXML) and AddDimensionedImage (SS common) as removed. The versioning page says the final scope is not decided.

  • log4j-api 2.26.1.

  • Zip hardening, for example duplicate ZIP entry validation against path separator bypasses.

  • XLSB reading no longer depends on XMLBeans.

  • Fixes in XSSF and XWPF, such as drawing anchors that move with shifted rows and columns, and theme font helpers in XWPF.

The draft items can change before the release. The sensible preparation, which works today, is to compile against 5.5.1 with deprecation warnings enabled, to set the DataFormatter flag explicitly instead of relying on the default, and to run on Java 17 or later.

Outdated idioms and their current code

Outdated idiom Current code Since

cell.getCellTypeEnum() == CellType.STRING

cell.getCellType() == CellType.STRING

4.0 (renamed), gone in 5.x

cell.getCellType() == Cell.CELL_TYPE_STRING (int constants)

cell.getCellType() == CellType.STRING

4.0; the constants are not in 5.5.1

ooxml-schemas or poi-ooxml-schemas dependency

poi-ooxml with poi-ooxml-lite (default) or poi-ooxml-full

5.0

Log4j 1.x or commons-logging configuration for POI

log4j-api plus a bridge or implementation, see the logging bridge in Setup & Dependencies

5.1

new XSSFWorkbook(new FileInputStream(file))

WorkbookFactory.create(file) or new XSSFWorkbook(file) in try-with-resources

Long-standing advice; lower memory

workbook.write(out); workbook.dispose(); in a finally

try (SXSSFWorkbook wb = new SXSSFWorkbook(100)) {...}

5.3.0

Relying on DataFormatter to format formula cells either way

formatter.setUseCachedValuesForFormulaCells(false) (or true) set explicitly

5.2.0; the default flips in 6.0

Assuming a DOCTYPE in a part is parsed

DTDs are refused; remove the DOCTYPE from the producing tool

5.1.0

Importing org.apache.poi.hssf.usermodel.* types in code that should handle .xlsx too

The org.apache.poi.ss.usermodel interfaces and WorkbookFactory

Always

The "current code" column was compiled and run against POI 5.5.1 for this page:

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Locale;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.FormulaEvaluator;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;

public class Migrated {
    public static void main(String[] args) throws IOException {
        File out = new File("target/migrated.xlsx");
        try (SXSSFWorkbook wb = new SXSSFWorkbook(100);
             FileOutputStream os = new FileOutputStream(out)) {
            Sheet s = wb.createSheet("Books");
            Row r = s.createRow(0);
            r.createCell(0).setCellValue("Dune");
            r.createCell(1).setCellValue(12.5);
            r.createCell(2).setCellFormula("B1*2");
            wb.write(os);
        } // close() deletes the temp files since 5.3.0, no dispose() needed

        DataFormatter formatter = new DataFormatter(Locale.ENGLISH);
        // false in 5.2.0 to 5.5.x, true by default in 6.0: set it explicitly
        formatter.setUseCachedValuesForFormulaCells(false);
        try (Workbook wb = WorkbookFactory.create(out)) {
            FormulaEvaluator ev = wb.getCreationHelper().createFormulaEvaluator();
            Row r = wb.getSheetAt(0).getRow(0);
            for (Cell c : r) {
                CellType t = c.getCellType();
                if (t == CellType.FORMULA) {
                    System.out.println("formula, cached " + c.getCachedFormulaResultType());
                }
                System.out.println(t + " -> " + formatter.formatCellValue(c, ev));
            }
        }
    }
}

Output observed with POI 5.5.1:

STRING -> Dune
NUMERIC -> 12.5
formula, cached NUMERIC
FORMULA -> 25

The old code in the left column is not shown as a compilable snippet, because by definition it does not compile against 5.5.1.

Upgrade checklist

  1. Read the changes page for every release between your version and the target, and move one major at a time.

  2. Compile with deprecation warnings on before changing the version, and fix them.

  3. Replace the schema artifacts with poi-ooxml-lite or poi-ooxml-full when coming from 4.x.

  4. Provide a log4j-api bridge or implementation, and align the log4j versions with the BOM.

  5. Move to 5.4.0 or later for the stricter zip handling, and test the files your users really upload.

  6. Set the DataFormatter cached-values flag explicitly, so 6.0 does not change your output.

  7. Run on Java 17 or later in preparation for 6.0.