---
title: "Prisma Client Extensions"
slug: "prisma-client-extensions"
category: "backend"
tags: ["backend", "prisma", "client-extensions", "orm", "typescript"]
status: "stable"
last_updated: 2026-05-29
summary: "Use $extends with the query, result, model, and client components for soft-delete, computed fields, and custom methods; it replaced the removed $use middleware."
related:
  [
    "[[backend/prisma]]",
    "[[backend/prisma-client]]",
    "[[backend/prisma-schema]]",
    "[[backend/prisma-transactions]]",
    "[[backend/prisma-v6-to-v7-upgrade]]",
    "[[coding/typescript]]",
  ]
---

## Overview

Client extensions are the supported mechanism for cross-cutting behavior in Prisma. `prisma.$extends()` returns a new client that layers extra behavior over the base client through four components: `query`, `result`, `model`, and `client`. Extensions replaced the `$use` middleware API, which was deprecated in v4.16.0 and removed in v6.14.0; it does not exist in Prisma 7. Use extensions for soft-delete filters, computed fields, audit logging, and custom helper methods. For the client lifecycle that holds these extensions, see [[backend/prisma-client]].

## Assign the extended client; the base is immutable

`$extends` does not mutate the client. It returns a new instance with the extension applied.

```ts
const prisma = base.$extends({
  /* components */
})
```

- Export and use the extended `prisma`, not `base`. Queries on `base` skip the extension.
- Chain `$extends` calls to compose extensions. Each layer wraps the previous one in order.
- Type inference flows through the chain, so custom methods and computed fields are fully typed downstream. See [[coding/typescript]].

## Use the `query` component to intercept and rewrite queries

The `query` component runs around each operation. It is the soft-delete and tenant-isolation tool that `$use` used to provide.

```ts
const prisma = base.$extends({
  query: {
    post: {
      findMany({ args, query }) {
        args.where = { ...args.where, deletedAt: null }
        return query(args)
      },
    },
  },
})
```

- Scope hooks to a model and operation (`post.findMany`) or to `$allOperations` across a model.
- Call `query(args)` exactly once to forward to the database. Mutate `args` before the call to filter or default values.
- Do not cache inside a `query` hook. It fires on every matching call, which makes invalidation unpredictable.

## Use the `result` component to add computed fields

The `result` component adds derived fields without a database round trip.

```ts
const prisma = base.$extends({
  result: {
    user: {
      fullName: {
        needs: { firstName: true, lastName: true },
        compute(user) {
          return `${user.firstName} ${user.lastName}`
        },
      },
    },
  },
})
```

- `needs` declares the columns the computed field depends on. Prisma selects them automatically when the field is read.
- Computed fields are virtual; they are not stored and cannot be filtered on in `where`. Promote to a real column when you need to query it. See [[backend/prisma-schema]].

## Use `model` and `client` for custom methods

The `model` component adds methods to a specific model; `client` adds top-level methods to the client.

```ts
const prisma = base.$extends({
  model: {
    user: {
      async signUp(email: string) {
        return base.user.create({ data: { email } })
      },
    },
  },
  client: {
    $health() {
      return base.$queryRaw`SELECT 1`
    },
  },
})
```

- Use `model` methods for domain operations that belong to one entity (`user.signUp`).
- Use `client` methods for cross-cutting helpers (health checks, raw maintenance queries). See [[backend/prisma-raw-queries]].
- Extensions interact with transactions: inside an interactive `$transaction`, the `tx` client carries the same extensions. See [[backend/prisma-transactions]].

## Related

- [[backend/prisma]]
- [[backend/prisma-client]]
- [[backend/prisma-schema]]
- [[backend/prisma-transactions]]
- [[backend/prisma-v6-to-v7-upgrade]]
- [[coding/typescript]]
