The Real Problem: 3 AM and No Plumber
It all started with a WhatsApp message at 3 AM. My sister had a burst pipe, water flooding the living room, and needed a plumber *right now*.
She did what everyone does: Google "emergency plumber near me". Found a 2003-era website with phone numbers that didn't answer. Called another. Closed. The third one charged $400 just to show up and look.
That's when I thought: "Here's a problem someone has at 3 AM, willing to pay for it, and can't solve easily".
That's gold in the startup world.
The Idea: Simple, But Viable?
My first instinct was to build a mobile app with push notifications. I even started designing the interface.
Then I stopped and thought differently.
Who searches for emergency plumbers? Panicked people on Google. They don't download apps. They don't create accounts. They want a phone number in 10 seconds.
Where's the best place to be? On the first page of Google when someone searches "emergency plumber in Los Angeles" at 2 AM.
That changed everything. I didn't need an app. I needed SEO.
The Strategy: 1,104 Static Pages
The strategy was brutal in its simplicity:
1. 90 major US cities 2. 1,251 verified plumbers with quality ratings 3. One static page per city optimized for SEO 4. Static generation at build time = maximum speed + guaranteed ranking
Instead of building dynamically, I used Next.js 16 with App Router to generate all pages at build time. This means:
- **Zero latency**: Pages are pre-rendered on Vercel's CDN
- **Perfect SEO**: Google sees HTML, not JavaScript
- **Infinite cache**: A generated page never changes (until redeploy)
```typescript // How I generated routes dynamically export async function generateStaticParams() { const cities = await getCitiesFromSupabase(); return cities.map((city) => ({ slug: city.slug, })); }
export default async function CityPage({ params }) { const plumbers = await getPlumbersByCity(params.slug); return <CityTemplate plumbers={plumbers} />; } ```
The magic: 1,104 pages generated in under 5 minutes. Once. Then Vercel serves them from a global CDN.
The Stack: I Chose Tools, Not Complexity
Most people would've picked Elasticsearch, Redis, microservices. I chose:
- **Next.js 16**: For static generation and React 19
- **Supabase (PostgreSQL)**: A simple SQL database. No NoSQL, no complications
- **Sanity CMS**: For the blog (because SEO needs content too)
- **Tailwind CSS 4**: Styling without thinking
- **TypeScript strict mode**: Because production errors aren't fun
Why this combination:
- Supabase costs 10x less than Firebase
- Sanity lets me write articles without touching code
- Everything runs on Vercel (automatic Git deployment)
- TypeScript strict catches bugs before users see them
The Real Problems (And How I Fixed Them)
My last commit was December 27th. Here are the problems I hit:
Problem 1: Google Wasn't Indexing
I generated 1,104 pages. Google indexed 47.
Reason: Broken canonicals and www redirects. Google thought there was duplicate content.
Fix:
```typescript // next.config.js const config = { async redirects() { return [ { source: '/:path*', destination: 'https://www.findemergencyplumber.com/:path*', permanent: true, has: [ { type: 'host', value: 'findemergencyplumber.com', }, ], }, ]; }, }; ```
After this, Google indexed 1,089 pages in two weeks.
Problem 2: Blog Images Broke Everything
I used Sanity for blog content. Its images came with special URLs. Vercel tried to optimize them and failed with 402 errors.
Solution: Disabled image optimization for Sanity URLs.
```typescript // next.config.js const config = { images: { unoptimized: process.env.NODE_ENV === 'production', }, }; ```
Not elegant, but it works. Sometimes pragmatism > perfection.
Problem 3: CSS Conflicts in Tailwind
The `py-*` utilities conflicted with `.container`. Spent 2 hours debugging why padding wasn't working.
Fix: Used `padding-inline` instead of `px-*`.
```css .container { padding-inline: 1rem; } ```
Stupid details that eat real time.
The Numbers (Real)
- **1,104 static pages generated**
- **1,251 verified plumbers** in the database
- **90 cities covered**
- **Build time: 4-5 minutes**
- **Page load: < 1 second** (from CDN)
- **Google indexed: 1,089 pages**
In revenue terms: Each plumber pays a monthly subscription to be in the directory. The model is simple: more plumbers = more revenue.
The Most Important Lesson
Most people would see this project and think: "I need a mobile app, REST API, push notifications, machine learning".
I thought: "Where is my user when they need this? On Google. What's fastest to build? Static pages".
The best technology is what solves the user's real problem, not what looks impressive on GitHub.
Next.js + Supabase + Sanity + Vercel. Four tools. One clear vision. 1,104 indexed pages.
What's Next
I have two paths:
1. SEO Expansion: Add 200 more cities, write 300 blog articles 2. Twilio Integration: Add SMS/Call system to connect plumbers directly with customers (this was the original plan, but turns out SEO is more valuable)
Right now, I'm on path 1. The numbers tell me SEO works better than any app.
---
Takeaway
If you have an idea but think you need complex technology to validate it:
You don't.
I validated Find Emergency Plumber with static pages. No API, no mobile app, no push notifications.
Think about where your user is. Then go there with the simplest tool that works.
Sometimes that's Webflow. Sometimes it's Next.js. Sometimes it's a shared Google Sheet.
What matters is that it solves the problem.
Everything else is noise.