Overview

The Prisma Client API is generated based on the models in your Prisma schema. Models are typically 1:1 mappings of your database tables.

In some cases, especially when using introspection, it might be useful to decouple the naming of database tables and columns from the names that are used in your Prisma Client API. This can be done via the @map and @@map attributes in your Prisma schema.

Example

Assume you have a database schema looking similar to this:

CREATE TABLE users (
user_id SERIAL PRIMARY KEY NOT NULL,
name VARCHAR(256),
email VARCHAR(256) UNIQUE NOT NULL
);
CREATE TABLE posts (
post_id SERIAL PRIMARY KEY NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
title VARCHAR(256) NOT NULL,
content TEXT,
author_id INTEGER REFERENCES users(user_id)
);
CREATE TABLE profiles (
profile_id SERIAL PRIMARY KEY NOT NULL,
bio TEXT,
user_id INTEGER NOT NULL UNIQUE REFERENCES users(user_id)
);
CREATE TABLE categories (
category_id SERIAL PRIMARY KEY NOT NULL,
name VARCHAR(256)
);
CREATE TABLE post_in_categories (
post_id INTEGER NOT NULL REFERENCES posts(post_id),
category_id INTEGER NOT NULL REFERENCES categories(category_id)
);
CREATE UNIQUE INDEX post_id_category_id_unique ON post_in_categories(post_id int4_ops,category_id int4_ops);

When introspecting a database with that schema, you'll get a Prisma schema looking similar to this:

model categories {
category_id Int @default(autoincrement()) @id
name String?
post_in_categories post_in_categories[]
}
model post_in_categories {
category_id Int
post_id Int
categories categories @relation(fields: [category_id], references: [category_id])
posts posts @relation(fields: [post_id], references: [post_id])
@@unique([post_id, category_id], name: "post_id_category_id_unique")
}
model posts {
author_id Int?
content String?
created_at DateTime? @default(now())
post_id Int @default(autoincrement()) @id
title String
users users? @relation(fields: [author_id], references: [user_id])
post_in_categories post_in_categories[]
}
model profiles {
bio String?
profile_id Int @default(autoincrement()) @id
user_id Int @unique
users users @relation(fields: [user_id], references: [user_id])
}
model users {
email String @unique
name String?
user_id Int @default(autoincrement()) @id
posts posts[]
profiles profiles?
}

The are a few "issues" with this Prisma schema when the Prisma Client API is generated:

Adhering to Prisma's naming conventions

Prisma has a naming convention of camelCasing and using the singular form for Prisma models. If these naming conventions are not met, the Prisma schema can become harder to interpret and the generated Prisma Client API will feel less natural. Consider the following, generated model:

model users {
user_id Int @default(autoincrement()) @id
posts posts[]
profiles profiles?
}

Although profiles refers to a 1:1 relation, its type is currently called profiles in plural, suggesting that there might be many profiles in this relation. With Prisma conventions, the models and fields were ideally named as follows:

model User {
user_id Int @default(autoincrement()) @id
posts Post[]
profile Profile?
}

Because these fields are "Prisma-level" relation fields that do not manifest you can manually rename them in your Prisma schema.

Naming of annotated relation fields

Foreign keys are represented as a combination of a annotated relation fields and its corresponding relation scalar field in the Prisma schema. Here's how all the relations from the SQL schema are currently represented:

model categories {
category_id Int @default(autoincrement()) @id
post_in_categories post_in_categories[] // virtual relation field
}
model post_in_categories {
category_id Int // relation scalar field
post_id Int // relation scalar field
categories categories @relation(fields: [category_id], references: [category_id]) // virtual relation field
posts posts @relation(fields: [post_id], references: [post_id])
@@unique([post_id, category_id], name: "post_id_category_id_unique")
}
model posts {
author_id Int?
post_id Int @default(autoincrement()) @id
users users? @relation(fields: [author_id], references: [user_id])
post_in_categories post_in_categories[]
}
model profiles {
profile_id Int @default(autoincrement()) @id
user_id Int @unique
users users @relation(fields: [user_id], references: [user_id])
}
model users {
user_id Int @default(autoincrement()) @id
posts posts[]
profiles profiles?
}

