# Author in PSL (/docs/orm/contract-authoring/psl-syntax)

> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.

Write the Prisma ORM contract in the Prisma schema language you already know, plus the Prisma ORM 8 additions.

Location: ORM > Contract authoring > Author in PSL

PSL, the Prisma Schema Language, is the preferred way to author [your contract](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract), the `contract.prisma` file that replaced `schema.prisma`. You write one file, usually `src/prisma/contract.prisma`, and [`npx prisma contract emit`](https://www.prisma.io/docs/cli/contract-emit) writes `contract.json` and `contract.d.ts` beside it. If you know the Prisma schema language, most of a contract file reads exactly as you expect. The five biggest additions are listed here, and the rest of the page is the full reference for every attribute and block:

* named types: give a database column type a name you can reuse on many fields.
* enums: an enum can now say how its values are stored, and what each member stores.
* value objects: a structured value stored inside its parent row, with no table of its own.
* base models and variants: one table can hold more than one kind of record. Put the shared fields in a base model, put the differences in each variant, and Prisma ORM uses one column to tell them apart.
* extension types: field types that come from an npm package, such as vectors.

The `datasource` and `generator` blocks are gone: the connection URL and the file paths are set in `prisma.config.ts` instead. [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7#schema) lists every change to the schema file, including what each old `@db.` attribute becomes.

## A complete contract [#a-complete-contract]

Every contract starts with `// use prisma-8`, so keep that line at the top.

  

#### PostgreSQL

```prisma title="src/prisma/contract.prisma" 
// use prisma-8

types {
  ShortName = VarChar(35)
}

type Address {
  street  String
  city    String
  zip     String?
  country String
}

enum Priority {
  @@type("pg/text@1")
  Low    = "low"
  High   = "high"
  Urgent = "urgent"
}

model User {
  id        Uuid     @id @default(uuid())
  email     String
  createdAt DateTime @default(now())
  address   Address?
  posts     Post[]

  @@map("user")
}

model Post {
  id        Uuid      @id @default(uuid())
  title     ShortName
  userId    Uuid
  priority  Priority  @default(Low)
  createdAt DateTime  @default(now())

  user User @relation(fields: [userId], references: [id])

  @@map("post")
}
```

#### MongoDB

```prisma title="src/prisma/contract.prisma" 
// use prisma-8

type Address {
  street  String
  city    String
  zip     String?
  country String
}

enum UserRole {
  @@type("mongo/string@1")
  Admin  = "admin"
  Author = "author"
  Reader = "reader"
}

model User {
  id      ObjectId @id @map("_id")
  email   String
  role    UserRole
  address Address?
  posts   Post[]

  @@map("users")
}

model Post {
  id       ObjectId @id @map("_id")
  title    String
  authorId ObjectId

  author User @relation(fields: [authorId], references: [id])

  @@index([authorId])
  @@map("posts")
}
```

`Uuid` is PostgreSQL's `uuid` type written as a field type. Run `npx prisma contract emit` after any change to refresh `contract.json` and `contract.d.ts`, and then [`npx prisma db init`](https://www.prisma.io/docs/cli/db-init) creates the tables.

## Point the config at the schema [#point-the-config-at-the-schema]

The config's `contract` path names the one file Prisma ORM reads: it takes a single path, so there is no folder of contract files. If the path ends in `.prisma`, Prisma ORM reads it as PSL, and if it ends in `.ts`, as TypeScript. The `db` key holds the connection URL:

```typescript title="prisma.config.ts"
import 'dotenv/config';
import { definePrismaConfig } from "prisma/config";
import { defineConfig as ormConfig } from "@prisma/orm-postgres/config";

export default definePrismaConfig({
  orm: ormConfig({
    contract: "./src/prisma/contract.prisma",
    db: {
      connection: process.env['DATABASE_URL']!,
    },
  }),
});
```

`npx prisma orm init` writes a config like this, `DATABASE_URL` included. The import chooses the database: `@prisma/orm-postgres/config` makes it a PostgreSQL project, and `@prisma/orm-mongo/config` a MongoDB one. [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7#schema) lists the other keys.

## Models and fields [#models-and-fields]

Models declare fields with a type, an optional `?` marker, and attributes. [Scalar fields](https://www.prisma.io/docs/orm/data-modeling#scalar-fields) lists the types a field can hold, among them `String`, `Int`, `Boolean`, `Decimal`, `DateTime`, `Json`, and `Bytes`. You can write a PostgreSQL type wherever you would write `String` or `DateTime`. The PostgreSQL types you can write are `VarChar`, `Char`, `Numeric`, `Timestamp`, `Timestamptz`, `Time`, `Timetz`, `Date`, `Uuid`, `Inet`, `SmallInt`, and `Real`, plus `DateString`, `TimestampString`, `TimestamptzString`, and `TimeString`, which store the same columns but read back as text. On PostgreSQL, plain `String` is a `text` column, `Int` is `int4`, and `DateTime` is `timestamptz`.

* `@id` marks the primary key. `@@id([a, b])` declares a composite key.
* `@unique` adds a unique constraint on one field. `@@unique([userId, title])` adds one across several fields.
* `@@index([...])` declares a secondary index.
* `@default(...)` sets a default. Database defaults are a literal, `@default(now())`, `@default(autoincrement())`, or `@default(dbgenerated("nextval('user_serial_seq')"))`, whose string is any SQL expression; the database fills them in. Generated defaults are `uuid()` (a version 4 UUID, the same as `uuid(4)`), `uuid(7)`, `cuid(2)`, `ulid()`, and `nanoid()`, where `nanoid(21)` sets the length to any value from 2 to 255; Prisma ORM computes them when it writes the row, and the database will not fill them in for you, so a row written by raw SQL or another application gets no value. Prisma ORM 7's `cuid()` is rejected with a hint to use `cuid(2)`.
* `@map("column_name")` sets a field's column name in the database. `@@map("table_name")` sets the table or collection name when it differs from the model name.
* `@@check(expression: "total >= 0", name: "order_total_positive")` adds a check constraint of your own to the table. See [Check constraints](#check-constraints).
* `@@control(observed)` says how far Prisma ORM manages the table. See [Control policy](#control-policy).

A field can be a list on PostgreSQL: `tags String[]` is a `text[]` column, and the same works for `Int[]` and the other scalar types. Prisma ORM adds a check constraint to a list column so it cannot hold a `NULL` element. To leave that constraint out, for example when the column already exists without it, add `@noCheck(elementNotNull)` to the field. Lists of enums and of named types are not supported; a list of a value object is, as [Value objects](#value-objects) shows.

`@updatedAt` is gone, so write `temporal.updatedAt()` where the field's type would go:

```prisma
model Post {
  updatedAt temporal.updatedAt()
}
```

Prisma ORM sets the field to the current time on every create and update. `temporal` is built in, so you do not import it or declare it. On PostgreSQL the column is `timestamptz`, and you can still set the field yourself on a write. `temporal.createdAt()` sets the field once, when the row is created.

How IDs map differs by database:

  

#### PostgreSQL

```prisma
model User {
  id Uuid @id @default(uuid())
}
```

#### MongoDB

```prisma
model User {
  id ObjectId @id @map("_id")
}
```

On PostgreSQL the primary key is an ordinary column, so pick its type and default yourself. On MongoDB the primary key is the document's `_id`, so type it `ObjectId` and map it to `_id`.

### Indexes [#indexes]

`@@index([...])` takes a list of fields, and on PostgreSQL the named arguments below. Either the list or `expression:` is required, and an `expression:` index needs a `name:`:

```prisma
model User {
  @@index([name], where: "(name IS NOT NULL)", name: "user_name_active")
  @@index(expression: "lower(handle)", unique: true, name: "user_handle_lower")
  @@index([slug], type: "hash", name: "user_slug_hash")
}
```

* `expression:` is the whole index expression as SQL, in place of the field list.
* `where:` makes a partial index; it is the condition as SQL, without the `WHERE` keyword.
* `unique:` makes a unique index. `@@unique([...])` is a unique constraint, which is the usual way to say a value must be unique; use `unique:` on `@@index` when you also need `expression:` or `where:`.
* `type:` picks the index method, such as `"hash"` or `"gin"`.
* `name:` names the index. The name in the database is not exactly what you typed: it gets an eight-character hash on the end, `user_name_active_000a85d8`, and if you change `name:` later, the next `migration plan` renames the index instead of dropping and recreating it. `map:` instead sets the exact name, for an index that already exists in the database, which is what [`contract infer`](https://www.prisma.io/docs/cli/contract-infer) writes for indexes it finds. Give one or the other, not both.

The `expression:` and `where:` strings go into the SQL as written, so they use column names, not field names (they differ when a field has `@map`), and you quote the names yourself. Prisma ORM does not check the SQL until the migration runs. On MongoDB, `@@index` takes different arguments; see [MongoDB indexes](#mongodb-indexes).

### Check constraints [#check-constraints]

`@@check` adds a check constraint you write yourself, on top of the ones Prisma ORM generates for enum and list columns:

```prisma
model Order {
  id    Int     @id @default(autoincrement())
  total Decimal

  @@check(expression: "total >= 0", name: "order_total_positive")
}
```

`expression:` is the condition as SQL, using column names, as on `@@index`. `name:` and `map:` work as they do on `@@index`: `name:` for a constraint you are adding, and `map:` for one that already exists in the database under that exact name. A model can carry any number of `@@check` attributes. PostgreSQL only.

Prisma ORM also adds two check constraints of its own: one on every enum column, so it accepts only the enum's values, and one on every list column, so it rejects `NULL` elements. When one of them gets in your way, `@noCheck` on the field leaves both out, `@noCheck(membership)` leaves out only the enum check, and `@noCheck(elementNotNull)` only the list check. The field's TypeScript type does not change, so the database can then hold values the type does not describe.

### Control policy [#control-policy]

`@@control(...)` says how far Prisma ORM manages the table, with one of four values:

| Value                   | `db verify`                                                             | Migrations                                    |
| ----------------------- | ----------------------------------------------------------------------- | --------------------------------------------- |
| `managed` (the default) | The table must exist and match the model exactly.                       | Create, alter, and drop it.                   |
| `tolerated`             | Declared columns must match; extra columns are accepted.                | Create it if missing; never alter or drop it. |
| `external`              | Declared columns must match; extra columns and constraints are ignored. | Never touch it.                               |
| `observed`              | Anything goes; a mismatch is a warning, not a failure.                  | Never touch it.                               |

Put it on a model whose table something else owns, such as an audit table another system writes:

```prisma
model AuditLog {
  id      Int    @id @default(autoincrement())
  message String

  @@control(observed)
}
```

## Named types [#named-types]

The `types` block gives a database column type a name you can reuse on many fields:

```prisma
types {
  ShortName = VarChar(35)
}
```

Fields then use `ShortName` like any built-in type. The name keeps the column decision in one place: a `varchar(35)` column rather than `text`. You do not have to name a type: a field can use the native PostgreSQL type directly, such as `VarChar(35)`, `Numeric(10, 2)`, `Uuid`, or `Timestamptz`.

Three types cover big integers, and they differ in what your code receives:

| Type           | Column    | In your code                                                                |
| -------------- | --------- | --------------------------------------------------------------------------- |
| `BigInt`       | `bigint`  | a JavaScript `bigint`                                                       |
| `BigIntNumber` | `bigint`  | a JavaScript `number`; a read or write outside the safe integer range fails |
| `UnboundedInt` | `numeric` | a JavaScript `bigint` of any size                                           |

In Prisma ORM 8 the native type is the field's type, so `String @db.VarChar(35)` from Prisma ORM 7 becomes `VarChar(35)`, and the `@db.` attributes are gone. The `types` block is PostgreSQL only.

## Enums [#enums]

An enum lists its members. It can also say, with `@@type`, how their values are stored, and what each member stores:

```prisma
enum Priority {
  @@type("pg/text@1")
  Low    = "low"
  High   = "high"
  Urgent = "urgent"
}
```

In `pg/text@1`, `pg` is PostgreSQL, `text` is the column type, and `@1` is the version of how the value is stored and read. Write `@@type("pg/int4@1")` to store the values as integers instead. When a member has no explicit value, the member name itself is stored.

`@@type` is optional, and when you leave it out Prisma ORM picks the type from the member values: bare member names and string values give the database's text type, and integer values give its integer type. Give every member the same kind of value, because a mix of string and integer values throws an error whose `code` is `PSL_ENUM_CANNOT_INFER_TYPE`. A `@default` names the member, as in `priority Priority @default(Low)`, even where the member stores a different value.

An `enum` block is not a PostgreSQL `enum` type: the column is text or an integer. For a PostgreSQL `enum` type, declare it in a `native_enum` block and type the field `pg.enum(Role)`:

```prisma
native_enum Role {
  admin  = "admin"
  member = "member"
}

model User {
  role pg.enum(Role)
}
```

Each member needs a value. `pg` comes with `@prisma/orm-postgres`, so there is nothing to import. You do not create the PostgreSQL type yourself: `npx prisma migration plan` includes the `CREATE TYPE`.

## Value objects [#value-objects]

A `type` block declares a value object: a structured value stored inside its parent row, with no table of its own.

```prisma
type Address {
  street  String
  city    String
  zip     String?
  country String
}

model User {
  id        Uuid     @id @default(uuid())
  address   Address?
  addresses Address[]
}
```

A value object field can be optional or a list, and a `type` block can hold a field of another `type`. Watch the two spellings: `types { ... }` declares named types, and `type X { ... }` declares a value object. Storage differs by database: on PostgreSQL a value object field is stored in a single `jsonb` column, while on MongoDB it is an embedded document. Either way, `contract.d.ts` types it as a structured object rather than untyped JSON. On MongoDB, whether to embed or reference is the central modeling decision, and [MongoDB data modeling](https://www.prisma.io/docs/orm/data-modeling/mongodb#embed-or-reference) covers it.

## Relations [#relations]

Relations use the `@relation` syntax you know from Prisma ORM. The side that holds the foreign key declares the scalar field and the mapping, and the other side declares a list:

```prisma
model Post {
  userId Uuid
  user   User @relation(fields: [userId], references: [id])
}

model User {
  posts Post[]
}
```

Add `onDelete` and `onUpdate` to the same `@relation`: they belong on the side that holds the foreign key, not on the list side, and each takes `Cascade`, `Restrict`, `NoAction`, `SetNull`, or `SetDefault`:

```prisma
model Post {
  authorId Uuid
  editorId Uuid?
  author   User  @relation("Authored", fields: [authorId], references: [id], onDelete: Cascade)
  editor   User? @relation("Edited", fields: [editorId], references: [id], onDelete: SetNull)
}

model User {
  posts  Post[] @relation("Authored")
  edited Post[] @relation("Edited")
}
```

When two relations join the same two models, as `Authored` and `Edited` do here, give each pair the same `@relation("Name")` on both ends so Prisma ORM can tell which list belongs to which foreign key; otherwise `npx prisma contract emit` fails with an error whose `code` is `PSL_AMBIGUOUS_BACKRELATION`. For a one-to-one, make the other side singular instead of a list, so `User` declares `profile Profile?`, and put `@unique` on the foreign-key field:

```prisma
model Profile {
  userId Uuid @unique
  user   User @relation(fields: [userId], references: [id])
}
```

Many-to-many relations need a model for the join table, and you write that model yourself: there is no implicit many-to-many. That model must follow two rules: if a side has a composite primary key, that model needs one foreign-key field for each part of it, and its `@@id([...])` must list exactly the foreign-key fields and nothing else.

```prisma
model Post {
  tags Tag[]
}

model Tag {
  posts Post[]
}

model PostTag {
  postId Uuid
  tagId  Uuid

  post Post @relation(fields: [postId], references: [id])
  tag  Tag  @relation(fields: [tagId], references: [id])

  @@id([postId, tagId])
  @@map("post_tag")
}
```

You then read `post.tags` as a list of `Tag`, without mentioning `PostTag` in the query. Break either rule and `npx prisma contract emit` reports which list field it could not match to a model. If two models qualify, `npx prisma contract emit` throws an error whose `code` is `PSL_AMBIGUOUS_BACKRELATION`: put the same `@relation("name")` on both ends of one pair, so on `PostTag.post` for `Post.tags`.

For which shape to choose and which side owns the foreign key, see [relational data modeling](https://www.prisma.io/docs/orm/data-modeling/relational-databases) and [MongoDB data modeling](https://www.prisma.io/docs/orm/data-modeling/mongodb).

## Namespaces [#namespaces]

A PostgreSQL schema other than `public` is a `namespace` block, and the models inside it get their tables there:

```prisma
namespace audit {
  model AuditLog {
    id      Int    @id @default(autoincrement())
    message String

    @@map("audit_log")
  }
}
```

Models outside any block are in `public`. In queries, the block name is the segment after `db.orm`, so this model is `db.orm.audit.AuditLog`. A relation can point at a model that another extension pack owns in a different schema, written `<pack>:<schema>.<Model>`, for example `supabase:auth.AuthUser`; the [Supabase extension](https://www.prisma.io/docs/orm/extensions) documents that form.

## Row-level security [#row-level-security]

Two block kinds and one attribute declare PostgreSQL row-level security, and [`migration plan`](https://www.prisma.io/docs/cli/migration-plan) turns them into `ENABLE ROW LEVEL SECURITY` and `CREATE POLICY` statements. `@@rls` on a model turns row-level security on for its table. A `policy_select`, `policy_insert`, `policy_update`, `policy_delete`, or `policy_all` block declares one policy for one operation, and a `role` block declares a database role a policy names:

```prisma
model User {
  id Uuid @id @default(uuid())

  @@map("user")
  @@rls
}

namespace unbound {
  role authenticated {}
}

policy_select user_self_read {
  target = User
  roles  = [authenticated]
  using  = "id = current_setting('app.user_id')::uuid"
}

policy_update user_self_write {
  target     = User
  roles      = [authenticated]
  using      = "id = current_setting('app.user_id')::uuid"
  withCheck  = "id = current_setting('app.user_id')::uuid"
  permissive = false
}
```

Policy and role blocks assign their settings with `=`, unlike model attributes. `target` names the model, which must carry `@@rls`; put the policy blocks inside the same `namespace` block as the model when it has one. `roles` lists bare role names. A role Prisma ORM should create needs a `role` block, whose braces stay empty; a role that already exists in the database, such as `public`, is written bare with no block: `roles = [public]`. `using` and `withCheck` are the two conditions as SQL, using column names: `policy_select` and `policy_delete` take `using`, `policy_insert` takes `withCheck`, and `policy_update` and `policy_all` take either or both. `permissive = false` makes the policy `AS RESTRICTIVE` in PostgreSQL's terms, so a row must pass it as well as the permissive policies. The block's name becomes the policy name with a hash on the end, as index names do. A `role` block must be inside `namespace unbound { }`; `unbound` is a reserved word meaning "not in any schema", which is where a role belongs.

## MongoDB indexes [#mongodb-indexes]

On MongoDB, `@@index` and `@@unique` take a list of fields, each with an optional sort direction, plus MongoDB's own index options as named arguments, and `@@textIndex` declares a text index:

```prisma
model Post {
  @@index([authorId])
  @@index([createdAt(sort: Desc), authorId])
  @@index([expiresAt], expireAfterSeconds: 3600, sparse: true)
  @@index([title], filter: "{ \"kind\": \"article\" }")
  @@index([location], type: "2dsphere")
  @@index([wildcard(meta)], exclude: ["meta.internal"])
  @@textIndex([title, body], weights: { "title": 10, "body": 1 }, language: "english")
}

model User {
  @@unique([email], collationLocale: "en", collationStrength: 2)
}
```

`sort: Asc` or `sort: Desc` on a field sets its direction; this form is MongoDB only. The keys in `weights` are field names, quoted. The named arguments are `type` (`"text"`, `"2dsphere"`, `"2d"`, or `"hashed"`), `sparse`, `expireAfterSeconds`, `filter` (a partial filter expression, written as a JSON string), `default_language` and `languageOverride` for a `type: "text"` index, `include` or `exclude` for a wildcard index, and the collation options `collationLocale`, `collationStrength`, `collationCaseLevel`, `collationCaseFirst`, `collationNumericOrdering`, `collationAlternate`, `collationMaxVariable`, `collationBackwards`, and `collationNormalization`. `@@textIndex` takes `weights`, `language`, `languageOverride`, `filter`, and the same collation options. There is no `name:` on MongoDB; MongoDB names the index from its keys.

A wildcard index covers every field under a path, which is how you index documents whose keys you do not know in advance. Write `wildcard()` in the field list to cover the whole document, or `wildcard(meta)` to cover the fields under `meta`; the key becomes `$**` or `meta.$**`. `include` and `exclude` are lists of field names, quoted, that narrow what the index covers; give one or the other, and only with `wildcard()`. An index can hold one `wildcard()`, and it cannot be an `@@unique`, take `expireAfterSeconds`, or set a `type:` such as `"hashed"`.

## Base models and variants [#base-models-and-variants]

A base model declares a discriminator field, the field whose value says which variant a row is. Each variant names its base and its discriminator value:

```prisma
model Task {
  id     Uuid   @id @default(uuid())
  title  String
  type   String

  @@discriminator(type)
  @@map("task")
}

model Bug {
  severity     String
  stepsToRepro String?

  @@base(Task, "bug")
  @@map("bug")
}
```

A field name is written bare, as `type` is in `@@discriminator(type)`, and a database name is quoted, as in `@@map("task")`. Rows whose `type` column holds `"bug"` are `Bug` records. A variant reuses its base model's fields, so a `Bug` has `id`, `title`, and `type` as well as `severity` and `stepsToRepro`. A variant does not declare an `@id` of its own: it takes the base model's primary key.

You query a variant through the base model: `db.orm.public.Task.variant('Bug')` returns the `Bug` rows only, and `public` here is the PostgreSQL schema. Writing a row of a variant starts with the same `variant('Bug')` call. See [`variant()`](https://www.prisma.io/docs/orm/reference/orm-client#variant).

On a variant, `@@map` does more than rename: on PostgreSQL it chooses between two storage layouts. Give the variant its own `@@map`, as `Bug` has here, and its fields are in a table of their own that shares the base model's primary key. Leave `@@map` out and they are nullable columns in the base table. [Relational data modeling](https://www.prisma.io/docs/orm/data-modeling/relational-databases#polymorphic-relations) covers choosing between the two.

On MongoDB, a variant adds its fields to documents in the base model's collection, so it declares `@@base` but no `@@map` of its own.

## Extension types [#extension-types]

An extension pack is an npm package that adds field types Prisma ORM does not ship, such as vectors. Install the pack, add the import and the `extensions` line to the config shown above, then call its types in the `types` block:

```bash
npm install @prisma/orm-extension-pgvector
```

```typescript title="prisma.config.ts"
import pgvector from "@prisma/orm-extension-pgvector/control";

// inside ormConfig({ ... }), beside contract and db:
    extensions: [pgvector],
```

```prisma title="src/prisma/contract.prisma"
types {
  Embedding1536 = pgvector.Vector(1536)
}

model Post {
  id        Uuid           @id @default(uuid())
  embedding Embedding1536?
}
```

A field can also use the pack's type directly, with the argument named: `embedding pgvector.Vector(length: 1536)?`. The `pgvector` part of `pgvector.Vector(1536)` is a fixed name the pack declares, not the name you gave the import. List the pack before using its types, and run `npx prisma contract emit` again after changing the extension list. [Using extensions](https://www.prisma.io/docs/orm/extensions/using-extensions) covers installing a pack and names the packs you can add.

## Starting from an existing database [#starting-from-an-existing-database]

If the database already exists, don't write the contract by hand: [`contract infer`](https://www.prisma.io/docs/cli/contract-infer) reads the live schema and writes a starter `contract.prisma` for you to review and edit.

## Prompt your coding agent [#prompt-your-coding-agent]

Projects created with `npm create prisma@latest -- my-app` include the [Prisma ORM skills](https://www.prisma.io/docs/ai/tools/skills#available-skills-for-prisma-8) for your coding agent: skills are instruction files the agent reads. In an existing project, run `npx prisma skills sync` to add them. The `prisma-8` skill covers PSL authoring, so ask your agent to:

* "Using the prisma-8 skill, add a Status enum stored as text and use it on the Order model."
* "Add a one-to-many between User and Post with the foreign key on Post."
* "Give the Post model a composite unique constraint on userId and title."

## Next steps [#next-steps]

* Run `npx prisma contract emit` and inspect [`contract.json` and `contract.d.ts`](https://www.prisma.io/docs/orm/contract-authoring/the-contract-artifact). You do not import them yourself. `db`, the client that reads both, is in `src/prisma/db.ts`, and `prisma orm init` writes that file. See [transactions and runtime](https://www.prisma.io/docs/orm/reference/transactions-and-runtime).
* If you prefer defining models in code, see [authoring in TypeScript](https://www.prisma.io/docs/orm/contract-authoring/typescript-schema-builder).
* Plan changes to a database you have already created with [`migration plan`](https://www.prisma.io/docs/cli/migration-plan).

## Related pages

- [`Author in TypeScript`](https://www.prisma.io/docs/orm/contract-authoring/typescript-schema-builder): Define the Prisma ORM contract with a typed builder in TypeScript instead of a schema file. Same models, same `contract.json` and `contract.d.ts`, no separate language.
- [`contract.json and contract.d.ts`](https://www.prisma.io/docs/orm/contract-authoring/the-contract-artifact): contract.json and contract.d.ts are the two files every other part of Prisma ORM reads. Here is what is inside them.
- [`Editor support`](https://www.prisma.io/docs/orm/contract-authoring/editor-support): What the Prisma VS Code extension does for a Prisma ORM contract, and what to do when it stops accepting the file.
- [`Supported database features`](https://www.prisma.io/docs/orm/contract-authoring/capabilities): The contract records which database features your packages support, so Prisma ORM can reject an unsupported one early with a clear error.
- [`The data contract`](https://www.prisma.io/docs/orm/contract-authoring/the-data-contract): The data contract is the one description of your data model and how it is stored. Prisma ORM types your queries, plans your migrations, and checks your database against it.