The problem
Finding a breeder is a research project. The information exists, but it is scattered across kennel-club registries, national breed clubs, shelter databases and thousands of individual breeder sites, in a dozen languages and formats. A buyer searching for a specific breed near a specific town gets either a marketplace that lists puppies like appliances, or a forum thread from 2014.
Pet Breeder Directory is a Frenchy Digital product, founded by Chris Machetto. The brief we set ourselves was to aggregate that public data into one searchable place, give breeders and shelters a profile they can claim and manage, and do it on infrastructure cheap enough to survive the years it takes a directory to earn its traffic. That last constraint decided most of the architecture: no per-seat SaaS bills, no managed database that charges by the row, one server we control.
What the directory is, and is not
- Aggregated, not vetted: The 249,614 listings are bulk-imported from public sources. A small number are PBD-verified after human review, and buyers are told plainly that they must do their own due diligence. The product never implies breeders are screened as a class.
- Majority European by coverage: The largest country counts are the Czech Republic, France, the United States, the United Kingdom, Sweden and Italy. US and Canada are the go-to-market focus, not the footprint.
- Seven species, not just dogs: 228 dog breeds, 80 cat, 57 bird, 30 reptile, 25 small animal, 20 fish and 12 horse breeds, each with an encyclopedia page.
- Early on the paid side: Billing, reviews, litters and alerts all ship as working code. This page reports what the code does, not traction it has not earned yet.
What we built
For buyers
For breeders and shelters
How it works
One box, four containers
Postgres 16 + PostGIS via Drizzle
Meilisearch for breeders, pg_trgm for breeds
MinIO behind a Cloudflare hostname
Coolify, Docker and a local build
Programmatic SEO at fourteen million pages
A single dynamic route under the app root resolves a slug into a breed and a US city, 452 by 31,190, and renders a breed-in-city page with incremental static regeneration. Nothing is pre-built; a page exists the first time someone or something asks for it, and Cloudflare cache rules hold anonymous HTML for the breed, breeder, blog and SEO surfaces at the edge. The site also publishes llms.txt files so answer engines can read the catalogue directly, and the 303 published blog posts feed the same cache.
Two Next.js details cost real time and are now rules in the repo. A root loading boundary flushes a 200 shell before a missing page can return 404, which soft-404s every bad URL site-wide, so there is none. And a fragment cannot be the root of a streaming boundary, because React needs a real DOM node to complete it.
Authentication without a vendor
Sessions are signed JWTs in a cookie, issued by the app. Google sign-in uses OAuth with PKCE and a CSRF state parameter. Two-factor is TOTP with recovery codes, with SMS as a fallback channel. Rate limiting sits in front of the auth routes. The trade-off is deliberate: owning auth means owning its bugs, but it also means the directory has no per-user cost and no third party in the session path.
Email as a state machine
The sequence engine is a registry of fourteen declarative drips, code-verified by count in the registry, covering buyer onboarding, free-to-premium upgrade, breeder onboarding and nudges, cold outreach and free-claim invitations, win-back, cancellation, abandoned signup and referral journeys. Each step is a React Email template. The engine enforces a 24-hour cooldown per recipient across every sequence, cancels an upgrade drip the moment a Stripe webhook reports a subscription, and pauses it while a human reply thread is open. Inbound mail arrives on a webhook that honours stop words and forwards a copy to a person.
Cold outreach to breeders goes out through Smartlead rather than the transactional domain, with warm-up, daily caps and automatic blocking if mailbox reputation drops. Reported honestly: as of the last documented audit the sequence cron was not yet scheduled in production, and the backlog has to be expired before it is switched on, or months-old sequences would all fire at once.
Problems worth talking about
Two kinds of verified
SSRF on a shared host
A search index that only grows
Edge cache versus content hashes
Where it stands
Reported honestly
Every number on this page comes from the production database audit recorded in the repository or from counting the code: listings, breeds, species, organizations, cities, sequences. The directory is live and indexed. We do not publish subscriber counts, revenue or review volumes here, because those figures are small and a case study is not the place to dress them up. This page will be updated as they change.
The directory is aggregated, not vetted. Never write copy implying breeders are screened as a class.
— Pet Breeder Directory engineering notes
What This Project Does Well
Technologies Used
Next.js 15 (App Router, ISR), React 19, TypeScript strict, Tailwind CSS 4, Drizzle ORM, PostgreSQL 16 with PostGIS and pg_trgm, Meilisearch, MinIO (S3-compatible), custom JWT sessions (JOSE), Google OAuth, TOTP MFA, Resend and React Email, Smartlead, Stripe (Checkout, Identity, Connect, webhooks), Mapbox GL JS, PostHog, Sentry, Zod, Vitest, Playwright, Bun for development, Node 22 in production, Docker, Coolify on a VPS, Cloudflare DNS, CDN and rate limiting
Ready to Build Something Similar?
Let's discuss how we can help transform your business with a custom digital solution.
