Most founders spend money on ads before they ask a simpler question: are your existing users happy enough to tell their friends? If the answer is yes, a referral program turns that word-of-mouth into a growth channel you can actually measure -- and reward.
The difference between an affiliate program and a referral program is who you are talking to. An affiliate program targets external partners who promote you for a commission. A referral program lives inside your app and is available to every signed-in user. Every customer becomes a potential sales channel.
A referral program has three moving parts:
None of those parts is complex on its own. The work is wiring them together reliably so you do not double-count, miss credits, or lose the attribution between a click and a signup seven days later.
You need two tables: one to store referral codes and one to track conversions.
-- referral_codes: one row per user
id, user_id, code (unique random string), created_at
-- referrals: one row per conversion
id, referrer_id, referred_user_id, status (pending/completed), reward_issued, created_at
The code column is a short random string tied to the referrer's user ID. When a visitor lands on your signup page with ?ref=ABC123, you store that code in a short-lived cookie. When they register, you read the cookie, look up the referrer, and create a referral record.
The Next.js SaaS Boilerplate gives you Drizzle ORM, JWT auth, and the module structure to add this without touching existing code. You add a referral module alongside your existing modules -- the pattern is identical, and the isolation means you are not changing anything that already works.
The hardest decision in any referral program is the trigger. Your options:
For most early-stage SaaS products, rewarding after the referred user makes their first payment is the right call. It aligns the incentive with revenue and is trivial to enforce: when your Stripe webhook receives checkout.session.completed, look up the referral record by referred_user_id and flip status to completed, then issue the reward.
Two options that work well without adding operational complexity:
trial_ends_at column or adjust the next billing date via the Stripe API.Avoid cash or gift cards at early stage. They create tax complexity and require identity verification you almost certainly have not built yet.
User opens Share panel
--> app generates or fetches their referral code
--> user gets: https://yourapp.com/signup?ref=ABC123
Visitor clicks the link
--> store ref=ABC123 in a cookie (7-day TTL)
Visitor signs up
--> registration handler reads cookie
--> creates referrals row with status=pending
Visitor pays
--> Stripe webhook fires checkout.session.completed
--> find referrals row by referred_user_id
--> flip status to completed, issue reward to both sides
Referrer sees reward notice in their dashboard
The cookie TTL matters. Seven to fourteen days is the standard window. Too short and you lose attribution when users click but come back later. Too long and you create incentive to game the system.
The simplest version is a section on your existing user settings page with a copy-to-clipboard button. Keep it inside the product rather than on a separate page -- users who are already logged in and engaged are the ones most likely to share.
For the reward copy, be specific: "Give a friend one free month, get one free yourself." Vague rewards underperform specific ones because people cannot picture what they are getting.
If you also want to compensate external publishers with tracked cash commissions, see the related post on building an affiliate program with Drizzle ORM -- the referral and affiliate modules can coexist.
Most founders add referral programs after they have paying customers, which means they paid to acquire people who might have come for free if the program had been running. The earlier you wire it in, the more referral data you accumulate and the more likely you are to catch the growth windows that matter most -- the first week after a user has a win inside your product.
The boilerplate already handles auth, Drizzle ORM, Stripe webhooks, and email. Adding a referral program is a new module, not a rewrite. Get started at boilerplate.iteam-company.com and follow the module pattern in the getting started docs to scaffold the referral module alongside everything you already have.