Settings are a null-prototype object on each app, written by app.set(key, value) and read by app.get(key) (one-argument form). app.enable/app.disable are boolean sugar. Mounted apps inherit settings through a prototype chain to their parent and shadow keys they set themselves (details). Keys are plain strings, and you can store your own -- examples/error-pages defines a custom verbose errors setting and reads it from templates via settings['verbose errors'].

The defaults, verbatim from lib/application.js:

lib/application.js
this.enable('x-powered-by');
this.set('etag', 'weak');
this.set('env', env);
this.set('query parser', 'simple')
this.set('subdomain offset', 2);
this.set('trust proxy', false);
// …
this.set('view', View);
this.set('views', resolve('views'));
this.set('jsonp callback name', 'callback');

if (env === 'production') {
  this.enable('view cache');
}

Core settings

Key Default Consumed in Effect
env process.env.NODE_ENV or 'development' lib/application.js (finalhandler opts, logerror), view cache default Environment name; production hides error stacks and enables view caching
x-powered-by true app.handle Sets X-Powered-By: Express on every response; disable to drop the header
etag 'weak' compiled to etag fn; read by res.send, res.sendFile ETag generation: 'weak', 'strong', false, or custom function
query parser 'simple' compiled to query parser fn; read by the req.query getter 'simple' (node querystring), 'extended' (qs, nested keys), false, or custom function
trust proxy false compiled to trust proxy fn; read by req.protocol, req.ip, req.ips, req.host, req.hostname Which upstream addresses may set X-Forwarded-*: boolean, hop count, CIDR list, or function
subdomain offset 2 req.subdomains getter How many trailing host parts are "the domain"
case sensitive routing unset (false) router construction in app.init /Foo vs /foo distinct when enabled; must be set before the first route
strict routing unset (false) router construction in app.init /foo vs /foo/ distinct when enabled; same before-first-route constraint

View settings

Key Default Consumed in Effect
views resolve('views') (cwd-relative) app.render Root directory or array of roots for template lookup
view engine unset app.render -> View constructor Default extension when res.render('name') has none
view cache true in production, else unset app.render Cache resolved View instances across renders
view the View class from lib/view.js app.render Replaceable view implementation -- examples/view-constructor substitutes one that renders inline strings

JSON output settings

All three read at send time by res.json and res.jsonp in lib/response.js:

Key Default Effect
json replacer unset Passed as JSON.stringify replacer
json spaces unset Passed as JSON.stringify indentation
json escape unset Escapes <, >, & in JSON bodies to \u003c-style Unicode escapes (anti-sniffing)
jsonp callback name 'callback' Query key res.jsonp reads for the callback name

Derived settings (do not set these directly)

Setting etag, query parser, or trust proxy triggers a switch in app.set that immediately compiles and stores a companion function -- etag fn, query parser fn, trust proxy fn -- via the compilers in lib/utils.js. Hot paths read only the compiled form. Two consequences: invalid values throw at configuration time ("unknown value for etag function"), and reading e.g. app.get('trust proxy fn') returns a function, not your original value.

Validation behavior is pinned in test/config.js ("should throw on bad value", "should set "etag fn"") along with the inheritance rules for mounted apps, including the special case where a child that never set trust proxy inherits the parent's compiled function.

Sources: lib/application.js, lib/utils.js, lib/request.js, lib/response.js · last synced 2026-07-27 · a371447 · version 5.2.1