Skip to main content

How to Migrate from Bitly to Dub in 2026

·OSSAlt Team
bitlydubmigrationurl-shortenerguide
Share:

How to Migrate from Bitly to Dub in 2026

Bitly's free plan limits you to 10 links/month. Paid plans start at $8/month for Basic (200 links/month) and climb to $29/month for the Growth plan (1,500 links/month). Dub is the open source alternative — unlimited links, detailed analytics, custom domains, team workspaces, QR codes, and a developer API on every plan. Self-hosted Dub runs on a single VPS for $5–15/month regardless of link volume.

This guide walks through exporting from Bitly, setting up Dub (cloud or self-hosted), importing your existing links, and handling the DNS cutover for custom domains.


Why Switch from Bitly to Dub?

The pricing comparison makes the case clearly. Bitly's model charges by the number of links you create and the number of clicks you can track. For marketing teams that create hundreds of campaign links per month and track millions of clicks, Bitly costs are substantial.

Bitly Enterprise pricing:

  • Free: 10 links/month, 5-year link history
  • Basic: $8/month — 200 links/month
  • Premium: $29/month — 1,500 links/month
  • Business: $199/month — custom volume

Dub pricing:

  • Free (dub.co): 25 links/month, 30-day analytics
  • Pro (dub.co): $24/month — unlimited links, 2-year analytics
  • Self-hosted: unlimited links, unlimited analytics, $5–15/month server

Beyond price, Dub has features Bitly doesn't: traffic routing by device/country/language, A/B split testing between destination URLs, and a TypeScript SDK with full API parity.


Bitly provides two export methods: the web UI (for small accounts) and the API (for bulk exports).

Web UI export:

  1. Log in to Bitly
  2. Go to Settings → Advanced Settings → Data Export
  3. Choose a date range and export format (CSV)
  4. The CSV includes: bitlink URL, long URL, title, tags, created date, click count

API export (for large accounts with 100+ links):

# Get your API token from Bitly Settings → API
BITLY_TOKEN="your_bitly_access_token"
GROUP_GUID="your_group_guid"  # From Bitly Settings → General

# Export all links (paginate with offset)
curl -H "Authorization: Bearer $BITLY_TOKEN" \
  "https://api-ssl.bitly.com/v4/groups/$GROUP_GUID/bitlinks?size=100&page=1" \
  > bitly-page1.json

# For large accounts, loop through pages:
for page in $(seq 1 20); do
  curl -H "Authorization: Bearer $BITLY_TOKEN" \
    "https://api-ssl.bitly.com/v4/groups/$GROUP_GUID/bitlinks?size=100&page=$page" \
    >> bitly-all-links.json
  sleep 0.5  # Rate limiting
done

Parse the response to extract id (the bitlink) and long_url for each link.


Step 2: Set Up Dub

You have two options: Dub's hosted cloud at dub.co, or self-hosted on your own infrastructure.

Option A: Dub.co Cloud (fastest setup)

  1. Sign up at dub.co
  2. Create a workspace (maps to a team/organization)
  3. Add your custom domain in Settings → Domains
  4. Skip to Step 3

Option B: Self-hosted Dub (best for privacy and volume)

Dub requires a PostgreSQL database and Redis. The recommended self-hosted setup uses Docker Compose:

# docker-compose.yml for self-hosted Dub
services:
  dub:
    image: dubinc/dub:latest
    restart: unless-stopped
    ports:
      - "3000:3000"
    environment:
      - NEXTAUTH_SECRET=your-nextauth-secret-32-chars
      - NEXTAUTH_URL=https://dub.yourdomain.com
      - DATABASE_URL=postgresql://dub:password@postgres:5432/dub
      - REDIS_URL=redis://redis:6379/0
      - NEXT_PUBLIC_APP_DOMAIN=dub.yourdomain.com
      - NEXT_PUBLIC_SHORT_DOMAIN=link.yourdomain.com
      - SMTP_FROM=noreply@yourdomain.com
      - SMTP_HOST=smtp.yourdomain.com
      - SMTP_PORT=587
      - SMTP_USERNAME=smtp-username
      - SMTP_PASSWORD=smtp-password
    depends_on:
      - postgres
      - redis
  postgres:
    image: postgres:15-alpine
    restart: unless-stopped
    environment:
      POSTGRES_DB: dub
      POSTGRES_USER: dub
      POSTGRES_PASSWORD: password
    volumes:
      - dub_db:/var/lib/postgresql/data
  redis:
    image: redis:7-alpine
    restart: unless-stopped
volumes:
  dub_db:
docker compose up -d
# Then visit https://dub.yourdomain.com to create the admin account

For HTTPS, put Caddy or Nginx in front:

dub.yourdomain.com {
    reverse_proxy localhost:3000
}

link.yourdomain.com {
    reverse_proxy localhost:3000
}

Step 3: Set Up Your Custom Domain

If you have a custom short domain on Bitly (e.g., go.yourcompany.com), you need to add it to Dub before importing links — so imported links get the right domain.

