Fixing the old build detected message in Nativefier

An app that has opened the same internal dashboard every morning for months suddenly stops to show a macOS warning box before the page loads. The title says "Old build detected". Under it sits a sentence about Chrome and Electron. Dismissing it lets the app carry on exactly as before, and the site behind it is fine. Nothing on the Mac changed overnight. What ran out is a timer that was packaged into the app on the day it was built, and from now on that box appears at every launch. The useful question is not how to click it away, but which of the three available routes is worth taking.

What the dialog is actually reporting

The check lives inside the app bundle, not on the website and not in macOS. Every app produced by Nativefier stores the date it was packaged. When the app starts and the main window has been created, it subtracts that stored date from the current time and compares the result against a fixed threshold. The threshold is 90 days, defined as a constant in the app's main process. Cross it, and the warning box is shown once per launch, with a type of "warning" and the fixed title "Old build detected".

The body text is the part that explains the intent, and unless it was overridden at build time it reads exactly like this.

This app was built a long time ago. Nativefier uses the Chrome browser (through Electron), and it is insecure to keep using an old version of it. Please upgrade Nativefier and rebuild this app. Source: github.com

Reading that literally clears up most of the confusion around the message. It is not reporting a broken certificate, a blocked network request, a change on the site, or an incompatibility with a new version of macOS. It is reporting that the copy of Chrome sealed inside this particular bundle has been sitting there without patches for at least three months. A browser fixes that problem by updating itself in the background. A packaged wrapper has no update mechanism at all, so the only thing the app can do is interrupt and say so.

That also explains why the box comes back every single time. Quitting the app, restarting the Mac, or clearing the site's data changes nothing, because none of those actions touch the build date sealed in the bundle. Only producing a new bundle changes it.

The threshold is worth reading as a deliberate compromise rather than an arbitrary number. Ninety days is long enough that an app built for a short project never nags, and short enough that anything kept in daily use is flagged within one quarter. It also means the appearance of the box carries information beyond the message itself: it dates the app. A bundle that has only just started warning was built roughly three months ago, while one that has been warning for a year has an engine well over a year behind the browser sitting next to it in the Dock.

Why rebuilding does not move the engine forward

The instruction in the dialog is to upgrade the tool and rebuild. Rebuilding does work in the narrow sense: a fresh bundle carries today's date, so the warning stops for another 90 days. What it does not do is what the reader probably assumes it does.

The tool is frozen. The last release published to npm is version 52.0.0, dated 25 August 2023, and there has been no release since. That version ships with Electron 25.7.0 as its default, which corresponds to Chrome 114. A rebuild performed today with default settings therefore produces an app containing a browser engine from mid 2023, with a build date of today. The dialog goes quiet for three months and the actual risk it was pointing at is untouched.

The reason for the freeze is stated plainly by the project itself, which was archived in September 2023.

Nativefier is unmaintained and has been publicly archived. It was built a couple of years ago before the ability to create shortcuts for websites in Chrome, or similarly on Firefox. Users who want to build and use their own website wrappers should strongly prefer these options as they are protected from security vulnerabilities by the browser's self updating mechanism. Source: github.com

That statement is worth taking at face value, because it names the exact property that matters here. The problem was never the wrapper concept. The problem is that a wrapper with a pinned engine and no maintainer cannot patch itself, and a browser can.

The two build flags that change the outcome

Two options exist, and both are applied when the app is built rather than when it is launched. Neither can be set from the app's own menus.

The first is --disable-old-build-warning-yesiknowitisinsecure. The flag name carries most of the documentation, and the reference describes it as disabling the warning shown when opening an app made a long time ago, using an old and probably insecure Electron. Because it is a build option, using it still requires a rebuild, which resets the date anyway. Its real purpose is the case the documentation names: a kiosk or a fixed terminal pointed at a controlled internal site, where the build is deliberately pinned and the interruption is pure noise.

The second is -e or --electron-version, which accepts a version string and pulls that release of Electron into the bundle instead of the default. Setting it to a recent version is the only way to get a newer Chrome out of this tool. The caveat is that the app shell in version 52.0.0 was written against the Electron 25 API, and later major versions remove and rename things it calls. Some combinations build and run without complaint, some produce a window that opens and immediately breaks. Test the result on a real workload before moving daily work onto it.

Two smaller flags matter on a modern Mac. --upgrade takes the full path to an existing app executable and rebuilds it in place while keeping the options it was originally created with, which saves reconstructing a long command from memory. --arch arm64 matters if the build machine and the target machine differ. The tool also needs Node 16.9 or newer and npm 7.10 or newer, and states macOS 10.13 or newer as its own requirement.

