@electron/osx-sign: codesigning Electron macOS apps from the command line or API
Codesign Electron macOS apps
At a glance
- What is it?
- @electron/osx-sign wraps Apple's codesign and productbuild utilities so an Electron app can be signed for Developer ID or Mac App Store distribution without hand-writing the certificate chain. It is a build-pipeline component, not a general macOS signing tool, and its defaults assume you already have an Apple Developer account and Xcode installed.
- Who is it for?
- Adopt @electron/osx-sign if your app is already packaged by Electron Packager or Electron Forge and you need a repeatable signature step for Developer ID or Mac App Store submission. Do not adopt it as a general-purpose signing library for arbitrary macOS binaries, and do not expect it to replace notarization, which it does not perform.
- Can I use it commercially?
- Yes. BSD-2-Clause 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 received new commits within the last day.
- 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 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What @electron/osx-sign solves, and for whom
Signing a macOS app by hand is a sequence of codesign invocations across nested frameworks, helper apps, and the outer bundle, each with different entitlements and flags. Get the order wrong and the signature is invalid; sign the wrong file with --deep and you can invalidate a nested binary that was already correct. @electron/osx-sign exists to encode that sequence once. The README describes it as minimizing "the extra work needed to eventually prepare your apps for shipping, providing options that work out of the box for most applications."
The audience is narrow and specific. You are shipping an Electron app, you have already produced a .app bundle through a packaging tool, and you need to sign it before upload. The README states the package is integrated into Electron Packager and Electron Forge, so for many teams it is never installed directly. It is also usable standalone when your pipeline does not involve those tools.
The prerequisites are Apple's, not the project's. The README lists a registered Apple Developer Program membership, Xcode from the Mac App Store, and the Xcode Command Line Tools, checked with xcode-select --install. For Mac App Store distribution you also need an app record on App Store Connect, a unique bundle ID, and a version number. None of that is something the package can supply.
Two utilities underneath: codesign and productbuild
The package exposes two functional groups. The sign functions wrap the codesign utility and produce a signed .app. The flat functions wrap productbuild and produce a .pkg installer. That split matters when you plan a release job: signing and packaging into an installer are separate steps with separate certificates.
Certificates follow the same split. For Mac App Store distribution the README names Mac App Distribution (3rd Party Mac Developer Application) and Mac Installer Distribution (3rd Party Mac Developer Installer). For distribution outside the store it names Developer ID Application and Developer ID Installer. The README notes these tend to come in related pairs and suggests installing both, while pointing out that if you only ship outside the store you do not need the 3rd Party Mac Developer certificates.
The signing procedure itself is not invented here. The README states it is based on Electron's Code Signing Guide, and the package depends on plist for reading and writing property lists, isbinaryfile for detecting binary files, semver, and debug. That dependency list is small, which is consistent with a tool whose real work is orchestration: deciding which files to sign, in what order, with which entitlements, and then shelling out to Apple's own binaries. There is no custom signing implementation to audit.
Installing @electron/osx-sign and signing a first app
If Electron Packager or Electron Forge already drives your build, configure signing there rather than installing this package directly. The README links to the OsxSignOptions interface in the Packager docs and to Forge's macOS code signing guide for that path.
For a pipeline that does not use those tools, install it as a development dependency:
npm install --save-dev @electron/osx-signThe package ships two binaries, electron-osx-sign and electron-osx-flat, plus a programmatic API. The API example in the README imports sign and passes an options object whose only mandatory field is the path to the .app:
import { sign } from '@electron/osx-sign'
const opts = {
app: 'path/to/my.app'
};
sign(opts)
.then(function () {
// Application signed
})
.catch(function (err) {
// Handle the error
})For Mac App Store submission the README shows platform, type, provisioningProfile and keychain alongside app. The README says platform should be auto-detected if your app was packaged for MAS via Packager or Forge, type defaults to distribution, the provisioning profile defaults to the current working directory, and keychain defaults to the system default login keychain.
import { sign } from '@electron/osx-sign'
const opts = {
app: 'path/to/my.app',
platform: "mas",
type: "distribution",
provisioningProfile: 'path/to/my.provisionprofile',
keychain: 'my-keychain',
};
sign(opts)On success the promise resolves and the .app on disk carries a valid signature. On failure it rejects, and the README's example leaves error handling to you. The README does not document the shape of the error object, so plan on logging the rejection and reading codesign's own output rather than branching on a documented error type.
The preAutoEntitlements default that breaks local runs
The most consequential default in the package is easy to miss. The README states that with the default option preAutoEntitlements, @electron/osx-sign adds the entry com.apple.developer.team-identifier to a temporary copy of the entitlements file you specified. The stated consequence is blunt: distribution builds can no longer be run directly.
This is not a bug, it is a deliberate alignment with how Apple treats team identifiers. The README quotes Technical Note TN2415 saying that "certain features are only allowed across apps whose team-identifier value match." The temporary entitlements copy is how the tool keeps those features working for a store submission.
If you need to run a distribution-signed app locally, the README gives a manual workaround: add ElectronTeamID to your Info.plist and com.apple.security.application-groups to the entitlements file, then set preAutoEntitlements: false. The alternative is to sign with type set to development, which the README says produces an app that runs on your provisioned development machine but is not eligible for submission through App Store Connect. Pick one deliberately. A team that flips preAutoEntitlements off to make local testing work and forgets to flip it back ships an app with different entitlements than intended.
Signing one file with --deep instead of the whole bundle
Some subresources bundled into an Electron app need the --deep flag. The README is explicit that applying it to the entire app is "not typically safe" and that it should be applied to just the file that needs it.
The mechanism is optionsForFile, a callback that receives a file path and a context object. The README's example shows the second argument carrying context about the current signing operation, including the resolved platform, which is either darwin or mas. Returning extra options from that callback merges them into the signing call for that one file.
This is the right shape for the problem. A blanket --deep hides ordering mistakes by re-signing nested code that was already signed correctly, and it is the usual cause of signatures that verify locally and fail on Apple's side. Per-file options force you to name the file. The cost is that you need to know which file needs deep signing, and the README does not enumerate which subresources typically require it. That knowledge comes from the failing binary, not from this documentation.
Where @electron/osx-sign is the wrong tool
It does not notarize. Notarization is a separate submission to Apple and a separate stapling step, and nothing in the README claims otherwise. If your release checklist ends at "signed," you have not finished a Developer ID release.
It is macOS-only by construction, because codesign and productbuild are macOS utilities. The topics list includes Windows code signing and the related searches surface electron/windows-sign and electron-builder Windows signing, but this package does nothing for those platforms. If you are searching for how to disable code signing on Windows, you are in the wrong project.
It is also a poor fit for signing a non-Electron macOS application. The defaults are tuned for the bundle layout Electron produces, and the README's framing is entirely about preparing Electron apps for shipping. For a native app, calling codesign directly through a small script is likely less indirection than adopting a package whose defaults encode assumptions about your bundle structure.
One more boundary: the README does not document rollback. If a signing run fails partway, there is no described mechanism that restores the .app to its pre-signing state. Keep an unsigned copy of the bundle if a failed run leaves you needing to retry from a clean artifact.
A real alternative is invoking codesign and productbuild directly from a shell script or a Makefile. The difference in approach is that a raw script gives you total control over ordering and flags but makes you responsible for walking the bundle, resolving entitlements per file, and keeping that logic current as Electron's bundle layout changes. @electron/osx-sign trades that control for a maintained traversal. If your bundle layout is unusual, the script may be less friction; if it is a standard Electron app, the traversal is the part you did not want to write.
Maintenance, licence and upgrade cost
The repository is not archived, and the last push was on 2026-09-03. Recent releases listed are v2.7.0 on 2026-08-18, v2.6.2 on 2026-08-17, and v2.6.0 on 2026-07-17. That cadence is consistent with a small, actively touched package rather than an abandoned one, though the release history alone says nothing about whether a given release will break your pipeline.
The licence is BSD-2-Clause, a permissive licence that permits use and redistribution with the copyright notice and disclaimer retained. That is a statement about the licence text, not legal advice for your situation; if your organization has a policy on permissive licences, run it through that policy.
Upgrade cost is dominated by the runtime requirement, not the API. package.json declares engines.node as >=22.12.0 and the package is type: module with exports pointing at dist/index.js. If your build image runs an older Node or your pipeline is CommonJS-only, that is the first thing to reconcile. The published version field in the repository is 0.0.0-development, which is normal for a repo that versions at release time, so read the version from the npm registry rather than from the checked-in package.json. The MIGRATION.md file at the repository root is the place to look when moving between major versions.
Editorial conclusion
Adopt @electron/osx-sign if your app is already packaged by Electron Packager or Electron Forge and you need a repeatable signature step for Developer ID or Mac App Store submission. Do not adopt it as a general-purpose signing library for arbitrary macOS binaries, and do not expect it to replace notarization, which it does not perform. Before wiring it into a release job, confirm three things: that the signing identity is installed in the keychain the build runs against, that the provisioning profile for MAS distribution is in the working directory or passed explicitly, and that preAutoEntitlements is set the way you intend, since the default adds com.apple.developer.team-identifier to a temporary entitlements copy and makes distribution builds unrunnable locally.
Frequently asked questions
What is OSX on Mac, and how does it relate to @electron/osx-sign?
@electron/osx-sign is not part of macOS itself; it is an npm package that codesigns Electron macOS apps. The README describes it as providing sign functions that wrap the codesign utility and flat functions that wrap productbuild.
What is the macOS logo?
The README does not cover macOS branding or logos. It documents the certificates, provisioning profiles and commands needed to sign an Electron app for Developer ID or Mac App Store distribution.
What is code signing used for?
In this package it prepares a packaged Electron app for shipping, producing a signed .app for Developer ID or Mac App Store distribution or a .pkg installer. The README notes that Mac App Store apps require a provisioning profile for submission to App Store Connect.
How do I notarize a macOS app?
The README lists two main functionalities: signing macOS apps via the sign functions and creating .pkg installer packages via the flat functions. Notarization is not among them.
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-osx-sign)