GenerateSaaS

Waitlist Mode

Turn your Next.js SaaS into a pre-launch waitlist with one config flag. Signups capture emails via Better Auth and the hero becomes a sign-up form.

Waitlist mode is a single flag in @repo/config that turns your SaaS into a pre-launch capture page: signups still create accounts but cannot log in until you launch. It is read in packages/auth/src/config.ts and reshapes the landing surface, the auth emails, and the post-signup redirects.

The flag

// packages/config/src/index.ts
export const config = {
  waitlist: false, // default - flip to true for pre-launch
};
StateBehavior
false (default)Normal app - signup, verification, auto sign-in, full marketing site.
truePre-launch capture - accounts created but inert, hero/CTA become email forms.

What flips when true

Signup still creates a user row - Better Auth records the account so you have the email list, but the visitor is not logged in.
Confirmation email swaps - sendVerificationEmail and magic-link both send the waitlist-confirmation template instead of the normal verification/magic-link mail, subject You're on the {config.siteName} waitlist!.
Auto sign-in disabled - autoSignInAfterVerification becomes !config.waitlist, so confirming the email does not start a session.
Hero & final CTA become capture forms - the landing page renders an inline email field submitting via authClient.signIn.magicLink (threading the Turnstile token when config.captcha.enabled); the navbar shows a single "Join" button.
Authenticated areas redirect home - the dashboard, auth, and onboarding layouts send visitors back to the landing page.

The confirmation email

The waitlist-confirmation template lives at packages/mail/src/templates/waitlist-confirmation.tsx, takes a single prop, and is delivered through the provider set in config.email.provider.

PropTypeNotes
verificationUrlstringConfirm-email link threaded from Better Auth.

The copy reads "You're Almost There!" and asks the subscriber to confirm their email to secure their spot - no login follows.

The template body hardcodes "This link will expire in 24 hours." The hero/CTA forms submit via authClient.signIn.magicLink, whose tokens expire in 15 minutes (expiresIn: 900 in packages/auth/src/config.ts). The 24-hour figure only holds for the email-and-password sign-up path. Adjust the copy or the magic-link expiresIn to match.

Flipping config.waitlist back to false reactivates normal accounts immediately, but users created during waitlist mode keep their existing rows. Confirm your launch flow before flipping.

Frequently asked questions

Does signing up during waitlist mode give the user access? No. The account row is created and the email is captured, but autoSignInAfterVerification is off and the dashboard/auth/onboarding layouts redirect home, so there is no usable session.

Where do the captured emails go? Into your normal users table via Better Auth - submitting the hero form calls authClient.signIn.magicLink, which creates the account and sends the waitlist-confirmation email.

How do I launch? Set config.waitlist to false. Existing waitlist accounts remain; new and returning users then get the normal signup, verification, and auto sign-in flow.

On this page