Code Generation
What is Code Generation?
Code generation in Bounda automatically creates type-safe interfaces from your domain and read model files. Rather than writing type definitions by hand, Bounda inspects your file structure and exports, then generates +types/ directories with fully typed interfaces for commands, events, policies, queries, projections, and process managers.
How It Works
When you run the code generator, Bounda scans your domain/ and read/ directories, analyzes the exported payload and apply functions, and produces typed interfaces in co-located +types/ directories:
domain/
order/
order-placed.ts
+types/
order-placed.ts <- generated
commands/
place-order.ts
+types/
place-order.ts <- generated
policies/
send-confirmation-on-order-placed.ts
+types/
send-confirmation-on-order-placed.ts <- generated
These generated files provide the types you import in your domain code:
import type { Event } from "./+types/order-placed";
import type { Command } from "./+types/place-order";
import type { Policy } from "./+types/send-confirmation-on-order-placed";
Running the Generator
One-Time Generation
npx bounda generate
Scans the project and generates all +types/ files. Run this after adding new files or changing payload schemas.
Watch Mode
npx bounda generate --watch
Continuously watches for file changes and regenerates types automatically. Useful during active development.
Cleaning Generated Files
npx bounda clean
Removes all generated +types/ directories. Useful when switching branches or troubleshooting stale types.
Vite Plugin
For projects using Vite, Bounda provides a plugin that triggers code generation automatically during development:
import { bounda } from "@bounda-dev/codegen/vite";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [bounda()],
});
The plugin watches for file changes and regenerates types in the background, eliminating the need to run the CLI separately during development.
TypeScript Configuration
To make TypeScript recognize the generated +types/ files, add the following to your tsconfig.json:
{
"include": [".bounda/**/*"],
"compilerOptions": {
"rootDirs": [".", "./.bounda"]
}
}
This tells TypeScript to treat the .bounda directory as a virtual root alongside your project root, enabling the +types/ imports to resolve correctly.
What Gets Generated
The code generator produces typed interfaces for each domain concept:
| Concept | Generated Types |
|---|---|
| Events | Event.PayloadFunction, Event.ApplierArgs |
| Commands | Command.PayloadFunction, Command.HandlerArgs, Command.CollaboratorArgs |
| Policies | Policy.HandlerArgs |
| Process Managers | ProcessManager.ConfigFunction, ProcessManager.HandlerArgs |
| Projections | Projection.HandlerArgs |
| Queries | Query.PayloadFunction, Query.Repository, Query.HandlerArgs |
These types encode the relationships between your domain files. For example, Command.HandlerArgs includes typed events builders based on the events defined in the same aggregate, and collaborator arguments based on the collaborator files in the command folder.
Guidelines
- Run
npx bounda generateafter creating new domain or read model files before writing the implementation. The generated types guide your code with autocompletion and compile-time checks. - Never edit files inside
+types/directories. They are overwritten on every generation run. - Add
+types/directories to.gitignoreif you prefer to generate them as a build step rather than checking them in. - If types seem stale or incorrect, run
npx bounda cleanfollowed bynpx bounda generateto rebuild from scratch.
Related Concepts
- Aggregates — events and commands that code generation scans
- Commands — generated
Command.HandlerArgstypes - Events — generated
Event.PayloadFunctionandEvent.ApplierArgstypes - Queries — generated
Query.RepositoryandQuery.HandlerArgstypes