# Adding Database Access to your SvelteKit App with Prisma URL: https://www.prisma.io/blog/sveltekit-prisma-kvCOEoeQlC Published: 2023-04-17 Authors: Sonia Lomo Tags: education Description: Learn how you can interact with a database from a SvelteKit application using Prisma. SvelteKit is a metaframework built on top of Svelte. In this article, you will learn how you can use Prisma to add database access to your SvelteKit application. ## Table of Contents [#table-of-contents] * [Introduction ](#introduction) * [Prerequisites](#prerequisites) * [1. Set up your SvelteKit starter project](#1-set-up-your-sveltekit-starter-project) * [2. Set up Prisma](#2-set-up-prisma) * [3. Create your database schema and connect your SQLite database](#3-create-your-database-schema-and-connect-your-sqlite-database) * [Set up seeding for your database](#set-up-seeding-for-your-database) * [Create your first database migration](#create-your-first-database-migration) * [Set up a Prisma Client singleton](#set-up-a-prisma-client-singleton) * [4. Define SvelteKit load functions](#4-define-sveltekit-load-functions) * [`/`: Get all published posts](#-get-all-published-posts) * [`/drafts`: Get all drafted posts](#drafts-get-all-drafted-posts) * [`/p/[id]`: Get a *single* post by its `id`](#pid-get-a-single-post-by-its-id) * [5. Define SvelteKit action functions](#5-define-sveltekit-action-functions) * [`/create`: Create a new post in your database](#create-create-a-new-post-in-your-database) * [`/p/[id]`: Publish and Delete a post by its `id`](#pid-publish-and-delete-a-post-by-its-id) * [`/signup`: Create a new user](#signup-create-a-new-user) * [Conclusion](#conclusion) ## Introduction [#introduction] SvelteKit is a meta framework built on top of Svelte; it’s what Next.js is to React. SvelteKit 1.0 introduced *[load](https://kit.svelte.dev/docs/load)* and *[action](https://kit.svelte.dev/docs/form-actions)* functions that open up multiple possibilities. For instance, building full-stack applications that query data directly from your application. This guide will teach you how to use *load* and *action* functions with Prisma to build a simple blog application. You will add a database and Prisma ORM to an existing application that currently only stores data in memory. The application is built using these technologies: * [SvelteKit](https://kit.svelte.dev/) as the framework * [Prisma](https://www.prisma.io/) as the ORM for migrations and querying * [TypeScript](https://www.typescriptlang.org/) as the programming language * [SQLite](https://www.sqlite.org/index.html) as the database ## Prerequisites [#prerequisites] To successfully finish this guide, you’ll need [Node.js](https://nodejs.org/en/) installed. If VS Code is your editor, you can install the [Prisma extension](https://marketplace.visualstudio.com/items?itemName=Prisma.prisma) to improve your developer experience by adding syntax highlighting, formatting, and auto-completion on your Prisma schema files. ## 1. Set up your SvelteKit starter project [#1-set-up-your-sveltekit-starter-project] To get started, navigate to the directory of your choice and run the following command to clone the repository: ```shell git clone https://github.com/sonylomo/demo-sveltekit.git cd demo-sveltekit ``` Install dependencies and fire up the application: ```shell npm install npm run dev ``` Awesome! Your application should be running on [http://localhost:5173/](http://localhost:5173/) .  The starter project has the following folder structure: ```tsx demo-sveltekit/ ├ src/ │ ├ lib/ │ │ ├ components/ │ │ │ ├ Header.svelte │ │ │ └ Post.svelte │ │ ├ styles/ │ │ │ └ style.css │ │ └ data.json │ ├ routes/ │ │ │ ├ create │ │ │ │ └ +page.svelte │ │ │ ├ drafts │ │ │ │ └ +page.svelte │ │ │ ├ p │ │ │ │ └ [id] │ │ │ │ │ └ +page.svelte │ │ │ ├ signup │ │ │ │ └ +page.svelte │ │ │ ├ +layout.svelte │ │ │ ├ +page.server.ts │ │ │ └ +page.svelte │ ├ app.d.ts │ └ app.html ├ static/ │ └ favicon.png ├ package-lock.json ├ package.json ├ svelte.config.js ├ tsconfig.json └ vite.config.js ``` Currently, the project uses dummy data from a `data.json` file to display published posts on the `/` route and unpublished posts on the `drafts` route. You currently cannot view individual posts and sign up as a user or create a post draft. You’ll implement these functionalities with SvelteKit functions and Prisma ORM later in the guide. Moreover, you’ll also replace data fetching from dummy data with a database. It’s now time to get your hands dirty! ## 2. Set up Prisma [#2-set-up-prisma] Start by installing Prisma’s CLI as a development dependency with the following command: ```shell npm install prisma@7.9.1 --save-dev ``` You can now set up Prisma in the project by running the following command: ```shell npx prisma init --datasource-provider sqlite ``` `prisma init` created a new `prisma` directory with a `schema.prisma` file inside it and a `.env` ([dotenv](https://github.com/motdotla/dotenv)) file at the root folder in your project. The `schema.prisma` defines your database connection and the Prisma Client generator. For this project, you’ll use SQLite as your database provider for an easier setup. The `--datasource-provider sqlite` shorthand automatically sets up Prisma using SQLite. However, you can use another database provider simply by changing the database provider from `sqlite` to your preferred choice and updating the [connection URL](https://www.prisma.io/docs/orm/v7/reference/connection-urls). The Prisma schema looks should resemble this: ```prisma datasource db { provider = "sqlite" url = env("DATABASE_URL") } generator client { provider = "prisma-client-js" } ``` The `DATABASE_URL` environment variable is stored in the `.env` file. It specifies the path to the database. The database does not yet currently exist but will be created in the next step. ## 3. Create your database schema and connect your SQLite database [#3-create-your-database-schema-and-connect-your-sqlite-database] First, you’ll define a `Post` and `User` model with a one-to-many relationship between `User` and `Post`. Navigate to `prisma/schema.prisma` update it with the code below: ```tsx // prisma/schema.prisma datasource db { provider = "sqlite" url = env("DATABASE_URL") } generator client { provider = "prisma-client-js" } model Post { id Int @id @default(autoincrement()) title String content String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt 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[] } ``` ### Set up seeding for your database [#set-up-seeding-for-your-database] Currently, the application uses dummy data directly from the `data.json` file. Since the database will be empty when created, you will set up a script to seed some data when it's created. Create a `seed.ts` file in the `prisma` folder and add the seed script below: ```tsx // prisma/seed.ts import { PrismaClient } from '@prisma/client' import userData from "../src/lib/data.json" assert { type: "json" } const prisma = new PrismaClient() async function main() { console.log(`Start seeding ...`) for (const p of userData) { const user = await prisma.user.create({ data: { name: p.author.name, email: p.author.email, posts: { create: { title: p.title, content: p.content, published: p.published, }, }, } }) console.log(`Created user with id: ${user.id}`) } console.log(`Seeding finished.`) } main() .then(async () => { await prisma.$disconnect() }) .catch(async (e) => { console.error(e) await prisma.$disconnect() process.exit(1) }) ``` > **Note**: The `@prisma/client` package has not yet been installed and should see a squiggly line next to the import. The package will be installed in the next step when you generate a migration. Then add this property to your `package.json` file: ```tsx -// existing config "prisma": { "seed": "ts-node prisma/seed.ts" } ``` ### Expand to view the full contents of the package.json file ```json { "name": "rest-sveltekit", "version": "0.0.1", "private": true, "scripts": { "dev": "vite dev", "build": "vite build", "preview": "vite preview", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch" }, "devDependencies": { "@sveltejs/adapter-auto": "^1.0.0", "@sveltejs/kit": "^1.0.0", "@sveltejs/package": "^1.0.0", "@typescript-eslint/eslint-plugin": "^5.45.0", "@typescript-eslint/parser": "^5.45.0", "eslint": "^8.28.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-svelte3": "^4.0.0", "prettier": "^2.8.0", "prettier-plugin-svelte": "^2.8.1", "prisma": "^4.9.0", "svelte": "^3.54.0", "svelte-check": "^2.9.2", "ts-node": "10.9.1", "tslib": "^2.4.1", "typescript": "^4.9.3", "vite": "^4.0.0" }, "type": "module", "prisma": { "seed": "ts-node prisma/seed.ts" }, "dependencies": { "@prisma/client": "^4.9.0" } } ``` Refer [Prisma docs](https://www.prisma.io/docs/orm/v7/prisma-migrate/workflows/seeding#how-to-seed-your-database-in-prisma) for more information on seeding. ### Create your first database migration [#create-your-first-database-migration] To apply the defined schema to your database, you'll need to create a migration. ```shell npx prisma migrate dev --name init ``` The above command will execute the following: 1. Create a migration called `init` located in the `/prisma/migrations` directory. 2. Create the `dev.db` database file, since it does not exist, and apply the new SQL migration. 3. Install [`@prisma/client`](https://www.npmjs.com/package/@prisma/client) package. 4. [Generate Prisma Client](https://www.prisma.io/docs/orm/v7/prisma-client/setup-and-configuration/generating-prisma-client) based on the current schema. 5. Seed the database with sample data defined in the previous step. You should see similar output on your terminal to the one below: ```shell Environment variables loaded from .env Prisma schema loaded from prisma/schema.prisma Datasource "db": SQLite database "dev.db" at "file:./dev.db" SQLite database dev.db created at file:./dev.db Applying migration `20230213164207_init` The following migration(s) have been created and applied from new schema changes: migrations/ └─ 20230213164207_init/ └─ migration.sql Your database is now in sync with your schema. ✔ Generated Prisma Client (4.9.0 | library) to ./node_mod ules/@prisma/client in 146ms Running seed command `ts-node prisma/seed.ts` ... Start seeding ... (node:94642) ExperimentalWarning: Importing JSON modules is an experimental feature. This feature could change at any time (Use `node --trace-warnings ...` to show where the warning was created) Created user with id: 1 Created user with id: 2 Created user with id: 3 Seeding finished. 🌱 The seed command has been executed. ``` You can browse the data in your database using [Prisma Studio](https://www.prisma.io/docs/orm/v7/reference/prisma-cli-reference#studio). Run the following command: ```shell npx prisma studio ``` ### Set up a Prisma Client singleton [#set-up-a-prisma-client-singleton] Create a `prisma.ts` file in the `src/lib` folder to create a Prisma Client instance that you’ll use throughout your application. Paste in the code below: ```tsx // src/lib/prisma.ts import { PrismaClient } from '@prisma/client' const prisma = new PrismaClient() export default prisma ``` ## 4. Define SvelteKit load functions [#4-define-sveltekit-load-functions] A [SvelteKit load](https://kit.svelte.dev/docs/load) function provides data when rendering a `+page.svelte` component. Load functions perform `GET` requests to a route. For this project, you’ll implement the following load functions: | Route with load function | Description | | ------------------------ | --------------------------- | | `/` | Get all published posts | | `/drafts` | Get all drafted posts | | `/p/[id]` | Get a single post by its id | ### `/`: Get all published posts [#-get-all-published-posts] Create a `+page.server.ts` file inside `src/routes` folder and add the code below: ```tsx // src/routes/+page.server.ts import prisma from '$lib/prisma'; import type { PageServerLoad } from './$types'; export const load = (async () => { // 1. const response = await prisma.post.findMany({ where: { published: true }, include: { author: true }, }) // 2. return { feed: response }; }) satisfies PageServerLoad; ``` The function above does the following: 1. Queries all published posts, including their authors, using the [`include` option](https://www.prisma.io/docs/orm/v7/reference/prisma-client-reference#include). 2. Assigns the `response` result to the `feed` object response. Currently, the client is still using dummy data from `data.json` instead of the SQLite database. Replace the code in `src/routes/+page.svelte` with the code below to rectify this: ```html