Getting Started
Quick Start
Seed

Seed Quick Start Guide

Assumptions

This guide will take you through the process of using @snaplet/seed to create realistic, production-like data.

📁

If you already have access to a database with production or production-like data you'd prefer to use as a source, you should instead follow the Snapshot Quick Start guide.

Prerequisites

  • Node.js and npm installed on your machine
  • a PostgreSQL database server running
1*1*1*useriduuidusernametextemailtextbiotextpostiduuidtitletextcontenttextauthor_iduuidcommentiduuidcontenttextauthor_iduuidpost_iduuidwritten_attimestamptz

The diagram above represents the relationships of your database.

From the SQL tab above, copy the SQL statement and insert this into your database to define your schema.

Setting up snaplet

We now need to add snaplet to your project.

Run the following in your project root directory and follow the interactive prompts:

>_ terminal

npx snaplet setup

@snaplet/seed

Describing your requirements

We now have a database with structure in it, and Snaplet set up to use it. We still do not yet have data though. In order to have Snaplet generate this data, you'll need to tell Snaplet how to generate the data.

This is where @snaplet/seed comes in: it gives you a programmatic interface to describe your seeding requirements.

snaplet setup would have generated an example script file called seed.mts in your project, which imports and uses @snaplet/seed. It should look something like this:

seed.mts

import { createSeedClient } from '@snaplet/seed';
const seed = await createSeedClient();

For your example blog application, let's assume we need the following data:

  • A post titled "Hello World!"
  • A post author, with an email address that ends with "acme.org."
  • Three comments on the post.

It's worth noting what we're not explicitly defining - that each comment needs to have a separate, unique author, for instance. We're assuming that @snaplet/seed will fill in the blanks based on your schema and seed realistic data as needed.

snaplet in the code above exposes all your models (i.e. your database tables, or the entities in your application - in this case "user" and "post") as functions.

During snaplet setup, Snaplet would have read your database structure (using the database connection string you entered), and used this to create these functions.

These functions return what we call a plan. When describing a plan, you always start from a "root" model - a model where we would start describing how to seed seed data, along with data for its related models (more on this soon).

Here we start from the posts models. awaiting a plan will execute it.

seed.mts

import { createSeedClient } from '@snaplet/seed';
const seed = await createSeedClient();
await seed.posts([{}]);

You can directly define the values of your model.

seed.mts

import { createSeedClient } from '@snaplet/seed';
const seed = await createSeedClient();
await seed.posts([
{
title: 'Hello World!',
},
]);

You can also define the values of your model's relationships. Here we define the author of the post represented by the author field.

seed.mts

import { createSeedClient } from '@snaplet/seed';
import { copycat } from '@snaplet/copycat';
const seed = await createSeedClient();
await seed.posts([
{
title: 'Hello World!',
author: {
email: (ctx) =>
copycat.email(ctx.seed, {
domain: 'acme.org',
}),
},
},
]);

Next, we also define the comments of the post represented by the comments field. As we need more than one comment, we can use the x function which will create a list of similar comments. You can read it as "comments times 3".

seed.mts

import { createSeedClient } from '@snaplet/seed';
import { copycat } from '@snaplet/copycat';
const seed = await createSeedClient();
await seed.posts([
{
title: 'Hello World!',
author: {
email: (ctx) =>
copycat.email(ctx.seed, {
domain: 'acme.org',
}),
},
comments: (x) => x(3),
},
]);

Finally:

  • We'll add a dryRun option when creating SeedClient - in dry run mode, we'll log the sql statements to the console instead of altering the database.
  • and a $resetDatabase() call - this will clear the database of any current data, but keep the structure around
seed.mts

import { createSeedClient } from '@snaplet/seed';
import { copycat } from '@snaplet/copycat';
const seed = await createSeedClient({
dryRun: process.env.DRY !== '0'
});
await seed.$resetDatabase()
await seed.posts([
{
title: 'Hello World!',
author: {
email: (ctx) =>
copycat.email(ctx.seed, {
domain: 'acme.org',
}),
},
comments: (x) => x(3),
},
]);

We're done!

Copy the code and add it to your seed.mts file.

seed.mts

import { createSeedClient } from '@snaplet/seed';
import { copycat } from '@snaplet/copycat';
const seed = await createSeedClient({
dryRun: process.env.DRY !== '0'
});
await seed.$resetDatabase()
await seed.posts([
{
title: 'Hello World!',
author: {
email: (ctx) =>
copycat.email(ctx.seed, {
domain: 'acme.org',
}),
},
comments: (x) => x(3),
},
]);

