GenerateSaaS

Waitlist

Turn your Nuxt app into a pre-launch email capture with one config flag. Waitlist mode rewires the hero, navbar, and auth using Better Auth magic links.

Waitlist mode turns the public app into a pre-launch email capture, governed by the config.waitlist flag in @repo/config. The flow is built on Better Auth magic links plus the waitlist-confirmation template from @repo/mail.

The flag

config.waitlist lives at the top level of packages/config/src/index.ts.

KeyTypeDefaultDescription
waitlistbooleanfalsePre-launch email capture instead of open sign-up
// packages/config/src/index.ts
export const config: AppConfig = {
  waitlist: false,
  // …
};

What flips when waitlist: true

The flag rewires the hero, the email, the auto-sign-in step, and the route guards - all from one boolean.

SurfaceFilefalse (default)true
Hero CTAapp/components/landing/hero/Hero.vuePricing / sign-up buttonsInline email capture form
Form submitHero.vue-authClient.signIn.magicLink
Verification emailpackages/auth/src/config.tsemail-verificationwaitlist-confirmation
Magic-link emailpackages/auth/src/config.tsmagic-linkwaitlist-confirmation
autoSignInAfterVerificationpackages/auth/src/config.tstruefalse (!config.waitlist)
Navbarapp/components/layout/navbar/Navbar.vueSign-in / dashboardSingle Join button → /#hero
Route guardsapp/middleware/auth.ts, guest.tsNormal redirectsnavigateTo(localePath("/")) (all protected routes go home)

How a join works

The hero form posts the email through authClient.signIn.magicLink. When config.captcha.enabled is true (provider turnstile), the token rides along in the x-captcha-response header.

Better Auth's sendMagicLink detects config.waitlist and sends the waitlist-confirmation email instead of the normal magic link (packages/auth/src/config.ts).

The visitor confirms via the link. Because autoSignInAfterVerification is false in waitlist mode, they stay on the list rather than landing in the dashboard.

The confirmation email

The waitlist-confirmation template lives at packages/mail/src/templates/waitlist-confirmation.tsx and takes a single verificationUrl prop.

export interface WaitlistConfirmationEmailProps {
  verificationUrl: string;
}

The confirmation email only sends when a mail provider is configured. Wire up your provider in Email before flipping the flag, or joins are captured with no confirmation sent.

Enabling it

Set waitlist: true in packages/config/src/index.ts.

Confirm a mail provider is configured so waitlist-confirmation can send - see Email.

Edit the email copy in packages/mail/src/templates/waitlist-confirmation.tsx and the waitlist.* i18n keys for the hero form.

Restart apps/web-nuxt and verify the hero shows the capture form and the navbar shows Join.

Frequently asked questions

Does the visitor get an account? Joining goes through magic link, so a user row exists, but autoSignInAfterVerification is off in waitlist mode - they aren't signed in and every protected route redirects home until you launch.

How do I launch? Set waitlist: false and redeploy. The hero, navbar, and route guards revert to the normal flow, and confirmed users can sign in as usual.

Can I keep the captcha on the waitlist form? Yes. When config.captcha.enabled is true (provider turnstile), the hero mounts an invisible Turnstile widget (appearance="interaction-only", screen-reader-only) and sends the token in the x-captcha-response header - see Authentication.

On this page