← Back to Blog

Ten versions, one API — what Esri’s semantic-versioning promise means for 59 @arcgis/core builds

Stacks of locked dependency cards feed a resolver that passes patch and minor updates, flags a breaking change, and outputs one verified package with its dependency tree.

We counted. Across three folders of ArcGIS Maps SDK for JavaScript apps, 59 builds declare @arcgis/core on six different version lines, and their lockfiles hold ten different versions. That looks like ten compatibility targets. Esri’s own versioning rules say it should not be: since 5.0.0 the SDK is semantically versioned, patches leave the public API alone, minors add without breaking, and removals wait for 6.0. So the ten versions are one 5.x API line, recorded at the moment each lock last resolved core. That promise comes with an escape clause Esri states itself, and 5.1 removed a small set of utility-network APIs that carried no beta tag, so it is worth knowing exactly where it holds.

This post sets out what we measured, what Esri promises and where that promise lives, and what a caret, a tilde and an exact pin actually resolve to. It then covers why an exact pin does not freeze the Esri packages underneath it, and what Esri’s own sources say — and disagree about — on how long 5.0 is supported. Every number below was read from npm, the lockfiles, git history, the CDN files or the documentation on October 19, 2026. The FAQ plans 5.2 for October 2026, so when 5.2 ships, the 5.1.27 figures below move with it.

59 builds, six declared lines, ten locked versions

The 59 builds (we call each one a unit below) sit in three folders: 20 React apps, 19 Calcite apps and 20 lab apps. Every one lists @arcgis/core under dependencies. What they declare:

Declared rangeUnits
^5.0.1530
^5.1.1220
5.1.24 (exact)4
5.1.25 (exact)2
5.1.26 (exact)2
5.1.27 (exact)1

What their lockfiles hold is a wider spread. Twenty-nine units are locked on 5.0.x — 5.0.15 once, 5.0.16 four times, 5.0.17 five times, 5.0.18 seven times, 5.0.19 twelve times — and 30 on 5.1.x: 5.1.12 eighteen times, 5.1.24 and 5.1.25 four times each, 5.1.26 three times and 5.1.27 once. The 30 identical ^5.0.15 declarations land on six versions across two minors: 29 on 5.0.15 to 5.0.19, and one on 5.1.26. Every lock satisfies its range.

Fifty-five of the 59 units are configured to deploy through npm ci, which installs exactly what the lockfile says, so a deploy that runs it does not move any of this.

What Esri actually promises, and where it says so

The governing text is the SDK’s FAQ, under “How are breaking changes managed?”: “Starting with 5.0.0, the SDK follows semantic versioning, which uses a version format of: MAJOR.MINOR.PATCH”. It defines each level:

Then comes the clause that matters: “While we follow these guidelines as much as possible, there may be infrequent circumstances when we introduce changes without prior notice. For example, breaking changes related to browser security updates or beta features.”

On deprecation, the same FAQ says deprecated functionality “will continue to work and is supported throughout the current major version (5.x)” and “is removed at the next major version (6.0)”, adding that it “typically will not receive new enhancements and may only receive critical bug fixes.” The 5.0 release notes announce the move to semantic versioning; the view-models page dates the next major: “no breaking changes will occur before version 6.0 (Q1 2027).” That sentence is about view models; we would not stretch it into a blanket promise. (If you are still moving off widgets, our post on the 5.0 widget deprecation covers that side.)

One thing to know before you go looking: the 5.1 release notes page does not carry this policy. It has no versioning text and no Breaking changes section, and the old /breaking-changes/ URL redirects to an anchor that does not exist on it. Cite the FAQ.

What a range resolves to, and when

Semantic versioning answers two different questions, and they come from different documents. The FAQ says what a patch or minor promises. npm’s range rules, from the node-semver package, decide what a range can resolve to. A caret, in that package’s words, “allows patch and minor updates for versions 1.0.0 and above.” Resolved against the registry on October 19, 2026:

RangeMeansStable versions it matchesHighest
^5.0.15>=5.0.15 <6.0.0-0335.1.27
~5.0.15>=5.0.15 <5.1.0-055.0.19
^5.1.12>=5.1.12 <6.0.0-0165.1.27
5.0.19exactly 5.0.1915.0.19

So a caret on 5.0.15 crosses into 5.1; a tilde keeps core on 5.0. None of the more than 400 published 5.x pre-releases matches ^5.0.15, because a pre-release only satisfies a range that itself names a pre-release on the same version.

