DEV Community

Marius Memu
Marius Memu

Posted on

Building a High-Performance Link Shortener with Next.js 16, Supabase, and Edge Functions

At CouponSwift, we process a lot of traffic. When we decided to replace our legacy link management tools, we had two requirements: Speed and Privacy.

We built WiseURL, an open-source link manager. Here is the technical breakdown of how we built it tailored for the modern web.

The Architecture

The application is split into two parts:

  1. The Dashboard: A standard Next.js App Router application (Server Components) for managing links, viewing analytics, and handling auth.
  2. The Redirect Engine: An ultra-lightweight Edge Route handling the high-traffic redirection logic.

1. The Database Schema (Supabase)

We keep it simple. We use PostgreSQL via Supabase. The core is just two tables: links and clicks.

-- The core links table
create table links (
  id uuid default gen_random_uuid() primary key,
  code text unique not null, -- The slug (e.g. 'hostgator')
  destination_url text not null,
  is_active boolean default true,
  group_id uuid references groups(id), -- For organizing campaigns
  created_at timestamp with time zone default timezone('utc'::text, now())
);

-- The analytics table
create table clicks (
  id uuid default gen_random_uuid() primary key,
  link_id uuid references links(id),
  country text, -- e.g. "US"
  city text,
  device_type text, -- "mobile", "desktop"
  os_name text,
  browser_name text,
  created_at timestamp with time zone default timezone('utc'::text, now())
  -- NOTICE: No IP address column!
);
Enter fullscreen mode Exit fullscreen mode

2. The Edge Redirect (The Fun Part)

We barely use Node.js for the redirects. Instead, we use the Edge Runtime. This allows the code to run on Vercel's or Netlify's global edge network, closer to the user.

In src/app/[code]/route.ts, we force the runtime:

import { NextRequest, NextResponse } from 'next/server'
import { createClient } from '@/lib/supabase/server'

export const runtime = 'edge' // <--- The magic keyword

export async function GET(request: NextRequest, { params }: Params) {
  const { code } = params
  const supabase = createClient()

  // 1. Fast Lookup
  const { data: link } = await supabase
    .from('links')
    .select('destination_url, id')
    .eq('code', code)
    .single()

  if (!link) return new NextResponse('Not Found', { status: 404 })

  // 2. Async Analytics (Non-blocking)
  // We extract geo data from headers injected by the hosting provider
  const country = request.headers.get('x-vercel-ip-country') || 'XX'

  // Fire and forget - don't await this!
  saveClickAnalytics(link.id, country, request.headers.get('user-agent'))

  // 3. Instant Redirect
  return NextResponse.redirect(link.destination_url, { status: 302 })
}
Enter fullscreen mode Exit fullscreen mode

(Code simplified for readability)

Why Edge?

Using the Edge Runtime reduces the "Cold Start" problem significantly compared to standard Serverless functions. For an affiliate link, every millisecond of delay drops conversion rates.

3. Solving the Privacy Dilemma

We wanted analytics (to know if our US traffic works better than UK traffic), but we didn't want to store PII (Personally Identifiable Information).

The solution was simple: Header Extraction.

hosting providers (Netlify/Vercel) resolve the IP to a location before the request hits our code. They pass x-vercel-ip-country or x-nf-geo-country-code headers.

We read these headers, store the string "US" or "London", and then discard the request data. The IP never touches our database.

Conclusion

WiseURL has allowed us to own our infrastructure at CouponSwift without maintaining a complex VPS. It scales infinitely on serverless, costs $0 on the free tiers for our volume, and keeps our data private.

It is 100% open source. You can fork it, deploy it, and use it for your own campaigns.

Repo: github.com/netwisemedia/wiseurl

Top comments (0)