Express Cheatsheet

The Response Object

Use this Express reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

Overview

The res object is a Node.js ServerResponse extended with Express helpers. Call exactly one response-ending method per request; calling more causes Cannot set headers after they are sent errors.

Sending Responses

res.send()

Sends a response. Sets Content-Type automatically based on argument type.

res.send('Hello');               // text/html
res.send('<h1>Hello</h1>');      // text/html
res.send({ key: 'value' });      // application/json (deprecated — prefer res.json)
res.send(Buffer.from('binary')); // application/octet-stream
res.send();                      // 204 No Content (no body)

res.json()

Serializes value with JSON.stringify, sets Content-Type: application/json. Respects json spaces and json replacer app settings.

res.json({ user: 'Alice', age: 30 });
res.json([1, 2, 3]);
res.json(null);               // valid JSON null
res.status(201).json(created);

res.jsonp()

Like res.json() but wraps in a JSONP callback.

// GET /data?callback=myFunc
res.jsonp({ value: 42 }); // → myFunc({"value":42})

res.sendStatus()

Set status and send its string representation as the body.

res.sendStatus(200); // 'OK'
res.sendStatus(201); // 'Created'
res.sendStatus(204); // 'No Content'
res.sendStatus(404); // 'Not Found'
res.sendStatus(500); // 'Internal Server Error'

res.end()

Node's low-level method — finishes response with no processing.

res.end();               // no body
res.end('done');         // raw string, no Content-Type set

Status Codes — res.status()

Chainable setter. Returns res for chaining.

res.status(404).json({ error: 'Not found' });
res.status(201).send('Created');
res.status(400).end();

Redirects — res.redirect()

res.redirect('/new-path');            // 302 (temporary, default)
res.redirect(301, '/permanent');      // 301 permanent
res.redirect(307, '/temp');           // 307 preserves method
res.redirect(308, '/permanent');      // 308 preserves method + permanent
res.redirect('back');                 // redirect to Referer header (or '/')
res.redirect('..');                   // one level up
res.redirect('https://example.com'); // absolute URL

Sending Files — res.sendFile() / res.download()

// res.sendFile — serve a file, Content-Type from extension
res.sendFile('/absolute/path/to/file.pdf');
res.sendFile(path.join(__dirname, 'public', 'index.html'));

// With options
res.sendFile('/path/to/file', {
  maxAge: '1d',        // cache max-age
  root: __dirname,     // allows relative path
  dotfiles: 'deny',    // 'allow', 'deny', 'ignore'
  headers: { 'X-Custom': 'value' },
}, (err) => {
  if (err) next(err);
});

// res.download — sets Content-Disposition: attachment (triggers browser download)
res.download('/path/to/report.pdf');
res.download('/path/to/report.pdf', 'my-report.pdf');       // custom filename
res.download('/path/to/report.pdf', 'my-report.pdf', (err) => {
  if (err) next(err);
});

Rendering Views — res.render()

app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));

res.render('index');                                   // views/index.ejs
res.render('user/profile', { user: req.user });        // pass locals
res.render('page', locals, (err, html) => {            // callback — don't send yet
  if (err) return next(err);
  res.send(html);
});

Setting Headers — res.set() / res.get() / res.removeHeader()

res.set('X-Custom-Header', 'value');
res.set({ 'X-Foo': 'bar', 'X-Baz': 'qux' });  // object form
res.header('X-Custom', 'value');                // alias for res.set()

res.get('Content-Type');   // read a set header (before sending)

res.removeHeader('X-Powered-By');

Content-Type — res.type()

Sets Content-Type from a MIME type string or file extension.

res.type('html');               // text/html; charset=utf-8
res.type('json');               // application/json
res.type('png');                // image/png
res.type('text/plain');         // explicit MIME type
res.type('application/octet-stream');

Streaming — res.write() / res.end()

For streaming large responses or Server-Sent Events.

// Manual streaming
res.set('Content-Type', 'text/plain');
res.write('chunk 1\n');
res.write('chunk 2\n');
res.end();

// Pipe a readable stream
const fs = require('fs');
fs.createReadStream('large-file.csv').pipe(res);

// Server-Sent Events
res.set({
  'Content-Type': 'text/event-stream',
  'Cache-Control': 'no-cache',
  'Connection': 'keep-alive',
});
res.flushHeaders();

const id = setInterval(() => {
  res.write(`data: ${JSON.stringify({ time: Date.now() })}\n\n`);
}, 1000);

req.on('close', () => clearInterval(id));

Locals — res.locals

Variables available to templates rendered during the request lifetime.

// Set in middleware
app.use((req, res, next) => {
  res.locals.user = req.user;
  res.locals.csrfToken = req.csrfToken?.();
  next();
});

// Available in all res.render() calls automatically
res.render('dashboard'); // template sees user, csrfToken

Vary Header — res.vary()

res.vary('Accept');          // Vary: Accept
res.vary('Accept-Encoding');

Quick Method Reference

MethodResponse ends?Description
res.send(body)YesSend any body
res.json(obj)YesJSON response
res.jsonp(obj)YesJSONP response
res.sendStatus(code)YesStatus + status text body
res.redirect([code,] url)YesHTTP redirect
res.sendFile(path)YesStream a file
res.download(path)YesForce-download file
res.render(view, locals)YesRender template
res.end([data])YesLow-level end
res.write(chunk)NoStream chunk
res.status(code)NoSet status code (chainable)
res.set(field, val)NoSet response header
res.get(field)NoRead a set header
res.type(type)NoSet Content-Type
res.cookie(name, val)NoSet cookie
res.clearCookie(name)NoClear cookie
res.location(url)NoSet Location header
res.links(links)NoSet Link header
res.vary(field)NoAppend to Vary header
res.attachment([file])NoSet Content-Disposition
res.append(field, val)NoAppend to header