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
// 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!,
},
},
});
Client Setup
// auth-client.ts
import { createAuthClient } from 'better-auth/react'; // or /vue, /svelte, /solid
export const { signIn, signUp, signOut, useSession } = createAuthClient();
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>
);
}
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>
);
}
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>
);
}
Two-Factor Authentication
import { twoFactor } from 'better-auth/plugins';
export const auth = betterAuth({
plugins: [
twoFactor({
issuer: 'MyApp',
}),
],
});
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)