Node.js & Express · Lesson 1 of 5
Environment Setup & First Express Server
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())