Node.js & Express Environment Setup
Install Node.js, scaffold an Express project with TypeScript, understand the module system, and run your first API server in under 20 minutes.
Node.js lets you run JavaScript on the server. Express is the most popular web framework for Node ā minimal, unopinionated, and battle-tested. Together they power APIs at companies from small startups to Netflix.
Install Node.js
Use the LTS version. Check at nodejs.org or use a version manager:
# Using nvm (recommended ā lets you switch Node versions)
nvm install --lts
nvm use --lts
# Verify
node --version # v20.x.x or higher
npm --version # 10.x.xCreate a Project
mkdir my-api && cd my-api
npm init -yInstall Express and TypeScript:
npm install express
npm install -D typescript ts-node-dev @types/node @types/expressInitialize TypeScript:
npx tsc --initUpdate tsconfig.json with sensible defaults:
{
"compilerOptions": {
"target": "ES2022",
"module": "commonjs",
"lib": ["ES2022"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"resolveJsonModule": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}Add scripts to package.json:
{
"scripts": {
"dev": "ts-node-dev --respawn --transpile-only src/index.ts",
"build": "tsc",
"start": "node dist/index.js"
}
}Your First Express Server
src/index.ts
import express, { Request, Response } from 'express';
const app = express();
const PORT = process.env.PORT ?? 3000;
// Middleware ā parse JSON bodies
app.use(express.json());
// Routes
app.get('/', (req: Request, res: Response) => {
res.json({ message: 'Hello from Express!' });
});
app.get('/health', (req: Request, res: Response) => {
res.json({ status: 'ok', timestamp: new Date().toISOString() });
});
// Start server
app.listen(PORT, () => {
console.log(`Server running at http://localhost:${PORT}`);
});Run the dev server:
npm run devOpen http://localhost:3000 ā you'll see the JSON response.
Project Structure
my-api/
āāā src/
ā āāā index.ts ā entry point
ā āāā app.ts ā Express app (without listen)
ā āāā routes/
ā ā āāā users.ts
ā ā āāā products.ts
ā āāā controllers/
ā ā āāā user.controller.ts
ā ā āāā product.controller.ts
ā āāā middleware/
ā ā āāā auth.middleware.ts
ā ā āāā error.middleware.ts
ā āāā models/ ā TypeScript interfaces + DB models
ā āāā services/ ā business logic
āāā package.json
āāā tsconfig.jsonSeparate app.ts from index.ts ā app.ts creates and exports the Express instance, index.ts starts the server. This makes testing easier (import the app without starting a server).
src/app.ts
import express from 'express';
import { userRouter } from './routes/users';
import { productRouter } from './routes/products';
const app = express();
app.use(express.json());
app.use('/api/users', userRouter);
app.use('/api/products', productRouter);
export { app };src/index.ts
import { app } from './app';
const PORT = process.env.PORT ?? 3000;
app.listen(PORT, () => console.log(`Server on port ${PORT}`));Environment Variables
Never hardcode secrets. Use a .env file with dotenv:
npm install dotenv.env (never commit this):
PORT=3000
DATABASE_URL=postgres://localhost:5432/mydb
JWT_SECRET=supersecretkeysrc/index.ts:
import 'dotenv/config'; // load .env before anything else
import { app } from './app';
const PORT = process.env.PORT ?? 3000;
app.listen(PORT);Add .env to .gitignore. Commit a .env.example with empty values so other developers know what's needed.
Node.js Module System
Node uses CommonJS (require/module.exports) by default. TypeScript compiles to CommonJS unless you configure otherwise. You'll also see ES Modules (.mjs or "type": "module" in package.json):
// TypeScript (compiles to CommonJS)
import express from 'express';
export function add(a: number, b: number): number { return a + b; }
// What Node actually runs (CommonJS):
const express = require('express');
function add(a, b) { return a + b; }
module.exports = { add };Stick with CommonJS for Node.js + TypeScript unless you have a specific reason to use ES Modules.
Useful Dev Tools
# REST client for testing APIs
npm install -g httpie
http GET localhost:3000/health
# Or use curl
curl http://localhost:3000/health
# nodemon alternative (built into ts-node-dev)
# ts-node-dev auto-restarts when TypeScript files changeInstall the Thunder Client VS Code extension or Postman for a GUI API client.
Quick Reference
Init project: npm init -y
Install: npm i express && npm i -D typescript ts-node-dev @types/node @types/express
Dev server: npm run dev (ts-node-dev --respawn src/index.ts)
Build: tsc ā dist/
Production: node dist/index.js
Environment: dotenv ā process.env.VAR_NAME
Split app: app.ts (express()) vs index.ts (app.listen())Found this helpful?
Leave a comment
Have a question, correction, or just found this helpful? Leave a note below.