Skip to main content

Hooks

VEF has two hook surfaces:

  • CRUD operation hooks for framework-managed create, update, delete, import, and export flows
  • Bun model hooks for lower-level ORM query lifecycle interception

They solve different problems and should not be treated as the same mechanism.

Hook Families Overview

Hook familyWhere it runsScopeTypical use
CRUD hooksinside CRUD buildersone CRUD endpointbusiness invariants, transactional side effects, file promotion coordination
Bun model hooksinside ORM model lifecycleone model and query typelow-level query mutation, model lifecycle behavior, persistence-side checks

CRUD Hook Surface

CRUD builders expose these hook APIs:

OperationPre hookPost hook
CreateWithPreCreate(...)WithPostCreate(...)
UpdateWithPreUpdate(...)WithPostUpdate(...)
DeleteWithPreDelete(...)WithPostDelete(...)
CreateManyWithPreCreateMany(...)WithPostCreateMany(...)
UpdateManyWithPreUpdateMany(...)WithPostUpdateMany(...)
DeleteManyWithPreDeleteMany(...)WithPostDeleteMany(...)
ExportWithPreExport(...)no post-export hook
ImportWithPreImport(...)WithPostImport(...)

CRUD Hook Signatures

The exact processor type declarations — single-record, batch, and export/import — are maintained in one place: the Generic CRUD processor reference. This page focuses on when to use which hook and what runs inside the transaction.

CRUD Transaction Boundary

The important rule is that CRUD write operations already run inside transactions. Your CRUD hook receives the current transaction-scoped orm.DB, so additional database work participates in the same transaction automatically.

Example:

crud.NewCreate[User, UserParams]().
WithPostCreate(func(model *User, params *UserParams, ctx fiber.Ctx, tx orm.DB) error {
_, err := tx.NewInsert().Model(&AuditLog{
UserID: model.ID,
Action: "created",
}).Exec(ctx.Context())
return err
})

CRUD Hook Error Behavior

If a CRUD hook returns an error:

  • the operation fails
  • the surrounding transaction rolls back
  • the framework returns the error through normal result handling

This makes CRUD hooks a good place for business invariants that must be enforced atomically.

CRUD Hooks And File Lifecycle

Create, update, and delete builders integrate with the storage.Files / FilesFor[T] lifecycle facade (the replacement for the old Promoter[T]).

That means:

  • meta-tagged file fields are reconciled inside the same transaction as the business write
  • update reconciliation enqueues asynchronous deletes for replaced file values
  • delete reconciliation enqueues every referenced file for asynchronous removal
  • on transaction rollback no claim is consumed and no deletion is enqueued — there is nothing to "restore"

Hooks and file lifecycle therefore share one transactional lifecycle; the actual backend deletion happens asynchronously through the storage delete worker (see Storage).

Bun Model Hook Surface

At the ORM layer, VEF also exposes Bun hook interfaces:

Hook interfaceTrigger
orm.BeforeSelectHookbefore SELECT
orm.AfterSelectHookafter SELECT
orm.BeforeInsertHookbefore INSERT
orm.AfterInsertHookafter INSERT
orm.BeforeUpdateHookbefore UPDATE
orm.AfterUpdateHookafter UPDATE
orm.BeforeDeleteHookbefore DELETE
orm.AfterDeleteHookafter DELETE

These hooks are implemented on model types and operate at the ORM lifecycle level, not at the API action level.

When To Use CRUD Hooks

CRUD hooks are a good fit when:

  • the business step belongs tightly to one CRUD action
  • the public API should remain CRUD-shaped
  • the extra behavior must share the same transaction
  • the hook needs access to both params and model state

When To Use Bun Model Hooks

Bun hooks are a better fit when:

  • the behavior belongs to the model lifecycle itself
  • the logic should apply outside the API layer too
  • the hook needs to mutate or inspect the underlying Bun query
  • the concern is persistence-oriented rather than endpoint-oriented

When Not To Use Hooks

Hooks are a poor fit when:

  • the operation is no longer conceptually CRUD
  • the endpoint orchestrates multiple unrelated workflows
  • the action semantics are clearer as an explicit command endpoint
  • the behavior would become hard to understand because it is split across many hook registrations

In those cases, a custom handler is usually clearer.

Practical Advice

  • keep CRUD hook logic short and local to one operation
  • keep Bun model hooks focused on persistence behavior
  • use CRUD hooks for transactional business steps, not for unrelated side effects
  • if you find yourself stacking many CRUD hooks, reconsider whether the resource needs a custom handler
  • if the behavior should apply everywhere the model is used, prefer a model hook over an API hook

Next Step

Read Validation and Error Handling to see how request failures and business errors are surfaced to clients.