DEV Community

Alex Spinov
Alex Spinov

Posted on

Better Auth Has Free Authentication for Any Framework — Here's Why It's Replacing NextAuth

NextAuth is great for Next.js. But what about Hono, SvelteKit, Nuxt, or Express? Better Auth works everywhere.

What is Better Auth?

Better Auth is a framework-agnostic authentication library for TypeScript. It supports email/password, OAuth, magic links, passkeys, 2FA, and more — with any framework and any database.

Quick Start

bun add better-auth
Enter fullscreen mode Exit fullscreen mode
// auth.ts
import { betterAuth } from 'better-auth';
import { drizzleAdapter } from 'better-auth/adapters/drizzle';
import { db } from './db';

export const auth = betterAuth({
  database: drizzleAdapter(db, { provider: 'pg' }),
  emailAndPassword: { enabled: 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!,
    },
  },
});
Enter fullscreen mode Exit fullscreen mode

Client Setup

// auth-client.ts
import { createAuthClient } from 'better-auth/react'; // or /vue, /svelte, /solid

export const { signIn, signUp, signOut, useSession } = createAuthClient();
Enter fullscreen mode Exit fullscreen mode

Email/Password Auth

function SignUpForm() {
  const handleSubmit = async (e: FormEvent) => {
    e.preventDefault();
    const formData = new FormData(e.target as HTMLFormElement);

    await signUp.email({
      email: formData.get('email') as string,
      password: formData.get('password') as string,
      name: formData.get('name') as string,
    });
  };

  return (
    <form onSubmit={handleSubmit}>
      <input name="name" placeholder="Name" required />
      <input name="email" type="email" placeholder="Email" required />
      <input name="password" type="password" placeholder="Password" required />
      <button type="submit">Sign Up</button>
    </form>
  );
}
Enter fullscreen mode Exit fullscreen mode

Social Login

function LoginButtons() {
  return (
    <div>
      <button onClick={() => signIn.social({ provider: 'google' })}>
        Continue with Google
      </button>
      <button onClick={() => signIn.social({ provider: 'github' })}>
        Continue with GitHub
      </button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Session Management

function Dashboard() {
  const { data: session, isPending } = useSession();

  if (isPending) return <p>Loading...</p>;
  if (!session) return <p>Please sign in</p>;

  return (
    <div>
      <h1>Welcome, {session.user.name}</h1>
      <p>{session.user.email}</p>
      <button onClick={() => signOut()}>Sign Out</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Two-Factor Authentication

import { twoFactor } from 'better-auth/plugins';

export const auth = betterAuth({
  plugins: [
    twoFactor({
      issuer: 'MyApp',
    }),
  ],
});
Enter fullscreen mode Exit fullscreen mode

Better Auth vs NextAuth vs Lucia Auth vs Clerk

Feature Better Auth NextAuth Lucia Auth Clerk
Framework Any Next.js Any Any
Database Any (adapter) Any (adapter) Any Managed
Self-hosted Yes Yes Yes No
Social OAuth Yes Yes Manual Yes
2FA Plugin No Manual Yes
Passkeys Plugin No No Yes
TypeScript Full Good Full Good
Free Yes Yes Yes Freemium

Building authenticated scraping dashboards? Check out my Apify actors — data extraction with API key auth. For custom solutions, email spinov001@gmail.com.

Top comments (0)