Open-Source Wikis

/

Express

/

Systems

/

Application

expressjs/express

Application

Active contributors: dougwilson, ulisesgascon, wesleytodd

Purpose

lib/application.js defines the app prototype. It owns settings (app.set/app.get), mount inheritance, the request entry point (app.handle), middleware registration (app.use), method-specific route registration (app.get/app.post/...), HTTP server creation (app.listen), and view rendering (app.render).

At 631 lines, it is the second-largest file in core after lib/response.js.

Directory layout

lib/
├── application.js   # this file
├── express.js       # mixes this prototype into the app function
└── ...

Key abstractions

Function / property Visibility What it does
app.init() private Creates app.cache, app.engines, app.settings; calls defaultConfiguration; defines a lazy getter for app.router.
app.defaultConfiguration() private Sets defaults: x-powered-by, etag: weak, query parser: simple, subdomain offset: 2, trust proxy: false. Wires up the 'mount' event handler that inherits parent settings/protos.
app.handle(req, res, cb) private The request entry point. Adds X-Powered-By, sets prototype chains, ensures res.locals, hands off to this.router.handle.
app.use([path,] ...fns) public Adds middleware to the lazy router. Special-cases sub-app mounting: detects an Express app via fn.handle && fn.set, sets its mountpath, emits 'mount', and wraps it so the parent prototypes are restored on next.
app.route(path) public Returns router.route(path) — a Route instance for chaining .get(), .post(), etc.
app.engine(ext, fn) public Registers a template engine for an extension. Stores in app.engines.
app.param(name, fn) public Adds a parameter handler. Accepts Array<string> for multiple names.
app.set(setting, val) / app.get(setting) public The settings store. Triggers compile-on-set for etag, query parser, trust proxy. Note: app.get(name) overlaps with app.get(path, ...) (HTTP GET).
app.enabled / app.disabled / app.enable / app.disable public Boolean wrappers over app.set / app.get.
app.path() private Returns the cumulative mount path for nested sub-apps.
app.METHOD(path, ...) public Generated for every HTTP method in node:http METHODS. Calls this.route(path)[method](...handlers).
app.all(path, ...) public Registers handlers for every HTTP method.
app.render(name, opts, cb) public Resolves a View, optionally caches it, runs it through the engine. Used by res.render.
app.listen(...) public http.createServer(this).listen(...). If the last arg is a callback, it's wrapped with once to fire on either error or listening.

How it works

Initialization

graph TD
    Factory[express'()'] --> Init[app.init]
    Init --> Cache[app.cache = Object.create null]
    Cache --> Engines[app.engines = Object.create null]
    Engines --> Settings[app.settings = Object.create null]
    Settings --> Default[defaultConfiguration]
    Default --> Defaults[set defaults: x-powered-by,<br/>etag, env, query parser,<br/>subdomain offset, trust proxy]
    Defaults --> MountListener[on mount: inherit settings & protos from parent]
    MountListener --> Locals[app.locals = Object.create null]
    Locals --> Mountpath["mountpath = /"]
    Mountpath --> ViewSettings[set view, views, jsonp callback name]
    ViewSettings --> ProdCache[if prod: enable view cache]
    ProdCache --> RouterGetter[define lazy router getter on app]

The router is created lazily — only on first access. The getter creates a Router({ caseSensitive, strict }) from the matching settings and memoises it.

Request handling

sequenceDiagram
    participant Caller as http.Server
    participant App as app(req,res)
    participant Handle as app.handle
    participant Router as this.router.handle
    participant Final as finalhandler

    Caller->>App: app(req, res)
    App->>Handle: app.handle(req, res, next)
    Handle->>Handle: done = next || finalhandler(req,res,{env, onerror})
    Handle->>Handle: setHeader X-Powered-By if enabled
    Handle->>Handle: setPrototypeOf(req, app.request)
    Handle->>Handle: setPrototypeOf(res, app.response)
    Handle->>Handle: ensure res.locals exists
    Handle->>Router: this.router.handle(req, res, done)
    Router-->>Final: stack done -> done(err?)
    Final-->>Caller: 404 / formatted error / nothing

