Question

Fix TS2304 Cannot Find Name 'require' in TypeScript for Node.js

typescriptnode.jsdefinitelytyped

Question

I am setting up my first TypeScript application for Node.js using DefinitelyTyped typings, and I am seeing this error when compiling:

TS2304: Cannot find name 'require'

I run this command in the shell:

tsc movie.server.model.ts

My TypeScript file looks like this:

'use strict';

/// <reference path="typings/tsd.d.ts" />

/* movie.server.model.ts - definition of movie schema */

var mongoose = require('mongoose'),
    Schema = mongoose.Schema;

var foo = 'test';

The error is reported on this line:

var mongoose = require('mongoose')

My typings/tsd.d.ts file contains:

/// <reference path="node/node.d.ts" />
/// <reference path="requirejs/require.d.ts" />

I added these typings with:

```bash
tsd install node --save
tsd install require --save

The generated JavaScript still seems to run correctly, but I want to understand why TypeScript reports this error and what I am doing wrong.

Short Answer

By the end of this page, you will understand why TypeScript sometimes does not recognize require in a Node.js project, how type definitions provide global names like require, and how to correctly configure a TypeScript project so Node globals are available without compiler errors.

Concept

In TypeScript, JavaScript code can run perfectly fine at runtime even when the compiler reports type errors. That happens because TypeScript checks types and known names before execution, while Node.js simply runs JavaScript.

The name require is not built into TypeScript itself. It is a Node.js-specific global function used in CommonJS modules. TypeScript only knows about it if your project includes the correct type definitions for Node.

That is why this error appears:

TS2304: Cannot find name 'require'

TypeScript is saying: "I do not know what require is."

Why this happens

Common causes include:

  • Node type definitions are missing
  • The type definitions are installed but not included correctly
  • The file is compiled outside the expected project configuration
  • Old typings tools such as tsd are used with a setup that TypeScript does not fully pick up
  • The project is mixing browser/module typings and Node typings in a confusing way

Why it matters

If TypeScript cannot see Node globals like require, module, process, or __dirname, you will keep getting compiler errors in server-side code. In real projects, correct typing gives you:

  • autocomplete
  • safer refactoring
  • better error checking
  • more accurate editor support

In modern TypeScript projects, this is usually solved by installing @types/node and using a proper tsconfig.json.

Mental Model

Think of TypeScript as a proofreader that checks whether every word in your code is defined in its dictionary.

Node.js knows the word require, but TypeScript does not automatically include the Node.js dictionary.

So your code is like writing this sentence:

Please require the package.

Node.js says: "Yes, that word makes sense."

TypeScript says: "I have never seen that word before."

Installing and including Node type definitions is like handing TypeScript the correct dictionary for Node.js development.

Take Quiz

Syntax and Examples

Core idea

In Node.js CommonJS code, require is used to import modules:

const fs = require('fs');

TypeScript accepts this only when Node type definitions are available.

Modern fix

Install Node types:

npm install --save-dev @types/node

Then use a tsconfig.json like this:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "strict": true,
    "types": ["node"]
  }
}

Now this works:

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

Preferred modern syntax

In many TypeScript projects, import is preferred over require:

import mongoose from 'mongoose';

const Schema = mongoose.Schema;

Depending on the library and compiler settings, you may also see:

import * as mongoose from 'mongoose';

const Schema = mongoose.Schema;

Beginner-friendly example

const path = require('path');

const fullPath = path.join('/users', 'alex', 'notes.txt');
console.log(fullPath);

What this does

  • require('path') loads Node's built-in path module
  • path.join(...) combines path parts safely
  • console.log(...) prints the result

If Node types are missing, TypeScript may complain about require even though Node can still run the generated JavaScript.

Step by Step Execution

Consider this example:

const os = require('os');
const platform = os.platform();
console.log(platform);

Step by step

1. TypeScript reads the file

TypeScript scans the code and finds require('os').

2. It checks whether require is known

If Node type definitions are loaded, TypeScript knows that require is a function available in CommonJS environments.

If Node type definitions are not loaded, it stops with:

TS2304: Cannot find name 'require'

3. If compilation still emits JavaScript

Depending on compiler settings, TypeScript may still produce this JavaScript:

var os = require('os');
var platform = os.platform();
console.log(platform);

4. Node.js runs the JavaScript

When Node executes the file, it already knows what require means, so the program works.

Key lesson

A runtime environment and a type-checking environment are not the same thing:

  • Node.js runtime knows require
  • TypeScript compiler only knows it if types are configured correctly

Real World Use Cases

This concept appears in many real Node.js projects.

Server applications

const express = require('express');
const app = express();

If Node types are missing, TypeScript may complain before you even build your server.

Database connections

const mongoose = require('mongoose');

This is similar to your example. Many backend apps load database libraries this way.

Reading files

const fs = require('fs');
const text = fs.readFileSync('data.txt', 'utf8');

Loading configuration

const path = require('path');
const envFile = path.join(__dirname, '.env');

This also depends on Node globals like __dirname, which come from Node type definitions.

Scripts and tooling

Build scripts, migration scripts, seed scripts, and CLI tools often rely on Node globals and CommonJS imports.

Take Quiz

Real Codebase Usage

In real codebases, developers usually solve this issue in one of these ways.

1. Use project-level configuration

Instead of compiling one file with:

tsc movie.server.model.ts

teams usually use:

tsc

with a tsconfig.json. This ensures consistent compiler settings and type loading.

2. Install @types/node

Modern projects use:

npm install --save-dev @types/node

This is the standard way to make Node globals available.

3. Prefer import in TypeScript code

Many codebases write:

import fs from 'fs';

or

import * as fs from 'fs';

instead of require, especially in newer TypeScript setups.

4. Use guard clauses and validation after import

Once a module is imported, codebases often validate configuration early:

const configPath = process.env.CONFIG_PATH;
if (!configPath) {
  throw new Error('CONFIG_PATH is required');
}

This pattern depends on Node globals such as process.

5. Keep environment types separate

Large projects may have separate frontend and backend configs. Browser code should not automatically receive Node globals unless needed.

Practical takeaway

For real projects, the most reliable setup is:

  • use tsconfig.json
  • install @types/node
  • compile the project, not just one file
  • use the module system consistently

Common Mistakes

1. Installing typings but not loading them correctly

A beginner may install types but compile in a way that does not use the expected project setup.

Problem

tsc movie.server.model.ts

This can behave differently from compiling through a configured project.

Better

tsc

with a proper tsconfig.json.

2. Assuming runtime success means TypeScript is configured correctly

Your JavaScript may run, but TypeScript can still be missing type information.

  • Runtime success means Node understands the code
  • Compiler success means TypeScript understands the code too

These are related, but not the same.

3. Mixing old typings approaches with modern TypeScript expectations

Older projects used tsd and triple-slash references:

/// <reference path="typings/tsd.d.ts" />

Modern TypeScript projects usually do not need this for package typings.

Instead, they use:

npm install --save-dev @types/node

4. Using the wrong module typing

requirejs typings are for RequireJS, which is different from Node's CommonJS require.

This line can confuse the setup:

/// <reference path="requirejs/require.d.ts" />

Node's require and RequireJS require are not the same thing.

5. Declaring require manually as a shortcut

Some people silence the error like this:

declare var require: any;
const mongoose = require('mongoose');

This removes the error, but it also throws away type safety.

Use Node typings instead whenever possible.

6. Using broken import syntax for the module

Depending on your TypeScript configuration, this may fail:

import mongoose from 'mongoose';

If default imports are not enabled for that package, use:

import * as mongoose from 'mongoose';

or configure the compiler appropriately.

Comparisons

ApproachWhat it doesGood forDrawbacks
require('module')CommonJS import styleOlder Node.js code, many existing backend appsNeeds Node typings, less idiomatic in modern TS
import * as moduleName from 'module'Namespace import syntaxTypeScript-friendly module importsCan be slightly more verbose
import moduleName from 'module'Default import syntaxCleaner syntax in many modern projectsMay require compiler options or compatible package exports
declare var require: anySilences missing-name error manuallyTemporary quick fixLoses type safety and is not the best long-term solution

Node require vs RequireJS require

FeatureNode.js requireRequireJS require
Main environmentServer-side Node.jsBrowser/module loader setups
Module systemCommonJSAMD
Typical use todayBackend apps, scripts, toolsMostly older frontend setups
Relevant typings@types/nodeRequireJS typings

Triple-slash references vs @types

MethodUsageStatus
Triple-slash referencesManual inclusion of .d.ts filesOlder style, still valid in some cases
@types packagesInstalled via npm and loaded by TypeScriptStandard modern approach
Take Quiz

Cheat Sheet

Quick fix

npm install --save-dev @types/node
{
  "compilerOptions": {
    "module": "commonjs",
    "types": ["node"]
  }
}

CommonJS syntax

const fs = require('fs');

Modern TypeScript syntax

import * as fs from 'fs';

or sometimes:

import fs from 'fs';

Why TS2304 happens

TypeScript does not know the global name require because Node type definitions are missing or not loaded.

Important rules

  • require is a Node/CommonJS feature, not a built-in TypeScript keyword
  • Node globals come from Node type definitions
  • requirejs typings are not the same as Node typings
  • Running tsc file.ts may differ from compiling with tsconfig.json

Temporary workaround

declare var require: any;

Use only as a last resort.

Best practice

  • install @types/node
  • use tsconfig.json
  • compile the project with tsc
  • use import syntax in new TypeScript code when possible

FAQ

Why does JavaScript run even though TypeScript reports an error?

TypeScript checks types and known names before runtime. Node.js can still execute the generated JavaScript if the emitted code is valid.

What does TS2304 mean?

It means TypeScript found a name that has not been declared or typed in the current compilation context.

Why is require unknown in TypeScript?

Because require is not a built-in global in TypeScript. It becomes known when Node type definitions are included.

Do I need requirejs typings for a Node.js app?

Usually no. RequireJS is different from Node's CommonJS module system.

What is the modern way to fix this in Node.js?

Install @types/node, use a tsconfig.json, and prefer import syntax where appropriate.

Can I just declare require manually?

Yes, but it is only a shortcut. You lose proper typing and editor support.

Should I compile a single file or the whole project?

In most real projects, compile the whole project with tsc and a tsconfig.json.

Is require still valid in TypeScript?

Yes. It is still valid in CommonJS-based Node.js projects, though many modern projects prefer ES module import syntax.

Take Quiz

Mini Project

Description

Build a small Node.js TypeScript script that loads a built-in Node module and prints system information. This demonstrates how to fix the Cannot find name 'require' error by setting up Node typings correctly.

Goal

Create a TypeScript Node.js script that uses a Node module without compiler errors.

Requirements

Requirement 1

Take Quiz

Keep learning

Related questions

View more