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

How to Add Promo Codes to Your Next.js SaaS -- Stripe Coupons, Discounts, and Black Friday Deals

November 3, 2026
nextjsstripesaaspaymentsboilerplate

Your first discount should take an afternoon, not a week. Stripe supports coupons and promotion codes natively, but the docs split the concept across two objects -- and most Next.js tutorials stop at "create a coupon in the dashboard." Here is the full workflow so you can run a real promotion today.

What Stripe Actually Gives You

Stripe separates discounts into two layers:

  • Coupon -- the actual discount rule (20% off, $10 off, duration)
  • Promotion Code -- the customer-facing code (LAUNCH20, BLACKFRIDAY) that maps to a coupon

You create one coupon, then create one or more promotion codes that point to it. A customer types the code; Stripe validates it against the coupon rule. This matters because one coupon can have many codes -- a referral code for one user, a bulk discount for a partner, and a public launch discount all pointing to the same "20% first year" rule.

The Checkout Flow

When a customer clicks "I have a promo code" during checkout, you have two options:

Option 1: Let Stripe handle it. Pass allow_promotion_codes: true to the Checkout Session. Stripe shows a built-in field and applies the discount automatically. This is the right default.

Option 2: Pre-apply a code. If you want to surprise the user -- auto-apply a referral code they got from a friend -- look up the promotion code ID from Stripe and pass it as discounts: [{ promotion_code: promoId }].

Here is what option 1 looks like in your checkout route:

const session = await stripe.checkout.sessions.create({
  mode: 'subscription',
  customer: stripeCustomerId,
  line_items: [{ price: priceId, quantity: 1 }],
  allow_promotion_codes: true,
  success_url: `${baseUrl}/dashboard?checkout=success`,
  cancel_url: `${baseUrl}/pricing`,
});

That one flag is all it takes for the most common case.

Pre-Applying a Code From Your App

If a user arrives from a link like /signup?promo=LAUNCH20, you can apply the code automatically at checkout without them typing anything:

const promoCodes = await stripe.promotionCodes.list({
  code: promoCodeParam,
  active: true,
  limit: 1,
});
 
const promoCode = promoCodes.data[0];
 
const session = await stripe.checkout.sessions.create({
  // ...
  discounts: promoCode ? [{ promotion_code: promoCode.id }] : [],
});

Store the code as a query param or in a short-lived cookie, then pull it out in the checkout route. This pattern works for launch specials, affiliate links, and partner codes.

Tracking Redemptions

Every time a promotion code is applied, Stripe fires a customer.discount.created webhook event. If you already handle Stripe webhooks for subscriptions (the Next.js SaaS Boilerplate ships this), you can add a new case:

case 'customer.discount.created': {
  const discount = event.data.object;
  const promoCodeId = discount.promotion_code as string;
  // store against the customer in your DB
  break;
}

This gives you a record of which users came in on a promotion -- useful for cohort analysis and support filtering.

What to Watch Out For

Stackable discounts: by default, Stripe does not let two promotion codes apply at once. If you pre-apply a code and the user also types one at checkout, Stripe picks only one. Test this before your launch.

Expiry dates: set an expiry on the promotion code in Stripe, not just in your UI. A code that shows as expired on your landing page should also be inactive in Stripe, or a determined user can still apply it.

Subscription vs one-time: coupon duration options are "once", "repeating" (N months), and "forever". For a monthly SaaS, a "3-month 50% off" repeating coupon retains better than a one-time discount -- users feel the value for longer before they see full price.

The Decision Checklist

Before you create your first promotion, answer three questions:

  1. Who gets the code? -- a public launch code goes on your landing page; a targeted code goes in an email to trial users who did not convert
  2. What is the goal? -- acquisition (attract new users) or conversion (push trial users to upgrade); these suggest different discount amounts and durations
  3. How will you measure it? -- track redemptions in your DB and compare conversion and churn rates for that cohort

Running a Black Friday Sale

The fastest path: create a coupon in your Stripe dashboard with 30% off and an expiry date. Create a promotion code (BLACKFRIDAY25). Add allow_promotion_codes: true to your checkout route. Announce it. Stripe handles the validation, application, and webhook -- your app just needs to handle the success URL.

You do not need a feature flag system, a marketing platform, or a separate campaign tool to run a Black Friday deal. The infrastructure is already in your checkout flow.


If you want to run your first promotion without the weeks of setup, this Next.js SaaS boilerplate ships with Stripe subscriptions, webhooks, and checkout already wired up -- so a promo code is an afternoon's work, not a sprint.