Create new

Seeding

Populate your development database with realistic test data using the seed script.

The seed script creates a predictable set of test data so you can develop against a realistic database without manually creating users, orgs, and subscriptions every time you reset.


Running the seed

pnpm db:seed

Or reset the entire database and re-seed in one command:

pnpm db:reset   # drops DB + pushes schema + runs seed

What gets seeded

The default seed creates:

EntityDetails
2 usersadmin@example.com / user@example.com, both with password password
1 organization"Acme Inc" with the admin as owner and the user as member
1 subscriptionActive Stripe subscription for the admin user (mocked)

The seed script

import { prisma } from "@/lib/prisma";
import { auth } from "@/lib/auth";

async function main() {
  console.log("Seeding database...");

  // Create users via Better Auth so passwords are hashed correctly
  const adminResult = await auth.api.signUpEmail({
    body: {
      name: "Admin User",
      email: "admin@example.com",
      password: "password",
    },
  });

  const userResult = await auth.api.signUpEmail({
    body: {
      name: "Regular User",
      email: "user@example.com",
      password: "password",
    },
  });

  const adminId = adminResult.user.id;
  const userId = userResult.user.id;

  // Create an organization
  const org = await prisma.organization.create({
    data: {
      name: "Acme Inc",
      slug: "acme",
      members: {
        create: [
          { userId: adminId, role: "OWNER" },
          { userId: userId, role: "MEMBER" },
        ],
      },
    },
  });

  // Create a mock subscription for the admin
  await prisma.subscription.create({
    data: {
      userId: adminId,
      stripeCustomerId: "cus_seed_admin",
      stripeSubscriptionId: "sub_seed_admin",
      stripePriceId: "price_seed_pro",
      status: "active",
      currentPeriodStart: new Date(),
      currentPeriodEnd: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),
    },
  });

  console.log("✓ Seed complete");
  console.log(
    "  admin@example.com  /  password  (owner of Acme Inc, active subscription)",
  );
  console.log("  user@example.com   /  password  (member of Acme Inc)");
}

main()
  .catch((e) => {
    console.error(e);
    process.exit(1);
  })
  .finally(() => prisma.$disconnect());

Register the script in package.json so pnpm db:seed finds it:

{
  "prisma": {
    "seed": "ts-node --compiler-options '{\"module\":\"CommonJS\"}' prisma/seed.ts"
  }
}

Always create users through auth.api.signUpEmail in the seed — never insert passwords directly into the database. The auth API hashes passwords with Argon2 correctly.


Adding your own seed data

Add whatever your app needs after the base data. Keep it idempotent — use upsert instead of create so the seed can run multiple times without failing:

await prisma.organization.upsert({
  where: { slug: "acme" },
  update: {},
  create: {
    name: "Acme Inc",
    slug: "acme",
  },
});