electron/asar: the archive format behind Electron app bundles
Simple extensive tar-like archive format with indexing
At a glance
- What is it?
- ASAR concatenates an app directory into one uncompressed file with a JSON index, so Electron can read files by offset instead of unpacking them. Here is how packing, deduplication and integrity work, and where the format stops being the right tool.
- Who is it for?
- Adopt @electron/asar if you ship an Electron app and want one file on disk instead of a tree of JavaScript, or if you need to read files out of somebody else's .asar bundle. Do not adopt it as a general compression or encryption layer: the README describes no compression, and the integrity block is a hash list, not a signature.
- Can I use it commercially?
- Yes. MIT 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 6 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What problem the asar format removes for Electron packagers
An Electron app is a directory of JavaScript, HTML, assets and native modules. Shipping that directory as-is means thousands of small files on the user's disk, and on Windows in particular, file count matters more than total size during installation and antivirus scanning. ASAR answers that by concatenating every file into one archive with no compression, in the manner of tar, while keeping random access. The archive is not a stream you unpack before use: a reader can seek straight to one file by offset.
The audience is narrow and identifiable. It is Electron application developers and the build tooling around them, plus anyone who has to inspect a shipped .asar bundle after the fact. The README frames the format itself as the deliverable, and lists four properties: random access, JSON metadata, a parser that is easy to write, and storage of duplicated file contents only once. Those four properties explain almost every design decision that follows, including the ones that look odd at first.
The layout: a Pickle header, a JSON index, then raw bytes
The format is deliberately flat. A UInt32 header_size comes first, then the header string, then the file contents back to back. Both header_size and header are serialized with Chromium's Pickle class, and the README notes that header_size's Pickle object is 8 bytes. The header is a JSON string describing a tree of directories and files.
Each file entry carries an offset, a size, an optional executable flag and an integrity object. The offset is relative to the start of the file contents, so a reader must add the size of header_size and header to get the real position. The README is explicit that offset is a UINT64 number stored as a string, because JavaScript Number cannot represent UINT64 precisely, while size stays a Number because Node.js reports file sizes as Numbers. That asymmetry is a good example of the format being shaped by its host language rather than by a spec.
Integrity is a SHA256 hash of the whole file plus an array of block hashes and a blockSize. According to the README, SHA256 is currently the only supported algorithm. This is a corruption check, not a trust mechanism: nothing in the header is signed, so a modified archive with a recomputed hash is indistinguishable from an untouched one.
Deduplication and unpacked files change what ends up on disk
The README describes deduplication as a storage decision, not a reader-visible one. When two files have identical contents, the first copy is written into the archive and every later copy's header entry points at the same offset. Each file still keeps its own entry, size, integrity hash and executable bit. The saving is real for bundled node_modules, which is exactly the shape of tree where the same licence file or the same helper module appears dozens of times, and the README adds that packing gets faster because the redundant bytes are never written.
The exception is unpacked files. Anything matched by unpack or unpackDir is written out in full next to the archive, because those files are meant to live on disk outside it. They are never deduplicated. This is the first place where a build decision has consequences a reader can see: a path you exclude to make a native module loadable will also stop benefiting from deduplication, and the archive plus its .unpacked directory is what you actually ship.
Installing @electron/asar and packing a first archive
The README states that the module requires Node 22.12.0 or later, and package.json agrees with an engines field of >=22.12.0. Install it globally or as a project dependency; the README's install line uses --engine-strict, which makes npm refuse the install on an older Node rather than warn.
npm install --engine-strict @electron/asarOnce installed, the CLI exposes four commands. pack takes a directory and an output path and creates the archive. Running the help output is the fastest way to confirm which build you have.
asar --helpPacking a directory is a single call. The README's own example uses a source directory and an output name.
asar pack app app.asarTo check what landed in the archive before shipping it, list the contents.
asar list app.asarExtraction comes in two forms: extract-file pulls one file out, while extract writes the whole archive to a destination directory.
asar extract app.asar ./unpackedIf you would rather drive it from code, the README's programmatic example imports createPackage and awaits it. Note the warning printed right below that example: there is currently no error handling provided.
import { createPackage } from '@electron/asar';
const src = 'some/path/';
const dest = 'name.asar';
await createPackage(src, dest);
console.log('done.');For selective exclusion, the README's --unpack-dir examples are worth reading closely, because the glob syntax decides how deep the match goes. Excluding the top-level entries only:
asar pack app app.asar --unpack-dir "{x1,x2}"And matching those names at any depth, which the README shows as excluding the nested copies as well:
asar pack app app.asar --unpack-dir "**/{x1,x2}"Patterns can be combined in one brace group, which is how the README excludes a specific nested path alongside the global matches:
asar pack app app.asar --unpack-dir "{**/x1,**/x2,z4/w1}"The transform hook, and the error handling it does not fix
Compression is not part of the format, but the library leaves a door open. createPackageWithOptions accepts a transform option, a function that receives a filename and returns either nothing or a stream.Transform. When it returns a Transform, that stream is applied to files going into the archive, and the README's stated example is compression. The function is called per file, so the decision of what to transform is yours to make by inspecting the name.
Two things are worth flagging. The first is that a transform changes the bytes on disk while the header still records size and integrity for what was written, so any external reader has to know how to reverse it. The second is the README's own note, placed directly under the programmatic example: there is currently no error handling provided. For a build step that runs unattended in CI, that is the constraint to design around. Wrap calls yourself and check the exit status of the CLI, rather than expecting a rejected promise with a useful message.
Where asar is the wrong choice
The README lists no compression, and that is not an oversight to work around with a transform unless you control both ends. If your goal is to shrink a download, a zip or tar.gz is the correct tool, because every consumer already knows how to read it. ASAR's advantage is random access without unpacking, and you pay for it in bytes on disk.
Nor is asar a secrecy mechanism. The header is a JSON string, offsets and sizes are plain, and the integrity field is a SHA256 hash list. Anyone can run asar list and asar extract on a bundle they have. If your threat model includes a user reading your JavaScript, asar does not address it, and the README does not claim otherwise.
The third boundary is unpacking itself. Native modules and anything that must exist as a real file on disk have to be excluded from the archive, which means your shipped output is no longer one file. The README's --unpack-dir examples exist precisely because that need is common, and once you use them, the single-file property that motivated the format is gone for those paths.
How asar differs from tar and zip
The closest comparison is tar, which the README names directly. Both concatenate files without compression, and both can be read without materialising the whole tree. The difference is the index. Tar interleaves a header with each file's bytes and walking it means reading sequentially through the stream, which is why tar is awkward to random-access without an external index. ASAR puts the entire directory tree in one JSON header at the front, so seeking to a file is a lookup followed by one read at a known offset. That is the whole reason Electron can serve files out of an archive without unpacking first.
Against zip, the split is compression and structure. Zip compresses by default and stores a central directory, so it also supports random access, but the entry metadata is a fixed binary record rather than a JSON tree, and zip has no equivalent of the deduplication described in the README. If you need a format that any operating system opens without extra tooling, zip wins. If you need a format that a small parser can read and that Electron's runtime understands natively, asar is the one that fits.
Maintenance, licence and what upgrading costs
The repository is not archived, and the last push was on 2026-09-23. Releases are frequent enough to matter: v4.2.0 on 2026-03-31, v4.2.1 on 2026-07-21, and v4.3.0 on 2026-08-18. The package is published with provenance enabled in publishConfig, which ties the published artifact to the build. The licence is MIT, stated in both the README badge area and package.json, which permits commercial and closed-source use; that is a statement about the licence text, not legal advice, and you should read LICENSE.md yourself.
The upgrade cost sits in the engine requirement. Node 22.12.0 or later is a hard floor in package.json, and the README's install command uses --engine-strict to enforce it. A project pinned to an older Node cannot simply bump the dependency. The runtime dependencies are small (glob and minimatch), so the surface you inherit is mostly the CLI and the exported functions. The README's note that no error handling is provided is the other thing to re-check on each upgrade, because it describes the current state of the API rather than a guarantee about the next version.
Editorial conclusion
Adopt @electron/asar if you ship an Electron app and want one file on disk instead of a tree of JavaScript, or if you need to read files out of somebody else's .asar bundle. Do not adopt it as a general compression or encryption layer: the README describes no compression, and the integrity block is a hash list, not a signature. Before you commit, check that your build machine runs Node 22.12.0 or later, and decide deliberately which paths go into --unpack-dir, because unpacked files are written to disk in full and are not deduplicated.
Frequently asked questions
How do I open an .asar file?
Install @electron/asar and use the CLI. asar list shows the contents, asar extract-file pulls out one file, and asar extract writes the whole archive to a destination directory.
What is an asar?
It is an archive format that concatenates files together without compression, like tar, while keeping random access. It stores the file information as JSON and uses Chromium's Pickle to serialize the header.
What is electron asar?
It is the @electron/asar package, an MIT-licensed CLI and library that creates and reads the archive format used to bundle Electron app files into a single .asar file.
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/electron-asar)