Ten versions, one API — what Esri’s semantic-versioning promise means for 59 @arcgis/core builds
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 range | Units |
|---|---|
^5.0.15 | 30 |
^5.1.12 | 20 |
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:
- Patch (5.0.1 to 5.0.2): “Bug fixes and internal improvements that do not change the public API. No breaking changes.”
- Minor (5.0.0 to 5.1.0): “New features, enhancements, and new APIs that are backward-compatible.”
- Major (5.x to 6.0.0): “Breaking changes, including the removal of deprecated APIs and other incompatible changes.”
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:
| Range | Means | Stable versions it matches | Highest |
|---|---|---|---|
^5.0.15 | >=5.0.15 <6.0.0-0 | 33 | 5.1.27 |
~5.0.15 | >=5.0.15 <5.1.0-0 | 5 | 5.0.19 |
^5.1.12 | >=5.1.12 <6.0.0-0 | 16 | 5.1.27 |
5.0.19 | exactly 5.0.19 | 1 | 5.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:
- Core and map components have to move together.
@arcgis/map-componentspeers core by minor (5.1.x requires core^5.1.0). Exact core 5.0.19 with map components at^5.0.15does not lock at all:ERESOLVE, because map components resolves to 5.1.27. Pinning both to 5.0.19 locks, but with toolkit 5.1.27 at the top level, nested toolkit 5.0.19 copies under map components, lumina and common-components, and Calcite still at 5.1.2. - Siblings drift past a pinned core. Two of our exact-pinned units declare core 5.1.24 and lock toolkit and lumina at 5.1.25.
- A pre-release can reach production. One of our units, locked on core 5.0.19,
carries
@arcgis/luminaand@arcgis/toolkit5.1.0-next.133. Its lock also holds Calcite 5.1.1, which declares lumina and toolkit as>=5.1.0-next.96 <6.0.0— a range with a pre-release lower bound — and that lock was first resolved before lumina 5.1.0 shipped.
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 life-cycle table on Esri Support lists both 5.0 and 5.1 in General Availability until the “Next major release”. Under 4.x, each minor left General Availability when the next one shipped.
- The same page’s summary card gives 5.1 a dated window instead: “General Availability June 25, 2026–June 25, 2029”. The card and the table do not agree.
- The product life-cycle policy (February 2026) says, for the JavaScript SDK in General Availability: “Software patches may be provided to resolve critical issues discovered in a release or associated with updates to supported browsers.” “May” is not a cadence.
- Esri’s October 2025 announcement of the move to semantic versioning, linked from the FAQ, said: “A new release will be in general availability until the next minor release” and “Patches for bugs are applied to the latest minor of a supported major version (MAJOR.LATEST).” Among what developers gain, it listed “Safe auto-upgrade”: “Default version ranges (e.g., ^5.1.0) pick up new minors automatically.” With a committed lock, that happens only when the lock is regenerated. (We read the announcement from a June 2026 archived copy because the live page refused our requests.)
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:
- Commit the lockfile and deploy with
npm ci. The lock, not the range, is your version. - Move
@arcgis/coreand@arcgis/map-componentstogether, always. - Do not expect an exact core pin to hold toolkit, lumina or Calcite still. Check the lock:
npm ls --package-lock-only @arcgis/core @arcgis/map-components @arcgis/toolkit @arcgis/lumina @esri/calcite-components. - Before you deploy, read the versions that command prints for
-nextpre-releases. Do not just search the lockfile’s text: it can also hold a Calcite dependency range with a-nextlower bound, like the one quoted above. - A committed lock takes no patch on its own. Regenerate it on a schedule, at least once per
minor, and take the latest patch, not just the current minor; a caret, a tilde or an exact pin
only acts at that moment. Regenerate in a clean state, with the old lock and
node_modulesboth removed, as in our test above, so core, map components, toolkit, lumina and Calcite all resolve together. A clean regeneration re-resolves every dependency in the app, not only Esri’s, and an exact core pin has to be raised to the target version first or core stays where it is. Then test the whole app. - Move 5.0.x apps to the current minor, and plan as if only the latest minor gets patches.
- Do not reach for a tilde such as
~5.0.15to stay on 5.0: it holds core at 5.0.19, and the 5.0 line has had no patch since April; toolkit, lumina and Calcite still resolve past 5.0. - Before crossing a minor, read the release notes’ “removed” lines against the
.d.ts, especially if you touch beta or utility-network APIs. - Plan a screen-reader and keyboard pass on Search, Bookmarks and Popup when you move off 5.0.
References
- Maps SDK for JavaScript — FAQ (semantic versioning from 5.0.0, the patch, minor and major definitions, the escape clause, and deprecation until 6.0)
- Maps SDK for JavaScript — release notes for 5.0 (the move to semantic versioning and the 5.0 patch list)
- Maps SDK for JavaScript — release notes for 5.1 (the removed and deprecated API lines, the accessibility changes and the Calcite version)
- Maps SDK for JavaScript — view models (no breaking changes before 6.0 (Q1 2027), in the view-model context)
- Maps SDK for JavaScript — get started (CDN URLs in MAJOR.MINOR and MAJOR.MINOR.PATCH form)
- Maps SDK for JavaScript — licensing (no additional purchase with an API key; services may cost; an account is required)
- ArcGIS location services — FAQ (pay-as-you-go on Location Platform and credits on ArcGIS Online)
- Esri Support — ArcGIS Maps SDK for JavaScript life cycle (the General Availability table and the 5.1 summary card)
- Esri Product Life Cycle Policy (February 2026) (patches may be provided; support requires maintenance or a paid subscription)
- ArcGIS Blog — ArcGIS Maps SDK for JavaScript is Moving to Semantic Versioning (archived June 2026) (general availability until the next minor; patches to the latest minor; a patch is bug and security fixes; default version ranges pick up new minors)
- node-semver — README (caret and tilde ranges, and how pre-releases match)
- npm — npm ci (errors instead of updating the lock; installs are essentially frozen)
- npm — npm install (locked versions that satisfy the range are kept)
- npm registry — @arcgis/core (published versions, dates and dist-tags)
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