01 · Before and afterThe pattern
Make the operation visible to hooks, and check uniqueness without treating the check as a guarantee.
// before: hook can't tell a dry run from a save
beforeChange: [async ({ data }) => { data.stripeId = await createCustomer(data) }]
// after
beforeChange: [async ({ data, operation }) => {
if (operation === 'validate') return data // no external calls on a dry run
data.stripeId ??= await createCustomer(data)
}]
// validate(): also query for an existing row with the same unique value,
// but still handle the unique-violation error on the real insert (no lock between the two).02 · Run it on your appThe check
If your app has a “preview / validate / dry run” mode, do your side-effecting hooks know they're in it?
If the honest answer is no or not sure, this is worth a look before it reaches production.