From empty project to SEO-ready directory with 200 listings in one session
By Øyvind · 2026-04-15
~20 min
A directory is a list of things, organised by category, with detail pages for each item. Boring. Underestimated. One of the highest-leverage site formats you can build.
Why they work.
SEO structure is ideal. Category pages target commercial-intent keywords. Listing pages target long-tail keywords. The internal linking structure naturally forms the kind of topical authority search engines reward.
Content scales without manual writing. Two hundred listings with auto-generated structured content rank better than fifty hand-written articles, in most cases, because the breadth signals authority to Google.
Monetisation is clear. Affiliate links on every listing. Premium listings. Sponsored placements. Newsletter sign-ups to build a list. All stackable.
Durability. A well-built directory keeps ranking for years with minimal maintenance. Add new listings occasionally, update old ones yearly, watch traffic compound.
What niches work.
Any category where buyers want to compare options before choosing. Tools, software, services, products, venues, events. Anywhere there are many options and buyers want a structured way to evaluate them.
Examples that work well: AI tools directory, VPN comparison, B-corp brands, remote job boards, newsletter recommendations, podcast directories, indie SaaS tools, Scandinavian design furniture.
Examples that do not work well: anything too generic (a directory of all products), anything that requires expert editorial judgement on every listing (a directory of fine art).
For this tutorial, we will build a directory of indie newsletter tools. Niche enough to rank, broad enough to have two hundred listings, commercial intent because users pay for these tools.
Substitute your niche. Steps are the same.
~90 min
Directory sites live or die on data quality. Garbage in, nothing ranks. Spend a full ninety minutes on this step.
What you need to collect.
Listing names. The things you are listing. For newsletter tools, that is names like Substack, Beehiiv, Ghost, ConvertKit, Kit, and so on. Aim for fifty as a minimum to launch. A hundred is better. Two hundred is great.
Listing URLs. The homepage of each tool.
Categories. Group your listings into five to ten meaningful categories. For newsletter tools: Writing Platforms, Email Service Providers, Audience Growth Tools, Monetisation Tools, Analytics.
Affiliate program availability. For each listing, check if they have an affiliate program. If yes, get the program URL. If no, flag it.
Key data points per listing. For newsletter tools: starting price, free tier available, custom domain support, best for (solo writers / publications / teams), notable feature.
Do this in a spreadsheet. Columns for each field. One row per listing.
You can do this manually, or you can use AI assistance. Ask Claude to list the top fifty newsletter tools with starting prices and categorise them. Verify every output. AI is wrong about specifics often. Never trust a directory build without verification.
Budget ninety minutes. Do not shortcut this. A directory with fifty meticulously researched listings outperforms one with two hundred sloppy ones. Search engines reward accuracy.
By the end of this step, you have a spreadsheet with fifty to two hundred rows and eight to ten columns filled out. Save as CSV. You will feed it to CONTENTFORGER.
~45 min
Directory prompts are structural. You are describing an architecture, not features.
Open a text file. Here is the template.
Build a directory site for indie newsletter tools. Users are people starting or running newsletters who want to compare platforms and service providers.
Stack: Next.js 15, TypeScript strict, Tailwind, Supabase for the listing database, Resend for newsletter signups. No auth needed for public browsing. Admin pages protected by a simple env-variable-based password for now.
Data model:
Tools have: slug, name, tagline, description (200 word), category, subcategory, homepage_url, affiliate_url, logo_url, starting_price, has_free_tier (boolean), custom_domain_support (boolean), best_for (writers/publications/teams/any), notable_feature, rating (editorial 1-5), last_updated.
Categories have: slug, name, description, icon.
Pages to build:
Home page: hero with search, category grid, top-rated tools section, recently added tools section, newsletter signup.
Category page at /category/[slug]: lists all tools in that category, filterable by price tier and best-for. Uses ItemList schema and BreadcrumbList schema for SEO.
Tool detail page at /tool/[slug]: full description, key details table, primary CTA to affiliate URL via /go/[slug], related tools from the same category. Uses Product schema.
Search page at /search: text search across tool names and taglines, filterable by category.
About page: who runs the site, how listings are chosen, disclosure about affiliate links.
Submit page: form for tool creators to request a listing. Submits to Supabase submissions table, admin reviews before publishing.
Admin pages at /admin: add tools, edit tools, approve submissions. Password-gated with ADMIN_PASSWORD env var.
SEO requirements:
Every listing page has unique metadata generated from the tool data. Every category page has unique metadata emphasising the category name. app/sitemap.ts includes every tool page and category page. app/robots.ts blocks /admin and /api but allows everything else. Structured data (JSON-LD) on home, category pages, tool pages.
Monetisation:
All outbound links to tools go through /go/[slug] for tracking. Each click fires a Vercel Analytics custom event named tool_click with the slug as a property.
Newsletter signup on every page, wired to Resend.
Design:
Clean, minimal, fast-loading. Light theme. Avoid dark navy. Emphasise readability. Card-based layout for listings. Single primary colour accent.
Non-negotiables:
next/image for every image with placeholder blur. await params in all dynamic routes. generateMetadata on every route. TypeScript strict, no any. Rate limiting on the submit form and newsletter endpoints. Zod validation on all form inputs.
Seed the database with the tools from this CSV: [paste your CSV here].
Paste into CONTENTFORGER. Generate. Three to four minutes for this scope on Sonnet.
~45 min
CONTENTFORGER will generate the schema and scaffolding. You still need to load the data into Supabase.
Two paths.
Path one, bulk insert via Supabase SQL Editor. CONTENTFORGER usually generates a seed file in the format of SQL INSERT statements. Open it, copy into Supabase SQL Editor, run. Your tools table populates.
Path two, CSV import. Supabase's table editor supports CSV import. Go to Table Editor, select the tools table, click Import data. Upload your CSV. Map columns. Import.
Whichever path you take, verify the data. Go to the tools table in Supabase. Count the rows. Should match your source CSV count.
Check a sample of rows. Are URLs correct. Are prices correct. Is the category slug matching the category table. Is the logo URL loading.
Fix any issues in the CSV or via SQL updates. This is the step people rush and regret. Directory quality is data quality.
Run the dev server. Open localhost:3000. Your home page should show real tools, real categories, real data.
Browse a category. Your listings should appear. Click into a tool. The detail page should render with real information.
If anything looks wrong, do not try to fix it by re-prompting CONTENTFORGER. Fix the data directly in Supabase. The code is fine. The data needs cleaning.
~30 min
Every outbound link should go through /go/[slug] before reaching the affiliate URL.
Why. Three reasons.
Tracking. You can count clicks per tool and know what converts.
Flexibility. If an affiliate program changes URL format or ends, you update one place in the database instead of editing every page.
SEO. Outbound affiliate links with rel=nofollow sponsored tell search engines not to pass ranking signals. A /go/ redirect route makes this systematic.
CONTENTFORGER usually scaffolds the /go/ route correctly. Verify by opening app/go/[slug]/route.ts. It should:
Accept a slug parameter. Look up the affiliate URL in Supabase. Fire an analytics event. Redirect (307) to the affiliate URL.
If it does not exist, create it. Simple implementation:
import { NextRequest, NextResponse } from 'next/server' import { supabase } from '@/lib/supabase'
export async function GET(req: NextRequest, { params }: { params: Promise<{ slug: string }> }) { const { slug } = await params const { data } = await supabase .from('tools') .select('affiliate_url, homepage_url') .eq('slug', slug) .single()
const destination = data?.affiliate_url ?? data?.homepage_url ?? '/' return NextResponse.redirect(destination, 307) }
Verify /go/ routes do not appear in sitemap.xml. Open app/sitemap.ts, confirm the /go/ path is excluded.
Verify robots.txt blocks /go/. Open app/robots.ts, confirm Disallow: /go/ is present.
Test a redirect. Visit /go/substack in your browser. It should redirect to the affiliate URL for Substack, or the homepage URL if no affiliate URL is set.
This is the monetisation foundation. Get it right now, it runs for years without attention.
~60 min
Push to GitHub. Deploy to Cloudflare Pages (the detailed steps are in the Weekend SaaS tutorial, chapter 6).
Once live on a .pages.dev URL, point your custom domain.
Now the critical steps for a directory site: Search Console submission.
Go to search.google.com/search-console. Add property. Use Domain property (not URL prefix).
Verify ownership via DNS TXT record. Google gives you the record. Add it in Cloudflare DNS. Verification usually completes within an hour.
Submit your sitemap. In Search Console, go to Sitemaps. Add your-site.com/sitemap.xml. Google starts crawling.
For a directory with two hundred listings, initial indexation takes a few days to a few weeks. Monitor progress in Search Console, Coverage report.
Also submit to Bing Webmaster Tools at bing.com/webmasters. Bing has an Import from Google Search Console option that is one click. Do this. It covers Bing, DuckDuckGo, Yahoo, and Ecosia all at once.
Early traffic.
Directory sites do not get instant traffic. They build over months. The critical first steps:
One. Share the directory on your own social media. Some traffic, but mostly to get Google to notice the site via mentions.
Two. Submit to relevant directories-of-directories. For newsletter tools: beehiivcommunity-style places, indie hacker communities, relevant subreddits. Be transparent it is a directory, not an article.
Three. Write two or three thoughtful blog posts on the directory about topics in the niche. Link them into relevant category pages. This gives Google a signal that the site has editorial content, not just listings.
By month three, expect to see some organic traffic. By month six, it should be growing meaningfully. By month twelve, directory sites in good niches generate real revenue.
~30 min
A directory is not done after launch. It needs ongoing maintenance to stay competitive.
Monthly tasks.
Add new listings. Aim for five to ten new additions per month. Fresh content signals to Google that the site is active.
Remove dead listings. Any tool that has shut down or been acquired, update or remove. Broken links hurt user trust and SEO.
Verify pricing. Tools change prices. Once a quarter, spot-check ten random listings against their current pricing. Update anything stale.
Respond to submissions. If you built a submit form, check it weekly. Approve legitimate tools. Reject spam.
Quarterly tasks.
Write a trend piece. What is new in the niche this quarter. What tools are gaining popularity. Internal link to relevant category pages.
Refresh category descriptions. Make sure they still reflect the current state of the niche.
Review affiliate programs. Are any programs ending. Any new ones worth joining. Update affiliate URLs.
Annual tasks.
Comprehensive data audit. Verify every listing's data. Remove dead tools. Update descriptions.
Re-photograph logos. Tool logos change. Fresh logos are a small but noticeable quality signal.
Revisit your search terms. Use Search Console's Performance report to see what terms are bringing traffic. Are your category pages well-optimised for those terms. Adjust copy where needed.
Monetisation.
At six months, evaluate affiliate earnings. Which listings convert. Which do not. For high-converting listings, consider featuring them more prominently (a "Featured" badge, top position in category, mention in homepage carousel).
Consider paid listings. Tools can pay to be featured. Price depending on your traffic. Rule of thumb: charge what a month of your top-position traffic would cost via Google Ads to that tool.
Consider a newsletter. Weekly digest of new listings plus one editorial pick. This builds an email list you can monetise directly via sponsored slots.
The pattern.
Directory sites are long-tail, high-margin businesses. They do not get exciting traffic spikes. They get steady, compounding traffic that turns into steady, compounding revenue. A good directory in a good niche is a five-year project that pays for itself for years after that.
Build it once, well. Maintain it monthly. Let it compound.