In Dub:

  1. Go to Settings → Domains → Add Domain
  2. Enter your domain: go.yourcompany.com
  3. Dub shows the required DNS record

DNS configuration (for Dub Cloud):

# Add CNAME record:
go.yourcompany.com CNAME cname.dub.co

DNS configuration (for self-hosted):

# Point to your server IP:
go.yourcompany.com A your.server.ip.address
# Or use CNAME if behind a load balancer

DNS propagation takes 5 minutes to 24 hours. During this window, keep Bitly active so existing links still work.


With the domain set up, import your Bitly links via the Dub API:

import fs from 'fs';

// Parse Bitly export
const bitlyLinks = JSON.parse(fs.readFileSync('bitly-export.json', 'utf8'));

const DUB_API_KEY = 'dub_xxx_your_api_key';
const DUB_WORKSPACE_SLUG = 'your-workspace';

async function importLink(bitlyLink) {
  // Extract the slug from the Bitly short URL
  const bitlySlug = bitlyLink.link.split('/').pop();

  const body = {
    url: bitlyLink.long_url,
    domain: 'go.yourcompany.com',
    key: bitlySlug,          // Preserve original slug if possible
    comments: `Imported from Bitly: ${bitlyLink.title || ''}`,
    tags: bitlyLink.tags || [],
  };

  const response = await fetch(`https://api.dub.co/links`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${DUB_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(body),
  });

  if (!response.ok) {
    const error = await response.json();
    console.error(`Failed to import ${bitlyLink.link}:`, error);
    return null;
  }

  return await response.json();
}

// Import with rate limiting (Dub API: 60 req/min on Pro)
async function importAll(links) {
  const results = [];
  for (const link of links) {
    const result = await importLink(link);
    if (result) results.push(result);
    await new Promise(resolve => setTimeout(resolve, 1000)); // 1 req/sec
    console.log(`Imported ${results.length}/${links.length}`);
  }
  return results;
}

importAll(bitlyLinks.links || bitlyLinks);

Note on slug conflicts: If a Bitly slug is already taken in Dub (e.g., a common word like abc), the API returns an error. You can either let Dub generate a new slug or manually rename the Dub link after import.


Step 5: DNS Cutover

Once all links are imported and verified in Dub, cut over the DNS:

If you had a custom domain on Bitly:

  1. Verify all important links work in Dub first
  2. Update the DNS record for go.yourcompany.com to point to Dub (instead of Bitly)
  3. Wait for DNS propagation (TTL matters — lower TTL before cutover for faster propagation)

If you used bitly.com links (no custom domain):

  • Bitly links (bit.ly/xxx) cannot be redirected to Dub
  • You must update any embedded links in emails, social posts, documents, or your website that used bit.ly URLs
  • Consider using a URL audit tool to find embedded Bitly links in your content

Step 6: Recreate Advanced Features

Tags: Dub supports tags for organizing links. Map your Bitly tags to Dub tags during import (the import script above includes tag handling).

QR codes: Every Dub link automatically generates a QR code. Access it via the link detail panel or API:

# Get QR code PNG for any Dub link
curl "https://api.dub.co/qr?url=https://go.yourcompany.com/your-slug&size=400" \
  -H "Authorization: Bearer $DUB_API_KEY" \
  -o qrcode.png

Analytics dashboards: Dub provides click analytics with breakdown by country, device, browser, and referrer. The Dub analytics API gives programmatic access:

// Get click analytics for a link
const analytics = await fetch(
  'https://api.dub.co/analytics?linkId=link_xxx&event=clicks&interval=30d',
  { headers: { Authorization: `Bearer ${DUB_API_KEY}` } }
).then(r => r.json());

Cost Comparison

FeatureBitly BasicBitly PremiumDub ProDub Self-Hosted
Links/month2001,500UnlimitedUnlimited
Monthly cost$8$29$24$5–15 (VPS)
Custom domains15UnlimitedUnlimited
Analytics window30 days2 years2 yearsUnlimited
QR codesPaid add-onIncludedIncludedIncluded
API access
Team members15UnlimitedUnlimited

What Changes After Migration

You gain:

  • Unlimited links and clicks
  • Traffic routing (serve different URLs by device, country, or language)
  • A/B split testing between destination URLs
  • TypeScript/JavaScript SDK
  • Full data ownership (self-hosted)

You lose:

  • Bitly's branded short domain (bit.ly) — your existing bit.ly links stop working
  • Bitly's click history (export before closing your account)
  • Bitly's enterprise security certifications (relevant for some compliance requirements)

Operational Considerations: Running Dub in Production

Self-hosting Dub is straightforward to set up, but running it reliably over months and years requires attention to a few operational concerns that aren't immediately obvious from the setup documentation.

