In TypeScript, module loading is a fundamental concept. With the advent of ECMAScript 2015 (ES6), the import statement was introduced as a modern alternative to the traditional require function used in Node.js.
In this blog, we will discuss a detailed comparison between require and import, their usage in TypeScript, and practical examples to help you understand their differences and benefits.
Understand Require and Import in TypeScript
What is Require?
In TypeScript, require is a function that is part of the CommonJS module system, primarily used in Node.js. It allows you to dynamically and synchronously include modules in your code. The syntax is straightforward:
const express = require('express');What is Import?
In TypeScript, import is part of the ES6 module system, which is a standardized way of including modules in JavaScript. It is more flexible and powerful than require, supporting static analysis and better optimization by modern JavaScript engines. The basic syntax looks like this:
import express from 'express';Key Differences Between Require and Import in TypeScript
Syntax
- require: Uses the CommonJS syntax, which is function-based.
- import: Uses the ES6 module syntax, which is more declarative.
Module Loading
- require: Loads modules synchronously, which can block the execution if the module is large.
- import: Supports both synchronous and asynchronous loading, allowing for better performance and non-blocking code.
Static vs. Dynamic
- require: Modules can be loaded dynamically at runtime.
- import: Modules are statically analyzed at compile time, leading to better optimization and error checking.
Check out: For Loop in TypeScript
Compatibility
- require: Works seamlessly with Node.js and CommonJS modules.
- import: Designed for ES6 modules, but can be used with CommonJS modules using transpilers like Babel or TypeScript.
Using require in TypeScript
In TypeScript, you can use require just like in plain JavaScript. However, TypeScript provides type checking and other features that make it more powerful. Here’s an example of using require in a TypeScript file:
const express = require('express');
// Import types only (using ES module import for types)
import type { Request, Response } from 'express';
const app = express();
app.get('/', (req: Request, res: Response) => {
res.send('Hello World!');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});Output:

Pros of Using require
- Dynamic Loading: You can conditionally load modules.
- Simplicity: Easier to use in a Node.js environment.
- Backward Compatibility: Works with older JavaScript codebases.
Check out: Check if a Value Exists in an Enum in TypeScript
Cons of Using require
- Synchronous Loading: Can block the event loop.
- Less Optimization: Not as optimized as import modern JavaScript engines.
Using import in TypeScript
TypeScript fully supports ES6 modules, and you can use import to include modules in your code. Here’s how you can use import in a TypeScript file:
import express from 'express';
const app = express();
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});Output:

Pros of Using import
- Static Analysis: Allows for better type checking and error detection.
- Asynchronous Loading: Can improve performance by non-blocking module loading.
- Modern Syntax: Aligns with the latest JavaScript standards.
Check out: Check if an Object is Empty in TypeScript
Cons of Using import
- Complexity: Slightly more complex to set up, especially in older environments.
- Transpilation Required: Often requires a transpiler like Babel or TypeScript for compatibility with older JavaScript engines.
Practical Examples
Example 1: Conditional Loading with Require
let db;
if (process.env.NODE_ENV === 'production') {
db = require('./db.prod');
} else {
db = require('./db.dev');
}Example 2: Static Import with import
import { connect } from './db';
connect();Example 3: Dynamic Import with import
(async () => {
if (process.env.NODE_ENV === 'production') {
const db = await import('./db.prod');
db.connect();
} else {
const db = await import('./db.dev');
db.connect();
}
})();Summary Table
| Feature | require | import |
|---|---|---|
| Syntax | CommonJS function-based | ES6 declarative |
| Module Loading | Synchronous | Synchronous and Asynchronous |
| Static vs. Dynamic | Dynamic | Static |
| Compatibility | Node.js, CommonJS | ES6, with transpilers for CommonJS |
| Performance | Can block the event loop | Optimized for modern engines |
| Complexity | Simple in Node.js environment | More complex setup |
| Type Checking | Limited | Enhanced with TypeScript |
Conclusion
In this blog, we explored the differences between require and import in TypeScript. We covered their syntax, use cases, and key advantages. While require is useful for dynamic and legacy scenarios, import is better suited for modern TypeScript development due to its cleaner syntax and improved performance.
You may also like to read:
- Loose vs Strict Equality in TypeScript
- Convert JSON to TypeScript Interface
- Unknown vs Any in TypeScript

I am Bijay Kumar, a Microsoft MVP in SharePoint. Apart from SharePoint, I started working on Python, Machine learning, and artificial intelligence for the last 5 years. During this time I got expertise in various Python libraries also like Tkinter, Pandas, NumPy, Turtle, Django, Matplotlib, Tensorflow, Scipy, Scikit-Learn, etc… for various clients in the United States, Canada, the United Kingdom, Australia, New Zealand, etc. Check out my profile.