An entity is a declarative definition of a data model and its behavior. It combines the schema, access rules, lifecycle hooks, and custom actions into a single object. The framework reads this definition and generates everything: routes, validation, access enforcement, error handling.Documentation Index
Fetch the complete documentation index at: https://docs.vertz.dev/llms.txt
Use this file to discover all available pages before exploring further.
Defining an entity
'users') determines the API path (/api/users). The model defines the table structure and column annotations that control what’s exposed to clients.
Column annotations
| Annotation | Effect |
|---|---|
.hidden() | Never sent to the client (e.g., internal fields) |
.readOnly() | Included in responses, excluded from create/update inputs |
.default(value) | Default value — field becomes optional in create input |
Access rules
Access rules define who can perform each operation. They’re evaluated at request time, before any data access.rules.* descriptors from @vertz/server to define access. rules.public allows unrestricted access. For authenticated-only access, use rules.authenticated(). For entitlement checks, use rules.entitlement('task:update').
Hiding operations
Only operations with an access rule get a route. If you don’t define an access rule for an operation, the route simply doesn’t exist — no endpoint, no 404, nothing to discover:Row-level access
Forupdate and delete, the second argument is the existing row — enabling row-level checks:
Lifecycle hooks
Hooks run before or after database operations. Use them for data transformation and side effects.Before hooks
Transform or enrich data before it’s written to the database:Before hooks are for data enrichment, not data transformation. The return type must match the
input type — you can set or modify values within the schema’s shape, but you can’t add new fields
or change field types. The schema defines the shape, the hook fills in values.
After hooks
Run side effects after a successful write. After hooks are fire-and-forget — they don’t affect the response:update after hook receives both the previous and new state of the record.
Custom actions
Add domain-specific operations beyond CRUD:POST /api/tasks/:id/archive. The handler receives:
input— validated request bodyctx— the entity contexttask— the existing record (loaded by:id)
access object, using the action name as the key.
Custom actions support an optional
path property to override the generated URL segment. When
provided, the path replaces the default /:id/actionName segment but still respects the API
prefix (e.g., path: 'tasks/bulk-archive' produces POST /api/tasks/bulk-archive). Prefer the
default generated paths — they follow REST conventions and keep your routes consistent. Use path
only when you need a different URL structure.Cross-entity access
Entities can access other entities through dependency injection:inject at compile time. Dependencies are explicit and auditable.
Entity operations
Inside hooks and actions,ctx.entity provides typed CRUD operations for the current entity:
Generated routes
For each entity, the framework generates up to 5 CRUD routes plus custom action routes:| Method | Path | Operation |
|---|---|---|
GET | /api/{entity} | List with filtering and pagination |
GET | /api/{entity}/:id | Get by ID |
POST | /api/{entity} | Create |
PATCH | /api/{entity}/:id | Update |
DELETE | /api/{entity}/:id | Delete |
POST | /api/{entity}/:id/{action} | Custom action |
- CORS check
- Middleware chain
- Access rule evaluation
- Before hook (for mutations)
- Database operation
- After hook (for mutations)
- Response serialization (strip hidden fields)
Every entity operation also generates typed SDK methods for the UI client. When you define
entity('tasks', { ... }) with access rules for list, get, create, update, and delete,
the SDK automatically produces api.tasks.list(), api.tasks.get(id), api.tasks.create(data), etc.
Custom actions generate SDK methods too — api.tasks.archive(id, data). The SDK is generated
automatically when you run vertz dev or vertz build — you don’t need to run codegen manually.
See Data Fetching for UI usage.Server setup
Pass entities tocreateServer():
apiPrefix. The server validates inputs against the model schema, enforces access rules, and returns appropriate HTTP status codes (200, 201, 204, 400, 403, 404, 405, 409, 500).
Every entity’s model must be registered in
createDb({models}). This is validated at two levels:
the compiler catches missing models at build time (flagging ENTITY_MODEL_NOT_REGISTERED
errors), and createServer() validates again at startup with a clear error listing all missing
models. You’ll never hit a cryptic runtime failure on first request.