Use the model and custom code alongside each other: configure standard fields, relationships and access in the UI; write payment checks, integrations and special components in custom. These files survive regeneration. Preserving a file does not guarantee its code remains compatible with every new model.
Configuration without code
Fields in Content offer Presentation: Markdown, Multiline, Email, URL and other inputs. List behavior controls supported search, filters and sorting. An entity's Record editor selects a side panel or separate page.
If a suitable setting exists, save the model and Generate. Use extension points for custom rules or screens. Write Go and React in a source editor: Generator UI does not edit arbitrary custom code.
Extending lists and forms
Each entity has two files:
custom/extension.tsx: complete page replacement and previously provided extension handlers.custom/ui-extension.tsx: additions to standard lists and forms under thegenerated/ui-extension.tsxcontract.
Lists support columns for new columns, cells for custom cell rendering, rowActions for actions and status for state. New column IDs must not collide with generated or reserved names. Custom columns do not automatically acquire server-side sorting or filtering.
textFields extends regular visible editable string and text inputs. Components receive inputProps. Preserve name, required, disabled, the value and label/error associations: the form still passes data through FormData. When wrapping the standard input, render defaultControl exactly once and preserve its value format.
This extension does not replace every field type. Readonly fields, generated identifiers, relationships, dates and enums have separate rules. Extend images with imageFields, which supplies typed references and processing state.
Replacing a whole page
Full replacement takes precedence over targeted extensions. It suits custom workflows, but you own data reads/writes, pagination, errors and accessibility. A small extension usually suffices for one column or form input; the generator continues updating the standard page.
When a column needs external data, fetch one bounded batch for current-page IDs. Match results by identifier. A missing result is not a zero amount. Display loading, errors and retry; do not apply an earlier page's response to the new page.
Connecting backend logic
In backend/internal/custom/app/composition.go, Configure connects dependencies and defines shutdown for custom clients. Do not close the shared database pool: the application owns it. The Configure context is for startup; requests need their own contexts.
Typed extension points connect operation handlers without editing generated startup code. The older public-route mechanism and newer composition mechanism pass dependencies differently. Do not connect them through globals or edit generated dependency assembly. For a separate public API, explicitly define its service and connection lifetimes.
Standard external APIs and read rules may suffice for content delivery. For example, the Admingen website can obtain data without a custom route.
Adding dependencies
cd admin
npm install clsx
npm run build
This installs a regular application package. Dependency files are preserved, but the generator still checks required dependencies and settings. Generate itself installs nothing.
Configure supported Vite plugins, aliases and build settings in admin/custom/vite.ts. This does not permit arbitrary tsconfig changes or execute plugins in an isolated secure environment.
After adding a model field, check your custom editor: it must preserve the complete current object, including fields unknown to its code. This does not automatically protect against concurrent editing. Check build, migration and actual persistence.
Replacing authentication storage
Regular custom handlers do not require a custom authentication repository. If you implement the internal Repository interface, however, RotateRefresh must perform every supplied RefreshSessionGuard check.
These checks run in the same transaction after credential/session validation but before marking the refresh token used. Do not move them to the browser. After a generator update, compare the generated contract and verify session refresh and revocation.
Continuing generation
Review model/file changes in Generate and earlier results in History. Ownership rules explain which files the generator updates and which remain your team's.