Installation
Adopting Heximon costs three packages, one plugin line in your Vite config, and one small config file — there's no entry file to write, no decorators to enable, and no runtime container to wire up.
The fast path: scaffold it
pnpm create heximon generates all of the setup below — the packages, the Vite config, the
heximon.config.ts config file, and TypeScript — into a working app you can pnpm dev immediately.
pnpm create heximon my-app
npm create heximon@latest my-app
yarn create heximon my-app
bun create heximon my-app
See Create a new app for the template and validator choices. The rest of this page is for adding Heximon to a project by hand, or bolting it onto one you already have.
Check prerequisites
- Node.js 24+
- A package manager — pnpm 10+ is recommended and is what Heximon's own CI verifies; npm, yarn, and Bun are expected to work but aren't CI-verified yet
- TypeScript 5.9+ in strict mode — type-checking is your job (via your IDE or
tsgo); Heximon's own compiler reads your source with oxc, so it never needstscto build
Heximon needs no decorator flags — it's decorator-free by design, so leave experimentalDecorators and
emitDecoratorMetadata off. Discovery comes from a class being listed in a module, not from metadata.
Install the packages
A minimal HTTP app needs three packages: the kernel (runtime), the HTTP layer (http), and the build
plugin (build) that hosts the compiler and dev server.
pnpm add @heximon/runtime @heximon/http
pnpm add -D @heximon/build vite-plus
npm install @heximon/runtime @heximon/http
npm install -D @heximon/build vite-plus
yarn add @heximon/runtime @heximon/http
yarn add -D @heximon/build vite-plus
bun add @heximon/runtime @heximon/http
bun add -d @heximon/build vite-plus
vite-plus is the build toolchain (it brings Vite along), so it goes in devDependencies next to the
plugin. Add the other layers — contract, cqrs, domain, drizzle, auth, and the rest — only when you
reach for them; each ships its own compiler plugin and runtime classes. The
Packages overview has the full list.
Configure Vite
The heximon() plugin runs the compiler over src/ and serves the generated app. Register the plugin with
no arguments — all compiler configuration lives in heximon.config.ts next to it, where you list
one compiler plugin per feature — here just HttpPlugin for the HTTP layer.
import heximon from "@heximon/build/vite";
import { defineConfig } from "vite-plus";
export default defineConfig({
plugins: [heximon()],
server: { port: 3000 },
});
import { defineHeximonConfig } from "@heximon/build";
import { HttpPlugin } from "@heximon/http/compiler";
export default defineHeximonConfig({
plugins: [new HttpPlugin()],
});
The split is deliberate: heximon() registers the build hook, while the compiler options — plugins, the
optional root module, wiringMode — live in heximon.config.ts.
As your app grows, you list more plugins there: [new HttpPlugin(), new CqrsPlugin(), new DomainEventsPlugin()]. Each feature page shows the plugin it needs. vp dev, vp build, vp test
(createTestApp), and every host all read this same file, so the config is declared once no matter how
you run the app.
You don't write a root entry: with it omitted, the single root module — the one no other module imports —
is auto-discovered as your app. Each feature page that adds a plugin reuses this exact config.
Configure TypeScript
Heximon is strict and ESM-only. Strictness here sharpens your type-checking — the Heximon compiler itself
parses with oxc and never reads your tsconfig.json. The options below are the ones that matter; extend
your team's base config for the rest.
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"verbatimModuleSyntax": true,
"strict": true,
"noUncheckedIndexedAccess": true,
"skipLibCheck": true,
"noEmit": true,
"lib": ["ES2022", "DOM", "DOM.Iterable"]
},
"include": ["src", "src/.heximon/**/*", "vite.config.ts", "test"]
}
verbatimModuleSyntax keeps type-only imports explicit, and noEmit is correct because the heximon()
plugin — not tsc — produces the running code. strict and noUncheckedIndexedAccess are what let the
compiler trust your constructor signatures as the dependency declaration. The first compile adds the
src/.heximon/**/* include entry to your tsconfig.json for you.
import type is fine for an injected dependency. Under verbatimModuleSyntax, your IDE may auto-import a
constructor-injected class as import type { UsersRepository }. That's harmless: the compiler reads class
identity from your source, so it resolves a type-only import exactly like a value import — there is no runtime
container, and the generated wiring imports the class itself.You only need a value import where the class also appears in a value position: listed in a module's
providers, or named in a useFactory/useValue.Add the scripts
vp is the vite-plus task runner — no global install needed.
Mark the package as ESM with "type": "module" and wire up dev, check, build, and test.
{
"type": "module",
"scripts": {
"dev": "vp dev",
"build": "vp build",
"check": "vp check",
"test": "vitest --run"
}
}
vp dev— compilesrc/and serve the generatedfetchapp, recompiling on every source changevp check— formatting, lint, and a full TypeScript type-check in one pass (viatsgo, the TypeScript Go toolchain — nevertsc)vp build— emit a standalone production server intodist/server.js(runs on Node, Bun, or Deno); publishing a library package usesvp packinstead
That's the whole setup. pnpm dev will compile and serve your app — the moment you add a module and a
controller, an HTTP route answers on port 3000.
Already running Nitro or Nuxt?
Heximon bolts onto a host you already have instead of owning its own server.
For a Nitro app, list the bare heximonNitroModule — no function call, no inline options; the same
heximon.config.ts file carries the plugin list:
import { defineNitroConfig } from "nitro/config";
import { heximonNitroModule } from "@heximon/nitro/module";
export default defineNitroConfig({
compatibilityDate: "2025-07-04",
serverDir: "server",
modules: [heximonNitroModule],
});
For a Nuxt app, add the module string — that's the whole Nuxt-side setup:
export default defineNuxtConfig({
compatibilityDate: "2025-07-04",
srcDir: "app",
modules: ["@heximon/nuxt"],
});
Either way your Heximon modules and controllers live under the host's server/ dir, and the same
heximon.config.ts file drives the compile. See Nitro and
Nuxt for the full setup, including how each host derives your deploy platform from
its own preset.
Next steps
- Quick Start — write your first provider, controller, and module, then curl a live route.
- Core Concepts — how modules, providers, and the compiled DI graph fit together.
- Project Structure — the directory layout that scales to a real app.
- Example L01 — Minimal application — the complete app this setup serves, with two GET routes and a module-level middleware.
What is Heximon?
A TypeScript backend framework for APIs, SaaS backends, and internal services — plain classes wired at build time, no decorators, no runtime container.
Quick Start
Build your first Heximon app in three files — a provider, a controller, and a module, wired by the compiler and served by Vite.