Layout: Module vs Feature
Axis supports two first-class directory layouts, chosen at scaffold time with --layout and recorded in axis.json. The framework doesn’t care which you pick — its only contract is the registries (Project Structure) — but tooling like axs add reads the recorded layout to place generated code correctly.
module — the default
Section titled “module — the default”Lambdas are grouped by module, then by kind, under lambdas/modules/; tables live centrally in config/tables/:
lambdas/modules/users/api/create/{index,service}.tslambdas/modules/jobs/workers/process/{index,service}.tsconfig/tables/billing.tsThis is the validated, battle-tested convention, it is the default, and it is valid for every starter. It suits small-to-medium REST apps where “show me all the API handlers” is the common navigation question.
feature — the advanced variant
Section titled “feature — the advanced variant”Lambdas are colocated by feature under lambdas/features/, with no kind segment, and a feature’s tables sit alongside its code (re-exported from the central config/tables/index.ts registry so the framework contract is unchanged):
lambdas/features/users/create/{index,service}.tslambdas/features/jobs/process/{index,service}.tslambdas/features/billing/tables/billing.ts ← colocated, registry re-exports itThis suits domain-driven teams where “show me everything about billing” is the common question.
How axs add places code
Section titled “How axs add places code”| Command | module layout | feature layout |
|---|---|---|
axs add lambda users/create --kind api --method POST --path /users | lambdas/modules/users/api/create/ | lambdas/features/users/create/ |
axs add lambda jobs/process --kind worker | lambdas/modules/jobs/workers/process/ | lambdas/features/jobs/process/ |
axs add table billing | config/tables/billing.ts + registry entry | lambdas/features/billing/tables/billing.ts + re-export |
The placement rules come straight from axis.json (paths.lambdas, conventions.lambdaGrouping, conventions.tableLocation) — never from inspecting the directory tree, which would be fragile on a fresh or customised project.
Support matrix
Section titled “Support matrix”In this version, feature layout is supported for the rest-v1, rest-v2, graphql, and worker starters. Only bare is module-only:
| Starter | module | feature |
|---|---|---|
rest-v1 | ✅ (default) | ✅ |
rest-v2 | ✅ (default) | ✅ |
graphql | ✅ (default) | ✅ |
worker | ✅ (default) | ✅ |
bare | ✅ (default) | ❌ not supported |
Passing an unsupported pairing fails fast at the CLI with an explicit error rather than scaffolding something half-supported:
[Axis] --layout feature is not supported with --template bare in this version.Starters supporting --layout feature: rest-v1, rest-v2, graphql, worker.Why the scope: every supported (starter, layout) pair is backed by a full CI-validated example project, so the matrix only lists what is genuinely validated. rest-v1, rest-v2, graphql, and worker each ship a feature twin — multi-module REST breadth for the first, the lean /{proxy+} v2 surface for the second, domain-grouped resolvers with colocated artifacts for the third, and job-domain grouping for the last. The rest-v2 twin exists mainly for matrix completeness: its single greedy /{proxy+} topology means the layout choice has less leverage than for rest-v1. bare is a single-Lambda floor with nothing to group, so it stays module-only by design — permanently, not pending. Because layout is an extensible enum in the manifest, adding pairings later breaks nothing.
Choosing
Section titled “Choosing”Default to module. Choose feature for a rest-v1, rest-v2, graphql, or worker project when your team organises ownership by domain and wants each feature’s handlers and tables in one place. On a graphql project the feature layout additionally colocates resolver artifacts (.vtl / APPSYNC_JS .js) at lambdas/features/<feature>/resolvers/, recorded as conventions.resolverLocation: "colocated"; the SDL stays central at assets/schema.graphql because one schema is the cross-feature contract. Both layouts are fully supported by axs add, the SDK generator, and the rest of the tooling — this is a navigation preference, not a capability trade.
© 2026 Axis Tech. Powered by axis-tech.co.