Files and conventions
Where state.ts and actions.ts go, how they map to routes, and what codegen checks before it writes the manifest.
Put state.ts and actions.ts next to the page.tsx they describe:
app/
page.tsx
state.ts → /
actions.ts → /
(shop)/products/[slug]/
page.tsx
state.ts → /products/[slug]
actions.ts → /products/[slug]
api/affordances/graph/[[...path]]/
route.ts (the route handler)- Route groups like
(shop)and parallel slots like@modaldon't appear in the route. - Folders starting with
_are skipped. - A route can have state without actions, or actions without state.
- Dynamic segments work as they do in Next:
[slug],[...slug], and[[...slug]].
The manifest
Codegen reads these files statically, without running them, and writes .affordances/manifest.ts. It imports each route's state and actions, and the route handler reads it.
It's regenerated:
- whenever Next loads the config (
withAffordancesruns it); - in
next dev, whenever anactionsorstatefile changes; - when you run
affordances build, for scripts and CI.
Commit it or not, as you like. affordances init adds .affordances to .gitignore.
What fails the build
Codegen stops with an error when:
- an
actionsfile doesn't start with'use server'; - a
defineActioncall'snameisn't a string literal; - two actions on one route share a name;
- a
statefile has no default export.
The lint rules catch the first two in your editor.