Upgrade Checker (Node 26, Laravel 13 and TypeScript 7)
Paste your package.json, composer.json or tsconfig.json and see what breaks moving to Node 26, Laravel 13 or TypeScript 7, on which line, and the fix.
Which version are you moving to?
Read only in your browser. No request carries its contents.
grep -rnE "_stream_(readable|writable|duplex|transform|passthrough|wrap)|writeHeader\(|module\.register\(|createRequire|experimental-transform-types|localStorage|QuotaExceededError|fetch\(" --include='*.js' --include='*.mjs' --include='*.cjs' --include='*.ts' --include='*.mts' --include='*.cts' --exclude-dir=node_modules --exclude-dir=dist --exclude-dir=build . ; grep -rnE "FROM node:|node-version" Dockerfile* .github/ 2>/dev/nullRun it at the project root. Without this step only the files above are checked; with it, your code too. Do not paste your .env.
Result: Node 26
Paste the manifest and what breaks shows up here, sorted by impact.
Check by hand (cannot be detected from outside)
- Look for fossils in your dependencies too:
grep -rln "_stream_" node_modules --include="*.js" | head. Explained in the article → - After switching to 26,
npm rebuild(or deletenode_modulesand reinstall) and rebuild the Docker image on the new base. Explained in the article → - Run the suite with deprecations visible:
node --pending-deprecation --trace-deprecation ./node_modules/.bin/vitest run. Explained in the article → fetchheaders that come from a database, a form or another API: clean them (.trim()) where they enter. Undici 8 throwsTypeErroron a\ninstead of sanitizing it. Explained in the article →- During install, watch for
EBADENGINEwarnings: they name the dependency that does not declare Node 26. Explained in the article →
Rules taken from this site’s Node 26 breakdown and checked on 2026-09-27. /en/blog/what-breaks-upgrading-to-node-26/
What this tool does
Paste your project’s manifest —package.json if you are moving to Node 26, composer.json for Laravel 13, tsconfig.json for TypeScript 7— and it returns what breaks, sorted by impact, with the concrete change for each case. If you also paste the output of the step 2 command, it checks your code too and points at the file and line.
The rules are not generic: they come from this site’s breakdowns of what breaks when upgrading to Node 26, what actually breaks in Laravel 13 and what breaks in TypeScript 7. Every finding links the section that explains it, with before-and-after code.
Why grep output and not your repository
The step 2 command is a grep -rn that looks for only the patterns that change in that version. Its output carries the path and line number of every match (tests/Feature/CheckoutTest.php:18:…), so the tool can tell you where each problem is without seeing the rest of your code. Everything is analyzed in the browser and no request carries what you paste.
What it catches for Node 26
- An
engines.nodethat excludes 26, or that still allows Node 22 or older. - Native addons (
bcrypt,better-sqlite3,canvas…) that need a binary for ABI 147, andnode-sass, which will not get one. - Observability agents and loaders (
dd-trace,@opentelemetry/*,tsx…) that live in the now-deprecatedmodule.register()layer. - The
--experimental-transform-typesflag, which no longer exists. - In your code:
require('_stream_readable')and friends,res.writeHeader(), extensionlessrequirein ESM packages,fetchcalls Undici 8 may reject, and the Docker image or CI matrix still pinned to an older version.
What it catches for Laravel 13
laravel/frameworkandphpconstraints that do not allow 13, and, if you are on 10 or 11, the warning to go one major at a time.- The dependencies that move with the framework:
laravel/tinker ^3.0,phpunit ^12.0,pest ^4.0andlaravel/boost ^2.0. laravel/helpers, whosearray_first()clashes with the PHP 8.5 polyfill’s.- In your code:
VerifyCsrfTokenin tests and routes,upsert()with an emptyuniqueBy,$event->exceptionOccurred,QueueBusy, domain routes, polymorphic pivots,Strfactories,extendcallbacks, thepagination::defaultviews andJs::from.
What it catches for TypeScript 7
- The
tsconfig.jsonoptions that no longer exist:baseUrl,target: "es5",downlevelIteration,moduleResolution: "node"and"classic",module: "amd"/"umd"/"systemjs"/"none", andesModuleInterop,allowSyntheticDefaultImportsoralwaysStrictset tofalse. It reads the file with comments and trailing commas, the waytscdoes. - It hands you the rewritten
pathsblock withoutbaseUrl, each target relative to the tsconfig and starting with./. It is the change people get half right: remove onlybaseUrland you getTS5090. - From
package.json: whether yourtypescriptrange jumps to 7 without you deciding, which dependencies need the API 7.0 does not ship (typescript-eslint,ts-jest,ts-morph, Vue, Svelte, Astro, MDX), and the compatibility package that leaves you compiling with 6 without noticing. - From pasted output: whether
npx tscand the real binary disagree, theTS5101(“is deprecated and will stop functioning in TypeScript 7.0”) that gives away you are still on 6, and CI scripts expecting exit code2.
What no tool sees from outside
Some changes depend on your environment, not your files: Laravel’s cache and session prefixes when they are not pinned in .env, or fetch headers that come from a database. That is why the result ends with a manual checklist. A clean report is a good sign, not a green light: run the whole suite before moving production.
Frequently asked questions
What exactly does it check?
From the manifest, the version constraints and config: whether engines.node allows 26, whether php and laravel/framework allow 13, which tsconfig options TypeScript 7 removes and the dependencies that must move with them, plus packages known to cause trouble (native addons, observability agents, laravel/helpers). From the grep output, the code patterns that change: _stream_ modules, writeHeader, VerifyCsrfToken, upsert with an empty uniqueBy, exceptionOccurred and the rest of each version's list.
Is my code uploaded anywhere?
No. Everything is analyzed in your browser with JavaScript and no request carries what you paste. Even so, you do not need to paste the whole project: the step 2 command only extracts the lines that matter. Never paste your .env.
Why does it ask for grep output instead of the repository?
Because grep -rn output carries the path and line number of every match, so the tool can tell you where each problem is without seeing the rest of your code. You can also paste a single file if you prefer: it is numbered from line 1.
If nothing is flagged, can I upgrade safely?
It is a good sign, but not enough. Some changes are invisible from outside, like Laravel cache prefixes that depend on your .env, or dynamic fetch headers in Node. That is why the tool ends with a manual checklist. Run the whole suite before moving production.
I get "Option 'baseUrl' is deprecated and will stop functioning in TypeScript 7.0". What do I do?
That is error TS5101: you are still compiling with TypeScript 6 and it warns you the option no longer exists in 7. Silencing it with ignoreDeprecations does not help, because on 7 the compiler will not start. Paste your tsconfig.json into the tool and it returns the paths block rewritten without baseUrl, with the relative targets TypeScript 7 requires.
Will it cover other versions?
Yes. Every rule comes from a what-breaks-when-you-upgrade breakdown published on this site. The next ones will be the versions from that series that people look up most.
Reviews & ratings
No reviews yet. Be the first to leave one!
Related guides
Blog tutorials where this tool comes in handy.
Related tools
Others from the catalogue that pair well with this one.