
Setting Up a Node.js, TypeScript, and Express Project
Node.js is a popular runtime environment for building server-side applications. It allows you to write JavaScript code that runs on the server, making it easy to build scalable and performant applications. TypeScript, a superset of JavaScript, adds static typing to the language, enhancing error detection and code maintainability. Express, a minimal and flexible Node.js web application framework, offers a robust set of features for building web and mobile applications. In this tutorial, we'll walk through how to set up a Node.js, TypeScript, and Express project from scratch.
Why Node.js, TypeScript, and Express?
Before we jump into setting up our project, let's take a moment to understand why Node.js, TypeScript, and Express are a great combination for building web applications.
- Node.js: Node.js is fast, lightweight, and scalable, making it a great choice for building server-side applications.
- Typescript: Adds type safety to JavaScript, making your code more predictable and easier to debug.
- Express: A minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications.
Prerequisites
To get started, make sure you have Node.js and npm (Node Package Manager) installed on your machine. You can verify this by running:
node -v
npm -v
If you don't have it installed, head over to the Node.js website and install it.
Get Coding
Initialize your project
- Create your project folder and enter into it by running:
mkdir node-typescript-express
cd node-typescript-express
- Next, initialize Node.js to add a
package.jsonfile by running:
npm init -y
Install essential packages
Now let's install a few npm packages that we'll need to build this project:
npm install express
npm install -D typescript @types/node @types/express ts-node nodemon
This installs Express and TypeScript essentials. We’ve used the -D flag for typescript, @types/node, @types/express, ts-node, and nodemon because these are developer dependencies, meaning they’re only needed during development.
Configuring typescript
Next, we'll configure typescript. Create a tsconfig.json file in the project's root folder by running:
npx tsc --init
Now, let’s adjust a few settings inside tsconfig.json:
{
"compilerOptions": {
"target": "ES6",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"outDir": "./dist"
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
These options specify that we’ll compile to ES6, use CommonJS modules, and output our files into a dist folder.
Using a structure for our project
- Create a
srcfolder in the root directory to hold your TypeScript files:
mkdir src
- Inside
src, create anindex.tsfile. This will be our entry point.
Writing the Server Code
Open src/index.ts and set up a simple Express server:
import express, { Request, Response } from 'express';
const app = express();
const PORT = process.env.PORT || 3000;
app.get('/', (req: Request, res: Response) => {
res.send('Hello, TypeScript with Express!');
});
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
Here, we import Express, define a basic route for the root path (/), and start the server on the specified port.
What’s Happening Here?
app.getdefines a GET route for our root URL.reqandresare typed automatically using TypeScript, making it clear what kind of objects we’re working with.- The server runs on
http://localhost:3000(or another port if specified in the environment).
Configure Nodemon for Development
Instead of manually restarting the server each time we make a change, we can use Nodemon.
In package.json, update the scripts section:
"scripts": {
"start": "node dist/index.js",
"dev": "nodemon --exec ts-node src/index.ts"
}
startruns the compiled Javascript in production mode.devruns the server in development mode withts-nodeautomatically restarting whenever any changes are made.
Running our project
Let's test the sample endpoint we just created!
Run the following in your terminal while being in the project folder:
npm run dev
You should see a message in the terminal like: Server is running on http://localhost:3000. Open your browser and go to http://localhost:3000 to see "Hello, TypeScript with Express!" displayed.
Adding Routes and Controllers
Let's make our server more dynamic by adding more routes and controllers.
- Create a
routesfolder insidesrc.
mkdir src/routes
- Create a new file in
src/routescalleduserRoutes.ts. This will define routes related to user actions.
import { Router, Request, Response } from 'express';
const router = Router();
router.get('/users', (req: Request, res: Response) => {
res.send('List of users');
});
export default router;
- Modify
index.tsto use this new route:
import express, { Request, Response } from 'express';
import userRoutes from './routes/userRoutes';
const app = express();
const PORT = process.env.PORT || 3000;
app.use('/api', userRoutes);
app.get('/', (req: Request, res: Response) => {
res.send('Hello, TypeScript with Express!');
});
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
What's happening here?
- In the
userRoutes.tsfile, we're creating a new router usingexpress.Router()and defining a route for/users. - In
index.ts, we're importing theuserRoutesand using it with the/apiprefix. - This means that the
/usersroute will be available athttp://localhost:3000/api/users.
Adding middlewares
Middlewares are functions that have access to the request and response objects and can modify them. Let's add a simple logging middleware to log the request method and path.
- Create a
middlewarefolder.
mkdir src/middleware
- Create a new file in
src/middlewarecalledlogger.ts.
import { Request, Response, NextFunction } from 'express';
const logger = (req: Request, res: Response, next: NextFunction) => {
console.log(`${req.method} ${req.path}`);
next();
};
export default logger;
- Update
index.tsto use this middleware:
import express, { Request, Response } from 'express';
import userRoutes from './routes/userRoutes';
import logger from './middleware/logger';
const app = express();
const PORT = process.env.PORT || 3000;
app.use(logger);
app.use('/api', userRoutes);
app.get('/', (req: Request, res: Response) => {
res.send('Hello, TypeScript with Express!');
});
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
What's happening here?
- In the
logger.tsfile, we're defining a middleware function that logs the request method and path. - In
index.ts, we're importing theloggermiddleware and using it withapp.use()to apply it to all routes. app.use()is used to mount the middleware function on the specified path.
Conclusion
This setup gives you a structured, scalable project with Node.js, TypeScript, and Express. Here’s a quick recap of what we covered:
- Project setup and dependency installation.
- TypeScript configuration.
- A basic Express server setup.
- Organized routes and middleware.
Now you’re ready to expand on this setup, whether that means adding database connectivity, more detailed routes, or additional middleware for error handling. Enjoy building with this efficient and type-safe setup!
Related articles
Development using CodeParrot AI