finalhandler is created per-request because it captures the current env setting. The onerror is a logerror helper bound to the app: it console.errors the stack unless env === 'test'.

Mount inheritance

When app.use('/admin', subApp) runs and subApp is itself an Express app, several things happen in order:

  1. subApp.mountpath = '/admin'.
  2. subApp.parent = parentApp.
  3. The router gets a wrapper that calls subApp.handle(req, res, next) and restores the parent's app.request/app.response prototypes when next is invoked.
  4. subApp.emit('mount', parentApp) fires.

The 'mount' listener (set up in defaultConfiguration) then inherits the parent's prototypes:

Object.setPrototypeOf(this.request, parent.request);
Object.setPrototypeOf(this.response, parent.response);
Object.setPrototypeOf(this.engines, parent.engines);
Object.setPrototypeOf(this.settings, parent.settings);

This is the prototype-chain trick that lets sub-apps see — but optionally override — parent settings, helpers, and engines.

A trustProxyDefaultSymbol keeps track of whether the child still has the default trust proxy value. If so, and the parent has its own, the child's defaults are deleted so they fall through to the parent on lookup.

Settings compile-on-set

app.set(name, value) triggers a switch:

Setting Side effect
etag Compiles value (boolean / 'weak' / 'strong' / function) into etag fn via compileETag (lib/utils.js).
query parser Compiles into query parser fn via compileQueryParser.
trust proxy Compiles into trust proxy fn via compileTrust. Marks the symbol as non-default.

Other settings are stored verbatim. app.get(setting) is just this.settings[setting].

Method delegation

methods.forEach(function (method) {
  app[method] = function (path) {
    if (method === 'get' && arguments.length === 1) {
      return this.set(path); // app.get('view engine')
    }
    var route = this.route(path);
    route[method].apply(route, slice.call(arguments, 1));
    return this;
  };
});

methods comes from node:http METHODS (lowercased) — see lib/utils.js. The app.get overload is the only ambiguity: with one argument it reads a setting; with multiple, it registers a GET route.

Rendering

graph TD
    Caller[res.render or app.render name, opts, cb] --> Render[app.render]
    Render --> MergeOpts[merge app.locals, opts._locals, opts]
    MergeOpts --> CacheCheck["renderOptions.cache?"]
    CacheCheck -- yes --> Cached[view = app.cache name]
    CacheCheck -- no --> NewView["new View name with defaultEngine, root, engines"]
    NewView --> NotFound["view.path missing? -> err Failed to lookup view"]
    NewView --> CacheStore["renderOptions.cache? store in app.cache"]
    Cached --> TryRender[tryRender view, opts, done]
    CacheStore --> TryRender
    TryRender --> Engine[view.render engine call]

tryRender wraps the call in a try/catch so synchronous template errors are passed to the callback rather than thrown.

Integration points

  • Imports: node:http, node:path, finalhandler, debug, once, router, ./view, ./utils.
  • Exposed via: module.exports on this file is the prototype that lib/express.js mixes into the callable app function.
  • Calls into: lib/utils.js (compile helpers, methods list), lib/view.js (new View(...)), the external router package (new Router(...), router.handle, router.use, router.route, router.param), node:http.createServer.
  • Called by: All of lib/express.js's exported functionality goes through this prototype.

Entry points for modification

  • New setting → add a case in app.set's switch only if it needs compile-on-set; otherwise it just lives in app.settings and any module that cares calls app.get(name).
  • New event on mount → modify the listener inside app.defaultConfiguration.
  • New method on the app → add it to the prototype here. Test it under test/app.<name>.js.
  • Change the request entry path (e.g., to add a default header) → modify app.handle.

Key source files

File Purpose
lib/application.js The app prototype
lib/express.js Mixes this prototype into the callable app
lib/utils.js Compile helpers (compileETag, compileQueryParser, compileTrust)
lib/view.js View constructor used by app.render

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Application – Express wiki | Factory