Websites
How many tables should a database have? Data from 13 site plans
A database should have one table for each kind of thing it records, so the count follows the business, not a target. Across 13 AI site and app plans, the ones that kept data planned 1 to 19 tables, with a median of 10, and almost every one started with profiles and a contact messages table.
Indunil Asanka · Co-founder
4 min read · Published
A database should have as many tables as the business has kinds of things to record: one for bookings, one for the sessions they book, one for people. In 13 AI site and app plans read on 21 October 2026, the 11 that kept data planned 1 to 19 tables, with a median of 10.
Where the numbers come from
Each OneCraft site or app is planned before any code is written, and the plan has a data section listing every table with its columns and who may read or write it. The table above counts those lines in OneCraft’s development project, read on 21 October 2026, taking the latest completed pipeline run for each business and job type: 13 plans, 11 websites and 2 apps.
Caveats. The briefs were written by the team to exercise features, so several ask for more than a typical first site. All runs used one development environment. The planner changed during the sample: the two yoga studio plans from 17 October list their data in an older format, and the dog sites on 18 October asked for no data at all. A plan is also a plan, the agent can add or drop a table while building, so this measures intent, not the final schema.
The tables nearly every site planned
Four kinds of table came up again and again among the 11 plans with data.
| Table | Plans that named it | Why it is there |
|---|---|---|
| profiles | 8 of 11 | Name, phone or role beside the sign in record |
| messages (contact form) | 5 of 11 | A contact form that keeps its messages, insert only for visitors |
| a booking table | 6 of 11 | bookings, class_bookings, class_signups, rentals or tour_bookings |
| a roles table | 3 of 11 | user_roles or staff_roles, read by the admin access rules |
Orders appeared in 3 plans, class sessions in 4, and payment records (purchases, memberships, subscriptions or member passes) in 3. The rest of each plan was specific to the business: guide hours for the kayak tours, shift swaps for the cleaners, bids for the running club’s auction.
What drives the count
Features, more than pages. The ceramics shop planned 19 tables because each selling feature brings its own: product variants, bundles, reviews, discount codes, loyalty points, delivery zones, time slots, gift cards, pre-order runs and pre-orders. The agency planned 17 because a client portal is many small things: projects, milestones, weekly updates, files, approvals, invoices, quotes, support tickets and their replies. The sourdough course stayed at 7 with courses, lessons, progress, purchases, memberships, a chat and profiles.
A useful rule of thumb from the sample: count the nouns a visitor or an admin can create, change or list on the site, then add profiles if anyone signs in. That gets within a few tables of every plan above.
How to decide for your own site
- List what the site must remember. A booking, an order, a donation, a comment. If nothing, you may not need a database at all, as the two dog sites show.
- Split repeated groups into their own table. Sessions and bookings, products and variants, posts and comments. A foreign key from the child to the parent keeps them linked.
- Separate who someone is from what they did. Profiles hold the person; bookings, orders and posts point at them.
- Add a table for roles only when the site has staff. Admin access belongs in the database, not only in the menu. See what an admin role is.
- Write each table as a migration. What a database migration is explains why, and what seed data is covers the starter rows a new table often needs.
Where the tables live on OneCraft
When a capability needs data, the agent turns on a backend: a schema of its own in OneCraft’s pool project, with a login role that can reach no other site, or a project on the owner’s own Supabase account. Every table must have row level security, and the agent checks each new table as an anonymous visitor and as a signed in person before a generation step can finish. The migrations and a supabase/schema.sql file are written into the site’s repository. Hosted schemas come with every plan, or the owner can connect their own Supabase account.
For the background, read what a Postgres schema is, row level security and what a Supabase project is. The website with a database page shows the result, and database per site vs a shared database covers the trade offs of where those tables sit.
| Kind of business | Site or app | Tables planned | Examples of the tables |
|---|---|---|---|
| Dog hotel and shop | Website | 0 | No database planned |
| Dog walking | Website | 0 | No database planned |
| Yoga studio | App | 1 | bookings |
| Yoga studio | Website | 2 | class_sessions, bookings (plus an availability view) |
| Pottery studio | Website | 6 | products, class_sessions, class_bookings, orders, messages, profiles |
| Online sourdough course | Website | 7 | courses, lessons, lesson_progress, purchases, memberships, chat_messages, profiles |
| Cleaning company staff app | App | 9 | sites, shifts, shift_swaps, time_entries, break_entries, checklist_items, checklist_ticks |
| Reformer pilates | Website | 10 | class_types, instructors, class_sessions, bookings, plans, member_passes, notifications |
| Yoga studio with packs | Website | 10 | class_sessions, class_signups, pack_products, pack_credits, orders, waivers, member_cards, checkins |
| Kayak hire | Website | 12 | kayak_types, rentals, return_checklists, guides, guide_hours, tours, tour_bookings, referral_codes |
| Running club | Website | 15 | posts, post_likes, post_comments, reports, campaigns, donations, auction_items, bids |
| Branding agency with a portal | Website | 17 | projects, milestones, approvals, invoices, quotes, tickets, ticket_replies, consents |
| Ceramics shop | Website | 19 | products, product_variants, bundles, reviews, orders, discount_codes, gift_cards, preorders |
Questions people ask
Is it bad to have a lot of tables?
No. A table per kind of thing is normal, and splitting is what keeps data correct: a booking points at a session instead of copying its time and price. The cost of more tables is more access rules to write and test, more joins in queries and more to explain to whoever maintains the site later. Fewer, wider tables usually hide repeated data instead.
When should something be a column rather than a table?
When there is exactly one of it per row and nothing else refers to it, it is a column: a booking's status, a product's price. When there can be many, or other rows point at it, it is a table: a product's variants, a post's comments. If you ever write item_1, item_2 and item_3 as columns, you wanted a table.
Why did two plans have no tables at all?
Their briefs asked only for information pages and a way to get in touch, so the planner wrote none. A site that shows services, prices and a contact link needs no database at all, which keeps it cheaper and simpler. Data comes in when the site has to remember something a visitor did, such as a booking or an order.
What is the profiles table for?
Sign in systems such as Supabase Auth keep the login itself in their own schema, with an email and a password hash. Anything else about a person, such as a display name, phone number or role, goes in a profiles table keyed by the user's id. Eight of the 11 plans with data named one.
Does every table need access rules?
On a database a website talks to directly, yes. Supabase's own guidance is to enable row level security on every table in an exposed schema, then add a policy for each kind of access. Without a policy, a table with security on returns nothing, which is safer than a table without it, which returns everything.
How do tables get added later?
With a migration: a numbered SQL file that creates or changes a table and is kept with the code, so every copy of the database can be brought to the same shape in order. Editing the live database by hand works once and is then impossible to repeat or review, which is why plans and tools prefer migrations.
Written by
Indunil Asanka · Co-founder
Builds the generation pipelines behind OneCraft: the slide, flyer and poster layout engines, the document grid and the render workers that turn a written brief into a finished file.
LinkedIn profileWritten and checked by the OneCraft team. Last checked .
Make your own website
Describe what you need and the generator writes and designs it, then you edit anything you like.
See what it can makeRead next
How much does Supabase cost? 1k, 10k and 100k rows measured
Supabase costs $0 on its Free plan, which includes a 500 MB database, and from $25 a month on Pro, which includes 8 GB of disk per project. For a small business site the rows are rarely what you pay for: 100,000 booking rows measured about 28 MB with their indexes, under 6 percent of the free database.
Homepage sections: what 13 planned home pages contain
A small business homepage usually needs six to eight sections: a hero, the offer in image and text rows, proof such as stats, how it works, live items such as classes or products, and a closing call to action. Across 11 planned website home pages the median was 7 sections, and every one had a hero, image rows and a call to action band.
Database per tenant vs a shared database: the trade offs
A database per tenant gives each customer the strongest separation and the simplest restore, at the highest cost and with migrations to run many times. A shared database is cheapest and simplest to change, but every query must filter by tenant correctly, forever; a schema per tenant with its own login role sits between the two.