Using Prisma with SvelteKit
Tags: svelte, javascript, database, webdev
Published: 2023-06-27 18:26:31

---
title: Using Prisma with SvelteKit
published: true
description: A short guide to adding database access to your SvelteKit project.
tags: svelte, javascript, database, webdev
# cover_image: https://direct_url_to_image.jpg
# Use a ratio of 100:42 for best results.
# published_at: 2023-06-27 17:53 +0000
---


Data is a critical part of every web app. Whether you're building a SvelteKit app to capture form inputs, visualize some data, or provide a dashboard to your users.

But dealing with databases can be challenging. Each database has it's own slightly different APIs. You need to write a lot of database access code and keep database schemas up to date. That work adds up.

That's why I like [Prisma](https://prisma.io), it's a developer friendly solution that simplifies many of the pain points of working with databases.

## What is Prisma?

Prisma is an ORM (object-relational mapper). It helps apps talk to databases. Kind of like a middleman between your JavaScript code and the underlying database.

It can read rows from the database and turns them into JavaScript objects (hydration). And vice-versa, it can take JavaScript objects and update the database or create new records. And it supports [many types of databases](https://www.prisma.io/docs/reference/database-reference/supported-databases).

### Code generator

In Prisma, models (aka tables) are defined in a file called `schema.prisma`. Then you run `prisma generate` to generate a custom client for your app.

So you can think of Prisma as a kind of code generator.

![Prisma converts schema.prisma file into a client wrapper](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/786f8h6qsrboq09v7grf.png)


### Schema syncing

Prisma keeps the database schema up-to-date by syncing changes.

It supports two styles:

- `push`: In this style, the `schema.prisma` is the source-of-truth. Additive changes, like adding a new table or a new column can be handled easily. It's the recommended approach during the prototype phase. But it's not ideal for more complex changes, like changing a data type.
- `migrate`: In this approach, the migration scripts are considered the source-of-truth. It provides a fine-grained control over schema changes. This is recommended for production apps. 

![Schema syncing diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5yz8hbb9fxs77y9ws5bt.png)

## Setup

To install the Prisma in a SvelteKit app, run:

```sh
pnpm install -D prisma @prisma/client
```

Then initialize the project:

```sh
pnpm prisma init
```

This does 2 things

1. It creates a `prisma/schema.prisma` where models can be defined.
2. It adds an environment variable `DATABASE_URL` to `.env`. 

The `DATABASE_URL` is the connection information Prisma needs to connect to the database.

For example, for Postgres, it would look like `postgresql://USER:PASSWORD@HOST:PORT/DATABASE`

For a full list of examples, see [Supported Connection URLs](https://www.prisma.io/docs/reference/database-reference/connection-urls).

### Starting points

For new apps, the Prisma schema is written from scratch, but Prisma also supports importing an existing legacy database's schema too.

To start with an **existing database**, run `prisma db pull` to pull the existing schema into `schema/prisma.schema`.

To start with a **new database**, define models in `prisma/schema.prisma` and Prisma will sync the database schema for you.

## Modeling

Here are some examples of models and indexes.

To define a basic model:

```
// in prisma/schema.prisma
model Product {
}
```

And fields can be added in the format `name DataType`:

```
model Product {
  // auto-incrementing primary key
  id Int @id @default(autoincrement())
  barcode String
  name String
}
```

To add an index:

```
model Product {
  // ...
  
  // define a unique index
  @@unique([barcode])
  
  // define a non-unique index
  @@index([name])
}
```

For more examples, see the [docs on modelling](https://www.prisma.io/docs/concepts/components/prisma-schema/data-model) or my course on [Svelte + Prisma](https://bit.ly/svelte-prisma).

## Syncing the database

To update the database schema, run:

```sh
pnpm prisma db push
```

**Note**: In some cases, a conflict can occur. For example, if a field's data type is changed from `String` to `Int`, there is no automatic way to reconcile that conversion. Prisma will notify you that there is a conflict and give you the option to reset the table (causing data loss), or you can use migrations for more control.

## Browsing your database

Prisma comes with a handy database viewer that runs in the browser. It's a useful tool for inspecting database tables during development.

Here's a screenshot:

![Screenshot of Prisma Studio](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yh9k7zf7gq55nm015jzt.png)

To view it, run: 

```sh
pnpm prisma studio
```

Then visit `https://localhost:5555`

## Accessing the database

It's likely that many places in your app will need to access the database. So, it's a good idea to centralize the db client.

To do that, create a file called `src/lib/db.server.js` and instantiate the client:

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

// expose a singleton
export const db = new PrismaClient()
```

Now, anytime a connection is needed, import `lib/db.server.js`:

```javascript
// import the centralized connection
import { db } from '$lib/db.server'

// then do stuff with the db connection
db.model.create(...)
db.model.update(...)
db.model.findMany(...)
// etc...
```

**Note**: Manual disconnection is rarely needed because Prisma automatically closes connections when the process ends.

## Seeding data

It's much easier to set up developer machines when the app ships with a seed dataset. It also makes it easier to reset the environment when if it ever gets hosed.

In Prisma, seed data is defined in `prisma/seed.js`.

Here's an example:

```javascript
// in prisma/seed.js

// import db client from previous step
import { db } from '$lib/db.server'

// create one record
await db.product.create({
  data: { barcode: '1234', name: 'Shirt' }
})

// or create records in bulk
await db.product.createMany({
  data: [
    { barcode: '5678', name: 'Pants' },
    { barcode: '91011', name: 'Socks' }
  ]
})
```

Then add a `prisma` section to `package.json`:

```json
"prisma": {
  "seed": "vite-node ./prisma/seed.js"
}
```

**Note**: `vite-node` is used instead of `node` because our `seed.js` imports a *vite* alias `$lib`. So make sure to install `vite-node` too:

```sh
pnpm install -D vite-node
```

Then to load the seed data:

```sh
pnpm prisma db seed
```

## Conclusion

Prisma is a great option for connecting SvelteKit projects with a database.

Prisma handles all the tricky stuff, like syncing your database schema and generating SQL queries, so you don't have to do that by hand.

It frees up developer time to focus on building features.

P.S. For a SvelteKit/Prisma repo with more examples, see [joshnuss/markdown-mail](https://github.com/joshnuss/markdown-mail).