Heximon Logo
Getting Started

Installation

Install @heximon/runtime, @heximon/http, and @heximon/build; register the heximon() Vite plugin and the HttpPlugin in heximon.config.ts; set strict ESM tsconfig options; and add the vp dev, check, and pack scripts.

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

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 needs tsc to 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

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.

vite.config.ts
import heximon from "@heximon/build/vite";
import { defineConfig } from "vite-plus";

export default defineConfig({
  plugins: [heximon()],
  server: { port: 3000 },
});
heximon.config.ts
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.

tsconfig.json
{
  "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.

package.json
{
  "type": "module",
  "scripts": {
    "dev": "vp dev",
    "build": "vp build",
    "check": "vp check",
    "test": "vitest --run"
  }
}
  • vp dev — compile src/ and serve the generated fetch app, recompiling on every source change
  • vp check — formatting, lint, and a full TypeScript type-check in one pass (via tsgo, the TypeScript Go toolchain — never tsc)
  • vp build — emit a standalone production server into dist/server.js (runs on Node, Bun, or Deno); publishing a library package uses vp pack instead

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:

nitro.config.ts
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:

nuxt.config.ts
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

Copyright © 2026