How to Build a Directory Site With AI
A working directory build: the schema, the seeding plan that decides whether it lives, and the four failures that kill directory sites.
To build a directory site with AI, you need three things in this order: a listing schema you will not have to change later, real listings to fill it, and one indexable page per listing. An AI app builder handles the first and third in an afternoon. The second one is the whole job, and it is the reason most directory sites die at forty listings. This walks through a working build using a local trades directory as the example, with the schema, the seeding plan, and the four things that break.
Start with the listing schema, not the homepage
Every directory is the same shape underneath: entities, categories, locations, and a search over the three. Get the entity table right and everything else is presentation.
Here is a schema that survives contact with a real directory rather than a demo one:
create table listings (
id uuid primary key default gen_random_uuid(),
slug text unique not null,
name text not null,
category_id uuid not null references categories(id),
city text not null,
region text,
postcode text,
lat numeric,
lng numeric,
phone text,
website text,
description text,
hours jsonb default '{}',
verified_at timestamptz,
claimed_by uuid references auth.users(id),
source text not null default 'manual',
status text not null default 'draft',
created_at timestamptz default now(),
updated_at timestamptz default now()
);
create unique index listings_dedupe on listings (lower(name), lower(city));Four columns there are not obvious and all four earn their place.
`source` records where the row came from: manual entry, a public dataset, a form submission, a scrape you are entitled to run. When a listing turns out to be wrong you will want to know whether the whole batch is suspect.
`claimed_by` is how a business owner takes over their own listing later. Retro-fitting ownership onto a directory that never had it is genuinely painful, and it costs you one column now.
`verified_at` separates "we have this listing" from "someone confirmed it is real". Those are different states and users can tell.
The unique index on lowercased name plus city is the single highest-value line in the file. Directories rot through duplicates, and duplicates arrive quietly.
When you hand this to a builder, paste the schema rather than describing it. Builders are good at generating a plausible schema and bad at generating yours. If you are unsure which database to start on, we compared the options in choosing a database for an AI-built app.
The seeding problem, which is the actual problem
A directory with no listings has no users, and a directory with no users attracts no listings. You break that loop by seeding, and there are only three legitimate ways to do it.
Public and open data. Government registers, open licensing portals, and datasets published under terms that allow reuse. Check the licence, record it in `source`, and keep the download.
Your own collection. Ringing round, walking a high street, reading local press. Slow, and the fastest route to a directory nobody else has.
Owner submission. A form. This works once you have enough listings that being absent looks bad, which means it cannot be your first move.
What is not on the list: scraping a competing directory. Compiled listing databases are frequently protected as databases in their own right, separately from copyright in the text, and directory operators are among the more litigious people on the internet. Do not build your product on top of somebody else's extraction.
A realistic seeding target for a niche directory is 150 to 300 listings before launch. Under a hundred and the site feels empty in every category a user actually searches.
AI helps here more than it helps with the code. Give a model a messy source and ask it to normalise names, split addresses, infer categories, and flag rows it is unsure about. Then read the flagged rows yourself. If your source data starts life in a spreadsheet, the same pattern applies as in turning a spreadsheet into an app with AI.
One page per listing, and make it real
The SEO logic of a directory is simple. Nobody searches for your directory. They search for "emergency locksmith in Wakefield" and land on a listing page or a category page. That means:
Every listing gets its own URL at `/listing/<slug>`, server rendered.
Every category and city combination that has at least three listings gets an index page. Under three, do not generate the page. Thin category pages with one result are the fastest way to look like a doorway site.
Category pages link down to listings, listing pages link back up to their category and city.
Ask the builder for server-side rendering explicitly. Client-rendered directories index badly and slowly, and you will not notice for six weeks. The specifics of getting crawled are in getting your AI app indexed by Google.
Each listing page needs one thing that is not on every other directory: opening hours, a photo, a verified badge, a short human sentence, something. Otherwise you are the fourth copy of the same data and there is no reason to rank you.
Search that works on real names
Directory search fails on misspellings and partial names, which is what people actually type. Two mechanisms cover most of it.
Problem | Fix |
|---|---|
Misspelled business name | Trigram similarity index on `name`, ordered by similarity |
Partial or reordered words | Full text search over name plus description |
Wrong city spelling | Match city against a controlled list, never free text |
No results at all | Fall back to the category page, never a blank screen |
In Postgres that is a `pg_trgm` index plus a `tsvector` column, and an app builder will write both correctly if you name them. The `pg_trgm` module gives you a `similarity()` function scoring 0 to 1 and GIN or GiST index support, which is all you need for fuzzy name matching. The wider options are covered in adding search to an AI-built app.
The last row matters more than the first three. An empty result page on a directory is the moment a user decides your site is broken.
The four things that break
Duplicates. Covered by the unique index above, but also add a soft check on submission: before inserting, search for similar names in the same city and show the submitter what already exists.
Stale listings. Businesses close. Add a `last_checked_at` and a quarterly job that flags anything untouched for a year. A directory of dead phone numbers is worse than no directory.
Spam submissions. The moment you accept public submissions you get spam. Default `status` to `draft`, review before publishing, and rate limit the form.
Category sprawl. Someone will add a category with two listings in it, then another. Fix the category list up front and treat adding one as a decision, not a form field.
A realistic build order
Schema and categories, seeded by hand.
Listing page and category page, server rendered, with the linking between them.
Import your seed data and read a random sample of thirty rows yourself.
Search.
Submission form, defaulting to draft.
Claim flow, using `claimed_by`.
Steps one to four are a weekend with an app builder. Step three is not optional and cannot be delegated, because a directory's only real asset is that the data is right. If you have not built anything with an AI builder before, start with the general walkthrough in how to build an app with AI and come back to this.
FAQ
How many listings does a directory need before launch?
For a niche directory, roughly 150 to 300, distributed so that the categories people actually search have at least a handful each. Fewer than a hundred and every search feels empty.
Can I scrape listings from another directory?
No. Compiled listing databases are commonly protected in their own right, separately from any copyright in the individual entries, and directory operators enforce it. Use open data, owner submissions, or your own collection.
Should each listing have its own page?
Yes. Listing pages and category pages are where directory traffic lands. A single filtered index behind JavaScript gives search engines nothing to rank.
How do I stop duplicate listings?
A database-level unique index on lowercased name plus city, plus a similarity check shown to the submitter before they save. The index catches what the check misses.
What is the hardest part of building a directory?
Getting and maintaining accurate data. The software is a weekend. The listings are the product, and they decay unless something in your process refreshes them.
A directory site is the simpler, one-sided cousin of a marketplace, listings without transactions. How to build a marketplace app with AI covers what changes once you add payment and two-sided trust to the mix.
How did this land?
About the author

Developer Advocate
Steve builds something with Swarmz every week and writes up what worked, what broke, and what he'd do differently. Tutorials and hands-on guides are his lane.


