Creating Seeding with Prisma
Tags: prisma, orm, nextjs, tutorial
Published: 2024-02-05 18:10:43

Hello,
In this article, I will try to explain how to create basic data using Prisma ORM while developing a full-stack application with Next.js.

## What is Prisma and what does it do?

"Prisma" is a modern and powerful ORM (Object-Relational Mapping) tool that provides developers with ease in managing and querying database operations. In short, its features 

include:
- Database Models
- Relationship Establishment (Relations)
- Query Creation
- Database Connection
- TypeScript Support
- Migration Management

## What is Seeding and what is its purpose?

"Seeding" refers to adding initial data to the database or populating the database with sample data. This process involves adding default or sample data to database tables that can be used during the development, testing, or initial stages of an application. Seeding ensures the necessary database content for an application to function correctly and be tested.

## Used in the sample project:

**Framework:** [Next js](https://nextjs.org)
**Database:** [PostgreSQL](https://www.postgresql.org)
**ORM:** [Prisma](https://www.prisma.io)

## Project setup
Since our topic is seeding, I will not talk about application setup and database connection processes too much.

**1. Next js installation:**

```
npx create-next-app@latest
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xvddwc1i9ikkm03zu25k.png)

**2. Install Prisma and other packages:**

```
npm i prisma --save-dev
npm i @prisma/client

npx prisma // you can use prisma cli via this command

npm i lodash
npm i @faker-js/faker --save-dev
npm i bcrypt
```
**3. Database creation and setup:**

**a.** Assuming that a PostgreSQL database is installed on our computer, let's create a database named example_db. Then create an .env file in our project and add the database connection url here.

```js
DATABASE_URL="postgresql://postgres:@localhost:5432/example_db?schema=public"
```

**b. **Create a folder called `prisma` in the project main directory and create a model file called `schema.prisma` in it. This file is where we define our database tables.

**schema.prisma**

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

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

model Post {
  id        Int      @id @default(autoincrement())
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  title     String   @db.VarChar(255)
  content   String   @db.VarChar(255)
  User      User     @relation(fields: [userId], references: [id])
  userId    Int
}

model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  createdAt DateTime @default(now())
  name      String   @db.VarChar(255)
  password  String?  @db.VarChar(255)
  posts     Post[]
}
```

**c.** Then we use the following command to create these tables:

```bash
npx prisma db push
```
If we check the database, we will see that the tables have been created.

**4. Seed File Creation**

Let's create a seed.ts file inside the prisma folder and create the basic structure.

**seed.ts**

```js
export default PostSeed;

import {PrismaClient} from "@prisma/client";

const prisma = new PrismaClient();

const main = async () => {
...
}

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

Now let's create the seeder structure that we will define in the main() function. Here we will benefit from the power of Typescript. First, let's create an abstract class assuming that there will be more than one seeder file.

**Seeder.ts**

```js
abstract class Seeder {
  protected count: number; // decides how much data to generate
  protected _data: any = []; // seed data

  constructor(count: number) {
    this.count = count;
  }

  protected abstract createData(): void; // function to generate the data

  get data(): [] {
    return this._data;
  }
}

export default Seeder;
```
Now let's create our seed files for the related tables.

**userSeed.ts**

```js
import bcrypt from "bcrypt";
import range from "lodash/range";
import { faker } from "@faker-js/faker";

import Seeder from "./Seeder";

class UserSeed extends Seeder {
  constructor(count: number = 10) {
    super(count);
    this.count = count;
    this.createData();
  }

  createData() {
    range(this.count).forEach(() => {
      this._data.push({
        name: faker.person.firstName(),
        createdAt: faker.date.anytime(),
        email: faker.internet.email(),
        password: bcrypt.hashSync("12345678", 10),
      });
    });
  }
}

export default UserSeed;
```
**postSeed.ts**

```js
import range from "lodash/range";
import { faker } from "@faker-js/faker";

import Seeder from "./Seeder";

class PostSeed extends Seeder {
  constructor(count: number = 10) {
    super(count);
    this.count = count;
    this.createData();
  }

  createData() {
    range(this.count).forEach(() => {
      this._data.push({
        title: faker.lorem.sentence(),
        createdAt: faker.date.anytime(),
        updatedAt: faker.date.anytime(),
        content: faker.lorem.sentence(),
      });
    });
  }
}

export default PostSeed;
```

Let's go back to seed.ts and add the seeders we created.

**seed.ts**

```js
import { Simulate } from "react-dom/test-utils";
import error = Simulate.error;
import { PrismaClient } from "@prisma/client";
import UserSeed from "./data/userSeed";
import PostSeed from "./data/postSeeder";

const prisma = new PrismaClient();

const main = async () => {
  try {
    await prisma.post.deleteMany();
    await prisma.user.deleteMany();

    const posts = new PostSeed();
    const users = new UserSeed(3);

    for (const user of users.data) {
      await prisma.user.create({
        data: {
          ...(user as any),
          posts: {
            create: posts.data,
          },
        },
      });

    }

    console.log(`Database has been seeded. 🚀`);
  } catch (e) {
    throw error;
  }
};

main()
  .then(async () => {
    await prisma.$disconnect();
  })
  .catch(async (e) => {
    console.error(e);
    await prisma.$disconnect();
    process.exit(1);
  });
```

**5. Add seed command**

To run these seeders we created, we need to add a command to our package.json file. There are some issues to be considered here. For example, when doing this with the Next js project, there may be module insertion errors in the seed file. To prevent this, we need to add a "compiler-options" flag to the seed command. Thus, we will not get a module error when the process is triggered.

**package.json**

```js
"scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "db-seed": "prisma db seed" 
  },
  "prisma": {
    "seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} prisma/seed.ts"
  },
```

Finally, let's run the command to create our data.

```bash
npm run db-seed
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wwvc5rtx4llubc4tuw69.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4si8t0ijrc06j3aao5aq.png)

As can be seen here, we have successfully generated test data 😊.

You can access the source code of the project from this link [github link](https://github.com/melihs/prisma-seeding-example)
Hope to see you in the next article 👋🏻