Building Shipstry in 9 Days: From Empty Folder to Production
How I built a product ship registry with TanStack Start, Cloudflare Workers, D1, and R2 in 8 days — 640 commits, zero cold starts, and a lot of coffee.
On March 3, 2026, I started with an empty folder. Eight days later, Shipstry went live.
640 commits. A lot of coffee. And plenty of things I'd do differently next time.
The name
Before writing any code, I needed a name.
I spent an entire afternoon brainstorming with AI. Hundreds of suggestions. The AI probably hated me by the end of it.
I wanted something that captured what makers actually do — we ship products. And I wanted it to feel like a registry, a place where products get recorded and discovered.
Ship + Registry = Shipstry.
The .com was available. Done deal.
The nautical thing grew from there:
- Primary color: Olive Moss (#6B8A67)
- Accent: Warm Sand (#D4A574)
- Pricing tiers: Harbor, Voyage, Expedition, Admiral
- The logo: a geometric sailboat with twin sails
Why I built this
After launching several side projects over the years, I kept hitting the same wall. Product Hunt is great, but it's not really built for indie makers anymore.
Big-budget launches dominate. Marketing teams game the algorithm. A solo dev's work gets buried in hours.
I wanted something different:
- A place for builders, not marketers
- Weekly cycles instead of daily chaos
- Quality over quantity
- Built by a maker, for makers
So I built Shipstry.
Choosing the stack
Stack selection is the decision that haunts you for months if you get it wrong.
I went with:
TanStack Start for the framework. Full-stack React with file-based routing and TypeScript support. Change a route and the compiler flags everything that needs updating. That kind of type safety saves real time.
Cloudflare Workers for deployment. Edge computing means users in Singapore, London, and New York all get the same fast experience. No cold starts, global distribution.
Cloudflare D1 for the database. SQLite at the edge — the same database that powers your phone, now running in 300+ locations worldwide. For a product like Shipstry, it fits.
Cloudflare R2 for file storage. Product logos and preview images go here. S3-compatible with zero egress fees, so no surprise bandwidth bills.
Better Auth for authentication. Email/password plus Google OAuth, native integration with TanStack Start.
Stripe for payments, Resend for emails, Tailwind CSS v4 for styling, shadcn/ui for components.
TanStack Start + Cloudflare turned out to be a really good combination. React's ecosystem with edge performance, and D1 gives you a real database with zero configuration.
Week one
Day 1-2: Foundation
The first commits set up everything — TanStack Start with SSR, the Cloudflare Workers adapter, Drizzle ORM, basic routing structure.
I also built the design system. I didn't want another generic AI landing page with purple gradients, so I created a custom "Olive Moss" palette. Muted greens and warm grays. Calm.
By end of day 2 I had a working dev server, a visual identity that didn't look like every other startup, and basic page layouts.
Day 3-4: Authentication
Auth is always more complicated than you expect.
Better Auth needs to create its instance per-request, not as a singleton. In Cloudflare Workers each request is isolated anyway, so this architecture actually works well. But figuring that out took a few hours of head-scratching.
I also designed the database schema upfront. The big decision was separating drafts from products.
Drafts have all nullable fields — save at any point, return later. Products have required fields — they only exist when fully submitted. This kept the data model clean.
Day 4-5: The submission flow
The submission form is the heart of Shipstry. I wanted it smooth, not overwhelming.
A progressive form with collapsible sections. Each section tracks its completion status. Save any time, leave, come back days later, pick up where you left off.
For the product description I integrated Milkdown, a plugin-driven Markdown editor with a custom toolbar. The tricky part was focus management — the toolbar kept stealing focus from the editor. I eventually fixed it by preventing default on mousedown for toolbar buttons.
Day 5: Pricing and payments
A nautical-themed pricing system:
- Harbor (Free): Basic submission, normal review
- Voyage ($9.9): Fast 24-hour review, same-week ship
- Expedition ($29): Featured on homepage, 7 days exposure
- Admiral ($59): 30 days featured, premium badge
Stripe integration was straightforward. The webhook handler needed more care — D1 doesn't support nested transactions, so I had to restructure the code to use sequential queries instead of wrapping everything in one transaction.
The AI feature
Filling out product forms is tedious. Paste a URL, then manually type the name, tagline, description, find the logo, find a preview image...
So I built an AI metadata fetcher. When someone pastes their product URL:
- The system fetches the page and extracts Open Graph tags
- Sends it to AI for an enhanced description
- Auto-fills all the form fields
Users review and edit everything before submitting. The point is reducing friction, not replacing judgment.
Multi-provider failover
AI APIs are unreliable. Timeouts, rate limits, random outages.
I built a failover system that tries multiple providers in priority order. If one fails it moves to the next. Configuration is a JSON array in environment variables:
[
{"name": "openai", "priority": 1},
{"name": "claude", "priority": 2},
{"name": "gemini", "priority": 3}
]
If all providers fail, the form still works — people just fill it manually. Graceful degradation.
SSRF protection
Letting users fetch arbitrary URLs is dangerous. You don't want someone hitting your internal services through your server.
I blocked private IP ranges (10.x, 172.x, 192.168.x), localhost, anything that isn't HTTP or HTTPS, and rate-limited to 5 requests per minute per user.
Community features
Comments support nesting. I used soft deletes so removing a parent comment doesn't destroy the thread structure.
For voting, I wanted instant feedback. Nobody likes waiting for a round-trip to see their vote register.
Optimistic updates: click vote, the UI updates immediately, the server request happens in the background. If it fails, the UI rolls back.
Notifications
Users get notified for comments on their products, replies to their comments, award wins, and status changes.
For email delivery I used Cloudflare's waitUntil(). The response goes back to the user immediately while the email sends in the background. Nobody waits for an email to send.
The final stretch
Caching
To reduce database load I built a caching layer using D1 itself as the cache store. Cached data has TTLs, and mutations trigger automatic invalidation.
This cut read load on the main tables during traffic spikes.
Environment config
I centralized all environment variables with validation. In development, the app checks that all required secrets exist and throws clear errors if something's missing. In production I trust that Cloudflare has everything configured.
This caught several configuration mistakes during development that would have been painful to debug in production.
Launch
March 11, 2026. Shipstry went live.
The final commits added a launch promo banner with a 50% discount code and adjusted the ship week logic to allow immediate launches during the launch period.
What I learned
TanStack Start is ready for production. Stable, well-typed, SSR works seamlessly with Cloudflare Workers.
D1 is good enough. SQLite at the edge sounds limiting, but for most apps it's fine. Zero configuration, fast queries, generous free tier. The main gotcha: no nested transactions.
Edge functions change how you think about code. No global state, waitUntil() for background tasks, zero cold starts, environment access through imports rather than process.env.
AI integration is easier than I expected. With multi-provider failover and graceful degradation, you can build reliable AI features.
640 commits in 9 days. Roughly 71 per day. Each one small and focused — that discipline saved me more than once when I needed to roll back a bad call.
After launch
Two days live now.
I've been doing link building — submitting to directories, reaching out to communities, getting featured on platforms.
DR went from 0 to 14 in two days.
Try it
- Shipstry: shipstry.com
- Submit your product: shipstry.com/submit
- Launch promo: Use code
SHIPSTRY50for 50% off paid plans
Built with TanStack Start, Cloudflare Workers, D1, R2, and too much coffee.