Why Nwire
The problem
Every Node framework I've used (Express, Koa, NestJS, Fastify) is built around HTTP. The framework knows what a request is, what a controller is, what a response is. It does not know what an action is. It does not know what a domain event is. It does not know what an aggregate is or what a state transition means.
So when you ship the app and want to know:
- "Which submissions are stuck waiting on a reviewer?"
- "What's the p95 latency of the grading flow specifically — not just any HTTP request that touches it?"
- "How often does the auto-grader fall back to manual review?"
- "Are all my workflows actually firing the way I declared, or has someone introduced drift?"
…you can't ask the framework. You have to bolt on a domain model in your APM tags, hope the developer remembers, and reconstruct it from spans.
The bet
If the framework's primitives are the domain — defineAction, defineActor, defineEvent, defineProjection, defineWorkflow — then the framework can answer those questions directly. And its companion tools (Studio, telemetry exporters, scaffolds) can do the same.
That's Nwire.
The six principles
(Full text: Architecture principles.)
- Screaming architecture. The file tree says what the system does, not what it's built with.
modules/submissions/, notmodules/services/. - Self-identifying files. Every filename reveals role + context.
submit-answer.action.ts, notsubmit.ts. - Conservation of meaning. Names preserve the user's reality through every layer. Code is the last link in the narrative chain.
- One-author coherence. Every file looks like the same person wrote it.
- Artisan engineering. Every decision traces to "why this serves the user." Engineers AND artists.
- Modeling ⊥ deployment. Domains never import from wires. Same modules run as monolith, split services, or queue workers — Nwire's topology composer materializes any shape.
What you give up
- Class-based service composition. Nwire is functions + composition. No decorators, no metadata reflection. If you love NestJS's DI, awilix is available as
@nwire/container-awilix. - One-size-fits-all routing. HTTP, queue, CLI, cron each get their own wire. They consume the same actions; they don't share a single "controller" surface.
- Stack traces as the primary debugging tool. Stack traces still work, but the canonical debugging tool is the telemetry stream + Studio's correlation trace tree. You read what the system did, not what this function did.
What you get
- Studio that natively shows your domain
- Telemetry stream that's structured by primitive, not by HTTP span
- Deployment topology as data
- Test harness that boots the whole app in-process
- Reusable common modules (auth, billing, notifications — coming) on the same substrate
When NOT to use Nwire
- You're building a static site or a thin proxy. Use Vite + the
fetchhandler. - You're building a single-purpose CLI. Use commander.
- You're building real-time games / collaborative editing where the bottleneck is the network, not the domain. Use a CRDT framework.
- Your team prefers classes / decorators / Java-flavored TS. NestJS will feel more natural.
For everything else — line-of-business apps, education platforms, fintech, e-commerce, support systems — Nwire's bet is that domain-native primitives beat HTTP-native primitives. The next pages walk through each primitive.