DEV Community

Cover image for I Built a Self-Hostable URL Shortener Because Bitly Now Charges $10/Month for Basic Links
Shivansh Goel
Shivansh Goel

Posted on

I Built a Self-Hostable URL Shortener Because Bitly Now Charges $10/Month for Basic Links

In 2023, Bitly's free plan gave you 100 links per month with full analytics.

In 2025, they slashed it to 5 links per month. Five. And they started showing full-screen interstitial ads before redirecting — even on links you created years ago.

In 2026, their cheapest paid plan is $10/month — just to shorten links without ads.

I was paying $120/year to turn long URLs into short ones. A problem that takes 3 lines of code to solve.

So I solved it myself. For free. Forever.


Introducing ZipLink

ZipLink is a fast, self-hostable URL shortener built with Next.js and Firebase. Deploy it once, use it forever. No monthly fees. No link limits. No ads. No "upgrade to unlock analytics."

Your links. Your data. Your domain. Your rules.

https://yourdomain.com/abc123 → https://some-really-long-url.com/path/to/thing?utm=whatever
Enter fullscreen mode Exit fullscreen mode

That's it. That's the product. Except you own it completely.


The State of URL Shorteners in 2026 (It's Embarrassing)

Let me show you what the "industry leaders" are charging for what is essentially a database lookup:

The Comparison Table

Feature Bitly Rebrandly Short.io Dub.co TinyURL Pro ZipLink
Monthly cost $10-$300/mo $13-$349/mo $19-$149/mo $24-$299/mo $9.99/mo $0
Annual cost $96-$2,388/yr $156-$4,188/yr $228-$1,788/yr $288-$3,588/yr $119.88/yr $0
Free tier links 5/month 10/month 1,000 total 25/month Unlimited (no analytics) Unlimited
Custom domain Paid only Free (1 domain) Required Paid only Paid only Yes (yours)
Click analytics Paid only Paid only Free (basic) Paid only Paid only Full, free
Link expiration Paid only Paid only Yes Yes No Yes
Password protection Enterprise only Paid only Paid Paid No Yes
API access Paid only Paid only Yes Yes Paid Full, free
QR codes 2 free, then paid Paid Yes Paid Paid Unlimited
Self-hostable No No No Yes (complex) No Yes (simple)
Data ownership Their servers Their servers Their servers Their servers Their servers Your Firebase
Ads/interstitials Yes (free tier) No No No Yes (free tier) Never
Links disappear if you stop paying Yes Yes Yes Yes Yes No — you own them

That last row is the killer. With every paid service, if you cancel your subscription, your links die. Years of shared URLs, printed QR codes, embedded links in emails — all broken. They're holding your links hostage.

ZipLink? Your links live as long as your Firebase project exists (which is free-tier forever for this use case).


What ZipLink Actually Does

Core Features

  • Instant shortening — Paste a URL, get a short link in <100ms
  • Custom slugs — Choose your own back-half: yourdomain.com/my-cool-link
  • Auto-generated slugs — Random 6-character codes when you don't care
  • Click analytics — Total clicks, clicks over time, referrers, countries, devices
  • Link expiration — Set links to auto-disable after a date or click count
  • Password protection — Require a password to access the destination
  • QR code generation — Every link gets a downloadable QR code automatically
  • Bulk shortening — Paste 100 URLs, get 100 short links
  • API — Full REST API for programmatic link creation
  • Dashboard — Clean UI to manage all your links

What It Doesn't Do (And Why)

  • No team collaboration — It's a personal tool. Fork it and add auth if you need teams.
  • No A/B testing — Keep it simple. Use proper A/B tools for that.
  • No "link-in-bio" pages — That's a different product. Focus.

The Technical Architecture

Stack

Layer Technology Why
Frontend Next.js 14 (App Router) SSR for fast link resolution, React for dashboard
Database Firebase Firestore Free tier handles ~50K reads/day, zero ops
Auth Firebase Auth Google sign-in for dashboard access
Hosting Vercel Free tier, global edge network
Domain Any registrar Point your domain, done
Analytics Custom (Firestore) No third-party tracking scripts

How Link Resolution Works

When someone hits yourdomain.com/abc123, the redirect happens at the edge in ~50ms:

// app/[slug]/route.ts — Next.js route handler
import { NextRequest, NextResponse } from 'next/server';
import { db } from '@/lib/firebase';
import { doc, getDoc, updateDoc, increment } from 'firebase/firestore';

export async function GET(
  request: NextRequest,
  { params }: { params: { slug: string } }
) {
  const { slug } = params;

  // Look up the short link
  const linkRef = doc(db, 'links', slug);
  const linkSnap = await getDoc(linkRef);

  if (!linkSnap.exists()) {
    return NextResponse.redirect('/404');
  }

  const link = linkSnap.data();

  // Check if link is expired
  if (link.expiresAt && new Date() > link.expiresAt.toDate()) {
    return NextResponse.redirect('/expired');
  }

  // Check if click limit reached
  if (link.maxClicks && link.clicks >= link.maxClicks) {
    return NextResponse.redirect('/expired');
  }

  // Record the click (non-blocking)
  updateDoc(linkRef, { 
    clicks: increment(1),
    lastClickedAt: new Date(),
  });

  // Record analytics
  recordClick(slug, {
    referrer: request.headers.get('referer'),
    country: request.geo?.country,
    device: parseUserAgent(request.headers.get('user-agent')),
    timestamp: new Date(),
  });

  // Redirect
  return NextResponse.redirect(link.destination, { status: 301 });
}
Enter fullscreen mode Exit fullscreen mode

The Analytics Pipeline

Every click is recorded with:

interface ClickEvent {
  slug: string;
  timestamp: Date;
  referrer: string | null;
  country: string | null;
  city: string | null;
  device: 'desktop' | 'mobile' | 'tablet';
  browser: string;
  os: string;
}
Enter fullscreen mode Exit fullscreen mode

These are stored in a Firestore subcollection and aggregated on-read for the dashboard. For the free tier's 50K daily reads, this handles ~5,000 link clicks per day with full analytics — more than enough for personal use.

Cost Breakdown: Why It's Actually Free

Service Free Tier Limit ZipLink Usage
Firebase Firestore 50K reads, 20K writes/day ~5K reads, ~1K writes for moderate use
Firebase Auth Unlimited users 1 (you)
Vercel Hosting 100GB bandwidth/month <1GB for a URL shortener
Domain N/A ~$10/year (only real cost)

Total: $0.83/month (just the domain, amortized). Compare that to $10-$300/month for Bitly.


Self-Hosting Guide (15 Minutes)

Prerequisites

  • A GitHub account
  • A Firebase account (free)
  • A Vercel account (free)
  • A custom domain ($10/year)

Steps

1. Clone the repo

git clone https://github.com/Tech-aficionado/ZipLink---Open-Source.git
cd ZipLink---Open-Source
Enter fullscreen mode Exit fullscreen mode

2. Create a Firebase project

  • Go to console.firebase.google.com
  • Create new project → Enable Firestore → Enable Authentication (Google)
  • Copy your config keys

3. Set environment variables

NEXT_PUBLIC_FIREBASE_API_KEY=your-api-key
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com
NEXT_PUBLIC_FIREBASE_PROJECT_ID=your-project-id
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your-project.appspot.com
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=123456
NEXT_PUBLIC_FIREBASE_APP_ID=your-app-id
Enter fullscreen mode Exit fullscreen mode

4. Deploy to Vercel

vercel deploy --prod
Enter fullscreen mode Exit fullscreen mode

5. Connect your domain

  • In Vercel dashboard → Settings → Domains → Add your domain
  • Update DNS records at your registrar

Done. You now own a URL shortener that will outlast every SaaS company charging you monthly.


The "But What If Firebase Shuts Down?" Argument

Fair concern. Here's why it doesn't matter:

  1. Firebase's free tier has existed for 10+ years — Google isn't killing it
  2. Your data is exportable — One command to dump all links as JSON
  3. The code is framework-agnostic — Swap Firestore for Supabase, PlanetScale, or even a JSON file in 30 minutes
  4. You have the source code — Worst case, migrate to any database. Your slugs and destinations are just key-value pairs.

Compare this to Bitly: if Bitly shuts down (or you stop paying), you have zero recourse. Your links are gone. Your QR codes on printed materials now point to nothing.


Real-World Use Cases

For Developers

  • Shorten GitHub links for tweets: yoursite.com/my-repo
  • Create memorable links for documentation: yoursite.com/docs
  • Track which README links get the most clicks

For Content Creators

  • Clean links for video descriptions: yoursite.com/latest-video
  • Track click-through rates from different platforms
  • Password-protect exclusive content links

For Indie Hackers

  • Product launch links with expiration: yoursite.com/ph-launch (expires after launch week)
  • Track which marketing channels drive traffic
  • Branded links that build domain authority

For Job Seekers

  • Portfolio link: yoursite.com/portfolio
  • Resume link with click tracking: yoursite.com/resume (know when recruiters view it)
  • Project-specific links: yoursite.com/my-saas

Why Not Just Use yoursite.com/redirect? (The "DIY" Argument)

You could set up Nginx redirects or a simple Express server. But you lose:

  • Analytics — Who's clicking? From where? When?
  • Dynamic management — Adding a new link means editing server config and redeploying
  • Expiration — No way to auto-expire links without custom cron jobs
  • Dashboard — No visual overview of all your links
  • QR codes — Manual generation every time
  • Password protection — Custom middleware for every protected link

ZipLink gives you all of this in a deployable package. It's the difference between "I could build a house" and "here's a house."


What's on the Roadmap

  • Edge caching — Cache popular links at Vercel's edge for <10ms redirects
  • Link grouping — Organize links into campaigns/folders
  • Webhook on click — Trigger automations when specific links are clicked
  • Import from Bitly — Migrate your existing Bitly links with one CSV upload
  • CLI toolziplink shorten https://long-url.com from your terminal
  • Browser extension — Right-click any page → "Shorten with ZipLink"
  • Slack bot — Share a link in Slack, auto-shorten with ZipLink

The Source


Final Thought

URL shortening is a solved problem. It's a database lookup. A key-value store. It's literally:

INPUT: slug
OUTPUT: redirect(destination)
Enter fullscreen mode Exit fullscreen mode

And yet companies are charging $10-$300/month for this. With link limits. With ads. With analytics paywalls. With the implicit threat of "stop paying and your links die."

That's not a service. That's a hostage situation.

ZipLink is the exit strategy. Deploy once. Own forever. Pay nothing.

Your links should outlive your subscriptions.


How much are YOU paying per year just to shorten URLs? Do the math and drop it in the comments. I bet it's more embarrassing than you think.


Built by Shivansh Goel — AI & Full Stack Developer who refuses to pay rent on solved problems.


Top comments (0)