Database backups. Dub stores all link data in PostgreSQL. A database failure without recent backups means losing your entire link history and analytics. Set up automated daily backups from day one. If you're on a VPS, the simplest approach is a cron job that runs pg_dump and ships the output to an S3-compatible bucket like Backblaze B2 (around $0.006/GB/month). A 90-day retention policy is reasonable for most teams. Periodically test your restore process — a backup you've never restored is a backup you don't actually have.

Redis persistence. Dub uses Redis for caching and rate limiting. By default, Redis stores data in memory only. If your Redis container restarts, cached data is lost. This is generally fine for rate limiting but worth being aware of. Enable Redis persistence (AOF or RDB) if you need Redis to survive restarts with state intact. Most Dub deployments tolerate Redis restarts gracefully.

Keeping Dub updated. The Dub team ships updates frequently, including security patches. Pin to a specific Docker image tag for stability, and monitor the Dub GitHub releases page for security advisories. A reasonable update cadence is monthly for minor releases and within 48 hours for any security-tagged release. The update process is straightforward: pull the new image and restart the container.

Monitoring uptime. A down link shortener means all your short links return errors — a visible problem for marketing campaigns. Set up Uptime Kuma or a similar monitoring tool to alert you if Dub's health endpoint stops responding. A five-minute check interval with SMS or email notification is usually sufficient.

SSL certificate renewal. If you're using Caddy as your reverse proxy, certificate renewal is automatic. If you're using Nginx with Certbot, ensure your renewal cron job is working. Certificates from Let's Encrypt expire every 90 days. A lapsed certificate means your short links serve a browser security warning — the worst possible time to discover your renewal was broken.


One area where Dub substantially improves on Bitly is team workflows and link governance — the organizational layer on top of raw link creation.

Workspaces as organizational units. Dub's workspace model maps cleanly to how marketing teams actually work. You can create separate workspaces for different brands, regions, or campaigns, each with their own custom domain, analytics, and team members. A holding company with three brands doesn't need three separate Bitly accounts — one self-hosted Dub instance handles all three workspaces cleanly.

Tagging for reporting. Tags in Dub are more than organizational labels. They're the primary way to aggregate analytics across multiple links. Tag all links for a given campaign with a campaign tag, and you can pull click totals across the entire campaign with a single API call. This is enormously useful for month-end marketing reporting where you need to show campaign performance across dozens of individual links.

Link archiving instead of deletion. Rather than deleting old links (which breaks any traffic that still hits them), Dub supports archiving links. Archived links still redirect — they're just removed from the active view. This is particularly important for links embedded in PDFs, print materials, or old email campaigns that might still drive occasional traffic years later. Archive aggressively rather than deleting.

Audit history. On self-hosted Dub, you have full access to your database, which means complete audit history of link creation, modification, and click events. For compliance-conscious teams, this is an advantage over Bitly's cloud service where audit data retention depends on your plan tier.

For teams running larger marketing operations, the combination of Dub's workspace model and tagging system provides a level of link governance that Bitly's interface doesn't match — particularly when combined with the API for programmatic link creation from campaign management tools. If your team also manages analytics at the infrastructure layer, the open source analytics tools ecosystem pairs naturally with Dub's click event webhooks.


When to Choose Dub Cloud vs. Self-Hosted

The decision between Dub's hosted cloud service and self-hosting comes down to three factors: volume, privacy requirements, and operational capacity.

Choose Dub Cloud (dub.co) if your link volume is modest (under a few thousand links/month), you don't have a team member comfortable managing a VPS, or you're a solo operator where your time is better spent on other things. Dub's Pro plan at $24/month is competitive with Bitly's equivalent tiers and requires zero operational overhead. The tradeoff is data sovereignty — your link analytics live on Dub's servers, which is acceptable for most use cases.

Choose self-hosted Dub if you process high link volumes where per-click costs would add up on cloud pricing, you have strict data residency requirements (healthcare, finance, EU-based companies under GDPR with conservative data handling policies), or you want to integrate Dub deeply with internal tooling via direct database access. A single developer spending two hours on initial setup and one hour per month on maintenance easily justifies the $10/month infrastructure cost if you're creating more than 200 links per month.

The hybrid approach works well for some teams: use Dub Cloud for low-stakes campaign links and self-hosted Dub for high-volume API-generated links or links carrying sensitive destination URLs you'd prefer not to route through a third-party service. Dub's architecture is identical between cloud and self-hosted, so both versions of the client libraries and API behave identically.

If you're evaluating the broader self-hosting landscape beyond link management, the SaaS subscription audit framework provides a structured way to calculate whether self-hosting a given tool is worth the operational investment relative to the savings.


Related: Best Open Source Link Management Tools 2026 · Dub vs Shlink: Which URL Shortener? · Dub vs Shlink vs Kutt Compared

See open source alternatives to Bitly on OSSAlt.

The SaaS-to-Self-Hosted Migration Guide (Free PDF)

Step-by-step: infrastructure setup, data migration, backups, and security for 15+ common SaaS replacements. Used by 300+ developers.

Join 300+ self-hosters. Unsubscribe in one click.