Fix "Could Not Find Declaration File for react/jsx-runtime"

jsx-runtime typescript react tsconfig declaration files

The "could not find declaration file for react/jsx-runtime" error means TypeScript can't locate type declarations for React's automatic JSX transform. The fix is almost always one of three things: you're missing @types/react, your tsconfig.json has the wrong jsx or moduleResolution setting, or your @types/react version is too old to include the jsx-runtime exports. Install the correct types, update your config, and the error disappears.

Step 1: Install or Update @types/react

The react/jsx-runtime module was added in React 17. If your @types/react package predates version 17, the declaration file doesn't exist. Install the latest types that match your React major version.

# Install types matching React 18.
npm install --save-dev @types/react @types/react-dom

# Verify the installed version is 18.x.
npm ls @types/react

Step 2: Fix tsconfig.json

Two settings matter here. First, jsx must be set to "react-jsx" (or "react-jsxdev" for development) instead of the legacy "react" value. The "react-jsx" mode tells TypeScript to import from react/jsx-runtime automatically, which is the exact module it can't find when things are misconfigured. Second, moduleResolution must be "node", "node16", or "bundler" so that TypeScript knows how to walk into node_modules and find the declaration files.

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "jsx": "react-jsx",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": false,
    "types": ["react", "react-dom"]
  },
  "include": ["src"]
}

Why "react-jsx" Instead of "react"

The legacy "jsx": "react" setting transforms JSX into React.createElement() calls and requires import React from 'react' at the top of every file. The newer "react-jsx" setting uses the automatic runtime introduced in React 17, which imports helpers from react/jsx-runtime behind the scenes. If you set "jsx": "react-jsx" but TypeScript can't resolve that module path, you get the declaration file error. The module path resolution depends on both @types/react being installed and moduleResolution being set correctly.

A common gotcha: setting "moduleResolution": "classic" breaks this entirely because Classic resolution doesn't look inside node_modules. If you inherited a legacy tsconfig, check this value first.

Step 3: Handling Props Typing Errors That Follow

After the jsx-runtime error is fixed, you might encounter a cascade of props typing errors in your components. This happens because TypeScript can now actually type-check your JSX. The following example shows how to type a function component with props.

interface UserCardProps {
  name: string;
  age: number;
  // Optional prop with a default value.
  isActive?: boolean;
}

function UserCard({ name, age, isActive = true }: UserCardProps) {
  return (
    <div className={isActive ? "active" : "inactive"}>
      <h2>{name}</h2>
      <p>Age: {age}</p>
    </div>
  );
}

If you're passing children, use React.PropsWithChildren<YourProps> or add children: React.ReactNode to your interface. The older React.FC type used to include children implicitly, but as of @types/react v18, it no longer does. This is the most common surprise after upgrading types.

import type { ReactNode } from "react";

interface LayoutProps {
  title: string;
  // Explicitly declare children.
  children: ReactNode;
}

function Layout({ title, children }: LayoutProps) {
  return (
    <main>
      <h1>{title}</h1>
      {children}
    </main>
  );
}

The Nuclear Option: skipLibCheck

Setting "skipLibCheck": true in your tsconfig silences the error by telling TypeScript to skip type-checking all .d.ts files. Many popular templates like Vite and Next.js enable this by default for build speed. It works, but it hides real type mismatches in your dependencies. Use it as a workaround while you track down the root cause, not as the permanent fix. If you see this error only in CI but not locally, the cause is almost always a mismatched @types/react version pinned in your lockfile. Delete node_modules and your lockfile, then reinstall.

# Clean install to resolve lockfile version mismatches.
rm -rf node_modules package-lock.json
npm install

# Confirm no duplicate @types/react versions exist.
npm ls @types/react

Monorepo and Path Alias Gotcha

In monorepos that use workspaces (npm, pnpm, or Yarn), @types/react might be hoisted to the root node_modules while your package-level tsconfig.json points typeRoots only at the local node_modules/@types. Either remove the typeRoots override so that TypeScript uses its default resolution, or add the root node_modules/@types path explicitly. Similarly, if you use path aliases like "paths": { "@/*": ["./src/*"] }, make sure that they don't accidentally shadow module resolution for react or react/jsx-runtime.

← Back to all articles