How to reset and seed a prisma.io database
On one of the projects that I’m working on, I needed to reset and seed the Prisma database so that I can make breaking changes in the GraphQL schema.
After digging through the Prisma docs for a while to learn how to do it, I decided to put this post together with all the steps needed to reset and seed a prisma.io database.
So this is what you’ll learn in this article, how I managed to reset and seed a Prisma database using data stored on a separate file.
The GraphQL Schema
Before we get started, this is the GraphQL Schema you will need to follow this guide:
type PaymentMethod {
id: ID! @unique
type: String! @unique
}
type Country {
id: ID! @unique
name: String!
image: String!
cities: [City!]!
}
type City {
id: ID! @unique
name: String!
image: String!
country: Country!
neighborhoods: [Neighborhood!]!
}
type Neighborhood {
id: ID! @unique
name: String! @unique
city: City!
}
The schema is made of 4 types. The first type stores the different payment
methods that the app accepts. The other types in the schema are made of a
Country
parent type which has a relation to a City
type, which in turn have
a relation to a Neighborhood
type.
If you already have inserted data in the database, and you want to make breaking changes to the schema, it is sometimes easier to just reset it entirely than trying to delete items one by one.
Resetting the prisma database
Using the Prisma CLI it’s easy to do by running in the terminal:
prisma reset
If don’t have it installed on your machine, you can install it with
npm install prisma
.
Then you will be asked to either confirm or cancel the database reset process:
? Are you sure that you want to reset the data of server in stage dev? y/N (n)
If you need to provide a .env
file you can add the --env-file
flag:
prisma reset --env-file .env
With this, you now have the Prisma database reset with all the previous data erased.
Resetting server@dev 4748ms
Once you have reset the database —or if it’s the first time you work with Prisma— you can begin seeding it with your data.
Storing the data
Following the previous schema, I will use a seed.js
file that holds the
seeding logic and a seedData.js
file that holds the data to seed.
First, the seedData.js
file is made of several objects that contain the data
needed in the seeding mutations.
//seedData.js
const paymentMethods = ["VISA", "MASTERCARD", "Paypal"];
const spainCities = [
{
name: "Barcelona",
image: "https://res.cloudinary.com/...",
neighborhoods: {
create: [
{ name: "El Raval" },
{ name: "Gothic Quarter" },
{ name: "La Barceloneta" },
{ name: "El Poblenou" },
],
},
},
{
name: "Madrid",
image: "https://res.cloudinary.com/...",
neighborhoods: {
create: [
{ name: "Chueca" },
{ name: "Las Cortes" },
{ name: "Huertas" },
{ name: "Gran Vía" },
],
},
},
];
module.exports = {
paymentMethods,
spainCities,
};
The paymentMethods
object is made of an array of strings with the names of the
different payment methods.
spainCities
is an array of objects that contain the names of the cities and
the nested neighborhoods for each of them.
You can also inline all of the data and skip the importing and exporting step, but I am separating mine since I have many more types and data that I’m seeding, so the file would get too long.
Seeding the database
The next step is the create a seed.js
file to handle the database seeding
logic.
First, you need to import your Prisma server that has the connection to the database.
Then, you need to import the objects with the data from the seedData.js
file
–if you decided to save them in a separate file, if not you can skip this step.
// the prisma server
const db = require("./db");
// the data to seed in the database
const { paymentMethods, spainCities } = require("./seedData");
The next step is to create a function that will be used to seed the data in the Prisma database.
async function main() {
paymentMethods.forEach(async (method) => {
await db.mutation.createPaymentMethod({
data: { type: method },
});
});
await db.mutation.createCountry({
data: {
name: "Spain",
image: "https://res.cloudinary.com/...",
cities: {
create: spainCities,
},
},
});
}
Here I am using two different mutations to create the payment methods and the country.
As you can see, I am using a forEach
loop to create them, so that I can reduce
the amount of code.
If you don’t have too many objects to create, you could also write everything inline, with a mutation call for each type of data, like so:
async function main() {
await db.mutation.createPaymentMethod({
data: { type: "VISA" },
});
await db.mutation.createPaymentMethod({
data: { type: "MASTERCARD" },
});
await db.mutation.createPaymentMethod({
data: { type: "Paypal" },
});
await db.mutation.createCountry({
data: {
name: "Spain",
image: "https://res.cloudinary.com/...",
cities: {
create: spainCities,
},
},
});
}
If you decide to loop over them, just remember to make the callback function
async
in the forEach
loop, otherwise, it will throw an error.
Resetting server@dev 4397ms
server/src/seed.js:45
await db.mutation.createRoomAmenityType({ ^^^^^
SyntaxError: await is only valid in async function at Module._compile (internal/modules/cjs/loader.js:718:23)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:785:10)
...
Then, to execute the seeding function you need to call it with:
main().catch((e) => console.error(e));
If any errors are returned when executing the mutations, they will show up in the console (terminal).
The createCountry
mutation is not inside a loop since I’m only creating a
single country, but if you need to create more than one, you can use the same
logic as before, by using a forEach
loop.
To create the cities, neighborhoods and their relations to the parent Country
type, I am using the create:
method of the mutation.
This way I can create many nested objects of the parent Country
type without
having to create them individually and then having to connect them.
await db.mutation.createCountry({
data: {
name: "Spain",
image: "https://res.cloudinary.com/...",
cities: {
create: spainCities, },
},
});
The create
method accepts an array of objects, which are stored in the
spainCities
object.
If you didn’t store them in a separate variable, the equivalent code would be to
inline them in the create
method:
await db.mutation.createCountry({
data: {
name: "Spain",
image: "https://res.cloudinary.com/...",
cities: {
create: [
{
name: "Barcelona",
image: "https://res.cloudinary.com/...",
neighborhoods: {
create: [
{ name: "El Raval" },
{ name: "Gothic Quarter" },
{ name: "La Barceloneta" },
{ name: "El Poblenou" },
],
},
},
{
name: "Madrid",
image: "https://res.cloudinary.com/...",
neighborhoods: {
create: [
{ name: "Chueca" },
{ name: "Las Cortes" },
{ name: "Huertas" },
{ name: "Gran Vía" },
],
},
},
],
},
},
});
This way you can create many nested types of a single parent type.
In this case, the parent type is Country
which has a relation to the City
type, which in turn has a relation to the Neighborhood
type.
If you already have created a type, and you have it’s id
, you can use the
connect
method instead of the create
one, to connect the parent type to a
nested one by using the id
, since both create
and connect
accept a list of
objects.
await db.mutation.createCountry({
data: {
name: "Spain",
image: "https://res.cloudinary.com/...",
cities: {
create: [
{
name: "Barcelona",
image: "https://res.cloudinary.com/...",
neighborhoods: {
connect: [
{ id: "id1" },
{ id: "id2" },
{ id: "id3" },
{ id: "id4" },
],
},
},
],
},
},
});
If you put everything together, the final seed.js
file will like this:
//seed.js
const db = require("./db");
const { paymentMethods, spainCities } = require("./seedData");
paymentMethods.forEach(async (method) => {
await db.mutation.createPaymentMethod({
data: { type: method },
});
});
await db.mutation.createCountry({
data: {
name: "Spain",
image: "https://res.cloudinary.com/...",
cities: {
create: spainCities,
},
},
});
main().catch((e) => console.error(e));
Resetting and seeding the database
Once you have all the logic in place, you can now reset and seed the database.
In the terminal, type prisma seed ./seed.js
. If you’d like to reset and then
seed the database, you can add the --reset
flag, which will first reset it,
and then begin seeding the data.
prisma seed --reset ./seed.js
If you need to provide a .env
file you can do it like so:
prisma seed --reset --env-file .env ./seed.js
If everything went fine 🤞, you should now have the database reset and seeded with your data.
Takeaways
So this just about all you need to reset and seed a Prisma database using their cli.
When I was trying to do it for the first time in my project I had to dig through
the prisma.io docs and several StackOverflow questions before it all made sense.
The most helpful thing I learned was that you can create
or connect
several
objects in a single mutation.
create: [
{ name: "Chueca" },
{ name: "Las Cortes" },
{ name: "Huertas" },
{ name: "Gran Vía" },
],
...
connect: [
{ id: "id1" },
{ id: "id2" },
{ id: "id3" },
{ id: "id4" },
],
I hope this article helped you learn how you can also reset or seed your Prisma database. If you have any questions, please feel free to leave a comment.