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 / nothingfinalhandler 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:
subApp.mountpath = '/admin'.subApp.parent = parentApp.- The router gets a wrapper that calls
subApp.handle(req, res, next)and restores the parent'sapp.request/app.responseprototypes whennextis invoked. 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.exportson this file is the prototype thatlib/express.jsmixes into the callable app function. - Calls into:
lib/utils.js(compile helpers,methodslist),lib/view.js(new View(...)), the externalrouterpackage (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
caseinapp.set's switch only if it needs compile-on-set; otherwise it just lives inapp.settingsand any module that cares callsapp.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 |
Related pages
- Factory — how this prototype gets attached to the app function.
- Request and Response — the prototypes whose
.appreferences point at the application. - Features / Routing and middleware — how the router stack interacts with
app.use/app.METHOD. - Reference / Configuration — full list of settings.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.