Setting Up Express Application

1. Installing Express

CommandPurpose
npm init -yInitialize package.json
npm install expressInstall Express 5+ EXPRESS 5
npm install -D nodemonAuto-restart on file changes
npm install -D @types/expressTypeScript type definitions
node --versionRequires Node.js 18+ (20 LTS recommended)

Example: Minimal install & run

mkdir my-api && cd my-api
npm init -y
npm install express
npm pkg set type="module"
node --watch app.js

2. Creating Basic Server

APIDescription
express()Factory creating an Express application instance
app.listen(port, host?, backlog?, cb?)Bind HTTP server; returns http.Server
http.createServer(app)Manual server creation (needed for HTTPS / WebSockets)

Example: Bootstrap server

import express from "express";

const app = express();
const port = process.env.PORT || 3000;

app.get("/", (req, res) => res.json({ status: "ok" }));

const server = app.listen(port, () =>
  console.log(`Listening on http://localhost:${port}`)
);

server.on("error", (err) => console.error("Server error:", err));

3. Configuring Application Settings

SettingDefaultPurpose
envprocess.env.NODE_ENVEnvironment mode
etagweakETag generation: weak, strong, false
case sensitive routingfalse/Foo/foo
strict routingfalse/foo/foo/
x-powered-bytrueDisable to hide framework
trust proxyfalseBehind reverse proxy / load balancer
json escapefalseEscape <, >, & in JSON output
query parsersimplesimple, extended, custom fn, or false
view cacheprod=trueCache compiled templates

4. Setting Port and Host

PatternNotes
process.env.PORT || 3000Honor PaaS-assigned port (Heroku, Render, Cloud Run)
app.listen(port, "0.0.0.0")Bind all interfaces (Docker, Kubernetes)
app.listen(port, "127.0.0.1")Localhost only (behind reverse proxy)
app.listen(0)OS-assigned ephemeral port (testing)

5. Setting View Engine

EngineInstallSetup
EJSnpm i ejsapp.set("view engine", "ejs")
Pugnpm i pugapp.set("view engine", "pug")
Handlebarsnpm i express-handlebarsapp.engine("hbs", engine())

6. Configuring Views Directory

Example: Views path

import path from "node:path";
import { fileURLToPath } from "node:url";

const __dirname = path.dirname(fileURLToPath(import.meta.url));
app.set("views", path.join(__dirname, "views"));
app.set("views", [path.join(__dirname, "views"), path.join(__dirname, "shared")]);
APIPurpose
app.set("views", path)Single directory or array of directories
app.engine(ext, fn)Register custom template engine

7. Enabling Trust Proxy

ValueEffect
trueTrust all proxies (use only in dev)
"loopback"Trust 127.0.0.1, ::1
"linklocal"Trust loopback + link-local
"uniquelocal"Trust loopback + private + ULA
1 (number)Trust nth hop from app
["10.0.0.1", "10.0.0.2"]Trust specific IPs/CIDRs
Warning: Setting trust proxy: true blindly in production allows IP spoofing via X-Forwarded-For. Use the exact hop count or proxy IP.

8. Disabling X-Powered-By Header

Example: Hide framework fingerprint

app.disable("x-powered-by");
// or with helmet
import helmet from "helmet";
app.use(helmet());  // also removes X-Powered-By
MethodPurpose
app.disable(name)Set boolean setting to false
app.enable(name)Set boolean setting to true
app.disabled(name)Returns true if disabled
app.enabled(name)Returns true if enabled

9. Configuring Static File Directory

OptionDescription
maxAgeCache-Control max-age (ms or string)
etagEnable ETag generation
indexIndex file (default index.html; false to disable)
dotfilesallow, deny, ignore
fallthroughPass to next middleware on 404
immutableAdd immutable directive to Cache-Control
setHeadersFunction to set response headers

Example: Static assets with caching

app.use(express.static("public", {
  maxAge: "1y",
  immutable: true,
  etag: false,
  setHeaders: (res, filePath) => {
    if (filePath.endsWith(".html")) res.setHeader("Cache-Control", "no-cache");
  }
}));
app.use("/cdn", express.static("assets"));

10. Setting Global Template Variables

ObjectScopeUse
app.localsApp-wide, persists across requestsSite name, version, helpers
res.localsPer-request onlyCurrent user, flash messages

Example: Globals

app.locals.siteName = "Acme";
app.locals.year = new Date().getFullYear();
app.locals.formatDate = (d) => new Intl.DateTimeFormat("en-US").format(d);
// Available in every view as siteName, year, formatDate