Three routes out, and what each one costs

The choice is easier to see side by side. The engine column is the one that decides how much the dialog was worth listening to.

Route Effect on the dialog Engine inside the app Recurring effort
Rebuild with default settings Silent for 90 days Chrome 114, unchanged Rebuild every quarter
Rebuild with the suppression flag Silent permanently Chrome 114, unchanged None after the rebuild
Rebuild with a newer Electron pinned Silent for 90 days Newer Chrome, if the build runs Rebuild, plus testing each time
Install the site from a browser Never appears The browser's own engine, patched with the browser None
Move to a maintained wrapper tool Never appears Maintained by the tool None

Anyone running a handful of apps built years ago should also check what those bundles are before deciding. An app built for Intel runs through Rosetta on Apple silicon, and Finder reports that in the Get Info panel as Application (Intel), while Activity Monitor shows the same thing in its Kind column for anything currently running. That is a second, separate expiry sitting on top of the browser engine question.

There is also the Gatekeeper step. Apps produced this way are unsigned, so the first launch on a current macOS goes through System Settings, Privacy and Security, and the Open Anyway button, rather than any shortcut in Finder.

What a browser install does differently

The route the archived project recommends is the browser's own install command, and on Chrome the menu wording changed in a way that hides it from people who learned the old path. Since Chrome 128, announced in July 2024, the item called Create shortcut makes a bookmark that opens the page in an ordinary tab. The behaviour that produces a real windowed app moved to a different item.

Starting in Chrome 128, the Create Shortcut menu item in More > Save and share now creates a bookmark on the user's desktop or homescreen. The previous behavior of this menu item on desktop has moved to the Install Page as App option. Source: developer.chrome.com

The current path is More, then Cast, save, and share, then Install page as app. The result has its own icon, its own Dock entry, its own window with no tab strip, and no build date to expire. On macOS the bundle is filed under a Chrome Apps folder inside the user's own Applications folder.

The cost is coupling. An app installed this way belongs to the browser profile that created it, and shares that profile's cookies, extensions, and signed in account. Two accounts on the same service means two browser profiles, and uninstalling the browser takes the apps with it. For a site opened by one person under one account, that coupling is invisible. For someone juggling a work account and a personal account on the same service all day, it is the whole problem.

Where a dedicated wrapper still earns its place

The archived project's advice covers the common case, and it is genuinely the right default. The gap it leaves is the one that made people reach for a wrapper in the first place: an app that keeps its own session, independent of whichever browser profile happened to be active. A maintained site to app tool fills that gap without reintroducing a frozen engine, because the tool is the thing being updated rather than each bundle sitting in the Applications folder.

The practical difference shows up in three places. Session isolation means a support console and a personal account on the same domain can be open at once without profile juggling. Icon and window handling is set per app rather than inherited from the browser. And the list of sites that have been prepared in advance matters more than it sounds, because most of the fiddling in a manual build is working out the right user agent, window size, and login behaviour for one specific service. A ready made list of Supported services removes that step, and the Features page is the fastest way to check whether the specific behaviour a wrapper was chosen for is present before anything is installed.

Where the browser install already covers the need, use it. Where it does not, the honest comparison is against a maintained tool, not against a build from 2023.

What to change first

Open the app that showed the warning and decide, in one pass, whether that site needs its own session or just its own window. If it only needs a window, install it from the browser and delete the old bundle today. If it needs its own session, rebuilding a frozen wrapper buys 90 days and nothing else, so compare the maintained options at Kagemusha instead of setting the same timer again.

Frequently asked questions

Does the old build detected warning mean the app is unsafe to use right now?

It means the browser engine inside the bundle has not been patched since the app was built, which is at least 90 days. Whether that is dangerous depends on the site. A controlled internal dashboard behind a login is a different risk from a site that renders untrusted content from the open web.

Can the warning be turned off without rebuilding the app?

No. Both the suppression flag and the build date live inside the packaged bundle, and there is no setting inside the running app that changes either. Any route that stops the message involves producing a new bundle or replacing the app entirely.

Why does the message come back even after a rebuild?

A rebuild resets the clock rather than stopping it. The new bundle carries today's date, so the check passes for another 90 days and then fires again. Only the suppression flag stops it permanently, and that leaves the underlying engine exactly where it was.

Is there a way to get a newer version of Chrome into an existing app?

Pinning a newer Electron release at build time is the only route, and it is not guaranteed to work because the app shell was written against Electron 25. Test the rebuilt app on real work before relying on it, and treat a browser install or a maintained wrapper as the lower effort answer for anything used daily.

Back to all posts