The catch is when a range is applied. A fresh resolve of ^5.0.15 on October 19 locks 5.1.27, and so does ^5.1.12: every caret unit would land on the same version. They do not, because a range only acts when the lock is resolved. npm ci never re-resolves — per the npm docs, if the lock and package.json disagree it “will exit with an error, instead of updating the package lock”, and “installs are essentially frozen.” And npm install keeps a locked version that still satisfies the range. That is why the caret is not the cause of the split.

It also means the date a lockfile was last committed is a poor guide. Three of our units rewrote their lock after 5.1.0 shipped and still hold core 5.0.19. What decides a unit’s version is when @arcgis/core itself was last resolved.

An exact pin is not a frozen stack

The usual reaction to a spread like this is to pin @arcgis/core exactly. That freezes core and nothing else. Core’s own Esri dependencies are ranges: core 5.0.15 and 5.0.19 depend on @arcgis/toolkit ^5.0.0 and @esri/calcite-components ^5.0.2; 5.1.12 and 5.1.27 on ^5.1.0 and ^5.1.1. We resolved this manifest into a fresh lock:

{"name":"c","version":"1.0.0","private":true,"dependencies":{"@arcgis/core":"5.0.19"}}

The lock held core 5.0.19 — next to @arcgis/toolkit 5.1.27, @arcgis/lumina 5.1.27 and Calcite 5.1.2. The command, run in a folder holding only that package.json:

npm install --package-lock-only --ignore-scripts

A tilde does not change that. The same test with ~5.0.15 locked core 5.0.19 and still pulled toolkit and lumina 5.1.27 and Calcite 5.1.2.

Three more things showed up in the same test matrix and in our own locks:

Minors: backward-compatible, with an asterisk

As noted above, the 5.1 release notes have no Breaking changes section. They do list APIs marked “removed”, and each deserves a read against the type definitions rather than a skim. We sorted them by one test, applied at 5.0.19: is the removed API marked @beta itself, or declared in the same file as a class or component marked @beta? Some pass it — for example triggerAction() on arcgis-popup, UtilityNetwork.generateCombineNetworkElements(), a slot on the @beta arcgis-assistant component, and the CircuitManager types, which sit in the same file as the @beta CircuitManager class. The FAQ’s escape clause names “beta features”; our reading, not Esri’s, is that it covers those. One pair, WaitForValidateOptions’s interval and statusCallback (in TopologyValidationJobInfo), is a typings refactor: the interface now extends a shared options type and the doc example still passes interval.

Not every removal passes that test, though. We compared the 5.0.19 and 5.1.27 type definitions. Eight members tagged @since 5.0, with no @beta tag in their own file, are gone in 5.1, all in the utility-network APIs. They are three exported types (PolicyType, ColorGroupJSON, PolicyJSON), the circuitHasBeenDeleted property of CircuitExportResult, and four class properties: location and returnConsumerCircuits on QueryCircuitsParameters, and allCircuits and continueOnFailure on VerifyCircuitsParameters. At 5.0.19 the only SDK consumer of those four properties was CircuitManager, a class marked @beta, so they are beta-adjacent in use; by the file test, they are not beta. Two Parquet geometry-encoding classes went too: ParquetGeometryEncodingLocation and ParquetGeometryEncodingWkb. They carry no @beta tag of their own; the @beta ParquetLayer uses them.

Type-checked with tsc under a Vite-style configuration (moduleResolution set to bundler, target ES2022), this TypeScript compiles against core 5.0.15 and fails against 5.1.27 with TS2305: ... has no exported member 'PolicyJSON':

import type { PolicyJSON, PolicyType } from "@arcgis/core/networks/support/jsonTypes.js";
const p: PolicyType = "esriDPTDefaultValue";
const j: Partial<PolicyJSON> = { sourceId: 1 };
console.log(p, j);

Who this reaches: if you write utility-network code, use the Parquet geometry-encoding classes, call triggerAction() on arcgis-popup or rely on the slot 5.1 removed from arcgis-assistant, at least one of these removals can touch your code. Whatever you use, read each “removed” line against the .d.ts before you cross a minor.

The 5.1 notes also flag deprecations, which are not removals. Among them, AMD require() “is deprecated since version 5.0 and may be removed at version 6.0”, and the __esri namespace “is no longer supported for importing types and will be removed at 6.0.”

Is 5.0 still supported? Esri’s sources disagree

Twenty-nine of our units are on 5.0.x, so this question matters to us. Here is what each Esri source says.

