Railway

Deploy Express API | TypeScript, Rate Limiting and Security Headers

Express 5 and TypeScript, proxy-aware rate limiting and security headers

Deploy Express API | TypeScript, Rate Limiting and Security Headers

Deploy and Host an Express API on Railway

Express 5 on TypeScript, with the middleware an internet-facing API actually needs.

About Hosting Express

The ExpressJS template on Railway deploys a repository whose package.json is a 2018 express-generator skeleton: express ~4.16.1, pug 2.0.0-beta11, debug ~2.6.9, http-errors ~1.6.3. Express 4.16 shipped in 2017 and that pug is a beta from the same year. Around four deployments in ten do not come up, and the ones that do run a stack nobody has patched in seven years.

This starter is Express 5 on current Node, with a committed lockfile that passes npm audit --audit-level=high - which matters here, because Railway refuses to build when the lockfile carries a HIGH advisory.

Common Use Cases

  • A JSON API for a front end you host separately
  • A webhook receiver that has to be reachable and rate-limited
  • A starting point that already handles proxies, CORS and shutdown correctly

Dependencies for Express Hosting

  • Nothing. One service, no database. Add Prisma or Mongoose and a database service when you need one.

Deployment Dependencies

Implementation Details

MethodPathDoes
GET/Lists the endpoints
GET/healthStatus and uptime - deliberately outside the rate limiter
GET/api/timeServer time
POST/api/echoEchoes {"message": "..."}, 400 when missing

Four decisions, each of which is a thing that bites in production rather than locally:

  • app.set("trust proxy", 1). TLS terminates at the platform proxy and the real client address arrives in X-Forwarded-For. Without this every request appears to come from the proxy, which breaks rate limiting and any per-client logic. The value 1 trusts exactly one hop; trusting all of them would let a client spoof its own address.
  • Rate limiting covers /api, not everything. A burst of traffic should not lock out the health check and cause the platform to replace a container that is working fine.
  • helmet() is on. The security headers a browser-facing API is expected to send, with no reason to omit them.
  • Graceful shutdown. SIGTERM arrives before a container is replaced; without a handler, in-flight requests are cut off on every deploy.

Why Deploy Express on Railway?

Push TypeScript, get a running API on a domain with TLS and a health check - and a middleware stack that behaves correctly behind a proxy, which is the part most starters get wrong.


Template Content

More templates in this category

View Template
open-excalidraw
Self-hostable collaborative drawing built on Excalidraw

Prateek Mohanty
1
View Template
caring-vibrancy
Deploy and Host caring-vibrancy with Railway

5
View Template
Flask WebSocket Chat
Single file, realtime multi-user websocket chat using flask-socketio

Clement Ochieng
3