Local publication · 2026
City business directory on Next.js
Taking an open-source directory template from demo to launch-ready, with AI-assisted development.
- Stack
- Next.js · React · TypeScript · Tailwind CSS · Drizzle · Postgres (Neon) · Vercel · Mapbox · Git-based content
- 01Reproduce
- 02Fix on a branch
- 03Type-check and lint
- 04Test on staging
- 05Review
- 06Merge
- 07Check live
| Catalog size | Seconds |
|---|---|
| 1,000 listings | 6.9 |
| 5,000 listings | 43.7 |
| 20,000 listings | 105.1 |
Measured locally with a warm cache, before any data-layer changes. Cached business pages stayed at 0.3–0.5 s at every size, which pointed the problem at how listings were loaded, not at the pages themselves.
Context
A city publication and business directory built on an open-source Next.js template, aiming for about 20,000 listings. The job: find out what works, what breaks at scale, and fix it properly.
What I did
- Deployed it with 215 real local businesses, imported from a scraped dataset with a converter script I wrote.
- Fixed the deployment blockers: the build running out of memory, missing admin seeding, and an auth cookie bug that bounced admins back to the login page.
- Load-tested at 1,000, 5,000 and 20,000 listings and reported real timings, so the data-layer decision was based on numbers.
- Found and fixed more than a dozen template bugs across six pull requests: a security policy blocking the map and fonts, a hydration error, a pagination route returning 404, a filter loop, an admin list capped too low, blog pages failing for posts published after a build, and keyboard accessibility issues.
- Built the featured-listings feature: one control in the admin dashboard, a status cache shared across serverless instances with tag-based revalidation, a showcase that follows search and filters, and extended profile fields for featured businesses.
- Audited which data fields reach the browser, to keep private data out of public pages.
How AI fit in
I used AI coding tools to navigate a large unfamiliar codebase and draft fixes. Every change was reproduced first, type-checked and linted, tested on a staging deployment and reviewed before merging. I turned down “quick fixes” that would have disabled caching, loaded 20,000 rows into a dropdown, or loosened the security policy.
Outcome
A launch-ready MVP with a documented fix history and a branch → staging → review → merge workflow.