In this video, I take a look at what’s inside the app files we creating when compiling extensions for Business Central.

Here are the fields hidden in the 40 byte header:
- NAVX (4 bytes)
- Size (4 bytes Int)
- Version (4 bytes Int)
- Package Guid (16 bytes)
- Zip size (64bit. 8 bytes)
- NAVX (4 bytes)
And the 8 extra bytes in a runtime app:
- (Runtime) .NEA (4 bytes)
- (Runtime) 0 (bytes)
In this video, Erik takes us on a deep dive into the anatomy of a Business Central .app file. While many developers create and deploy app files daily as part of their workflow, few have ever looked at what’s actually inside one. Erik pulls apart an app file piece by piece — from the ZIP contents to the mysterious 40-byte header — using tools like 7-Zip and a hex editor to reveal the inner workings of this fundamental artifact of Business Central development.
It’s a ZIP File… But Not Quite
The common assumption is that an app file is simply a ZIP archive of everything in your extension folder. That’s not entirely wrong, but it’s not the whole truth either. Erik demonstrates this by taking an app file (from the Tic Tac Toe game built on the channel) and trying to rename it with a .zip extension.
When you associate 7-Zip with the .app extension, it opens just fine and displays the contents. However, if you copy the file and rename it to app.zip, 7-Zip throws an error: “This is not an archive.” So what’s going on?
Looking at the file properties in 7-Zip reveals an important clue: there’s an offset of 40 bytes. The app file was 28,271 bytes total, but the actual ZIP content was only 28,231 bytes. Those 40 extra bytes are a header that prefixes the ZIP data — and that’s what makes it technically not a standard ZIP file.
What’s Inside the ZIP
Once you get past the header and unzip the contents, here’s what you’ll find inside a typical app file:
SymbolReference.json
This JSON file contains all the symbols for your extension — table definitions, field names, properties, enum types, and more. It’s essentially the metadata that describes your extension’s objects. If you’re working with enums used as text constants, those values appear here as part of the symbol properties.
NavxManifest.xml
This is your app.json file converted to XML format. Erik finds this particularly amusing — it’s clear that different teams at Microsoft had different preferences for data formats. The JSON team wrote app.json, the XML team wanted XML, and the compiler team ended up converting between the two.
Navigation.xml
When you define a UsageCategory and ApplicationArea on objects, that information gets compiled into this file. It contains the department menu structure (reminiscent of the old NAV menu system) that enables your pages to appear in the search function, along with captions and the object references needed to run them.
Other Files
- Media folder — Contains logos and other media assets (if any exist in the extension)
- Documentation comments — Empty in this case (“this is a hacker channel, we don’t do comments”)
- Extension types file — A file listing the extension types present in the app
Source Folder
The source folder contains your AL files, organized in the same folder structure as your project. One thing to note: non-compilable files like PNG images are excluded — they simply don’t make it into the app file. The AL files themselves are the raw source, though spaces in filenames get replaced with escape codes.
Local Add-in Folder
Control add-in files get special treatment. JavaScript files from your project are moved into this folder, along with a control add-ins manifest XML file. This format echoes how control add-ins worked in NAV 2018 with ZIP files and manifests. The startup script gets embedded directly into the manifest XML, while other scripts sit alongside it as separate files.
The 40-Byte Header: A Hex Editor Adventure
The most interesting part of the dissection is the 40-byte header that precedes the ZIP content. Erik opens the app file in a hex editor to examine it byte by byte.
For context, every standard ZIP file begins with the bytes PK (for Phil Katz, who invented the ZIP format in 1993 after losing a lawsuit related to the ARC format). In an app file, PK doesn’t appear until byte 41 — confirming that 40 bytes of header data come first.
Header Structure Breakdown
Here’s the complete layout of the 40-byte app file header:
| Bytes | Size | Description | Example Value |
|---|---|---|---|
| 1–4 | 4 bytes | Magic identifier | NAVX |
| 5–8 | 4 bytes (integer) | Header size | 40 |
| 9–12 | 4 bytes (integer) | Extension version | 2 (Extensions v2) |
| 13–28 | 16 bytes (GUID) | Package ID | Unique per compilation |
| 29–36 | 8 bytes (64-bit integer) | ZIP content size | 28231 |
| 37–40 | 4 bytes | NAVX identifier (repeated) | NAVX |
The NAVX Identifier (Bytes 1–4)
The file begins with the ASCII characters NAVX, a throwback to the early days of extensions when the file format was called “NAV X.” This four-byte magic number identifies the file type.
Header Size (Bytes 5–8)
A 4-byte integer storing the value 40 — the total size of the header in bytes. This tells the system where the ZIP content begins.
Extension Version (Bytes 9–12)
A 4-byte integer indicating the extension framework version. For modern extensions, this is 2. Erik also examined an old Extensions v1 file, which had 1 in this position. With a 4-byte integer, there’s room for about four billion different extension versions — “I think we’re covered on that.”
Package ID (Bytes 13–28)
This 16-byte GUID is the Package ID, and it’s critically important. This ID is generated fresh every time you compile your extension. This is why you must preserve the exact app file when deploying to multiple tenants in the cloud — you can’t just rebuild from source code and expect it to work. The cloud validates that the Package ID matches, so two compilations of the same source code will produce different Package IDs and be treated as different apps.
Content Size (Bytes 29–36)
An 8-byte (64-bit) integer representing the size of the ZIP content. Using 64 bits means the format theoretically supports app files larger than 4 gigabytes — an interesting design choice that Erik jokingly suggests testing someday by creating the world’s largest extension.
Closing Identifier (Bytes 37–40)
The NAVX magic bytes repeated, marking the end of the header. After this, the standard ZIP data begins with the familiar PK signature.
Extension v1 vs. v2 Comparison
Erik also examined an old Extensions v1 app file to compare. The header structure is identical — same NAVX prefix, same 40-byte header size — but the version field reads 1 instead of 2. The contents of an Extensions v1 file are quite different, however:
NavxManifest.xml
src/COD6030591.DELTA
src/PAG21.DELTA
src/PAG26.DELTA
src/PAG51.DELTA
src/PAG52.DELTA
src/TAB18.DELTA
src/TAB23.DELTA
src/TAB5050.DELTA
MediaIdListing.xml
[Content_Types].xml
Notice the .DELTA file extensions and the [Content_Types].xml file — this format is heavily influenced by the old NAV development paradigm where extensions were delta files applied on top of base objects.
Runtime App Files: The Encrypted Variant
Normal app files have a sibling: the runtime app file. Erik opens one of these in the hex editor and finds that the 40-byte header is structurally identical — same NAVX prefix, same header size of 40, same version 2 indicator.
However, at byte 41 where you’d normally find PK to start the ZIP content, the runtime app instead begins with .NEA. Erik’s educated guess is that NEA stands for “Net Encrypted Archive.”
After the .NEA marker and a zero byte, the rest of the file is encrypted data — completely unreadable without the decryption key. The math works out: the header reports a content size, plus the 8 bytes for the .NEA marker and padding, plus the 40-byte header, equals the total file size.
The key takeaway is that the system reads the same 40-byte header to identify whether it’s dealing with a normal app file (which contains a ZIP archive) or a runtime app file (which contains encrypted content), and handles each accordingly.
Summary
An app file is more than just a ZIP archive — it’s a ZIP archive with a 40-byte binary header containing critical metadata. Here are the key takeaways:
- The 40-byte header contains the file identifier (
NAVX), extension version, a unique Package ID, and the content size - The Package ID is regenerated on every compilation, which is why you must keep the exact same app file for multi-tenant cloud deployments — rebuilding from source won’t produce the same file
- Inside the ZIP, your AL source files, control add-ins, navigation metadata, symbols, and the manifest are organized and sometimes transformed (JSON to XML, control add-in restructuring)
- Runtime app files share the same header structure but contain encrypted content (marked with
.NEA) instead of a ZIP archive - Non-compilable assets like images are excluded from the final app file
- The format is future-proofed with 4 bytes for version numbers and 8 bytes for content size, supporting extensions well beyond current practical limits