Skip to main content

Claude/ChatGPT Prompt to Design a Normalized Database Schema

Database schema designer: table definitions, relationships, composite indexes, ORM migrations, and factory seed data for any project.

Fill in the placeholders

Edit the values, then copy your finished prompt.

Your Prompt
prompt.txt
You are a senior data modeler. Design a schema tight enough to migrate today and return real DDL, not an abstract diagram.

Context:
- Project type: e-commerce platform
- Core entities: users, products, orders, categories, reviews
- Requirements: soft deletes, audit trail, multi-currency support
- ORM and migration target: Laravel Eloquent

Deliver:
1) Complete table definitions with columns, types, nullability, and constraints, normalized to 3NF.
2) Relationship mapping (1:1, 1:N, M:N with pivot tables), with foreign keys named explicitly.
3) An index strategy, including composite indexes, tuned for read-heavy access patterns.
4) Migration files in the chosen ORM.
5) Factory and seeder examples that produce realistic test data.
6) An ER diagram description in text.

Optimize for read-heavy workloads. Output each section under a heading, with the migrations and factories as copy-ready code.

What this prompt does

This prompt drives ChatGPT to produce a complete, opinionated database design from a single structured request. By locking in the normalization level, ORM target, and specific query patterns upfront, you get output that actually reflects your constraints — not a generic textbook schema. The template forces the model to commit to relationship cardinality (1:1, 1:N, M:N with pivot tables named explicitly) and an index strategy tied to your actual query patterns, which is where most AI-generated schemas fall short.

The [requirements] variable is where you drop constraints that don't fit neatly into entity lists: multi-tenancy via a team_id on every table, soft deletes across all models, or a specific audit trail pattern. Keep it to 3–5 bullet points; more than that and the model starts trading depth for coverage.

The [optimization_goal] variable is the lever that separates a read-heavy reporting schema from a write-heavy transactional one. Feed it read throughput and you get covering composite indexes and suggestions for where to add summary columns. Feed it write concurrency and you get narrower tables, shorter transactions, and guidance on which FK constraints to enforce at the application layer rather than the database layer — particularly relevant when targeting MySQL, which does not support deferred constraints.

When to use it

  • Starting a new SaaS product and need a schema baseline before the first migration
  • Designing a pivot-heavy feature (multi-tenant permissions, tag systems, product variants) where relationship modeling is the hard part
  • Onboarding a junior dev who needs a concrete, annotated migration file to learn from
  • Prototyping a client project where you need a credible schema to discuss in a discovery call
  • Generating realistic factory and seeder data for a test suite on a new domain model
  • Getting a second opinion on relationship cardinality before committing a design to production

Example output

For [project_type] = SaaS subscription platform, [entities] = users, plans, subscriptions, invoices, [orm] = Laravel, [optimization_goal] = read throughput:

-- plans table
id          BIGINT UNSIGNED PK
name        VARCHAR(80) NOT NULL
price_cents INT UNSIGNED NOT NULL
interval    ENUM('month','year') NOT NULL   -- MySQL ENUM
INDEX idx_plans_interval (interval)

-- subscriptions table
id          BIGINT UNSIGNED PK
user_id     BIGINT UNSIGNED NOT NULL  -- FK users.id
plan_id     BIGINT UNSIGNED NOT NULL  -- FK plans.id
status      ENUM('active','paused','cancelled') NOT NULL
starts_at   TIMESTAMP NOT NULL
ends_at     TIMESTAMP NULL
INDEX idx_subs_user_status (user_id, status)  -- covers dashboard lookup
INDEX idx_subs_ends_at (ends_at)              -- covers expiry sweep job

The Laravel migration for subscriptions includes foreignId('user_id')->constrained()->cascadeOnDelete(). The accompanying UserFactory state withActiveSubscription() is generated inline, wiring the factory chain so User::factory()->withActiveSubscription()->create() produces a complete test fixture without additional setup.

Pro tips

  • Set [normalization_level] to 3NF for transactional data and denormalized (star schema) for reporting pipelines — the model handles both confidently but needs explicit instruction to choose one over the other.
  • Name your [query_patterns] specifically: user dashboard lookup by status, monthly invoice aggregation gets you targeted composite indexes. Vague patterns like typical web app produce generic single-column indexes that miss multi-column cardinality.
  • After getting the schema, follow up with: "Show me the three most likely N+1 query paths and the eager-load fix for each" — the model already holds the full relationship map in context and gives precise with() chains rather than generic advice.
  • For Laravel output, specify [orm] as Laravel 11 with $casts property (not casts() method) to match current conventions and avoid the deprecated casts() method that still appears in older training examples.
  • The ER diagram description output is prose — paste it into Mermaid or dbdiagram.io immediately after receiving it. Modeling errors the model glosses over in text become obvious the moment you see a foreign key arrow pointing the wrong direction.

Frequently Asked Questions

Can I use this prompt for NoSQL or document databases?
The template is written around relational concepts — table definitions, FK constraints, pivot tables, and ORM migrations. You can adapt it by replacing `[orm]` with `Mongoose` and `[normalization_level]` with `embedded vs. referenced document strategy`, but expect to reframe several output sections manually. It works best for MySQL, PostgreSQL, or SQLite targets where the migration and index concepts map directly.
How specific do the [entities] need to be?
List the core nouns only — 4 to 7 entities is the sweet spot. If you include every model upfront the output gets shallow on relationships and indexes. Start with the entities that share the most relationships, get a solid schema, then prompt for satellite entities (audit logs, notifications, webhook deliveries) in a follow-up that references the first output by name.
Does the generated migration code run without edits?
Usually not without small fixes. Column type aliases differ between Laravel versions, and the model occasionally inverts FK direction on M:N relationships or omits an `->unsigned()` modifier on older-style integer foreign keys. Treat the output as a reviewed draft: copy it into your editor, run `php artisan migrate`, and fix the one or two errors that surface. The index strategy and relationship mapping are the real value — the syntax is easy to patch.
Engr Mejba Ahmed

Need this built for real?

Engr Mejba Ahmed

AI Developer · Software Engineer

I'm Mejba — I design and ship production AI systems, automations, and full-stack apps. If you want this turned into a working solution for your team, let's talk.

More in ChatGPT Prompts for Developers

Engr Mejba Ahmed

Engr Mejba Ahmed

AI assistant · trained on my work

👋

Hey there!

Quick Actions

WhatsApp Direct line to me

Chat on WhatsApp

+880 1723 741224 · Replies within the hour on working days

Popular Questions

Engr Mejba Ahmed is connected
Engr Mejba Ahmed is typing...
Engr Mejba Ahmed avatar

✉ Want me to follow up? Drop your email

Engr Mejba Ahmed avatar

📞 Connect Directly

Choose how you'd like to reach me

WhatsApp

+880 1723 741224

Email

mejba.13@gmail.com

✓ Details sent! I'll get back to you shortly.

Powered by OpenAI

335+

Blog Posts

25

AI Courses

63

Projects

Services & Expertise

Pricing & Process

Learning & Resources

Connect & Support