With such a rich selection of ORMs out there, choosing which one to use for your JavaScript-based project can be tough. Depending on your goals or stack you have a ton available: libraries like TypeORM, Sequelize, and Mongoose, and many more.
In this article and throughout the rest of this series we'll be taking a deep dive into another option; One that offers tons of cool features, a unique "ORM" experience, and an active, dedicated team of developers supporting and working on it. That option is Prisma.
What is Prisma?
At the most basic level, Prisma provides a set of tools that enable you to access and interact with your database. While offering many of the same features a traditional ORM would, Prisma describes itself as a next-gen ORM because of its unique implementation of what is known as the "data-mapper" model of ORM and its careful consideration of Type-Safe interactions.
Along with offering a great ORM tool (the Prisma Client), Prisma also offers a database migration tool called Prisma Migrate
and a nice GUI that allows you to visualize and update data in your connected database called Prisma Studio
. Our focus in this article and the rest of the series will be on the Prisma Client
and its rich feature-set.
As we learn more about how Prisma works in this series, we will get to play with a lot of the features that make Prisma so powerful and different from the other tools available.
If you'd like to learn more about the different types of ORMs and where Prisma fits in and differs from those, please give this page a read.
Jumping In
As much as I'd love to start going through all the benefits, downsides, use-cases, and don't-use-cases (that's a phrase right?) of Prisma, I'm sure you're anxious to get to the good stuff. Let's dive right into a super simple setup of Prisma so we can get some context into what Prisma is and take a look at the whats and why’s later on.
This tutorial will assume a basic knowledge of JavaScript and its development ecosystem, TypeScript, and Database Terminology. If you want to brush up on these, check out these pages on npm, TypeScript, and SQLite
For the example here we'll connect Prisma to a SQLite database, however Prisma currently also supports Postgres, MySQL, MSSQL, and MongoDB.
To start things off, let's create a folder for our project and initialize npm
inside of it, which we will be using to install various packages. (For all you yarn-lovers 🐈, feel free to use that instead)
mkdir <my-project>
cd <my-project>
npm init -y
Next, we'll install our development dependencies for TypeScript and Prisma
npm i -d prisma typescript ts-node @types/node
With all of our packages installed, we can now configure TypeScript by adding a tsconfig.json
file, a simple TypeScript file, and a script to our package.json
that we can run to start our development server.
// tsconfig.json
// This is just a basic setup, feel free to tweak as needed
{
"compilerOptions": {
"sourceMap": true,
"outDir": "dist",
"strict": true,
"lib": ["esnext"],
"esModuleInterop": true
}
}
// main.ts
console.log("I'm Running!")
In package.json
, add the following to the "scripts"
section:
"dev": "ts-node main",
Now, in your terminal at the root of your project run
npm run dev
...and you should see output similar to the following:
Our project is set up with TypeScript and ready to get fancy! Now we'll move on to setting up Prisma.
Setting up Prisma
Initializing
The steps to get Prisma going are pretty simple. We have the dependency installed already, so to start we'll just run Prisma's init
command and tell it we're going to use SQLite as our datasource. For a full list of options available to the init
command, check out these docs.
prisma init --datasource-provider sqlite
You'll notice a new folder in your project named prisma
as well as a .env
file in your project's root. The contents of that folder should just be a file named schema.prisma
, which is the file where we will define how the Prisma Client
should get generated and model our data.
Then you'll need to tell Prisma where to output the SQLite db file. In the .env
file let's make sure the DATASOURCE_URL
env variable specifies a file location that makes sense (I'm outputting it directly into the prisma
folder):
DATABASE_URL="file:dev.db"
Prisma allows us to access .env
variables using the env()
function in a .schema
file. You can see its usage by opening up prisma.schema
and checking out the url
attribute of the datasource
block.
Defining our Data Model
There are various different kinds of blocks in a .schema
file that do different things and have tons of different options. We'll just set up a simple User
model for the purposes of this tutorial.
model User {
id Int @id @default(autoincrement())
firstName String
lastName String
email String
}
In a future article we'll dive deeper into the contents of this file and how to model out your data
This defines a User table for Prisma so it will know how to generate a nice, typed client that allows us to interact with the data. Right now our database is empty though, we'll need to push our schema into the database to actually create that table. (This command should also generate the Prisma Client
after pushing the schema)
prisma db push
After running that, we can make sure our table was created using Prisma Studio
. Run this command to open up the studio
prisma studio
This should open up a window at http://localhost:5555 and look something like this.
If you click on the User
model you should see a nice table view of your database table with options to search and add rows to the table. Pretty sweet! This tool definitely comes in handy working with your data.
Now that we've got our data modeled, the model available in the database, our datasources set up, AND the client generated, let's put it to use!
Prisma Client
The Prisma Client
is generated by default into your node_modules
folder under @prisma/client
. To start, go ahead and modify your main.ts
. Import and instantiate the Prisma client.
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
async function main() {}
main()
.catch( e => { throw e })
.finally( async () => await prisma.$disconnect() )
So what does this do? This imports and creates an instance of the PrismaClient
class that was generated by Prisma based off of the model definitions you gave it. Right now our main()
function doesn't do anything, this is where we will add some code to interact with our data.
The ending piece is important. Prisma opens up and handles connections automatically, however we need to tell it that when the application closes or reloads it should disconnect. If not, connections would be generated for each time your application starts and stay alive until manually disconnected.
If your application gets an error when you try to run it, it is likely the Prisma Client was not generated on the db push
. Go ahead and run the following command to generate the Prisma Client and try again.
prisma generate
Querying the Database
We can now start playing with some data! In your main()
function, lets try to print out all of the users
in our database.
async function main() {
const users = await prisma.user.findMany();
console.log(JSON.stringify(users));
}
As you type that out, check out the awesome IntelliSense! Prisma generated a set of types and definitions for the Client to help make our lives easier.
Pretty awesome! Although you may notice after running this the results are empty... that's because we have no data yet! We can fix that, head back over to the Prisma Studio
and add a record to your User table.
Now if you run your code again, you should see your user outputted in the console!
Wrapping Up
This is just the beginning, Prisma has such a rich set of features and potential for so much more. In the coming series we will be taking a deep look at everything Prisma has to offer, design patterns, custom extensions, and more! So if you enjoyed this and Prisma is piqueing your interest, keep an eye out for the coming articles.
We managed to set up Prisma with TypeScript, a SQLite database, and an entire database client to connect to that database in this article with very little effort. That's pretty awesome to me. If you want to dig deeper and expand on what we talked about, check out the Prisma Client
docs.
Thanks for reading, and happy coding!
Top comments (2)
Great article Sabin!
One thing to note is that you don't need to explicilty define the type for queries as its inferred:
This also works in combination with
include
so if you fetch a relation the return type will automatically include the relation type too.Thanks for the advice! I'd added that Typing there primarily to demonstrate the fact that Prisma generated a User type for us, but you are absolutely right and I didn't make that clear!