Skip to main content

Best Boilerplates Using Better Auth in 2026

·StarterPick Team
better-authauthenticationsaasboilerplatestarter-kitnextjs2026

Better Auth launched in 2024 as a TypeScript-native authentication library and has moved fast. In 2026 it's become the go-to auth solution for new SaaS starters — offering a self-hosted alternative to Clerk that doesn't charge per-user, more features than NextAuth.js without the v5 migration pain, and first-class support for passkeys, RBAC, multi-tenancy, and magic links out of the box.

The boilerplates in this guide have adopted Better Auth as their authentication layer. That choice has real implications: your auth data stays in your database, you pay no per-MAU fees, and you can extend the auth system with Better Auth plugins rather than waiting for a vendor to ship features.

Why Developers Are Switching to Better Auth

FeatureBetter AuthNextAuth v5Clerk
Self-hosted✅ Always✅ Always❌ Managed
Per-MAU cost$0$0$0.02+ above free tier
Passkeys
RBAC built-in❌ (DIY)
Organization/teams✅ Plugin
Impersonation✅ (paid)
Two-factor auth❌ (DIY)
Magic links
TypeScriptFirst-classGoodFirst-class
Session typeDatabaseJWT/DBJWT (managed)
Plugin system✅ Extensible

Better Auth occupies a unique position: it has Clerk's features with NextAuth's cost model (free, self-hosted).


How Better Auth Works

Better Auth is installed as a dependency in your project and connects to your existing database. No external service, no dashboard to maintain:

// lib/auth.ts — Better Auth server setup
import { betterAuth } from 'better-auth';
import { prismaAdapter } from 'better-auth/adapters/prisma';
import { organization, twoFactor, passkey, admin } from 'better-auth/plugins';
import { prisma } from '~/lib/prisma';

export const auth = betterAuth({
  database: prismaAdapter(prisma, {
    provider: 'postgresql',
  }),

  emailAndPassword: {
    enabled: true,
    requireEmailVerification: true,
  },

  socialProviders: {
    google: {
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    },
    github: {
      clientId: process.env.GITHUB_CLIENT_ID!,
      clientSecret: process.env.GITHUB_CLIENT_SECRET!,
    },
  },

  plugins: [
    organization(), // Multi-tenant teams with invitations
    twoFactor(),    // TOTP 2FA
    passkey(),      // WebAuthn/Passkeys
    admin(),        // User impersonation, ban/unban
  ],
});
// lib/auth-client.ts — Client-side SDK
import { createAuthClient } from 'better-auth/react';
import { organizationClient, twoFactorClient } from 'better-auth/client/plugins';

export const authClient = createAuthClient({
  baseURL: process.env.NEXT_PUBLIC_APP_URL!,
  plugins: [
    organizationClient(),
    twoFactorClient(),
  ],
});

export const { signIn, signUp, signOut, useSession } = authClient;

Quick Comparison

BoilerplatePriceStackOrg SupportBilling
Supastarter BA$149Next.js + DrizzleStripe / Polar
NEXTY.DEV$97Next.js + PrismaStripe
IndieSaas StarterFreeNext.js + DrizzleStripe
Launch (mobile)$199Expo + Node.jsStripe
v1.runFreeNext.js + ConvexPolar.sh
TurboStarter$149Next.js + HonoStripe

1. Supastarter (Better Auth Edition) — Best Complete Kit

Price: $149 | Stack: Next.js 15 + Drizzle + Better Auth + Stripe/Polar

Supastarter was one of the first major commercial starters to adopt Better Auth. They offer two editions — one with Supabase Auth and one with Better Auth — letting you choose based on your vendor preference.

The Better Auth edition uses Drizzle ORM directly against PostgreSQL (no Supabase dependency) with Better Auth handling all authentication. This means fully self-hosted auth: no Supabase project needed, no Clerk dashboard, just your Postgres database.

Features:

  • Organization/team management with invitations
  • Role-based access control (owner, admin, member)
  • Magic link, email/password, OAuth (Google, GitHub)
  • Two-factor authentication
  • Stripe billing with subscription management
  • Polar.sh billing as alternative
  • shadcn/ui components
  • Dark mode
  • i18n (internationalization)
  • Resend email integration
// Supastarter's organization middleware pattern
// middleware.ts
import { auth } from '~/lib/auth';
import { redirect } from 'next/navigation';

export async function requireOrganizationMember(
  request: Request,
  organizationSlug: string,
  minimumRole: 'member' | 'admin' | 'owner' = 'member'
) {
  const session = await auth.api.getSession({ headers: request.headers });
  if (!session) redirect('/login');

  const membership = await prisma.organizationMember.findFirst({
    where: {
      userId: session.user.id,
      organization: { slug: organizationSlug },
    },
    include: { organization: true },
  });

  if (!membership) redirect('/dashboard');

  const roleHierarchy = { member: 0, admin: 1, owner: 2 };
  if (roleHierarchy[membership.role] < roleHierarchy[minimumRole]) {
    redirect('/dashboard');
  }

  return { session, membership };
}

