softDelete() function

Build the query extension that turns deletes into deletedAt stamps and hides stamped rows from reads.

Signature:

export declare function softDelete(input: SoftDeleteOptions): (client: any) => import("@prisma/client/extension").PrismaClientExtends<import("@prisma/client/runtime/client").InternalArgs<{}, {}, {}, {}>>;

Parameters

Parameter

Type

Description

input

SoftDeleteOptions

The unextended client and the per-model column config.

Returns:

(client: any) => import("@prisma/client/extension").PrismaClientExtends<import("@prisma/client/runtime/client").InternalArgs<{}, {}, {}, {}>>

A Prisma extension to pass to client.$extends().

Remarks

For every model listed in models, delete and deleteMany become an update/updateMany that writes the current time into the configured column, and the read operations (findMany, findFirst, findUnique, their OrThrow variants and count) gain a <column>: null filter. Models not listed pass straight through, deletes included.

Deletes themselves also filter on <column>: null, so only live rows are deletable and an original stamp is never overwritten by a second delete. The consequence is worth stating plainly: deleting an already-soft-deleted row throws not-found, exactly as deleting a row that was never there does.

findUnique works here because Prisma's extended where-unique accepts non-unique scalars as extra filters alongside the unique key.

The filter is applied to TOP-LEVEL reads only. A nested include or select that reaches a soft-deleted model through a relation is not intercepted, and it DOES return stamped rows; add where: { deletedAt: null } to the nested relation at those call sites when it matters.

Example

const base = new PrismaClient();
const client = base.$extends(softDelete({
    client: base,
    models: { User: { deletedAt: 'deletedAt' } },
}));

await client.user.delete({ where: { id } }); // stamps, does not remove
await client.user.findMany();                // stamped rows are absent

Read this page as plain markdown — no HTML, no navigation. For pasting into an LLM, or for an agent to fetch.