Skip to content

From Monolith to Modules: Why NanoXLSX Finally Broke Its Own Traditions

Raphael Stoeckli edited this page Jan 10, 2026 · 3 revisions

Recently, NanoXLSX was released in version 3 (or as release candidates, respectively). And as you may have noticed, it is now a meta-package that relies on several dependencies. Wait, what?! Wasn’t there once a proud “No dependencies” statement… later softened to “Minimum dependencies”… and now it’s full of them? But hold on! There is a reason for all of this. Let me tell you the story of NanoXLSX and PicoXLSX.

Many years ago, when I was a student at a university of applied sciences, some colleagues and I had a group assignment to solve an IT problem for a small company. To be honest, I don’t even remember the company’s name or the actual problem anymore. What I do remember is a strange server setup that had to generate Excel files (and no, CSV was absolutely not an option) but had no Microsoft Excel installation. So, a “simple” Interop solution was off the table.

Back then, it was a time when our Java teacher would casually say: “Just copy that JAR into your project,” and none of us had the faintest idea about dependency management or package repositories like Maven or NuGet.

So, clueless as we were, the “solution” to generate Excel files was simply to write them manually. I discovered that an XLSX file is just a ZIP archive containing a bunch of XML documents. So, I generated those XML files in code and zipped them with the extension “.xlsx” — and thus, PicoXLSX was born! That tiny library consisted of maybe two or three classes… and back then, that was perfectly fine. The assignment was completed — and for some reason, I kept maintaining the library long before it ever saw GitHub.

Over time, many features were added and many bugs were fixed. Then came the need to read XLSX files — and NanoXLSX was born! PicoXLSX and NanoXLSX became two independent codebases with partially overlapping functionality. Later, their Java siblings, PicoXLSX4j and NanoXLSX4j, joined the family. There was even a plan for a Node.js version, but thankfully(* that idea was scrapped. Even with “just” the four codebases, maintenance became a serious workload. Every feature and every bug fix had to be implemented or at least checked in both the .NET and Java versions.

The extremely monolithic design of PicoXLSX and PicoXLSX4j didn’t help at all. The original two-to-three-class solution grew into a maintenance nightmare, while NanoXLSX and NanoXLSX4j evolved into more granular, but also more complex, libraries. The first victim was PicoXLSX4j: maintenance stopped because NanoXLSX4j covered everything Pico could do. But the .NET side was also heading toward trouble. PicoXLSX became less relevant, but still required bug fixes because a surprising number of people were using it. Meanwhile NanoXLSX was growing, classes were getting bigger, and the old reader/writer logic was becoming dated. Working on PicoXLSX, NanoXLSX, and NanoXLSX4j at the same time turned into something like a Kung Fu battle where people whirl through the air without ever touching the ground — impressive to look at, but absolutely unrealistic. And by “unrealistic” I mean “no longer maintainable.” The problems were clear:

  • Classes that were far too large
  • Duplicate code across multiple repositories
  • No unit tests for PicoXLSX / PicoXLSX4j
  • Diverging functionality due to completely different architectures

So, what was the solution? Dropping PicoXLSX support, as already done with PicoXLSX4j? Possible — but far too sad. No, the answer was obvious: modularization! A concept that exists in pretty much every modern ecosystem (Maven artifacts in Java, NuGet packages in .NET, etc.). Since NanoXLSX(4j) already contained all the functionality of PicoXLSX(4j), why not split everything into separate modules? And so NanoXLSX v3 was born. The library is now divided into a core, a reader, and a writer component. Even better: PicoXLSX could be renovated within one or two hours using this architecture. It is now essentially NanoXLSX, but only with the core and writer components.

Unit tests for PicoXLSX? No problem — the core and writer tests already cover it. And if the concept proves itself in .NET, the same approach will be brought to Java, reviving PicoXLSX4j as a meta-package, just like the new PicoXLSX.

New features like inline formatting, modern password handling, or even charts can now be added as separate components. Will this architecture solve all problems? Maybe not. Some things get more complex, and breaking up a monolithic design comes with its own challenges. But overall, maintenance becomes easier, and new features come with fewer side effects.

So, are the old claims of “No dependencies” now meaningless? I’d say no. There are dependencies now, but they are still fully under the same roof. There won’t be any scenario where dependency X suddenly stops being compatible with dependency Y. External dependencies may appear in special cases — for example, when implementing modern password encryption — but that should remain reasonable, since most Pico|NanoXLSX(4j) functionality still uses native framework features (.NET, JDK).

Of course, this is all forward-looking. At the time of writing, Pico|NanoXLSX are still in release-candidate stage. But I’m fairly confident that the new modular architecture has far more advantages than drawbacks. So, thanks for sticking around — and for your patience. 😊


*) I have nothing against Node.js, but that ecosystem already has its fair share of dependency headaches. A NanoXLSX.js would hardly make things better — it would likely just become another brick in the great NPM Dependency Pyramid.

Clone this wiki locally