TidyURLs
Go to Tools
BLOG
The TidyURLsJournal

Practical guides, tutorials, and insights about URLs, SEO, web development, and online marketing. Learn, troubleshoot, and get the most of the web.

Back to the Journal
TidyURLs Journal

Fix TypeScript Cannot Find Module and Name Errors

Practical insights, clear explanations, and useful ideas for understanding the web.

October 26, 20269 min read6 topics
Fix TypeScript Cannot Find Module and Name Errors
Explore the details
#TypeScript#Next.js#Debugging#Module Resolution#JavaScript#Web Development
October 26, 20269 min read

TypeScript’s “Cannot find module” and “Cannot find name” errors can look similar, but they point to different problems: one concerns resolving an import, while the other means a name is unavailable in the current scope or type environment. This guide shows how to tell compiler errors from bundler errors and troubleshoot dependencies, module settings, package exports, aliases, declarations, and file-name casing.

Key Takeaways

  • Read the full error and identify whether it names an imported module or an undeclared identifier.
  • Confirm the package or file exists before changing TypeScript configuration.
  • Choose moduleResolution to match your runtime or bundler; avoid changing it as a guess.
  • TypeScript paths aliases help the compiler resolve imports but do not rewrite them for your runtime or bundler.
  • A successful tsc run does not prove that Next.js or another bundler can resolve every import, and a bundler error is not necessarily a TypeScript error.

First identify which resolver is failing

A TypeScript diagnostic such as TS2307: Cannot find module 'some-package' or its corresponding type declarations means the TypeScript compiler cannot resolve the module or its types. TS2304: Cannot find name 'someName' means the identifier is not available in that scope or in the project’s known declarations. A missing global such as process may instead produce a related “Cannot find name” diagnostic.

A message from Next.js, webpack, or another bundler may report that it cannot resolve a module even when TypeScript accepts the code. Conversely, tsc --noEmit may fail even when a development bundler can build or serve the application. These tools can use different configuration and resolution rules.

Start by noting who produced the message, its error code if present, and the exact import or name. Then check the relevant layer:

SymptomFirst place to check
TS2307 on a package importInstallation, package entry points, TypeScript module resolution
TS2307 on a local importRelative path, extension rules, file name and casing
TS2304 on an identifierSpelling, scope, import, and available type declarations
Bundler says “module not found” but tsc passesBundler aliases, package exports, and bundler configuration
TypeScript fails but the app appears to runProject tsconfig, included files, and compiler-only type resolution

Check that the dependency is installed

For a package import, verify that the package is listed in the correct project’s package.json and installed in the workspace where the application runs. In a monorepo, a dependency installed at the repository root may not be available to every package, depending on the package manager and workspace setup.

npm ls some-package
npm install some-package

If the package provides no TypeScript declarations, check its documentation and package metadata before installing a separate type package. Some packages bundle their own types; others rely on a community package such as @types/some-package.

npm install -D @types/some-package

Do not install @types automatically: it may not exist, may be outdated, or may conflict with types already included by the package. For a missing Node global such as process, check that Node.js types are available to the project—for example, by installing @types/node if the project needs it—and that the relevant tsconfig includes those types. A Next.js project may already configure some of this; inspect its generated or existing configuration before adding redundant settings.

For a local file import, check the path relative to the importing file. For example, import { helper } from './utils/helper' points to a different location from import { helper } from '../utils/helper'.

Match moduleResolution to the project

TypeScript’s moduleResolution setting determines how it looks for imports. The right mode depends on where the code runs and how dependencies expose their entry points. Modern projects commonly use bundler for code resolved by a bundler, or node16/nodenext for Node.js module behavior. These modes differ in how they handle package metadata, file extensions, and package exports; they are not interchangeable fixes.

For a Next.js application, begin with the project’s existing tsconfig.json and the framework’s recommended configuration. Do not copy a setting from an unrelated Node application or change moduleResolution solely to silence one error. In particular, TypeScript requires compatible module and moduleResolution settings for some modes; consult the TypeScript reference for the pairing and behavior appropriate to your installed TypeScript version.

Inspect the effective configuration rather than relying on what you expect TypeScript to read:

npx tsc --showConfig
npx tsc --noEmit

In a workspace, run these from the affected package or specify its project configuration with -p. If the command-line compiler and editor disagree, check that the editor has opened the correct workspace and is using the project’s TypeScript version, then restart its TypeScript service after configuration changes.

Check package exports and entry points

A package can be installed and still fail to resolve if it does not expose the imported entry point in a way supported by the project’s module settings. Its package.json may define exports, types, or related entry-point metadata. When exports is present, a package may intentionally make only certain paths public. Importing an undocumented internal path such as some-package/dist/internal/file can therefore fail even if a similarly named file appears in node_modules.

