Skip to content

Seed script in Next.js tutorial has transaction, constraint, and conflict issues #1271

Description

@poopgpt69

Hi Next.js team 👋
While following the Next.js App Router tutorial and implementing the /seed/route.ts file, I noticed a few issues in the seed script that can cause confusion or subtle bugs for learners. I wanted to document them here in case it’s helpful to improve the tutorial.

Below is a summary of the findings and suggested fixes.

Issues identified

1. Transaction is not actually used

The seed script uses:

sql.begin((sql) => [
  seedUsers(),
  seedCustomers(),
  seedRevenue(),
  seedInvoices(),
]);

However, the seed* functions use the outer sql client, not the transactional client passed into begin. As a result, the queries do not run inside the transaction, despite appearing to do so.

Suggested fix

  • Pass the transaction client into each seed function and use that client for queries.
await sql.begin(async (tx) => {
  await seedUsers(tx);
  await seedCustomers(tx);
  await seedInvoices(tx);
  await seedRevenue(tx);
});

2. ON CONFLICT (id) used without inserting id (invoices)

In the invoices seed:

INSERT INTO invoices (customer_id, amount, status, date)
VALUES (...)
ON CONFLICT (id) DO NOTHING;

Since id is auto-generated and never inserted, this conflict clause will never trigger and is effectively a no-op.

Suggested fix

  • Remove the ON CONFLICT clause

3. Missing foreign key constraint on invoices.customer_id

The invoices table defines:
customer_id UUID NOT NULL
but does not reference the customers table. This allows invoices to exist without a valid customer.

Suggested fix
customer_id UUID NOT NULL REFERENCES customers(id)
This aligns with how invoices are queried later in the tutorial.


4. Repeated CREATE EXTENSION calls

CREATE EXTENSION IF NOT EXISTS "uuid-ossp" is executed in multiple seed functions. Extensions are database-wide, so this is redundant (though harmless).

Suggested fix

  • Run the extension creation once before the transaction begins.
export async function GET() {
  try {
    // Create extension once for the whole database
    await sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`;

    await sql.begin(async (tx) => {
      await seedUsers(tx);
      await seedCustomers(tx);
      await seedInvoices(tx);
      await seedRevenue(tx);
    });

    return Response.json({ message: 'Database seeded successfully' });
  } catch {
    return Response.json(
      { error: 'Failed to seed database' },
      { status: 500 }
    );
  }
}

Other than that, thanks for the excellent tutorial content overall, it’s been a great learning experience!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions