Skip to content

Hello Express ​

Smallest useful server: import express, define a route, listen. Everything else is layers on this.

The whole app (for now) ​

ts
// src/index.ts
import express from 'express'

const app = express()
const PORT = 3000

app.get('/health', (_req, res) => {
  res.json({ ok: true })
})

app.listen(PORT, () => {
  console.log(`listening on http://localhost:${PORT}`)
})

Run it:

bash
npx tsx src/index.ts
# or: npm run dev  (if you wired tsx watch)

Hit it:

bash
curl -s http://localhost:3000/health
# {"ok":true}

Comments for the code above ​

  • express() creates an app instance - think "router root + middleware stack"
  • app.get(path, handler) - only GET matches; POST would 404 here
  • res.json(...) sets Content-Type: application/json and stringifies
  • _req - underscore says "I know it's unused" (lint-friendly)
  • listen binds the port; without it, nothing answers

FE mental map ​

BrowserExpress
fetch('/health').then(r => r.json())app.get('/health', (req, res) => res.json(...))
Network tab status 200default if you don't set otherwise
Opening DevTools on localhost:5173opening localhost:3000 for the API

Your Vite SPA and this server are two processes. CORS shows up later when the browser blocks cross-origin calls - chapter Env & CORS.

A slightly less tiny version ​

ts
import express from 'express'

const app = express()

app.get('/', (_req, res) => {
  res.type('html').send('<p>API lives under /api - this is not a SPA host.</p>')
})

app.get('/api/hello', (req, res) => {
  const name = typeof req.query.name === 'string' ? req.query.name : 'friend'
  res.json({ message: `hey ${name}` })
})

app.listen(3000)
bash
curl -s 'http://localhost:3000/api/hello?name=Ada'
# {"message":"hey Ada"}

Query strings are just req.query - like URLSearchParams, but already parsed into an object.

Common first-hour footguns ​

  1. Forgot listen - process exits or sits idle with no port
  2. Wrong port - Vite is 5173, API is often 3000; don't mix them
  3. Expecting HMR - restart / tsx watch; the browser won't hot-patch your server handlers
  4. Opening the API URL as a "site" - JSON endpoints aren't your React app

As you can see, it's not magic. It's a labeled box that answers HTTP.

Next: routing for real - params, routers, mounting /api.

Best,

-- ł.

Notes-style Express tutorial for front-end folks