Clerk provides complete user management — sign-up, sign-in, user profiles, organizations, and MFA — with pre-built UI components that look great out of the box.
Why Clerk?
-
Pre-built components —
<SignIn />,<UserButton />— production-ready UI - Next.js middleware — protect routes with one line
- Organizations — multi-tenant auth built-in
- Free tier — 10,000 monthly active users
Quick Start (Next.js)
npm install @clerk/nextjs
// middleware.ts
import { clerkMiddleware } from '@clerk/nextjs/server';
export default clerkMiddleware();
export const config = { matcher: ['/((?!.*\\..*|_next).*)', '/', '/(api|trpc)(.*)'] };
// app/layout.tsx
import { ClerkProvider, SignedIn, SignedOut, SignInButton, UserButton } from '@clerk/nextjs';
export default function RootLayout({ children }) {
return (
<ClerkProvider>
<html>
<body>
<header>
<SignedOut>
<SignInButton />
</SignedOut>
<SignedIn>
<UserButton />
</SignedIn>
</header>
{children}
</body>
</html>
</ClerkProvider>
);
}
Pre-Built Components
import { SignIn, SignUp, UserProfile } from '@clerk/nextjs';
// Full sign-in page
export default function SignInPage() {
return <SignIn />;
}
// Full sign-up page
export default function SignUpPage() {
return <SignUp />;
}
// User profile management
export default function ProfilePage() {
return <UserProfile />;
}
Protect Routes (Server)
import { auth } from '@clerk/nextjs/server';
export default async function Dashboard() {
const { userId } = await auth();
if (!userId) {
redirect('/sign-in');
}
const user = await currentUser();
return <h1>Welcome, {user.firstName}!</h1>;
}
Protect API Routes
import { auth } from '@clerk/nextjs/server';
export async function GET() {
const { userId } = await auth();
if (!userId) {
return new Response('Unauthorized', { status: 401 });
}
const data = await getDataForUser(userId);
return Response.json(data);
}
Hooks (Client)
import { useUser, useAuth, useOrganization } from '@clerk/nextjs';
function Dashboard() {
const { user, isLoaded } = useUser();
const { getToken } = useAuth();
const { organization } = useOrganization();
if (!isLoaded) return <Loading />;
return (
<div>
<h1>Hi, {user.firstName}</h1>
<p>Email: {user.primaryEmailAddress?.emailAddress}</p>
<p>Org: {organization?.name}</p>
</div>
);
}
Organizations (Multi-Tenant)
import { OrganizationSwitcher, CreateOrganization } from '@clerk/nextjs';
// Org switcher in navbar
<OrganizationSwitcher />
// Create org page
<CreateOrganization />
Webhooks
import { Webhook } from 'svix';
export async function POST(req: Request) {
const body = await req.text();
const wh = new Webhook(process.env.CLERK_WEBHOOK_SECRET!);
const event = wh.verify(body, headers) as WebhookEvent;
switch (event.type) {
case 'user.created':
await db.createUser(event.data);
break;
case 'user.deleted':
await db.deleteUser(event.data.id);
break;
}
return new Response('OK');
}
Building authenticated apps? Check out my Apify actors for web scraping behind auth, or email spinov001@gmail.com for custom solutions.
Clerk, Auth.js, or Lucia — which auth solution do you use? Share below!
Top comments (0)