The npm record matches the announcement. The 5.0 line has 20 stable releases, from 5.0.0 (published February 20, 2026) to 5.0.19 (April 29, 2026). No 5.0.x has been published since npm published 5.1.0 on June 18, 2026, while 5.1 has had 27 patches. As of October 19, that is 173 days since 5.0.19, the last 5.0 patch. That is a fact about publishing, not a policy, and it does not make 5.0 “end of life” — none of the Esri sources we read says that. Nor does any of them say which statement governs when two conflict. Our own reading, not Esri’s: plan as if only the latest minor gets patches, because that is what the npm record shows.

Two practical notes. First, “General Availability” does not buy you phone, email or chat help: the same policy says “Phone, email, and chat support are available to Esri customers with current maintenance or paid support subscriptions.” Second, as of October 19, npm’s latest tag is still 5.1.27, and the next major is already on npm as a pre-release (a 6.0.0-next build on the next tag).

If you are not the one writing the scripts

“Which version are our apps on?” has a precise answer, and it lives in each app’s lockfile, not in its package.json. If most of your apps are on 5.0.x, the npm record shows they have had no Esri patch since April, whatever the life-cycle table says. Esri’s announcement defined a patch as bug and security fixes. Our recommendation is to move them to the current minor and keep them there. For each app that is one lock regeneration (moving toolkit, lumina, Calcite and, where the app declares it, map components with core) and one test pass, repeated on a schedule: at least once per minor, taking the latest patch each time. Budget separately for 6.0: Esri’s view-models page dates it to Q1 2027, the FAQ says deprecated functionality is removed there, and the 5.1 notes say AMD require() may be removed and the __esri namespace will be removed at 6.0.

CDN and npm: same number, different bytes

The CDN versions differently from npm. Esri’s get-started page: “The CDN is available in MAJOR.MINOR format, and patch-specific versions are available in MAJOR.MINOR.PATCH format.” We compared the files: js.arcgis.com/5.1/core.js is byte-identical to /5.1.27/core.js, and /5.0/ to /5.0.19/. A CDN page on a MAJOR.MINOR URL needs no lockfile and takes patches automatically within its minor — which also means new Esri code reaches your page without a deploy or a test pass of yours. If you need the bytes to stay put, use the patch-specific URL.

But the CDN entry imports Calcite at an exact patch — 5.1.1 for /5.1/ — while an npm build of core 5.1.27 resolves Calcite ^5.1.1 to 5.1.2. Both are on “5.1”; the Calcite bytes differ. Each is inside what the 5.1 notes recommend: “the same version or any minor version greater than ^5.1.1”. And js.arcgis.com/5.2/ already answers, but on October 19 it served a 5.2.0-next build. That is not a release; do not point a production app at it.

License, supply chain and accessibility

@arcgis/core is not open source. Its license file says it is “licensed for use under the Esri Master License Agreement (MLA)”. The licensing page adds that “no additional purchase is required for the JavaScript SDK when using an API key to access content and ArcGIS location services”, but “costs may be incurred to access some services”. The page’s pop-up definition of location services adds: “An ArcGIS Location Platform or ArcGIS Online account is required to use the services.” Installing or upgrading the npm package, or pointing at a CDN minor or patch URL, is not itself a purchase. What is billed is service use, under the account’s model: pay-as-you-go with a monthly free tier for select services on Location Platform, credits on ArcGIS Online.

On supply chain: npm audit reported zero vulnerabilities on October 19 for a fresh 5.1.27 tree and an exact 5.0.19 tree, and the registry signatures verify. A clean audit means no published advisory matched those trees; it does not mean 5.0.19 carries the fixes 5.1 has had since. Esri’s announcement, unlike the FAQ, defined a patch as “Backward-compatible bug and security fixes”, and 5.0 has had none since April. @arcgis/core publishes no provenance attestation, so “registry-signed” is as far as we would go. Watch the names, too: the old arcgis-js-api and esri-loader packages are deprecated with the message “Use @arcgis/core instead.” The plain arcgis package, with no @arcgis scope, is unrelated and deprecated. Install the scoped name.

Staying on 5.0 also gives up accessibility work Esri has already done. In 5.1, “The Bookmarks and Search components now announce dynamic changes during interactions to assistive technologies”, and the Popup component takes focus when it opens (focusTrapDisabled turns that off). Five of our 5.0.x units use the <arcgis-search> component the note names. Six more use only the Search or Bookmarks widgets, and the notes do not say whether the change applies to those.

What we would do — our opinion, not Esri’s

The documentation supports the mechanics; what to do with them is a judgment call. Ours:

References

Want a second pair of eyes on your SDK versions?

Book a free intro call and we will walk through your apps’ lockfiles with you.

Book a free intro call