SDK version drift: how far behind SDK users really fall
What SDK version drift actually is
Almost nothing your software does is written by you. Payments come from one vendor, email from another, authentication from a third, error tracking from a fourth. Each of those arrives as an SDK: a package you install once and then mostly forget about.
The vendor keeps working on it. New versions ship, old behaviour is retired, and occasionally something that used to work stops working. Your copy does not move. It sits at whatever version it was on the day someone installed it, until a person deliberately goes and changes it.
Version drift is the gap that opens between those two facts. It is measured in two different ways, and confusing them is the most common mistake in this whole subject:
- Major versions behind. Whether the version you run is on an older major line than the one the vendor currently ships. This is the one that predicts breakage, because majors are where vendors are allowed to break things.
- Age. How long ago your installed version was published. This is the one that predicts security exposure and how painful the eventual upgrade will be.
A codebase can look fine on one measure and terrible on the other. That is not a hypothetical, and there is a table of it further down.
The measured gap: what 32 vendors show
In early August 2026 I measured 32 widely used vendors through the public npm registry: 355.7 million weekly installations spread across 7,190 distinct published versions. For each vendor I took the share of last week's downloads sitting on an older major than the current one, and the median age of the version being installed.
The worst end of the distribution is not close:
| Vendor | Package | % a major behind | Median age | Slowest 10% |
|---|---|---|---|---|
| Google APIs | googleapis | 100.0% | 699d | 1491d |
| Linear | @linear/sdk | 99.7% | 208d | 825d |
| OpenAI | openai | 99.0% | 227d | 467d |
| DocuSign | docusign-esign | 98.1% | 707d | 1699d |
| Auth0 | auth0 | 97.0% | 270d | 1053d |
| Square | square | 96.4% | 591d | 747d |
| Pinecone | @pinecone-database/pinecone | 95.8% | 467d | 1201d |
| Plaid | plaid | 95.5% | 528d | 1020d |
Google APIs sees literally none of its measured traffic on the current major. DocuSign's median install is 707 days old, and its slowest tenth is running code published over four and a half years ago. Across all 32 vendors, the worst single figure is a slowest-decile age of 1,893 days, which is five years and two months.
The pattern is that the older and larger the vendor, the further behind its customers sit. Newer vendors with smaller install bases look far healthier, and some of that is genuinely better release discipline, but a good deal of it is just that there has been less time for drift to accumulate.
The other end is more interesting than it first appears:
| Vendor | Package | % a major behind | Median age | Slowest 10% |
|---|---|---|---|---|
| Supabase | @supabase/supabase-js | 0.1% | 87d | 382d |
| Datadog | @datadog/datadog-api-client | 0.0% | 413d | 1022d |
| Temporal | @temporalio/client | 0.0% | 80d | 447d |
| AWS SDK | @aws-sdk/client-s3 | 0.0% | 132d | 698d |
Datadog scores a perfect zero on major-version lag while its median install is 413 days old. Nobody is behind, because the vendor has not shipped a new major for a long time. Everyone is still running year-old code. If your dashboard only tracks majors behind, that vendor looks green and is not.
The full report has all 32 rows, and every figure is linked to the public endpoint it came from.
Why teams fall behind, even good ones
The usual explanation is neglect, and it is wrong. Drift is what a rational team produces when it prioritises correctly.
Upgrading a vendor SDK ships no feature. It wins no customer, closes no deal, and appears on no roadmap. It has a real chance of breaking something that currently works. And the cost of not doing it is invisible right up until the moment it is enormous. Every incentive points at "later", and later is not a decision anyone remembers making.
Compare it to servicing a boiler. Nobody schedules it because they are excited about it. They schedule it because the failure mode is bad enough and familiar enough to override the fact that nothing is visibly wrong today. Vendor SDKs have the same failure mode and none of the familiarity, so they do not get scheduled.
What version drift actually costs
To check whether any of this hurts, I searched public GitHub discussions for engineers describing vendor changes that broke something or forced an unplanned migration. Restricted to discussions opened since January 2024 and de-duplicated, that produced 1,234 distinct discussions from 767 different engineers. Thirty-one percent were still unresolved when the research was done.
Those are the cases visible enough to be written down in public. The costs land in three places:
- Security exposure. A version published 377 days ago has had 377 days of disclosed vulnerabilities it will never receive fixes for, unless the vendor backports, and most do not past the current major.
- Fire-drill migrations. The upgrade does not get scheduled, so it happens under time pressure when something has already broken. That is the most expensive possible moment to do it.
- Compounding difficulty. Skipping one major is an afternoon. Skipping four is a project, because you now have to work through every intermediate breaking change at once with no working state in between.
How vendors make it worse
Drift is not only the customer's doing. The same 32 vendors ship breaking changes at a steady rate. Across the 27 vendors whose release histories could be parsed cleanly, the median is 1.3 breaking releases per year. The heaviest offenders are far above that:
| Vendor | Breaking releases/yr | Share of releases | Releases sampled |
|---|---|---|---|
| Linear | 17.3 | 34.4% | 270 |
| Sentry | 13.2 | 12.0% | 300 |
| Twilio | 9.8 | 42.0% | 257 |
| Shopify | 6.1 | 7.9% | 76 |
| Stripe | 5.1 | 5.7% | 300 |
| Temporal | 4.4 | 17.3% | 75 |
A mid-sized company with thirty vendor connections is therefore absorbing something on the order of forty breaking changes a year, arriving unannounced and unbatched, none of which it scheduled.
Self-audit: check your own SDK versions in an afternoon
The whole method above works on public data, which means it works on your data too. Here is the short version for a JavaScript project.
- Inventory what you actually have installed, not what the manifest
asks for.
package.jsonstates a range; the lockfile andnode_modulesstate a fact. Usenpm ls --depth=0. - Ask the registry when that exact version was published, and what
the current version is. Both come from
npm view <package> time dist-tags, which needs no authentication. - Compute age and major-version lag per dependency.
- Rank by age, not by name. The oldest thing you depend on is the one most likely to surprise you.
- Treat anything over six months old or a major behind as debt, with a ticket and an owner. Not optional, not "when there's time".
That is thirty lines of Node, and it needs nothing but network access:
// sdk-age.mjs — how far behind is every direct dependency?
import { execFileSync } from 'node:child_process';
const sh = (args) =>
execFileSync('npm', args, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
const tree = JSON.parse(sh(['ls', '--depth=0', '--json']));
const rows = [];
for (const [name, info] of Object.entries(tree.dependencies ?? {})) {
const installed = info.version;
if (!installed) continue; // unmet or linked
let meta;
try {
meta = JSON.parse(sh(['view', name, 'time', 'dist-tags', '--json']));
} catch {
continue; // private or unpublished
}
const published = meta.time?.[installed];
const latest = meta['dist-tags']?.latest;
if (!published || !latest) continue;
rows.push({
name,
installed,
latest,
ageDays: Math.floor((Date.now() - Date.parse(published)) / 86400e3),
majorsBehind: parseInt(latest, 10) - parseInt(installed, 10),
});
}
rows.sort((a, b) => b.ageDays - a.ageDays);
for (const r of rows) {
console.log(
r.name.padEnd(34) + r.installed.padEnd(14) + r.latest.padEnd(14) +
(r.ageDays + 'd').padEnd(10) + (r.majorsBehind > 0 ? r.majorsBehind + ' behind' : 'current'),
);
}
const stale = rows.filter((r) => r.ageDays > 180 || r.majorsBehind > 0);
console.log(`\n${rows.length} direct dependencies, ${stale.length} over six months old or a major behind.`);
Run it with node sdk-age.mjs in any project with a
node_modules. On a deliberately stale test project it prints:
package installed latest age majors behind
stripe 12.0.0 22.5.0 1223d 10 behind
openai 4.0.0 7.4.0 1091d 3 behind
@slack/webhook 7.0.0 8.0.0 1043d 1 behind
3 direct dependencies, 3 over six months old or a major behind.
If your own output has a line over 365 days, you are at the median of the 32 vendors measured here. That is not reassuring; it is the point of the research.
Common mistakes to avoid
- Trusting the lockfile. A lockfile guarantees the same version every install. That is its job. It is a record of what you froze, not evidence that what you froze is current.
- Measuring only majors behind. As the Datadog row above shows, a vendor that has not shipped a major in two years gives every one of its users a perfect score while they all run two-year-old code.
- Chasing latest blindly. Not every vendor confines breaking changes to majors. Some ship them in minors, which means "we only take minors automatically" is not the safety guarantee it sounds like.
- Ignoring transitive dependencies. The SDK you installed pulls its
own.
--depth=0is the right place to start and the wrong place to stop. - Counting CI as usage. Some registry download traffic is build runners re-pulling pinned versions rather than humans with a migration backlog. That inflates every ecosystem-wide number here, including mine, by an amount I cannot yet bound.
Could the gap close itself?
Nothing today closes it automatically. Dependency bots open pull requests, which is genuinely useful and also exactly where the work stops: somebody still has to read the changelog, understand the breaking change, edit the calling code, and be confident enough to merge it. The bot moves the version string. It does not do the migration.
Whether the rest of that can be automated is the open question this project exists to answer. I do not have a product and I am not selling one. I am trying to establish first whether the problem is as large and as mechanical as it looks.
Frequently asked questions
How much vendor software runs an outdated version?
Across 32 major vendors measured in August 2026, the typical vendor sees 78.6% of its live traffic coming from customers running at least one major version behind. 23 of the 32 have most of their users behind, not a minority.
How old is the SDK code running in production?
The median installed version is 377 days old. The slowest tenth of users runs versions several years old, with the worst measured case at 1,893 days.
How often do vendors ship breaking SDK changes?
1.3 per year at the median across the 27 vendors whose release histories could be parsed cleanly. The heaviest ship more than a dozen a year.
Is anyone actually hurt by SDK version drift?
1,234 public GitHub discussions from 767 engineers document vendor changes that broke something or forced an unplanned migration. 31% were unresolved when the research was done.
How do I check whether my own SDKs are outdated?
Inventory installed versions, ask the registry when each was published and what is current, then rank by age. The script above does it in one command.
Why doesn't anyone fix the gap automatically?
Because updating a vendor connection is never urgent until it is an emergency. It ships no feature, wins no customer, and appears on no roadmap, so it loses every prioritisation contest until something breaks.
The research behind this page
32 vendors, measured through public npm registry download counts by version and the vendors' own published release histories. 355.7 million installations across 7,190 distinct versions. Collected 3 to 7 August 2026, so the live figures will have moved since: expect small drift, not different conclusions. No vendor was contacted, none participated, and none reviewed the findings before publication.
Every figure above is checkable. Sources and method lists each one against the endpoint it came from, and the dataset is published as CSV and JSON under CC0. About the project and who runs it.
Download the full report (PDF)Last updated 13 August 2026.