From Side Project to Open Source: Why I Built My Own URL Shortener
How a frustration with third-party URL shorteners turned into an open-source project with self-hosting, privacy, and full control.

黃小黃
· 7 min read
Ever stared at a third-party service's pricing page and thought, "I could build this myself"? That's exactly how Open Short URL was born.
The Moment Everything Changed
It started with a simple realization: I was paying for something I didn't fully control.
Like many developers, I relied on third-party URL shorteners for everything—marketing campaigns, sharing links, tracking clicks. It worked fine until it didn't. Google URL Shortener shut down. Other services started limiting features behind expensive paywalls. And worst of all, I had no idea who was looking at my click data.
That's when I asked myself: What if I just built my own?
The Problem with Third-Party URL Shorteners

The Hidden Costs of "Free"
When Google finally shut down goo.gl redirects in 2025 — seven years after first announcing its deprecation — millions of links became ticking time bombs. It was a wake-up call for anyone relying on free services.
But even paid services come with hidden costs:
Data Privacy: Your click data—geographic locations, devices, referrers—sits on someone else's servers. Who's analyzing it? Who are they selling it to?
Brand Perception: Let's be honest, a
bit.lylink in a professional email looks... questionable. Some spam filters even flag them.Feature Limitations: Want A/B testing? Pay more. Need API access? Pay more. Custom domains? You guessed it.
Why Existing Open-Source Solutions Weren't Enough
I'm not the first person to have this idea. There are solid open-source alternatives:
YOURLS: The OG of self-hosted URL shorteners. But it's PHP-based, and I'm more comfortable with TypeScript. The UI also feels dated.
Shlink: Excellent API design and Docker support. But I wanted a more complete frontend experience out of the box.
Kutt: Clean and simple, but missing some features I needed.
None of them were wrong—they just weren't right for me. I wanted something built with a modern stack, something I could extend and customize, and honestly, something that would be fun to build.
Tech Stack Decisions
Here's where things get interesting. Choosing a tech stack for a side project is like choosing what to cook for dinner—you could go with something safe, or you could experiment.
I chose to experiment.

Backend: NestJS + Fastify
Most Node.js projects default to Express. It's battle-tested, well-documented, and... slow.
I went with Fastify instead. The benchmarks don't lie—Fastify handles 2-3x more requests per second than Express. For a URL shortener where redirects need to be lightning-fast, this matters.
NestJS on top of Fastify gives me the best of both worlds: Fastify's performance with NestJS's modular architecture. Dependency injection, decorators, and a clear project structure make the codebase maintainable as it grows.
Frontend: Next.js 16 + React 19
I'll admit it—part of choosing Next.js 16 and React 19 was pure curiosity. I wanted to play with the latest features.
But beyond the hype, the App Router and Server Components genuinely improve the developer experience. The dashboard loads fast, navigation is smooth, and the codebase is cleaner than anything I could've built with the old Pages Router.
Database: PostgreSQL + Prisma
NoSQL might be trendy, but for a URL shortener with complex relationships (users, URLs, clicks, bundles, webhooks), a relational database makes more sense.
Prisma as the ORM was an easy choice. Type-safe queries, automatic migrations, and a beautiful query API. It catches errors before they happen.
The "Redis Optional" Design
Here's a design decision I'm particularly proud of: Redis is completely optional.
Many self-hosted solutions require Redis, which adds complexity and cost. Open Short URL works perfectly without it—the system automatically falls back to in-memory storage for caching and rate limiting.
Without Redis: Perfect for < 10K daily clicks
With Redis: Handles 100K+ clicks with 10-20ms redirects
This means you can start simple and scale up when needed. No configuration changes required—the system detects Redis automatically and adapts.
Features Worth Highlighting
Building a basic URL shortener takes a weekend. Building one with features you'd actually want to use? That takes longer. Here are some features I found interesting to implement.
Dynamic Slug Length
Most URL shorteners use fixed-length slugs. Open Short URL dynamically adjusts based on how many URLs exist:
// Simplified logic
if (urlCount < 1000) return 4; // abc1
if (urlCount < 50000) return 5; // abc12
if (urlCount < 500000) return 6; // abc123
return 7; // abc1234
This keeps URLs as short as possible while ensuring uniqueness. Small detail, but it matters.
Built-in A/B Testing