2. NEXTY.DEV — Best for User Source Tracking

Price: $97 | Stack: Next.js 16 + Better Auth + Stripe + Prisma

NEXTY.DEV stands out for a specific feature: User Source Tracking — automatically capturing how users found your product (referral source, UTM parameters) on signup. Combined with Better Auth, it includes Google/GitHub OAuth, email OTP, and magic link authentication.

User source tracking setup:

// NEXTY's user acquisition tracking
// app/api/auth/[...all]/route.ts
export const { GET, POST } = toNextJsHandler(auth.handler);

// Better Auth's onSignUp hook captures UTM params
export const auth = betterAuth({
  // ... other config
  hooks: {
    after: [
      createAuthMiddleware(async (ctx) => {
        if (ctx.path === '/sign-up/email') {
          // Capture referral source from cookie set by middleware
          const referralSource = ctx.cookies.get('referral_source');
          if (referralSource && ctx.newSession?.userId) {
            await prisma.user.update({
              where: { id: ctx.newSession.userId },
              data: { referralSource: referralSource.value },
            });
          }
        }
      }),
    ],
  },
});

3. IndieSaas Starter — Best Free Better Auth Boilerplate

Price: Free (MIT) | Stack: Next.js 15 + Better Auth + Drizzle + Stripe

The IndieSaas Starter is a free Next.js boilerplate using Better Auth, Drizzle ORM, shadcn/ui, and Stripe. MIT licensed — use it commercially, modify it freely, no attribution required.

It covers the core MVP surface: auth (email/password, Google OAuth), billing (Stripe subscriptions), database (Drizzle + PostgreSQL), and a basic dashboard. No multi-tenancy, no admin panel — just the foundation you extend from.

// IndieSaas: Better Auth with Drizzle adapter
import { betterAuth } from 'better-auth';
import { drizzleAdapter } from 'better-auth/adapters/drizzle';
import { db } from '~/db';
import * as schema from '~/db/schema';

export const auth = betterAuth({
  database: drizzleAdapter(db, {
    provider: 'pg',
    schema: {
      user: schema.users,
      session: schema.sessions,
      account: schema.accounts,
      verification: schema.verifications,
    },
  }),
  emailAndPassword: { enabled: true },
  socialProviders: {
    google: {
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    },
  },
});

4. v1.run — Best Free Modern Stack

Price: Free (MIT) | Stack: Next.js + Convex + Better Auth + Polar.sh

v1.run (based on the Midday codebase) uses Better Auth for authentication and Convex for the database — an interesting combination where Better Auth handles sessions while Convex handles application data. No Stripe: Polar.sh instead, with 4% + $0.40 fees vs Stripe's 2.9% + $0.30.

The Polar.sh choice reflects an interesting philosophical alignment: Polar is developer-first, open-source-friendly billing infrastructure, similar to Better Auth's position in the auth space.


Better Auth Multi-Tenancy Pattern

For SaaS products that need organizations, Better Auth's organization plugin handles the full multi-tenant workflow:

// Server: Create organization
const createOrg = async (name: string, userId: string) => {
  return await auth.api.createOrganization({
    body: {
      name,
      slug: name.toLowerCase().replace(/\s+/g, '-'),
      userId,
    },
  });
};

// Server: Invite team member
const inviteMember = async (
  organizationId: string,
  email: string,
  role: 'member' | 'admin'
) => {
  return await auth.api.createInvitation({
    body: {
      organizationId,
      email,
      role,
    },
  });
};

// Client: Accept invitation
const { data } = await authClient.organization.acceptInvitation({
  invitationId: params.invitationId,
});

// Client: Switch active organization
await authClient.organization.setActive({
  organizationId: selectedOrg.id,
});

Migrating to Better Auth from NextAuth

Better Auth ships a migration CLI for NextAuth projects:

# Install Better Auth migration tool
npx @better-auth/cli migrate

# It will:
# 1. Scan your NextAuth config
# 2. Generate Better Auth equivalent config
# 3. Create database migration to rename columns
# (NextAuth: accounts.userId → Better Auth: accounts.userId, same schema)

# Run the generated migration
npx drizzle-kit push
# or
npx prisma migrate dev

The migration is straightforward because Better Auth's schema is similar to NextAuth v5's schema. Most migrations complete in an hour.


Find all Better Auth boilerplates at StarterPick.

Related: AuthJS v5 vs Lucia v3 vs Better Auth 2026 · Best React Router v7 SaaS Starter Kits 2026

Comments