snaplet setup would have generated an example script file called seed.mts in your project, which imports and uses @snaplet/seed. It should look something like this:

For your example blog application, let's assume we need the following data:

  • A post titled "Hello World!"
  • A post author, with an email address that ends with "acme.org."
  • Three comments on the post.

It's worth noting what we're not explicitly defining - that each comment needs to have a separate, unique author, for instance. We're assuming that @snaplet/seed will fill in the blanks based on your schema and seed realistic data as needed.

snaplet in the code above exposes all your models (i.e. your database tables, or the entities in your application - in this case "user" and "post") as functions.

During snaplet setup, Snaplet would have read your database structure (using the database connection string you entered), and used this to create these functions.

These functions return what we call a plan. When describing a plan, you always start from a "root" model - a model where we would start describing how to seed seed data, along with data for its related models (more on this soon).

Here we start from the posts models. awaiting a plan will execute it.

You can directly define the values of your model.

You can also define the values of your model's relationships. Here we define the author of the post represented by the author field.

Next, we also define the comments of the post represented by the comments field. As we need more than one comment, we can use the x function which will create a list of similar comments. You can read it as "comments times 3".

Finally:

  • We'll add a dryRun option when creating SeedClient - in dry run mode, we'll log the sql statements to the console instead of altering the database.
  • and a $resetDatabase() call - this will clear the database of any current data, but keep the structure around

We're done!

Copy the code and add it to your seed.mts file.

seed.mts

import { createSeedClient } from '@snaplet/seed';
const seed = await createSeedClient();

Executing the plan

At this point, you're ready to run your seed script for the first time!

Let's see what statements are generated by using the DRY environment variable we defined.

Run this command in your terminal:

>_ terminal

npx tsx seed.mts

You should see the following output:

>_ terminal

INSERT INTO public.user (email,id,username) VALUES
('Craig.Bednar82365@acme.org', '24058b0d-21ec-54b8-a3fa-b0ad8034f10f', 'site-glance56860'),
('Humberto.Bruen34274@meternephew.org', '241ed1d9-c36c-50d4-b783-e12ce5187076', 'Alexis-Gleason29168'),
('Mattie.Braun26688@plodantechamber.com', '8c84c800-1b34-5843-b34b-73d3239f0c5b', 'blissful-fountain21234'),
('Dannie_Osinski74665@brownmidline.name', '0e041e68-00c0-53db-b0f8-e28be8a009e0', 'visualise-service97805');
INSERT INTO public.post (title,content,author_id,id) VALUES
('Hello World!', 'Ramo ramukin rae racea rakesoma, me vayota yume vi keyo munavima.', '24058b0d-21ec-54b8-a3fa-b0ad8034f10f', '1a294726-1661-5d42-aaf6-cdb66e6c6eaf');
INSERT INTO public.comment (content,id,post_id,author_id,written_at) VALUES
('Ma ceasova yuviketa shira chiyomu.', '13fdf8d2-2199-5dfd-81d0-c8dd3ce3b8a6', '1a294726-1661-5d42-aaf6-cdb66e6c6eaf', '241ed1d9-c36c-50d4-b783-e12ce5187076', DEFAULT),
('Mukinra kahyceako kiva kai me hameso rae.', '71a504eb-a859-5217-9e27-e15975ac69c6', '1a294726-1661-5d42-aaf6-cdb66e6c6eaf', '8c84c800-1b34-5843-b34b-73d3239f0c5b', DEFAULT),
('Ma nacea va memumi ta, mami viyua yoma shimusona viyo metake.', '8e826b31-f774-57f3-8ef2-183bddb35f3e', '1a294726-1661-5d42-aaf6-cdb66e6c6eaf', '0e041e68-00c0-53db-b0f8-e28be8a009e0', DEFAULT);

Click the 'Next' button on the slider above to see a step-by-step explanation of this output.

It's now time to seed this data into your database.

In order to do that, run this command in your terminal (notice how the DRY environment variable is set to 0):

>_ terminal

DRY=0 npx tsx seed.mts

All done, you're now ready to code against your generated data!

Evolving your application

Whenever your database structure changes, @snaplet/seed will need to be re-generated so that it is in sync with your new database structure.

You can do this by running:

>_ terminal

npx snaplet generate

If you are familiar with @prisma/client (opens in a new tab), you can think of snaplet generate doing the same thing, just in this case for @snaplet/seed rather than @prisma/client.

Next steps

Learn more about how @snaplet/seed works and define more complex plans in our seed reference guide