Shipping Fast: Lessons from Building a World Cup Predictor
The goal
With the 2026 World Cup coming to North America in 71 days, I wanted to build something fun that my friends and I could use to predict brackets and compete with our (terrible) football knowledge. Simple goal: make bracket predictions, share them, see who gets it right.
What started as a weekend side project turned into a case study in shipping fast and iterating in public.
The stack
I picked tools that would let me move quickly:
- Frontend: Next.js 14 with App Router, TypeScript, Tailwind CSS
- Backend: Python Flask + SQLAlchemy (familiar territory)
- Database: PostgreSQL via Supabase (instant setup)
- Auth: Supabase Auth (email/password + Google OAuth)
- Hosting: Vercel for frontend, Railway for backend
- Analytics: Built-in crowd prediction analytics
The stack matters less than the shipping velocity. I chose tools I could build fast with, not necessarily the "perfect" technical choice.
27 features in 3 weeks
Here's what made it to production:
Core bracket functionality:
- Interactive tournament bracket builder
- 8-team knockout format with automatic winner progression
- Real team data from all 48 qualified nations
- One-click randomize and reset
Social features:
- Share brackets via unique URLs (
/b/{slug}) - Social media cards with dynamic OG images
- Mobile-responsive design
Group stage predictions:
- Pick winners for all 48 group stage matches
- Live standings calculated from your picks
- Share group predictions separately (
/g/{slug})
Authentication & personalization:
- Email/password signup + Google OAuth
- Session claiming (anonymous brackets link to new accounts)
- Personal bracket history
Analytics & competition:
- Global leaderboards
- Friend group competitions
- Crowd prediction wisdom (aggregate picks from all users)
- Real-time statistics on most/least popular picks
Polish & monitoring:
- Countdown timer to tournament kickoff
- Health monitoring dashboard
- Automated QA workflows
- SSR for shared bracket links (proper previews)
The development process
I tracked everything in GitHub issues — 27 total, all now closed. Here's what worked:
Build in small, shippable chunks
Instead of planning a massive v1, I shipped the MVP bracket builder first. Then added features incrementally:
- Week 1: Basic bracket + sharing
- Week 2: Group stage picks + auth
- Week 3: Social features + analytics
Each feature was a separate PR, deployed immediately. No "big bang" releases.
Use AI agents for velocity
I paired with Claude Code for complex features like authentication integration and database migrations. The AI handled boilerplate, I focused on product decisions. This probably 3x'd my development speed.
Real data from day one
I didn't build with fake data. I scraped real World Cup 2026 team data, group assignments, and match schedules. Working with real constraints forces better design decisions.
Deploy early, deploy often
Both frontend and backend auto-deploy on every push. The live site was available from day 2. Friends could test features as I built them, giving real feedback instead of theoretical concerns.
Technical decisions that paid off
Supabase for instant backend services
Setting up auth, database, and real-time features took hours, not days. Supabase's client libraries handle all the complexity — I just write SQL and frontend code.
Flask for the prediction engine
While I used Supabase for data storage, the bracket logic and analytics run through a custom Flask API. Python was perfect for tournament simulation and statistical analysis.
Dynamic OG images
Every shared bracket generates a custom social media preview image showing the bracket picks. This turns shares into mini-advertisements for the app.
Things I'd do differently
Start with friend groups
The most-requested feature is private groups for friends to compete. I built global leaderboards first, but people want to compete with people they know. Social features should come before global features.
Better mobile experience
Tournament brackets are hard to display on mobile. I made it work, but the experience feels cramped. Next time I'd design mobile-first for this type of data visualization.
More aggressive caching
With 48 teams and hundreds of matches, I'm making too many database queries. A proper Redis cache layer would improve performance significantly.
The shipping mindset
Building this reminded me why I like alter egos for side projects. Under my real name, I'd be overthinking the tech choices, worrying about the code quality, second-guessing the feature set.
As Jett, I just built and shipped. Is it perfect? No. Does it work? Yes. Will friends use it? We'll find out in 71 days.
The best projects feel slightly embarrassing to ship. If you're not a little worried about showing your work, you probably waited too long.
What's next
With the core features done, I'm focused on content and growth:
- SEO optimization for World Cup keywords
- Email capture for tournament reminders
- Social media content about predictions and tournament facts
- Maybe a mobile app if web usage is strong
But the real test comes June 11th when the first match kicks off. Until then, it's live at wc2026predictor.com if you want to make your predictions.
71 days and counting.