Interresting approach(es)... for recent applications, I've been using Koa, just because the middleware and context handling are much better than everything else.
I create an EnvironmentContext on startup that contains my settings (based on environment variables), configuration (based on application configurations) additional services (database client, redis client etc) and a general logger (bunyan, with console and optionally ES and Seq sinks).
The AppContext extends EnvironmentContext and my first middleware (begin-request) adds the environment context, adds methods for RequestInfo and ResponseInfo and wraps the logger methods to include RequestInfo for each log statement, and the final output being the general error logging middleware then the response middleware (which doesn't output, if error middleware already did). I also add additional providers for easy apiResult and apiError responses as well as for Role based authentication (Jwt bearer tokens).
It works pretty well... made the switch to TS to make context handling easier... I also have it generically typed Context<TBody, TParams, TQueryString> so that I can have typed instances in my route handlers.
Each of my route handlers returns an array, so that it can include parameter/body/query validators (Joi or Yup), with the Role validation where all the routes are mounted.
Hoping to get permission to put the Configuration Service, which only delivers build configuration(s) output on Github in the next month or so.