Question
Fix TS2304 Cannot Find Name 'require' in TypeScript for Node.js
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
tsdare 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
requirethe 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.
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-inpathmodulepath.join(...)combines path parts safelyconsole.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.
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
| Approach | What it does | Good for | Drawbacks |
|---|---|---|---|
require('module') | CommonJS import style | Older Node.js code, many existing backend apps | Needs Node typings, less idiomatic in modern TS |
import * as moduleName from 'module' | Namespace import syntax | TypeScript-friendly module imports | Can be slightly more verbose |
import moduleName from 'module' | Default import syntax | Cleaner syntax in many modern projects | May require compiler options or compatible package exports |
declare var require: any | Silences missing-name error manually | Temporary quick fix | Loses type safety and is not the best long-term solution |
Node require vs RequireJS require
| Feature | Node.js require | RequireJS require |
|---|---|---|
| Main environment | Server-side Node.js | Browser/module loader setups |
| Module system | CommonJS | AMD |
| Typical use today | Backend apps, scripts, tools | Mostly older frontend setups |
| Relevant typings | @types/node | RequireJS typings |
Triple-slash references vs @types
| Method | Usage | Status |
|---|---|---|
| Triple-slash references | Manual inclusion of .d.ts files | Older style, still valid in some cases |
@types packages | Installed via npm and loaded by TypeScript | Standard modern approach |
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
requireis a Node/CommonJS feature, not a built-in TypeScript keyword- Node globals come from Node type definitions
requirejstypings are not the same as Node typings- Running
tsc file.tsmay differ from compiling withtsconfig.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
importsyntax 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.
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
Keep learning
Related questions
@Directive vs @Component in Angular: Differences, Use Cases, and When to Use Each
Learn the difference between @Directive and @Component in Angular, including use cases, examples, and when to choose each.
Accessing Input Value from EventTarget in TypeScript
Learn why EventTarget has no value property in TypeScript and safely read values from HTML input events in Angular applications.
Angular (change) vs (ngModelChange): What’s the Difference?
Learn the difference between Angular (change) and (ngModelChange), when each fires, and which one to use in forms and inputs.