Using @map and @@map to rename fields and models in the Prisma Client API

You can "rename" fields and models that are used in the Prisma Client by mapping them to the "original" names in the database using the @map and @@map attributes. For the example above, you could e.g. annotate your models as follows to prevent the mentioned issues.

After you introspected your database with prisma introspect, you can manually adjust the resulting Prisma schema as follows:

model Category {
category_id Int @default(autoincrement()) @id
post_in_categories post_in_categories[]
@@map(name: "categories")
}
model PostInCategories {
category Category @map(name: "category_id")
post Post @map(name: "post_id")
@@unique([post, category], name: "post_id_category_id_unique")
@@map(name: "post_in_categories")
}
model Post {
post_id Int @default(autoincrement()) @id
author User? @map(name: "author_id")
post_in_categories PostInCategories[]
@@map(name: "posts")
}
model Profile {
profile_id Int @default(autoincrement()) @id
user_id User @map(name: "user_id")
@@map(name: "profiles")
}
model User {
user_id Int @default(autoincrement()) @id
posts Post[]
profiles Profile?
@@map(name: "users")
}

With these changes, you're now adhering to Prisma's naming conventions and the generated Prisma Client API feels more "natural":

// Nested writess
const profile = await prisma.profile.create({
data: {
bio: 'Hello World',
user: {
create: {
name: 'Alice',
email: 'alice@prisma.io',
},
},
},
})
// Fluent API
const userByProfile = await prisma.profile
.findOne({
where: { id: 1 },
})
.user()

Warning: @map and @@map attributes are removed when you run prisma introspect again. You therefore might want to back up your Prisma schema with these attributes in order to not having to annotate everything from scratch again after a re-introspection.

Renaming relation fields

Prisma-level relation fields (sometimes referred to as "virtual relation fields") only exist in the Prisma schema, but do not actually manifest in the underlying database. You can therefore name these fields whatever you want.

Consider the following example of an ambiguous relation in a SQL database:

CREATE TABLE "User" (
id SERIAL PRIMARY KEY
);
CREATE TABLE "Post" (
id SERIAL PRIMARY KEY,
"author" integer NOT NULL,
"favoritedBy" INTEGER,
FOREIGN KEY ("author") REFERENCES "User"(id),
FOREIGN KEY ("favoritedBy") REFERENCES "User"(id)
);

Prism's introspection will output the following Prisma schema:

model Post {
id Int @default(autoincrement()) @id
author User @relation("Post_authorToUser", references: [id])
favoritedBy User? @relation("Post_favoritedByToUser", references: [id])
}
model User {
id Int @default(autoincrement()) @id
Post_Post_authorToUser Post[] @relation("Post_authorToUser")
Post_Post_favoritedByToUser Post[] @relation("Post_favoritedByToUser")
}

Since the names of the virtual relation fields Post_Post_authorToUser and Post_Post_favoritedByToUser are based on the generated relation names, they don't look very friendly in the Prisma Client API. In that case, you can rename the relation fields to anything you like, e.g.:

model Post {
id Int @default(autoincrement()) @id
author User @relation("Post_authorToUser", references: [id])
favoritedBy User? @relation("Post_favoritedByToUser", references: [id])
}
model User {
id Int @default(autoincrement()) @id
writtenPost Post[] @relation("Post_authorToUser")
favoritedPosts Post[] @relation("Post_favoritedByToUser")
}

Warning: Prisma-level relation fields that were renamed in the Prisma schema will be reset when you run prisma introspect again. You therefore might want to back up your Prisma schema with these attributes in order to not having to annotate everything from scratch again after a re-introspection.

Edit this page on Github