Response header · non-standard
< X-Response-Time: 42msX-Response-Time
Learn how the X-Response-Time header indicates server processing time in milliseconds. Useful for performance monitoring and debugging slow requests.
- Direction
- Response
- Category
- Diagnostics
- Status
- Non-standard: Framework convention, not a registered header
On this page
TL;DR:
X-Response-Timehas no standard measurement boundary or format. Express’s response-time middleware measures from middleware entry until response headers are written, in milliseconds. It does not measure complete body transfer or browser round-trip latency.
The field is an application convention. Check the producer before interpreting its units or comparing values across services. This page’s concrete behavior refers to Express’s documented response-time middleware.
Example Response
Field format:
X-Response-Time: <elapsed-milliseconds>ms
With default options, the middleware uses the name X-Response-Time, three decimal places, and the ms suffix. Options can change the name, precision, and suffix.
What It Usually Measures
For this middleware, the clock starts when the request enters it and stops before headers are written. Work before that middleware is excluded. With a streamed response, later chunks can be generated long after this timer stops. DNS, TLS negotiation, and browser rendering are outside its measurement boundary.
Correct Express Implementation
Install express and response-time in your example project with pnpm add express response-time. Save this as app.mjs and run node app.mjs:
import express from 'express'
import responseTime from 'response-time'
const app = express()
app.use(responseTime())
app.get('/', (req, res) => res.json({ status: 'ok' }))
app.listen(3000, '127.0.0.1')
Inspect the measured value:
curl -sS -D - http://127.0.0.1:3000/ -o /dev/null
To change precision and the field name, replace the middleware registration with documented options:
app.use(responseTime({ digits: 1, header: 'X-Response-Time', suffix: true }))
Changing precision affects formatting, not the clock’s start and stop boundaries. With this registration, the field still stops at header output even if a later streaming chunk takes much longer to generate.
When to Expose It
Treat the timing as public response data wherever you send it. If a cross-origin browser client must read it through Fetch, the server also needs the appropriate CORS policy and this illustrative exposure field:
Access-Control-Expose-Headers: X-Response-Time
This controls script access, not visibility to curl or other HTTP clients. See the Fetch Standard’s CORS exposure rules.
Recommended Standard Alternative
Server-Timing defines named metrics and Performance API integration. To publish both from the same measurement, replace app.use(responseTime()) above with:
app.use(responseTime((req, res, time) => {
res.setHeader('X-Response-Time', `${time.toFixed(3)}ms`)
res.setHeader('Server-Timing', `app;dur=${time.toFixed(3)}`)
}))
Measuring and Exposing Response Time Correctly
Setting a header in Node’s finish event is too late. Calling setHeader() after headers were sent throws ERR_HTTP_HEADERS_SENT; it does not silently update the response.
The middleware source uses on-headers and process.hrtime() to calculate the duration before header output. It does not simply wait for res.end() or for the response to finish.
Frequently asked questions
What is X-Response-Time?
X-Response-Time is a non-standard response field whose units and measurement boundary depend on its producer. Express response-time reports elapsed milliseconds until headers are written.
How is X-Response-Time calculated?
Express response-time measures from when the request enters that middleware until response headers are written. It excludes earlier middleware, subsequent body transfer, and client-side work.
Should I use X-Response-Time or Server-Timing?
Server-Timing defines named metrics and browser Performance API integration. X-Response-Time is an implementation-specific convention; use a documented boundary for either measurement.
Should I expose X-Response-Time in production?
It can help debugging but may leak performance information. Consider exposing only in development or to authenticated monitoring systems.
Sources
Related
Access-Control-Max-Age Header
Learn how Access-Control-Max-Age specifies how long browsers can cache CORS preflight results. Reduce preflight requests and improve cross-origin performance.
Content-Encoding
Learn how Content-Encoding specifies compression algorithms (gzip, br, deflate) used to encode response bodies. Reduce bandwidth and improve load times.
Early-Hints
Learn how 103 Early Hints allows servers to send preload hints while preparing the main response. Improve page load performance with early resource loading.
Link Header
Learn how the Link header provides resource hints and enables preloading of CSS, fonts, and scripts to improve page load performance and user experience.