How to Set Up Absolute Imports in Node.js and TypeScript with Nodemon
TLDR
Switching from relative to absolute imports in TypeScript can greatly enhance code readability and manageability. By updating the
tsconfig.json
settings to use a fixed path from your project's root, you can simplify import statements. Additionally, when using nodemon and ts-node for development with absolute imports, you need to installtsconfig-paths
and configure it intsconfig.json
. Updating these configurations ensures smooth functioning of absolute imports in your TypeScript project.
Introduction
I was working on a TypeScript project when I noticed messy relative imports. I'm sure you too may have stumbled across something like this. Relative imports make our code verbose and hard to understand where things are coming from, especially when files are nested in folders. For every relative import I write, I have to calculate the number of dots and slashes from the current file.
// example of relative imports
import User, { validateUser } from '../../models/user';
import { cors, middleware } from '../../middlewares';
import connectDb from '../../db';
Absolute imports to the rescue, they make your code cleaner and easier to manage by letting you use a fixed path from the root of your project instead of complex relative paths. This improves readability, and avoids confusion from navigating nested directories. For instance:
// example of absolute imports
import User, { validateUser } from '@/models/user';
import { cors, middleware } from '@/middlewares';
import connectDb from '@/db';
To switch from relative to absolute imports, make sure your tsconfig.json
has these configurations set to appropriate values:
// tsconfig.json
{
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
// configurations for absolute imports
"rootDir": "./src",
"baseUrl": "./",
"paths": {
"@/*": [
"./src/*"
]
},
"outDir": "./dist",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
}
}
Also, since we use nodemon
for hot module reloading on the development server, it needs ts-node
, a TypeScript compiler, to work. This setup works perfectly with relative imports. However, with absolute imports, we need to install another development dependency and add some configuration to tsconfig.json
.
# install this package as development dependency
npm install -D tsconfig-paths
// tsconfig.json(final)
{
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"rootDir": "./src",
"baseUrl": "./",
"paths": {
"@/*": [
"./src/*"
]
},
"outDir": "./dist",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
},
// This module registers the TypeScript path resolver,
// which enables the resolution of TypeScript paths.
"ts-node": {
"require": ["tsconfig-paths/register"]
}
}
Now, if we run the project in development using nodemon
, absolute imports work just fine. Here's an example of how the scripts
section in package.json
looks:
...
"scripts": {
"build": "tsc",
"start": "nodemon ./src/index.ts",
}
...
I'm using tsc
for production build and ts-node
for development server through nodemon
. Deciding between tsc
and ts-node
requires understanding how they work internally and what purpose they serve. To learn more about it, read here.
Subscribe to my newsletter
Read articles from Utkarsh Dhiman directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by