Directory Structure
Andurel v2 separates application code, generated artifacts, and process boundaries. Everything outside the generated files is ordinary code you own.
Application layout
1cmd/app/ web process: load env, runtime.New, lifecycle.Run
2cmd/queue/ River worker process: runtime.NewQueue
3cmd/ssr/ Inertia SSR runtime for production
4cmd/migrate/ one-shot process that applies pending SQL
5cmd/seeds/ one-shot process that runs a named seed set
6config/ typed, validated configuration
7domains/ business logic and persistence; one file per domain
8domains/<entity>.sql hand-written SQL colocated with its domain
9domains/internal/queries/ narsilc output; imported only by domains/**
10services/ cross-domain workflows, transactions, side effects
11handlers/ flat HTTP package; func(ctx context.Context) error
12routes/ route data: names, paths, URL builders
13middleware/ app HTTP policy and the session definition
14internal/runtime/ composition root and process lifecycle
15resources/root.templ the Inertia root document
16resources/js/Pages/ Inertia page components
17resources/js/Layouts/ shared page layouts
18resources/js/Components/ reusable frontend components
19resources/js/routes.ts generated TypeScript URL helpers
20resources/js/types/ generated TypeScript payload types
21email/ templ email templates and send helpers
22queue/ River workers and registration
23queue/jobs/ River argument types
24migrations/ embedded goose SQL migrations
25seeds/ named seed sets
26css/ Tailwind source and theme tokens
27assets/ embedded static files and the Vite build in assets/dist
28bin/ pinned tools downloaded by andurel tool sync
29andurel.toml project metadata and pinned tool versions
30andurel.lock platform hashes for those tools
31AGENTS.md instructions for agents working in this project
Processes
A project has three long-running process shapes and two one-shot ones:
cmd/appbuilds the web graph: HTTP server, renderer, handlers, and the queue insert client. It is the only process that serves requests.cmd/queuebuilds the worker graph. It registers workers and periodic jobs and does not serve HTTP.cmd/ssrruns the Node Inertia renderer in production.cmd/migrateandcmd/seedsconnect, do one task, and exit. Migrations are never applied from application start.
internal/runtime owns each graph. cmd/* only loads the environment, creates a signal context, and calls lifecycle.Run around the runtime's start and stop functions.
Dependency direction
Dependencies point inward:
handlers/parse HTTP input, call a domain or service, and render. They never speak SQL.services/coordinate domains, own transactions, and call external side effects.domains/own entity rules, SQL, and generated queries. They import no HTTP, Inertia, routing, handler, middleware, or route package.- Only
domains/**importsdomains/internal/queries. Onlydomains,internal/runtime,cmd/,seeds/, andmigrations/namestorage.Connection. routes/holds data only. The router itself belongs topkg/anduin, not to the project.
andurel verify enforces these boundaries and reports a fix for each violation.
Generated files
These files are derived from a source of truth and should not be edited by hand:
| Path | Written by | Refresh with |
|---|---|---|
domains/internal/queries/** |
narsilc, from domains/**/*.sql |
andurel sync queries |
resources/js/routes.ts |
the route manifest in routes/ |
andurel sync routes |
resources/js/types/payloads.ts |
named handler payload structs and handler-owned inertia.FromStruct props |
andurel sync payloads |
resources/root_templ.go, email/*_templ.go |
templ | andurel run or andurel build |
assets/css/**, assets/dist/** |
Tailwind and Vite | andurel build |
andurel verify fails when generated output is stale and names the command that refreshes it. Hand-written code that happens to live beside generated code, such as domains/<entity>.go and resources/js/Pages/**, is yours.
Project metadata
andurel.toml is the scaffold's own record: schemaVersion, the Andurel version, the project name, the Inertia adapter, the JavaScript package manager, the SSR runtime, the database engine and null type, and the pinned tool versions. andurel.lock records the platform hashes for those tool binaries.
Commit both files. Framework package versions live in go.mod and are refreshed by andurel upgrade or andurel packages update.
Next, read Frontend Options for the UI layer, or Routing for the HTTP side.