Want to test which landing page converts better? Create URL variants with traffic allocation:
Variant A:
example.com/page-v1→ 50% trafficVariant B:
example.com/page-v2→ 50% traffic
The system automatically distributes clicks and tracks conversion data for each variant. No external tools needed.
Smart Routing
Conditional redirects based on:
Device type (mobile users → app store, desktop → website)
Geographic location (US visitors → .com, Taiwan visitors → .tw)
Time of day (business hours → sales page, after hours → support)
You can set up rules with priorities, and the system evaluates them in order to determine where each visitor should go.
MCP Server: Ready for the AI Era
This one's a bit unconventional. Open Short URL includes an MCP (Model Context Protocol) server that lets AI assistants manage your URLs.
Install it globally:
npm install -g @open-short-url/mcp
Configure it in Claude Desktop or Cursor, and you can say things like:
"Create a short URL for example.com with the slug 'promo'"
"Show me click statistics for my campaign URLs"
"Set up A/B testing with 60/40 traffic split"
Is this necessary? No. Is it cool? Absolutely.
Lessons Learned
URL Shortening Is Harder Than It Looks
The basic concept is simple: store a mapping, redirect when visited. But production-ready URL shortening involves:
Click tracking performance: Recording every click without slowing down redirects
Bot detection: Googlebot, Bingbot, and countless crawlers inflate your stats
Geographic parsing: IP-to-location lookups add latency if not cached
Concurrent access: Multiple clicks to the same URL at the exact same millisecond
Each of these took more time than I expected.
What Actually Took the Most Time
Surprisingly, it wasn't the core URL shortening logic. It was:
The webhook system: Ensuring reliable delivery with retries, HMAC signatures, and detailed logging took weeks.
The analytics dashboard: Getting Recharts to display time-series data exactly how I wanted was... an adventure.
Edge cases: What happens when a URL expires mid-click? When Redis goes down? When someone submits a slug that's already taken?
Side projects have a way of revealing just how many edge cases exist in "simple" features.
Why Open Source?
I've benefited enormously from open source throughout my career. YOURLS taught me how URL shorteners work. NestJS documentation helped me structure the backend. Countless Stack Overflow answers saved me hours of debugging.
Open sourcing Open Short URL under the MIT license is my way of giving back. No commercial plans, no "open core" upsells—just a tool that I hope others find useful.
Open source projects also get better through community feedback. Bug reports I'd never find on my own. Feature requests I'd never think of. PRs that improve the codebase in ways I couldn't have imagined.
What's Next
The roadmap includes:
Open Graph Customization: Custom social previews for shared links
Deep Linking: Native app integration (App Links / Universal Links)
Retargeting Pixels: Integration with ad platforms
More one-click deploy options: DigitalOcean, Vercel, Netlify templates
But more than features, I'm excited to see how others use it. What workflows will people build? What integrations will they create?
Try It Yourself
Open Short URL is free, open source, and ready to deploy:
Documentation: supra126.github.io/open-short-url
One-click deploy: Railway (more platforms coming soon)
MCP Package: @open-short-url/mcp
If you find it useful, a star on GitHub would mean a lot. If you find bugs, issues are welcome. And if you want to contribute, PRs are always open.
Sometimes the best way to solve a problem is to build the solution yourself. And if you're lucky, that solution might help others too.
黃小黃
Full-stack product engineer and open source contributor based in Taiwan. I specialize in building practical solutions that solve real-world problems with focus on stability and user experience. Passionate about Product Engineering, Solutions Architecture, and Open Source collaboration.
More Posts
Beyond Chatbots: Building Real-World Stateful AI Agents on Cloudflare
Most "AI agents" you see today are just LLM wrappers with a fancy prompt. They process a request, return a response, and forget everything. No memory. No scheduling. No persistence. Real agents are different. They remember what happened yesterday. Th...
Your API Wasn't Built for AI Agents — Here's How to Fix It
By 2026, over 30% of API traffic will come from AI agents rather than human-driven applications. That number will keep climbing. Here's the uncomfortable truth: most APIs were designed for human developers who read documentation, interpret ambiguous ...
When Microservices Are Wrong: A Solutions Architect's Decision Framework
I've been that architect. The one who spun up AWS Lambda functions and ECS clusters for every new service, convinced that microservices were the only "proper" way to build modern software. After years of managing distributed complexity — and eventual...