Claude Code Boilerplate
FeaturesPricingBlogDocs
Get started →

Product

  • Features
  • Pricing
  • Skills

Compare

  • vs ShipFast
  • vs MakerKit
  • vs supastarter

Resources

  • Docs
  • Blog
  • Discord

Legal

  • License
  • Privacy Policy
  • Terms of Service
Claude Code Boilerplate

© 2026 Claude Code Boilerplate. All rights reserved.

← All posts

Referral program in Next.js SaaS -- unique codes, signup attribution, and reward tracking with Drizzle ORM

July 4, 2026
nextjsdrizzle-ormsaasgrowthauth

Every SaaS that grows without a massive marketing budget has one thing in common: its users talk about it. A referral program turns that word of mouth into something you can measure, reward, and scale.

If you are building a SaaS on Next.js and Drizzle ORM, you already have everything you need. Here is what the system looks like and how to wire it up.

Why a referral program is worth building early

Paid ads are expensive and unpredictable. A referral program is neither. You only pay out when a referred user actually converts -- a paid subscription, a completed onboarding step, or whatever milestone matters to your business. That makes your cost per acquisition predictable and tied directly to revenue.

The other advantage: referred users churn less. They signed up because someone they trust recommended the product, not because they clicked a banner. That trust carries over into how they use it.

The database schema

You need two additions to your existing Drizzle schema.

First, a referral_code column on the user table -- a short, unique string generated at registration time:

referral_code  text not null unique

Second, a referrals table that records who referred who:

referrals
  id            uuid primary key
  referrer_id   uuid -- references users.id
  referee_id    uuid -- references users.id (unique -- one referrer per signup)
  converted_at  timestamp -- null until the referee converts
  rewarded_at   timestamp -- null until the referrer is rewarded
  created_at    timestamp

Two timestamps -- converted_at and rewarded_at -- are enough to drive the entire reward lifecycle without a separate payouts table.

Generating unique referral codes

On registration, generate a short code using Node's built-in crypto module:

import { randomBytes } from 'crypto'
 
function generateReferralCode(): string {
  return randomBytes(4).toString('hex') // e.g. "a3f82c10"
}

Eight hex characters give you over 4 billion possible codes. Store it as a text.notNull().unique() column on the user table and add a database index on it so the lookup at signup is fast.

How attribution works at signup

When a visitor arrives at /register?ref=a3f82c10, your registration route reads the ref query param and passes it into the service layer. After the user row is created, the service inserts a row into referrals linking the new user to the referrer who owns that code.

// Inside userService.register()
if (referralCode) {
  const referrer = await userRepo.findByReferralCode(referralCode)
  if (referrer && referrer.id !== newUser.id) {
    await referralRepo.create({
      referrerId: referrer.id,
      refereeId: newUser.id,
    })
  }
}

Wrapping this in the same Drizzle transaction as the user insert means you never end up with a signup that lost its referral attribution due to a partial failure. If the referral code is invalid or missing, registration proceeds normally -- no error, just no referral row.

Tracking conversions

A "conversion" is whatever you define. Paid subscription, verified email, completed onboarding -- the referrals table does not care. In your service, after the conversion event happens, mark the referral row:

await referralRepo.markConverted(referee.id)
// sets converted_at = now() where referee_id = referee.id

When you are ready to pay out -- or unlock a bonus feature for the referrer -- query for referrals where converted_at IS NOT NULL and rewarded_at IS NULL, process the reward, then set rewarded_at. A Vercel cron route running once a day works well for batch processing.

This keeps your payout logic decoupled from your conversion logic. You can change how you reward referrers without touching the attribution or conversion code.

What to show your users

Every user gets a referral link they can copy and share. A server component fetches the data in one query:

const stats = await referralService.getStatsForUser(userId)
// { code: "a3f82c10", total: 12, converted: 5 }

Render a share link -- https://yourapp.com/register?ref={code} -- alongside the stats. No third-party widget needed. Users copy the link and share it wherever they already talk to people: in emails, Slack channels, or social posts.

What you get without extra infrastructure

This entire system runs on your existing stack. No third-party referral service, no JavaScript SDK to maintain, no extra webhook surface to secure. The referrals table is the source of truth. Drizzle ORM queries it. A Vercel cron route processes rewards. Your existing auth layer already has the user context you need.

A referral program is one of the highest-leverage growth tools available to early-stage SaaS founders, and it is cheaper to build than most people expect.

The Next.js SaaS Boilerplate ships with Drizzle ORM, Neon DB, Vercel cron, and JWT auth already wired together. You can add this referral system on top in an afternoon -- no new infrastructure, no new services, no SDK to babysit.

Get the boilerplate and start turning your signups into a growth channel this week.