An application developer can treat Nuxt as a black box with a good API. Someone who builds Layers and modules for other teams cannot: every module is a function that runs inside that box, at a specific point in a sequence, mutating state that later stages read. If you do not know when nuxt.options stops being writable in practice, when Nitro's config is assembled, or why an auto-import works in a component but throws in a server route, you will write code that happens to work in your playground and fails in the consumer's app for reasons neither of you can see.
That is exactly why interviewers probe internals for a tooling role. The question is never "do you know what nitro:config does" — it is whether you can say why the hook exists at that point and what would break if you did the same work in setup(). The answers separate three levels: someone who has read the docs names the API; someone who has shipped a module names the ordering constraint; someone who supports a module in ten apps names the failure mode the consumer will report. Internals questions are cheap to ask and extremely hard to bluff, so they get asked a lot.
Nuxt itself is small. Most of what you think of as "Nuxt" is a set of independent unjs packages wired together by a hook system:
.env; untyped resolves it against a schema so every option has a documented default.server/ directory plus the Vue SSR renderer and produces a deployable output for whichever platform preset you target; h3 is the request layer inside it, unstorage the storage and cache layer.Two boundaries cause most real-world bugs, and both are covered here. The first is build world versus runtime world: a module runs once in Node and never again, so anything the app needs at runtime must be carried across deliberately. The second is app registry versus Nitro registry: they are different auto-import scopes, different module graphs, and different sets of globals, which is why "it works in a component" proves nothing about a server route.
The pages below follow that machinery in the order you meet it: first what actually happens between typing nuxt dev and getting a URL, then the server half, then the toolbelt you build with, then the two transform systems that rewrite your code, then how pages are rendered and data crosses the wire — and finally the one decision every toolkit author has to defend out loud.
"Because a module is not a consumer of the API, it is a participant in the build. My code runs at a particular point in a sequence — after internal modules, before app resolution, before Nitro is configured — and the things I can do depend entirely on where I am in that sequence. If I mutate nuxt.options.nitro after Nitro has been initialised, nothing happens and nothing warns me. If I register an app auto-import and a consumer calls it in a server route, they get an undefined-function error in production with no obvious cause. An app developer can learn the API and be productive; I have to be able to predict the consumer's failure mode before they hit it, which means knowing the hook order, the two auto-import registries and the build-versus-runtime boundary."
Building, versioning and publishing
What nuxt-module-build emits, the package.json fields that decide whether your module resolves, semver for modules, deprecating an option safely, and getting listed on nuxt.com/modules.
The startup sequence
What actually happens between typing nuxt dev and getting a URL — c12 config loading, schema resolution, the hookable instance, module order, app resolution, the Vite and Nitro builds.