snappy-java: Snappy compression for Java, and the JDK 24 flag you now need
Snappy compressor/decompressor for Java
At a glance
- What is it?
- snappy-java is a JNI based Java port of Google's Snappy, and the newest thing in its documentation is not about compression at all but about JEP 472, which restricts native access in JDK 24 and means applications now have to opt in explicitly. That requirement, spread across four build tools in the README, is the first thing to get right when you upgrade.
- Who is it for?
- Adopt snappy-java if you compress data at a rate where a general purpose compressor is the bottleneck, and if the modest compression ratio is acceptable for your storage.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 5 days ago.
- What is it written in?
- Mainly Java, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A JNI port of a compressor whose point is speed
snappy-java is a Java port of Snappy, the fast C++ compresser and decompresser developed by Google, and the README states the design goal in plain terms. Snappy's main target is very high-speed compression and decompression with a reasonable compression size, so the compression ratio of snappy-java is modest and about the same as LZF, ranging from 20 to 100 percent depending on the dataset. That is the trade you are making, and the feature list quantifies the other side, with compression and decompression around 200 to 400 megabytes per second. The implementation is JNI based to achieve comparable performance to the native C++ version, and the README notes that although it uses JNI it can be used safely with multiple class loaders, which matters in a container like Tomcat where the library can be loaded by more than one class loader. The practical use case is a service where compression is on the hot path, in a columnar store, a cache or a message payload, rather than a service that wants the smallest possible bytes.
JDK 24 changed the rules for loading native code
The most useful section in the README is the one about JDK 24 and later, and it exists because of JEP 472, which prepares to restrict the use of JNI. Since snappy-java uses JNI to load its native libraries for high performance compression, applications running on JDK 24 or later must enable native access, with the flag `--enable-native-access=ALL-UNNAMED`. The README is explicit that per the JEP's policy of integrity by default, it is the application developer's responsibility and not the library's to enable native access, and that the change improves security by making native operations visible and controlled at the application level. The warning you get without the flag names the library directly, saying a restricted method in java.lang.System has been called and that java.lang.System::load has been called by org.xerial.snappy.SnappyLoader, and the README says these warnings will become errors in future JDK releases. The requirement applies only to JDK 24 and later, with earlier versions from 8 to 23 unaffected.
Where the flag goes in four different build tools
Because the requirement is on the application rather than the library, the flag has to be added in the right place for whichever build tool you use, and the README gives all four. Running a jar means putting the flag before the `-jar` argument. Maven means setting the argument line in the surefire plugin configuration. Gradle means adding the JVM argument to the test tasks. sbt means appending it to the java options.
java --enable-native-access=ALL-UNNAMED -jar your-application.jartasks.withType(Test) {
jvmArgs '--enable-native-access=ALL-UNNAMED'
}The Gradle and sbt forms matter most in practice, because a service that passes its unit tests locally and then fails in a container that runs a newer JDK will have the difference buried in the test harness rather than in the application start up, and the surefire configuration is the one to check first when a build breaks on a JDK upgrade.
Three layers of API, from byte arrays to framed streams
The API surface is wider than a single compress method, and the layers exist for different workloads. The simplest is the static pair on `Snappy`, with `compress(byte[])` and `uncompress(byte[])`, and the README's example compresses a string, uncompresses it and prints the result. On top of that there are high-level methods such as the String and float array variants, and low-level ones like `rawCompress` and `rawUncompress`, which exist to minimise memory copies. Then there is the stream layer, with `SnappyOutputStream` and `SnappyInputStream` for reading and writing large data sets, and the framed variants `SnappyFramedOutputStream` and `SnappyFramedInputStream` for the Snappy framing format, which the feature list says has been supported since version 1.1.0. The framing format matters if you interoperate with other implementations, since it is the wire format the upstream project defines, and the README links the format specification directly. The memory characteristic of the stream path is worth noting too, since the feature list says SnappyOutputStream uses only 32KB plus by default, which is what makes it usable on a busy server.
Primitive arrays, and why BitShuffle is bundled in
Beyond text and bytes, the library handles Java primitive arrays, with float, double, int, short and long among the types named, and it points at a fast data rearrangement implementation called BitShuffle to improve the compression ratio of those arrays. The mechanism is straightforward once you know it, since rearranging the bytes of a float array so that the significant bytes are adjacent turns a pattern that compression can find into one it can find faster, at the cost of a shuffle on the way in and an inverse shuffle on the way out. The interesting part is where the code comes from, because the Makefile shows that the native side is built from two upstream projects fetched during the build. The Snappy sources come from the google/snappy repository, with a variable that can be pointed at a specific commit instead of the version tag, and the BitShuffle sources come from kiyo-masui/bitshuffle, compiled from `bitshuffle_core.c` and `iochain.c` and linked alongside the Snappy objects into the native library. The build also tunes the instruction set per architecture, with a comment explaining that SSE2 is supported on all x86-64 platforms while AVX2 is only supported on a small part of them, which is a good example of how a native library deals with the long tail of hardware.
Where the performance numbers come from
The README's performance section is careful about attribution, which is unusual and worth reading for what it implies about the numbers. It links a benchmark suite for JVM compressors and credits Tatu Saloranta for providing it, and the comparison set includes LZO-java, LZF, QuickLZ, Gzip and Bzip2. The claim that snappy-java is the fastest compressor and decompressor in Java, and that the decompression speed is twice as fast as the others, is backed by round trip results on the Canterbury corpus, and the links point at result pages dated 2011. That date is the important detail. These are old measurements on a specific corpus, and the README's own framing, that the target is high speed with a modest ratio, is a better guide to what to expect than a fifteen year old table. The claim that has held up is the design one. Snappy trades ratio for speed, and the same trade shows up in the choice of implementation, since a JNI wrapper exists precisely to get the native speed without giving up the Java API.
Packaging, licensing and the project behind the port
Distribution is the boring, solved part. The artifact is on Maven Central under the group `org.xerial.snappy` and the artifact `snappy-java`, and the README gives the dependency snippet for Maven, the Gradle line and the sbt line. There is also a snapshot repository for beta builds, and a `Milestone.md` file that serves as the release notes. The library supports OSGi, and the licence is Apache 2.0, described as free for both commercial and non-commercial use. The repository is larger than a single module would suggest, with a `src/` directory for the Java, a `lib/` directory, a `docker/` directory, `script/` and `project/` directories, an sbt build with `build.sbt` and a bundled `sbt` launcher, a Scala Steward configuration and a scalafmt configuration, a `SECURITY.md` and a `NOTICE` file, plus a `Makefile`, a `Makefile.common` and a `Makefile.package` for the native build. The release line is 1.1.10.x, with 1.1.10.12 published on 2026-10-10 and 1.1.10.11 a few days earlier, so the port is actively maintained even though its headline feature, a compressor that trades size for speed, has not changed in years.
Editorial conclusion
Adopt snappy-java if you compress data at a rate where a general purpose compressor is the bottleneck, and if the modest compression ratio is acceptable for your storage. Do not adopt it if you need the smallest possible output, since the README says the ratio is about the same as LZF and that the target is speed rather than size, and do not adopt it on JDK 24 or later until you have added the native access flag, because the library loads its native library through JNI and the warning you will see becomes an error in a future JDK. Before you upgrade a service to JDK 24, add `--enable-native-access=ALL-UNNAMED` to the run command, the surefire argument line, the Gradle test JVM args or the sbt java options, depending on your build. The licence is Apache 2.0, free for commercial and non-commercial use, the current release is 1.1.10.12 from 2026-10-10, and the last push was the same day.
Frequently asked questions
Why does snappy-java need --enable-native-access on JDK 24?
Because JEP 472 prepares to restrict the use of JNI, and snappy-java uses JNI to load its native libraries for performance. The README says the application developer is responsible for enabling it, and that without the flag you will see warnings naming org.xerial.snappy.SnappyLoader, and that those warnings will become errors in future JDK releases. The requirement applies only to JDK 24 and later.
How do I add the native access flag in Gradle, Maven or sbt?
In Gradle, add the JVM argument to the test tasks with `tasks.withType(Test) { jvmArgs '--enable-native-access=ALL-UNNAMED' }`. In Maven, set the argument line in the surefire plugin configuration. In sbt, append it to the java options. For a plain jar, put the flag before the `-jar` argument.
What compression ratio should I expect from snappy-java?
A modest one. The README says the compression ratio is about the same as LZF, ranging from 20 to 100 percent depending on the dataset, because Snappy's main target is very high speed with a reasonable size rather than the best possible ratio.
What APIs does snappy-java offer beyond a simple compress call?
High-level methods for strings and primitive arrays, low-level raw methods such as `rawCompress` and `rawUncompress` that minimise memory copies, the `SnappyOutputStream` and `SnappyInputStream` pair for large data sets, and the framed stream pair for the Snappy framing format, which has been supported since version 1.1.0. The library also handles Java primitive arrays, with BitShuffle used to improve their ratio.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/xerial-snappy-java)Was this useful?