What changes for a web application when the HTTP server is embedded in its own process instead of an external server hosting it?
answer
- same contract, different owner
- who starts the process
- configuration travels with code, or not
- shutdown draining is the host's behaviour
- shared server means shared blast radius
basics
~10 sApplication code barely changes, because the adapter boundary is the same either way. What moves is ownership: process lifecycle, listener and transport configuration, timeouts, size caps, shutdown behaviour and the deployment unit.
solid answer
~40 sIn the **embedded** model the application starts the server: one process, one application, and the listener, thread or event-loop settings, timeouts and size caps are configured by the application itself and travel with it. In the **externally hosted** model a separately managed server process owns the listener and calls into the application, which is deployed as a unit into it; several applications may share one server, and the operator owns the server configuration. The adapter boundary is what makes the code portable between the two - the entry point still receives a request and produces a response. The differences that bite are operational: who wins on a configuration conflict, whether shutdown drains in-flight requests, what the deployment artifact is, and whose default error page a client sees for a request refused before hand-off.
go deeper
Know that the same application code can run with a server it starts itself or inside a server someone else runs, and that your handlers look the same in both cases.
Be able to list what moves between the models - listener and transport configuration, timeouts and caps, deployment unit, shutdown - and say who owns each.
Bring the operational failure modes: readiness versus a bound port, shutdown grace periods that cut long requests, a shared server's blast radius, and pre-hand-off errors formatted by a host you do not control.
Treat it as an ownership boundary decision, not a technology one. Decide deliberately which settings belong to the team that deploys the service and which to the platform, and make that split explicit rather than inherited from the hosting shape.
## Two hosting shapes, one contract The seam does not care who owns the process. A framework that speaks the adapter contract can be driven by a server the application started itself, or by a server that was already running and loaded the application into it. That is the whole point of the boundary: application code is the same, hosting is a deployment decision. What differs is **ownership** - and ownership is where operational surprises live. ## What actually differs | concern | embedded server | externally hosted server | |---|---|---| | process lifecycle | the application starts and stops the server | the server process exists independently and loads the application | | listener, port, transport security | configured by the application, versioned with it | configured by the operator, outside the application artifact | | timeouts and size caps | application configuration, shipped together | server configuration, applied to every hosted application | | deployment unit | a self-contained runnable artifact | a package deployed into a running server | | isolation | one application per process by construction | several applications may share one process and its resources | | startup order | application initialises, then binds the listener | the server may start accepting before an application is fully ready | ## The consequences that actually bite 1. **Configuration lives in different places.** With an embedded server, a change to timeouts or caps is a code or config change reviewed and deployed with the application. Hosted externally, the same change is an operations task on a shared server - and it affects every application in it. Teams get caught by this when a limit they believe they raised was raised in the artifact but the enforcing layer was elsewhere. 2. **Graceful shutdown is a negotiation.** Embedded, the application can stop accepting new requests, let in-flight requests drain, run its own cleanup and then exit, because it owns both halves. Hosted externally, draining is the server's behaviour and the application only gets whatever shutdown signal the host chooses to give it; an application that assumes it can finish long requests on the way down may be cut off. 3. **Readiness is not liveness.** Embedded servers commonly bind the listener as part of startup, so a bound port does not prove initialisation finished - the exposed readiness signal must come from the application, not from the port being open. 4. **Pre-hand-off errors look like the host.** Requests refused for size or framing are answered by whichever server parsed them, in that server's default format. Under an external server that format is not yours and may not even be consistent with your other applications. 5. **Resource isolation is coarser when shared.** Several applications in one server share its accept queue, its worker resources and its memory, so one misbehaving application degrades the others. One application per process trades that for more processes to operate. ## What does not differ Because the contract is the same, the things people expect to differ mostly do not: routing, the request object, the response model, how handlers are written, how the application is tested. A test that synthesizes a request and invokes the entry point is valid under both models, which is also the reason it proves nothing about hosting behaviour - limits, timeouts and shutdown are precisely what such a test does not exercise. ## How to choose Argue from operations, not from taste: - **Embedded** favours independent deployability, one artifact per service, configuration versioned with code, and straightforward per-service resource limits. It suits many small services deployed frequently, and it makes the application responsible for settings that used to be somebody else's. - **Externally hosted** favours centrally operated configuration, shared transport-security material, uniform policy applied to many applications at once, and environments where an operations team owns runtime settings by design. It suits fewer, larger deployments with a strong operations boundary. A third arrangement is common and blurs the question: an embedded server behind a reverse proxy. The application still owns its process, but caps, transport security and connection policy are enforced in front of it - so the decision about *who owns each setting* has to be made explicitly rather than inherited from the hosting model. ## The interview-worthy summary The seam keeps application code portable, so answering "nothing much changes in my handlers" is right but incomplete. What changes is who owns the listener, the limits, the shutdown behaviour and the error format for requests your code never sees - and every production incident that hinges on this hinges on that ownership, not on the handlers.
- Why is an open port a poor readiness signal for an embedded server?Because binding the listener is usually part of startup and can happen before caches are warm, connections are established or initialisation has finished. Traffic then arrives at an application that is running but not ready. Readiness has to be reported by the application after its own initialisation completes, separately from the port being bound.
- What makes graceful shutdown harder under an externally hosted server?Draining is the host's behaviour, not the application's. The application does not own the listener, so it cannot decide to stop accepting while finishing in-flight work; it reacts to whatever signal and grace period the host provides. Long-running requests can be cut off by a host whose grace period is shorter than the application assumes.
- Does the choice change how you write handlers?Almost never - that is what the adapter boundary buys. The contract above the seam is the same, so routing, the request object and the response model are unchanged. What changes is the environment around the handler: limits, timeouts, shutdown and who owns them, none of which appear in handler code.
saying these in an interview costs you the question
- Claims handlers must be rewritten to move between hosting models
- Treats a bound listener as proof the application finished initialising
- Assumes in-flight requests always drain cleanly on shutdown
- Forgets that applications sharing one server share its failure domain
- Thinks the deployment model changes what the request object contains