Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
273 changes: 273 additions & 0 deletions docs/200-orm/050-overview/100-introduction/100-what-is-prisma.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
---
title: 'What is Prisma?'
metaTitle: 'What is Prisma? (Overview)'
metaDescription: "This page gives a high-level overview of what Prisma is and how it works. It's a great starting point for Prisma newcomers!"
---

## What is Prisma?

Prisma is an [open-source](https://github.com/prisma/prisma) next-generation ORM. It consists of the following parts:

- **Prisma Client**: Auto-generated and type-safe query builder for Node.js & TypeScript
- **Prisma Migrate**: Migration system
- **Prisma Studio**: GUI to view and edit data in your database.

<Admonition>

**Prisma Studio** is the only part of Prisma ORM that is not open source. You can only run Prisma Studio locally.

</Admonition>

Prisma Client can be used in _any_ Node.js (supported versions) or TypeScript backend application (including serverless applications and microservices). This can be a [REST API](/orm/overview/prisma-in-your-stack/rest), a [GraphQL API](/orm/overview/prisma-in-your-stack/graphql), a gRPC API, or anything else that needs a database.

<div style={{ textAlign: 'center', margin: '2em auto' }}>
<iframe
width="560"
height="315"
src="https://www.youtube.com/embed/EEDGwLB55bI"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen
></iframe>
</div>

## How does Prisma work?

### The Prisma schema

Every project that uses a tool from the Prisma toolkit starts with a [Prisma schema file](/orm/prisma-schema). The Prisma schema allows developers to define their _application models_ in an intuitive data modeling language. It also contains the connection to a database and defines a _generator_:

<TabbedContent>
<TabItem value="Relational databases">

```prisma
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}

generator client {
provider = "prisma-client-js"
}

model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
author User? @relation(fields: [authorId], references: [id])
authorId Int?
}

model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
}
```

</TabItem>
<TabItem value="MongoDB">

```prisma
datasource db {
provider = "mongodb"
url = env("DATABASE_URL")
}

generator client {
provider = "prisma-client-js"
}

model Post {
id String @id @default(auto()) @map("_id") @db.ObjectId
title String
content String?
published Boolean @default(false)
author User? @relation(fields: [authorId], references: [id])
authorId String @db.ObjectId
}

model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
email String @unique
name String?
posts Post[]
}
```

</TabItem>
</TabbedContent>

> **Note**: The Prisma schema has powerful data modeling features. For example, it allows you to define "Prisma-level" [relation fields](/orm/prisma-schema/data-model/relations) which will make it easier to work with [relations in the Prisma Client API](/orm/prisma-client/queries/relation-queries). In the case above, the `posts` field on `User` is defined only on "Prisma-level", meaning it does not manifest as a foreign key in the underlying database.

In this schema, you configure three things:

- **Data source**: Specifies your database connection (via an environment variable)
- **Generator**: Indicates that you want to generate Prisma Client
- **Data model**: Defines your application models

### The Prisma data model

On this page, the focus is on the data model. You can learn more about [Data sources](/orm/prisma-schema/overview/data-sources) and [Generators](/orm/prisma-schema/overview/generators) on the respective docs pages.

#### Functions of Prisma models

The data model is a collection of [models](/orm/prisma-schema/data-model/models#defining-models). A model has two major functions:

- Represent a table in relational databases or a collection in MongoDB
- Provide the foundation for the queries in the Prisma Client API

#### Getting a data model

There are two major workflows for "getting" a data model into your Prisma schema:

- Manually writing the data model and mapping it to the database with [Prisma Migrate](/orm/prisma-migrate)
- Generating the data model by [introspecting](/orm/prisma-schema/introspection) a database

Once the data model is defined, you can [generate Prisma Client](/orm/prisma-client/setup-and-configuration/generating-prisma-client) which will expose CRUD and more queries for the defined models. If you're using TypeScript, you'll get full type-safety for all queries (even when only retrieving the subsets of a model's fields).

### Accessing your database with Prisma Client

#### Generating Prisma Client

The first step when using Prisma Client is installing the `@prisma/client` npm package:

```terminal
npm install @prisma/client
```

Installing the `@prisma/client` package invokes the `prisma generate` command, which reads your Prisma schema and _generates_ Prisma Client code. The code is [generated into the `node_modules/.prisma/client` folder by default](/orm/prisma-client/setup-and-configuration/generating-prisma-client#the-prismaclient-npm-package).

After you change your data model, you'll need to manually re-generate Prisma Client to ensure the code inside `node_modules/.prisma/client` gets updated:

```terminal
prisma generate
```

#### Using Prisma Client to send queries to your database

Once Prisma Client has been generated, you can import it in your code and send queries to your database. This is what the setup code looks like.

##### Import and instantiate Prisma Client

<TabbedContent>
<TabItem value="import">

```ts
import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()
```

</TabItem>
<TabItem value="require">

```js
const { PrismaClient } = require('@prisma/client')

const prisma = new PrismaClient()
```

</TabItem>
</TabbedContent>

Now you can start sending queries via the generated Prisma Client API, here are a few sample queries. Note that all Prisma Client queries return _plain old JavaScript objects_.

Learn more about the available operations in the [Prisma Client API reference](/orm/prisma-client).

##### Retrieve all `User` records from the database

```ts
// Run inside `async` function
const allUsers = await prisma.user.findMany()
```

##### Include the `posts` relation on each returned `User` object

```ts
// Run inside `async` function
const allUsers = await prisma.user.findMany({
include: { posts: true },
})
```

##### Filter all `Post` records that contain `"prisma"`

```ts
// Run inside `async` function
const filteredPosts = await prisma.post.findMany({
where: {
OR: [
{ title: { contains: 'prisma' } },
{ content: { contains: 'prisma' } },
],
},
})
```

##### Create a new `User` and a new `Post` record in the same query

```ts
// Run inside `async` function
const user = await prisma.user.create({
data: {
name: 'Alice',
email: 'alice@prisma.io',
posts: {
create: { title: 'Join us for Prisma Day 2020' },
},
},
})
```

##### Update an existing `Post` record

```ts
// Run inside `async` function
const post = await prisma.post.update({
where: { id: 42 },
data: { published: true },
})
```

#### Usage with TypeScript

Note that when using TypeScript, the result of this query will be _statically typed_ so that you can't accidentally access a property that doesn't exist (and any typos are caught at compile-time). Learn more about leveraging Prisma Client's generated types on the [Advanced usage of generated types](/orm/prisma-client/type-safety/operating-against-partial-structures-of-model-types) page in the docs.

## Typical Prisma workflows

As mentioned above, there are two ways for "getting" your data model into the Prisma schema. Depending on which approach you choose, your main Prisma workflow might look different.

### Prisma Migrate

With **Prisma Migrate**, Prisma's integrated database migration tool, the workflow looks as follows:

1. Manually adjust your [Prisma data model](/orm/prisma-schema/data-model/models)
1. Migrate your development database using the `prisma migrate dev` CLI command
1. Use Prisma Client in your application code to access your database

![Typical workflow with Prisma Migrate](/img/prisma-migrate-development-workflow.png)

To learn more about the Prisma Migrate workflow, see:

- [Deploying database changes with Prisma Migrate](/orm/prisma-client/deployment/deploy-database-changes-with-prisma-migrate)

* [Developing with Prisma Migrate](/orm/prisma-migrate)

### SQL migrations and introspection

If for some reason, you can not or do not want to use Prisma Migrate, you can still use introspection to update your Prisma schema from your database schema.
The typical workflow when using **SQL migrations and introspection** is slightly different:

1. Manually adjust your database schema using SQL or a third-party migration tool
1. (Re-)introspect your database
1. Optionally [(re-)configure your Prisma Client API](/orm/prisma-client/setup-and-configuration/custom-model-and-field-names))
1. (Re-)generate Prisma Client
1. Use Prisma Client in your application code to access your database

![Introspect workflow](/img/prisma-evolve-app-workflow.png)

To learn more about the introspection workflow, please refer the [introspection section](/orm/prisma-schema/introspection).
95 changes: 95 additions & 0 deletions docs/200-orm/050-overview/100-introduction/200-why-prisma.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
---
title: 'Why Prisma?'
metaTitle: 'Why Prisma? Comparison with SQL query builders & ORMs'
metaDescription: 'Learn about the motivation for Prisma and how it compares to other Node.js and TypeScript database tools like ORMs and SQL query builders.'
---

<TopBlock>

On this page, you'll learn about the motivation for Prisma and how it compares to other database tools like ORMs and SQL query builders.

Working with relational databases is a major bottleneck in application development. Debugging SQL queries or complex ORM objects often consume hours of development time.

Prisma makes it easy for developers to reason about their database queries by providing a clean and type-safe API for submitting database queries which returns _plain old JavaScript objects_.

</TopBlock>

## TLDR

Prisma's main goal is to make application developers more productive when working with databases. Here are a few examples of how Prisma achieves this:

- **Thinking in objects** instead of mapping relational data
- **Queries not classes** to avoid complex model objects
- **Single source of truth** for database and application models
- **Healthy constraints** that prevent common pitfalls and anti-patterns
- **An abstraction that makes the right thing easy** ("pit of success")
- **Type-safe database queries** that can be validated at compile time
- **Less boilerplate** so developers can focus on the important parts of their app
- **Auto-completion in code editors** instead of needing to look up documentation

The remaining parts of this page discuss how Prisma compares to existing database tools.

## Problems with SQL, ORMs and other database tools

The main problem with the database tools that currently exist in the Node.js and TypeScript ecosystem is that they require a major tradeoff between _productivity_ and _control_.

![Productivity vs Control in ORMs, SQL query builders, and SQL](node-js-db-tools-tradeoffs.png)

### Raw SQL: Full control, low productivity

With raw SQL (e.g. using the native [`pg`](https://node-postgres.com/) or [`mysql`](https://github.com/mysqljs/mysql#readme) Node.js database drivers) you have full control over your database operations. However, productivity suffers as sending plain SQL strings to the database is cumbersome and comes with a lot of overhead (manual connection handling, repetitive boilerplate, ...).

Another major issue with this approach is that you don't get any type safety for your query results. Of course, you can type the results manually but this is a huge amount of work and requires major refactorings each time you change your database schema or queries to keep the typings in sync.

Furthermore, submitting SQL queries as plain strings means you don't get any autocompletion in your editors.

### SQL query builders: High control, medium productivity

A common solution that retains a high level of control and provides better productivity is to use a SQL query builder (e.g. [knex.js](https://knexjs.org/)). These sort of tools provide a programmatic abstraction to construct SQL queries.

The biggest drawback with SQL query builders is that application developers still need to think about their data in terms of SQL. This incurs a cognitive and practical cost of translating relational data into objects. Another issue is that it's too easy to shoot yourself in the foot if you don't know exactly what you're doing in your SQL queries.

### ORMs: Less control, better productivity

ORMs abstract away from SQL by letting you _define your application models as classes_, these classes are mapped to tables in the database.

> "Object relational mappers" (ORMs) exist to bridge the gap between the programmers' friend (the object), and the database's primitive (the relation). The reasons for these differing models are as much cultural as functional: programmers like objects because they encapsulate the state of a single thing in a running program. Databases like relations because they better suit whole-dataset constraints and efficient access patterns for the entire dataset.
>
> [The Troublesome Active Record Pattern, Cal Paterson (2020)](https://calpaterson.com/activerecord.html)

You can then read and write data by calling methods on the instances of your model classes.

This is way more convenient and comes closer to the mental model developers have when thinking about their data. So, what's the catch?

> ORM represents a quagmire which starts well, gets more complicated as time passes, and before long entraps its users in a commitment that has no clear demarcation point, no clear win conditions, and no clear exit strategy.
>
> [The Vietnam of Computer Science, Ted Neward (2006)](http://blogs.tedneward.com/post/the-vietnam-of-computer-science/)

As an application developer, the mental model you have for your data is that of an _object_. The mental model for data in SQL on the other hand are _tables_.

The divide between these two different representations of data is often referred to as the [object-relational impedance mismatch](https://en.wikipedia.org/wiki/Object-relational_impedance_mismatch). The object-relational impedance mismatch also is a major reason why many developers don't like working with traditional ORMs.

As an example, consider how data is organized and relationships are handled with each approach:

- **Relational databases**: Data is typically normalized (flat) and uses foreign keys to link across entities. The entities then need to be JOINed to manifest the actual relationships.
- **Object-oriented**: Objects can be deeply nested structures where you can traverse relationships simply by using dot notation.

This alludes to one of the major pitfalls with ORMs: While they make it _seem_ that you can simply traverse relationships using familiar dot notation, under the hood the ORM generates SQL JOINs which are expensive and have the potential to drastically slow down your application (one symptom of this is the [n+1 problem](https://stackoverflow.com/questions/97197/what-is-the-n1-selects-problem-in-orm-object-relational-mapping)).

To conclude: The appeal of ORMs is the premise of abstracting away the relational model and thinking about your data purely in terms of objects. While the premise is great, it's based on the wrong assumption that relational data can easily be mapped to objects which leads to lots of complications and pitfalls.

## Application developers should care about data – not SQL

Despite being developed in the 1970s(!), SQL has stood the test of time in an impressive manner. However, with the advancement and modernization of developers tools, it's worth asking if SQL really is the best abstraction for application developers to work with?

After all, **developers should only care about the _data_ they need to implement a feature** and not spend time figuring out complicated SQL queries or massaging query results to fit their needs.

There's another argument to be made against SQL in application development. The power of SQL can be a blessing if you know exactly what you're doing, but its complexity can be a curse. There are a lot of [anti-patterns](https://www.slideshare.net/billkarwin/sql-antipatterns-strike-back) and pitfalls that even experienced SQL users struggle to anticipate, often at the cost of performance and hours of debugging time.

Developers should be able to ask for the data they need instead of having to worry about "doing the right thing" in their SQL queries. They should be using an abstraction that makes the right decisions for them. This can mean that the abstraction imposes certain "healthy" constraints that prevent developers from making mistakes.

## Prisma makes developers productive

Prisma's main goal is to make application developers more productive when working with databases. Considering the tradeoff between productivity and control again, this is how Prisma fits in:

![Prisma makes developers productive](prisma-makes-devs-productive.png)
Loading