← Back to Fixes

TypeScript in 2026: Install & Configure with Node.js 20+

Install TypeScript 5.4.5+ with npm 9.8+, configure for Node.js 20.x LTS, and resolve Supabase/Next.js type errors — with strict tsconfig.json and Jest/ESLint setup.

TL;DR#

If you run npm install typescript@latest and see Cannot find module '@types/node', Property 'auth' does not exist on type 'SupabaseClient', or ESLint/Prettier break after the upgrade, the root cause is usually a mismatch between your Node.js runtime, TypeScript version, and type declaration packages.

Fix it by upgrading Node.js to 20.x LTS, installing typescript@5.4.5 (or the current stable), @types/node@latest, and upgrading @supabase/supabase-js to the latest version, then setting "module": "esnext" and "moduleResolution": "bundler" in tsconfig.json (the Next.js defaults) along with esModuleInterop: true.

If that doesn’t work, check your engines field in package.json, verify npm ci runs in CI, and ensure ts-jest@29+ is installed for Jest compatibility.

What you'll see#

You run npm install typescript@latest in a fresh or existing project — maybe after seeing "npm typescript latest version" in Google — and npm run build fails with:

bash
src/lib/supabase.ts:3:23 - error TS2307: Cannot find module '@types/node' or its corresponding type declarations.

Then, when you try to use Supabase:

ts
const supabase = createClient(process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!)
const { data, error } = await supabase.auth.getSession()

You see:

bash
Property 'auth' does not exist on type 'SupabaseClient<Database, PublicSchemaName>'.

It happens when you run npm run dev, npm run build, or deploy to Vercel/GitHub Actions — especially in projects that started on Node.js 16 or 18, or where engines in package.json is outdated. The behavior is the same across macOS, Linux, and Windows.

Root cause#

TypeScript 5.4.5 (released April 2024) requires Node.js >=14.17 — so Node 16, 18, and 20 all satisfy it. npm’s engines field checking is a warning by default (not a hard block), so if you see install failures the cause is something else: a mismatched engines declaration in your own package.json, or a peer-dependency conflict with another tool.

TypeScript 5.4+ tightened module resolution and type inference, and some projects find they need @types/node installed explicitly when they import Node.js APIs (such as Buffer or process). Global DOM types like URL and Event live in lib.dom.d.ts and do not require @types/node.

The Supabase client (@supabase/supabase-js) has shipped several type-definition improvements across versions. If you see Property ‘auth’ does not exist on type ‘SupabaseClient’, the usual cause is an outdated version of the package or a tsconfig that does not match what the library expects — not a TypeScript runtime enforcement change (TypeScript erases all types at build time and adds no runtime checks).

The relevant code path in your project is:

ts
// src/lib/supabase.ts
import { createClient } from '@supabase/supabase-js'
 
const supabase = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL!,
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
 
export default supabase

This fails when @supabase/supabase-js is out of date and the installed type definitions do not match what TypeScript 5.4 resolves.

The fix#

Here’s the minimal, verified sequence that works in production:

  1. Upgrade Node.js to 20.x LTS (e.g., via nvm install 20.15.0 && nvm use 20)
  2. Install typescript@5.4.5 (or the current stable), @types/node@latest, and the latest @supabase/supabase-js
  3. Update tsconfig.json to use "module": "esnext", "moduleResolution": "bundler", esModuleInterop: true, and skipLibCheck: true (the Next.js create-next-app defaults)
  4. Ensure engines in package.json matches Node.js 20.x
bash
# Check current Node version
node -v
# If <20.x, upgrade:
nvm install 20.15.0 && nvm use 20.15.0

Then:

bash
# Install compatible versions
npm install typescript@5.4.5 @types/node@latest @supabase/supabase-js@latest

Update tsconfig.json:

json
{
  "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"]
}

That single change addresses the cause because "module": "esnext" + "moduleResolution": "bundler" are the defaults generated by create-next-app and what Next.js’s bundler (webpack/Turbopack) expects — using NodeNext in a Next.js project breaks module resolution because Next.js is not a Node.js ESM loader.

Step by step#

  1. Open your terminal and run nvm install 20.15.0 && nvm use 20.15.0.
  2. Run npm install typescript@5.4.5 @types/node@latest @supabase/supabase-js@latest.
  3. Open tsconfig.json and set "module": "esnext" and "moduleResolution": "bundler" (the Next.js defaults).
  4. Add "esModuleInterop": true and "skipLibCheck": true if missing.
  5. Update package.json to set "engines": { "node": ">=20.0.0" }.
  6. Run npm run build to verify.

Verify the fix#

Run:

bash
# Check versions
node -v && npm -v && npx tsc --version
 
# Expected output:
v20.15.0
9.8.1
Version 5.4.5

Then:

bash
# Install missing dev dependencies
npm install --save-dev ts-jest@29.1.1 @types/jest@29.5.13
 
# Run type check
npx tsc --noEmit

You should see:

bash
Found 0 errors.

If you’re still seeing Cannot find module '@types/node', run:

bash
npm install --save-dev @types/node@latest

If you see Property 'auth' does not exist, verify @supabase/supabase-js is up to date:

bash
npm ls @supabase/supabase-js
npm install @supabase/supabase-js@latest

If you're still seeing the error, two common variants exist:

Variant A — npm ERR! peer optional dependency failed#

This happens when @next/eslint-plugin-next has a peer dependency range that does not yet cover the TypeScript version you installed.

Fix by running:

bash
npm install --save-dev @next/eslint-plugin-next@latest

npm 9 will auto-resolve compatible versions — no manual downgrade needed.

Variant B — Jest fails with Cannot find module 'ts-jest'#

This occurs when ts-jest is before v29 and TypeScript is 5.4.5.

Fix by updating jest.config.js:

js
// jest.config.js
module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'],
  transform: {
    '^.+\\.(ts|tsx)$': 'ts-jest',
  },
}

Then run:

bash
npm install --save-dev ts-jest@29.1.1 @types/jest@29.5.13

Why this happens (and how to avoid it next time)#

TypeScript 5.4+ tightened module resolution and stricter type inference. It erases all types at compile time — no runtime type checks are added. If you see type errors after upgrading TypeScript, the cause is always a compile-time definition mismatch, not a runtime enforcement change.

The underlying invariant is: TypeScript’s type system is only as safe as the type definitions it reads. Outdated @supabase/supabase-js or @types/node packages are the most common culprit after a TypeScript version bump.

To avoid this next time:

  • Always declare "engines": { "node": ">=20.0.0" } in package.json.
  • Use npm ci (not npm install) in CI pipelines to enforce exact versions.
  • Run npm ls typescript before deploying to catch version mismatches.
  • For Next.js projects, keep "module": "esnext" and "moduleResolution": "bundler" in tsconfig.json — these are the create-next-app defaults and what Next.js’s bundler expects.

I cover this in detail in TypeScript Migration Guide 2024: Upgrade JavaScript Projects Safely, including how to migrate legacy CommonJS projects without breaking Jest or ESLint.

Related fixes & guides