TypeScript in 2026: Install & Configure with Node.js 20+
Install the latest TypeScript on Node 20 LTS, align @types/node and @supabase/supabase-js, and fix the errors after a TS upgrade.
The search query "npm typescript latest version" usually ends with a broken build. You run npm install typescript@latest, and the next npm run build throws one of:
src/lib/supabase.ts:3:23 - error TS2307: Cannot find module '@types/node' or its corresponding type declarations.or, the moment you touch the Supabase client:
const { data, error } = await supabase.auth.getSession()Property 'auth' does not exist on type 'SupabaseClient<Database, PublicSchemaName>'.It happens in npm run dev, npm run build, and in CI (Vercel/GitHub Actions) — especially in projects that started on Node.js 16 or 18, or where package.json has a stale engines field. The behavior is identical on macOS, Linux, and Windows.
The invariant that explains every symptom#
TypeScript's type system is only as safe as the type definitions it reads. It erases all types at compile time and adds no runtime checks. So when a TypeScript upgrade breaks your build, the cause is always a compile-time definition mismatch — never a runtime enforcement change.
Three things must move together, or you get the errors above:
- The TypeScript version itself.
@types/node— the type definitions for Node.js APIs (Buffer,process, etc.). TypeScript 5.x tightened module resolution, so projects that used to get these transitively now need them installed explicitly.@supabase/supabase-js— its type definitions are versioned separately from the runtime. An outdated client paired with a newer TS resolver producesProperty 'auth' does not exist.
npm's engines field is a warning by default, not a hard block — npm's own package.json documentation confirms it "is advisory only" unless the engine-strict config flag is set — so if you see install failures, look at a package.json engines mismatch or a peer-dependency conflict, not at Node.js itself.
The alignment fix#
# 1. Land on Node.js 20.x LTS
node -v
nvm install 20 && nvm use 20
# 2. Move TypeScript, the Node types, and the Supabase client forward together
npm install typescript@latest @types/node@latest @supabase/supabase-js@latest
# 3. Declare what you actually run
# in package.json:
# "engines": { "node": ">=20.0.0" }Then make tsconfig.json match what Next.js's bundler expects. create-next-app ships these defaults; using NodeNext in a Next.js project breaks resolution because Next.js is not a Node.js ESM loader.
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022", "DOM"],
"module": "esnext",
"moduleResolution": "bundler",
"esModuleInterop": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"jsx": "preserve",
"incremental": true,
"paths": { "@/*": ["./src/*"] }
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}"module": "esnext" + "moduleResolution": "bundler" is the single change that resolves most "Cannot find module" errors after a TS bump, because it matches what webpack and Turbopack actually do. Per TypeScript's own moduleResolution reference, bundler mode is built specifically for this: unlike the node16/nodenext modes it never requires file extensions on relative imports, mirroring how bundlers resolve modules in practice.
Verify everything lines up#
node -v && npm -v && npx tsc --version
# v20.x.x
# 10.x.x
# Version 5.x.x
npx tsc --noEmit
# Found 0 errors.If Cannot find module '@types/node' persists:
npm install --save-dev @types/node@latestIf Property 'auth' does not exist persists, the Supabase client is still stale:
npm ls @supabase/supabase-js
npm install @supabase/supabase-js@latestTwo stubborn variants#
npm ERR! peer optional dependency failed — @next/eslint-plugin-next has a peer range that does not yet cover the TypeScript you installed. Fix with npm install --save-dev @next/eslint-plugin-next@latest; npm 9+ auto-resolves compatible versions, no manual downgrade needed.
Jest: Cannot find module 'ts-jest' — ts-jest before v29 does not understand TypeScript 5.x. Update jest.config.js to preset: 'ts-jest' and install ts-jest@^29 @types/jest@^29.
Keep it from happening again#
- Declare
"engines": { "node": ">=20.0.0" }inpackage.jsonso a mismatched runtime fails fast. - Use
npm ci(notnpm install) in CI to enforce the lockfile. - Run
npm ls typescript @supabase/supabase-js @types/nodebefore deploying to catch version drift. - In Next.js projects, keep
"module": "esnext"and"moduleResolution": "bundler"— they are thecreate-next-appdefaults and what the bundler expects.
TS7016 in a pnpm or Yarn PnP monorepo#
Everything above assumes npm's flat node_modules, where a hoisted @types/node
anywhere in the tree is usually resolvable from any package. pnpm and Yarn's
Plug'n'Play mode both deliberately break that assumption, and a TypeScript upgrade
inside a monorepo built on either one produces the same TS7016: Could not find a declaration file for module error for a structurally different reason.
pnpm's node_modules is a symlink farm by design — a package can only resolve
dependencies it declares directly in its own package.json, not whatever happens to be
hoisted elsewhere in the workspace. If @types/node is installed only at the
monorepo root and a workspace package imports something that needs it without
declaring it as its own dependency, that package's tsc run fails to find it — even
though the exact same file exists on disk two directories up. The fix is to add the
type package as an explicit devDependency of the package that actually needs it,
not just at the root:
# inside packages/api, not the monorepo root
pnpm add -D @types/nodeYarn PnP goes further: it removes node_modules entirely and resolves packages from a
single .pnp.cjs manifest, so any code that expects to find a node_modules folder
on disk — including some older tsc plugins and a handful of build tools that
walk the filesystem directly instead of using Node's resolution API — breaks
regardless of version pinning. When a TypeScript upgrade surfaces resolution errors
specifically inside a PnP repo, yarn dlx @yarnpkg/sdks vscode (or the equivalent for
your editor/build tool) regenerates the SDK shims that let TypeScript's language
service and CLI understand PnP's virtual file layout — a step that has no npm
equivalent because npm's flat layout doesn't need it.
Both cases are diagnosable the same way: npm ls-style dependency resolution differs
per package manager, so a working tsc --noEmit at the monorepo root proves nothing
about whether an individual workspace package can resolve its own types. Run the
check from inside the specific package that's failing, not the root, before assuming
the fix from the flat-node_modules case above applies unchanged. For the broader
class of "cannot find module" declaration errors this overlaps with, see
Fix TS7016: Could Not Find Declaration File for Module.
Further reading: TypeScript 6.0 Migration: What Actually Breaks in Next.js/Supabase, Next.js Server Actions with Supabase: Complete Guide.
Still stuck? Paste your error.
Paste the error message or stack trace — we check it against every fix and tool on the site.
Related fixes & guides
- Fix: Event handlers cannot be passed to Client props
- Fix: Multiple GoTrueClient instances detected (Supabase)
- Fix: Next.js middleware not triggering
- Type Safety Guide for Next.js + Supabase in TypeScript
- Next.js 16 Removed next lint: ESLint 9 Migration
- Production RAG with Supabase pgvector and Next.js
- Custom font is not working in Tailwind CSS: fix @font-face
- Fix UnhandledSchemeError: Reading from "node:buffer"
- Fix tsc SyntaxError: Unexpected token '?' on old Node.js
- Fix: useRouter query undefined on first render

