Java JAR file format
A Java Archive — a ZIP bundling compiled .class files and a manifest.
- MIME type
- application/java-archive
- Extensions
- .jar
- Category
- Archives & compression
Magic-number signature
| 0x00000000 | 504B0304 | PK·· | 'PK' — it is a ZIP |
Inside the ZIP: 'META-INF/MANIFEST.MF' plus one or more '.class' entries.
About the Java JAR format
A JAR is a ZIP with one convention layered on top: a META-INF directory whose MANIFEST.MF describes the archive — the main class for an executable JAR, the class path, the module name, and, in a signed JAR, a digest for every entry. Nothing else about the ZIP changes, which is why any archive tool can open a JAR and why the format has been reused for WARs, EARs, Spring Boot fat JARs and, historically, Android APKs. The catch is that the convention includes entry order: streaming readers look for the manifest at the very front and give up quickly if it is not there.
Header layout, byte by byte
| Offset | Length | Field | Meaning |
|---|---|---|---|
| 0 | 4 | Local file header signature | 50 4B 03 04. A JAR is a ZIP byte for byte; nothing at offset 0 mentions Java. Every entry starts with one of these, and only the first is at a fixed position. |
| 4 | 2 | Version needed to extract | 10 for a stored entry, 20 for deflate — and the first entry of a JAR written by the jar tool is the directory META-INF/, which is stored, so this field commonly reads 10 in a file whose real contents are all deflated. |
| 6 | 2 | General purpose bit flag | 0x0800 (bit 11) marks the entry name UTF-8, which the JDK's jar tool sets. Bit 3, the streaming flag that pushes sizes after the data, appears in JARs produced by servers that generate them on the fly. |
| 8 | 2 | Compression method | 0 stored, 8 deflate. Directory entries such as META-INF/ are stored with zero length, which is why a JAR's first entry often has a CRC and both sizes of zero without anything being wrong. |
| 10 | 4 | Last modified time and date | MS-DOS packed time at 10 and date at 12: two-second resolution, no time zone, nothing before 1980. Reproducible builds pin these to a constant, which is why so many JARs claim to be from 1980-01-01 or 2010-01-01. |
| 14 | 4 | CRC-32 | CRC-32 of the uncompressed entry, with the compressed size at 18 and the uncompressed size at 22. In a signed JAR these are independent of the SHA digests in META-INF, so an entry can pass its CRC and still fail signature verification. |
| 26 | 2 | File name length | Byte length of the name at offset 30. For a JAR written by the jar tool this is 9 — the length of META-INF/ — which is a quick, if informal, tell in a hex dump. |
| 30 | variable | First entry name | Where a JAR announces itself in practice: META-INF/ followed by META-INF/MANIFEST.MF. The order is not decorative, because a streaming reader only looks at the front of the file for the manifest. |
| -22 | 4 | End of central directory signature | 50 4B 05 06, exactly 22 bytes from the end with no archive comment. The class loader reads the central directory from here, which is why it can load one class out of a 60 MB JAR without decompressing the rest. |
| -6 | 4 | Offset of the central directory | Start of the central directory, measured from the beginning of the file. A self-extracting or executable JAR with a shell script prepended still works because readers tolerate the shift, but the value here no longer matches the raw file layout. |
Telling it apart from its neighbours
| Easily confused with | How to tell |
|---|---|
| ZIP | Identical at byte level. What makes a ZIP a JAR is META-INF/MANIFEST.MF in the central directory, plus normally .class entries. Renaming a JAR to .zip changes nothing; renaming a ZIP to .jar produces a file java -jar rejects for having no main manifest attribute. |
| Android APK | An APK began life as a JAR and still has META-INF, so the two look alike in an archive viewer. The separator is content: .dex entries and AndroidManifest.xml mean APK, .class entries and MANIFEST.MF alone mean JAR, and only an APK carries the 'APK Sig Block 42' magic before its central directory. |
| war / ear | Same format, different required layout: a WAR keeps its classes under WEB-INF/classes and its libraries under WEB-INF/lib, an EAR holds application.xml plus other archives. A servlet container reads the layout, not the extension, so a misnamed WAR fails on a missing WEB-INF rather than on anything about the ZIP. |
| Spring Boot jar | A runnable JAR whose own classes live under BOOT-INF/classes and whose dependencies are nested JARs under BOOT-INF/lib, with a launcher named in MANIFEST.MF as the real Main-Class. It opens as an ordinary JAR, but its application classes are not where a class loader would normally look, which is why extracting one and running the main class directly does not work. |
How these files break
- The manifest is no longer at the front. Rebuilding a JAR with a general-purpose ZIP tool preserves every byte of content and loses the ordering, and a streaming reader then reports no manifest at all. Measured here with the JDK's own API: a JAR written by the jar tool (META-INF/ then META-INF/MANIFEST.MF) returned the manifest, while archives with the manifest as the second and third entry after a class file both returned null. java -jar still ran them, because it reads the central directory rather than streaming — so the same file works one way and fails the other.
- Truncated tail. Every local header survives and the file looks healthy from offset 0, but the end of central directory record is gone and the class loader, which starts from the end, cannot list a single entry. Recovery means scanning forward for 50 4B 03 04 and rebuilding the directory.
- Broken signatures after repackaging. A signed JAR stores a digest for every entry in META-INF/MANIFEST.MF and a signature file beside it, so shading, re-compressing or merging changes the digests and the JVM refuses the archive with a security exception rather than a corruption message.
- Duplicate entries from a naive merge. Concatenating dependencies into one archive can produce two entries with the same path; ZIP permits it and the class loader takes the first, so which version of a class wins depends on the order in the central directory — a real file with an invisible defect.
Where the format stands today
The JAR is the unit of distribution for the entire JVM ecosystem: everything on Maven Central is a JAR, every dependency a build tool resolves is a JAR, and every server-side Java application ships as one, whether as a plain library, a WAR for a container or a self-contained Spring Boot archive. Nothing has replaced it — the module system added module-info.class inside the JAR rather than a new container, and native-image and jlink produce executables from JARs instead of replacing them upstream. Where it has lost ground is client-side delivery: applets are gone and Java Web Start with them, so a JAR today is a server or build-time artefact. Its enduring advantage is the ZIP central directory, which lets a class loader pull one class out of thousands without touching the rest.
Open Java JAR files on this site
Every one of these runs in your browser — the file never leaves your machine.
Related formats
Formats that are easy to confuse with Java JAR — compare their leading bytes.
| Format | First bytes | Extension |
|---|---|---|
| ZIP | 50 4B 03 04 | .zip |
| Android APK | 50 4B 03 04 | .apk |
| Java class file | CA FE BA BE | .class |