Use the package’s documented public import first. Check its documentation and package.json for supported entry points, type declarations, and module formats. If the failure occurs only in one environment, compare that environment’s TypeScript and bundler resolution settings rather than bypassing the package’s export map with a deep import.

Align path aliases in TypeScript and the bundler

A paths mapping can tell TypeScript how to interpret an alias, but it does not rewrite the import in emitted JavaScript. The runtime or bundler must also understand the same alias. Next.js supports aliases configured through baseUrl and paths in tsconfig.json; other bundlers may require their own matching configuration.

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}

With this mapping, import { Button } from '@/components/Button' is intended to resolve to src/components/Button. Confirm that the target file exists and that the tool running the application uses the same mapping. If TypeScript accepts the alias but the bundler reports a resolution error, investigate the bundler’s configuration rather than assuming the compiler setting changed runtime behavior.

Add declarations only when the module really lacks types

A declaration file can describe an untyped module, but it should reflect the module’s actual API. For a simple asset import, a declaration may be appropriate if the project’s tooling supports that asset type. For a JavaScript package, prefer the package’s own declarations or a maintained @types package when available.

For example, a minimal declaration for a package that exports a string might look like this:

// src/types/legacy-label.d.ts
declare module 'legacy-label' {
  const label: string;
  export default label;
}

Put the file somewhere included by the project’s tsconfig.json. This declaration only tells TypeScript what to expect; it does not install the package, add a runtime implementation, or make an unsupported import work in the bundler. Avoid broad declarations such as declare module '*' as a general fix: they can hide unresolved imports and remove useful type checking.

For “Cannot find name” errors, first check spelling, scope, and imports. If the name is intended to be global, confirm that the appropriate type package is installed and included. If it is your own global declaration, ensure the declaration file is included and uses the right scope; an ambient declaration inside a module may not behave like a global declaration.

Check file-name casing across operating systems

An import that differs from the actual file name only by letter casing may work on a case-insensitive filesystem and fail on a case-sensitive one. For example, ./components/header may accidentally resolve locally when the file is named Header.tsx, but fail on a Linux build machine.

Match the import’s spelling and casing exactly to the file name, including directory names. Enable forceConsistentCasingInFileNames in tsconfig.json to have TypeScript check for inconsistent casing:

{
  "compilerOptions": {
    "forceConsistentCasingInFileNames": true
  }
}

If a case-only rename is not recognized by your version-control workflow, rename the file through an intermediate name and then to the intended casing, and verify the final change in version control.

Diagnostic checklist

Work through these checks in order, changing one thing at a time:

  1. Identify the reporter. Is the message from TypeScript, the editor, Next.js, or another bundler? Record the error code and exact failing import or name.
  2. Check spelling and location. Confirm the package name, relative path, export name, and exact file-name casing.
  3. Verify installation. Check the affected workspace’s package.json and run npm ls package-name or the equivalent for your package manager.
  4. Check package support. Review the package’s documented entry points, exports, and type declarations. Avoid unsupported deep imports.
  5. Inspect effective TypeScript settings. Run npx tsc --showConfig and check the project’s module, moduleResolution, paths, and included files.
  6. Test compiler resolution. Run npx tsc --noEmit from the correct project. This tests TypeScript, not the complete Next.js build.
  7. Test the application toolchain. Run the project’s normal build or development command. If TypeScript passes but this fails, focus on bundler/runtime resolution and alias configuration.
  8. Check environment differences. Compare the local and CI operating systems, workspace directory, installed dependencies, and file-name casing.
  9. Refresh tooling last. After correcting configuration or dependencies, restart the editor’s TypeScript service and development server if they still appear to use stale state.

Common Mistakes

  • Changing moduleResolution without matching it to the runtime, TypeScript version, or bundler.
  • Assuming paths rewrites imports for JavaScript output or configures every bundler automatically.
  • Installing @types when the package already includes declarations, or when no compatible @types package exists.
  • Fixing a package import while ignoring a different failure from Next.js or the bundler.
  • Using an internal package path that is not part of the package’s public exports.
  • Relying on case-insensitive local behavior and discovering a casing mismatch only in CI.
  • Adding a catch-all module declaration that makes the error disappear while concealing a broken import.

Best Practices

Keep aliases and module settings consistent with the tool that runs the code. Prefer public package entry points, maintain declarations that match real runtime behavior, and run both the TypeScript check and the application’s build in CI. In cross-platform projects, use consistent file-name casing and enable forceConsistentCasingInFileNames.

Conclusion

Treat “Cannot find module” as a resolution problem and “Cannot find name” as a scope or declaration problem, then determine whether TypeScript or the bundler is reporting it. Checking installation, package exports, configuration, aliases, declarations, and casing in that order usually narrows the cause without masking it.

References