A backend for frontend (BFF) is a backend that serves one browser-facing application. This page covers the pattern and whether it is still current, then the runbooks for deploying an Express BFF behind a gateway and for handling its common production incidents.

Backend for frontend

A backend for frontend (BFF) is a backend used by a browser-facing application. It can enforce session and authorization rules, adapt requests, and call downstream services; it is neither the gateway in front of it nor the downstream API behind it.1

Is the pattern still current?

The assessment guide argues that it is not obsolete: a BFF still provides browser-specific authorization, request adaptation, and aggregation. What ages is the operating model around it: manually managed hosts, mutable releases, process-local state, shared long-lived credentials, and no usable evidence during an incident. It should stay browser-focused and not become a catch-all for unrelated domain logic.2

Minimum operating contract

ContractMinimum behaviour
HealthLiveness separate from readiness; readiness fails before a terminating instance gets new work
ShutdownOn SIGTERM/SIGINT, stop accepting requests, finish bounded in-flight work, exit non-zero past the deadline
StateNo session, upload, job, or authoritative state held only in worker memory
DependenciesExplicit timeouts; retries only for safe, bounded, idempotent operations
ObservabilityOne correlation ID across gateway, BFF, and downstream; structured, redacted logs; RED metrics and release version
DeliveryOne immutable artifact, progressive exposure, a rollback owner, and a tested rollback

The guide asks for this contract on the current platform before any move.2 Stateless workers are also what PM2 cluster mode requires.1

Choosing a platform

OptionChoose it whenNot merely because
VM with systemd or PM2One or few stable services, predictable traffic, a clear host owner, automated release and rollbackContainers or Kubernetes are fashionable
Managed container serviceA stateless BFF needing repeatable images and simple autoscaling, without operating KubernetesIt is assumed to provide SLOs or security automatically
KubernetesMany independently released services and a staffed platform ownerThere are only a few services and nobody can run the cluster

As described in the assessment. It lists five gates before any migration, ending with approved network, identity, secret rotation, logging, on-call, and escalation for the target; if they are not met, improving the current platform is itself the modernization outcome.2

Deploying an Express BFF

A baseline for deploying an Express BFF on a Linux VM, with PM2 running several workers as an unprivileged account behind a separately operated gateway.1

Host and account

  • Use a supported Node.js LTS exact patch version recorded in the change; never an EOL or Current-only line.
  • Create a system account and group, a release layout under /srv/<app-name> (releases, shared, shared/logs), and an environment file /etc/<app-name>/production.env owned root:<app-group> with mode 0640. The account gets no root access and no SSH login.1

Application contract

A private GET /healthz and a graceful exit on SIGINT or SIGTERM that closes the server and exits within a timeout. Install dependencies with npm ci, which needs package.json and package-lock.json to agree; never run npm install on the server to fix a release.

The example ecosystem file runs instances: 2 in exec_mode: 'cluster' with max_memory_restart: '512M', kill_timeout: 30000, and watch: false, loading secrets with --env-file. The guide says these are safe examples, not capacity recommendations.1

Release and rollback

  1. Unpack the approved artifact into a new directory under releases/, then run npm ci --omit=dev, tests, and node --check there.
  2. Take a baseline (pm2 status, pm2 describe, readlink -f current, health).
  3. Atomically repoint current with ln -sfn, then pm2 start (first time) or pm2 reload (cluster), pm2 save, and check status, logs, and health. PM2 can fall back to a restart if workers never become ready.
  4. Continue only after health, a gateway request, a representative user flow, error rate, and release identity pass. Otherwise repoint current to the known-good release and reload; never delete the known-good release during observation.

Set up boot recovery once with pm2 startup (run only the command it prints, after review) and pm2 save; repeat when the Node binary location changes.1

Common incidents

Triage for an Express BFF supervised by PM2 cluster mode. Collect read-only evidence first (pm2 status, pm2 describe, recent logs, the current release target, loopback health, the listener, disk and memory); never start with pm2 restart, reload, delete, or flush.3

The ten incidents

#IncidentFirst checksRecovery
1Request never reaches the BFFGateway logs, DNS/LB/TLS, gateway upstream, BFF healthGateway or DNS owner’s path; do not restart the BFF
2PM2 daemon or boot restore missingpm2 ping, startup unit, Node path after upgradesRebuild startup via the reviewed command, then pm2 save
3Crash or restart loopRestart count, logs against release ID, journalRoll back a failing release, or escalate the error signature
4Port conflict or wrong bindPORT versus ss -lntp, loopback health, gateway upstreamRestore the approved private listener
5Node, artifact, or lockfile mismatchVersions, release ID, npm ci outputRedeploy the tested artifact, or return to known-good
6Env, secret, or permission failureKey names, env file owner and mode, redacted errorsFix only the reference or permission; rotate if exposed
7Gateway 502 / 504BFF health, gateway reachability, logs, latencyFix the first failed layer; do not raise all timeouts
8Downstream failureDNS, TCP/TLS, HTTP status, response parsingDownstream owner’s fix, or roll back BFF adaptation
9Memory growth or OOMPM2 memory and restarts, host OOM, release correlationRemove unhealthy capacity or roll back; do not raise heap limits blindly
10CPU, event-loop, disk, or log pressureCPU vs I/O wait, df -h, df -i, log growthApproved capacity, rate limit, rollback, or retention

As described in the runbook. A PM2 memory restart is mitigation, not leak diagnosis; Node diagnostic reports should use --report-exclude-env and a restricted directory.3

Footnotes

  1. Express BFF Production Deployment for Beginners, original ↩ ↩2 ↩3 ↩4 ↩5 ↩6

  2. Modern BFF Architecture Assessment for Beginners, original ↩ ↩2 ↩3

  3. Express BFF: Ten Common Incidents Runbook, original ↩ ↩2