Deployment Targets

Fly.io, Render, Railway, AWS, Cloud Run

Deployment Targets

Fastify deploys anywhere Node runs. Pick a target by latency, scaling model, and cost.

4 min read Level 2/5 #fastify#deployment#infra
What you'll learn
  • Deploy as a container to Cloud Run, Fly, Render, or Railway
  • Self-host on a VM with Hetzner, EC2, or similar
  • Set NODE_ENV=production and trustProxy correctly

Fastify runs on plain Node, so anything that hosts Node hosts Fastify. The choice is mostly about scaling model and cost.

Containers (Cloud Run, Fly.io, Render, Railway)

If you already have a Dockerfile, these platforms are mostly “push, get a URL”. Cloud Run scales to zero; Fly keeps a small machine warm; Render and Railway are in between.

# Fly
fly launch --dockerfile Dockerfile --name my-api
fly deploy

# Render and Railway pick up Dockerfile automatically on push.

Self-Hosted (Hetzner, EC2, VPS)

Build the Docker image, push to GHCR, then docker run on the box with --restart unless-stopped. Or skip Docker and use systemd directly (covered in the next lesson).

Required Environment

const app = Fastify({
  logger: true,
  trustProxy: true,
});

await app.listen({
  host: '0.0.0.0',
  port: Number(process.env.PORT) || 3000,
});
  • NODE_ENV=production — strips dev-only behaviors, disables pino-pretty.
  • trustProxy: true — required behind any load balancer, otherwise request.ip is the LB IP.
  • host: '0.0.0.0' — bind on all interfaces inside a container.

Graceful Shutdown

Most platforms send SIGTERM before killing the process. Drain in-flight requests:

for (const sig of ['SIGTERM', 'SIGINT'] as const) {
  process.on(sig, async () => {
    await app.close();
    process.exit(0);
  });
}
PM2, systemd & Process Managers →