sb-kit

Getting started

Quick start guide for setting up sb-kit with default configuration.

Install dependencies

If you're adding sb-kit to an existing Next.js project:

npx shadcn@latest init

npm install @supabase/supabase-js @supabase/ssr @sb-kit/core @sb-kit/ui
pnpm dlx shadcn@latest init

pnpm add @supabase/supabase-js @supabase/ssr @sb-kit/core @sb-kit/ui
yarn dlx shadcn@latest init

yarn add @supabase/supabase-js @supabase/ssr @sb-kit/core @sb-kit/ui
bunx shadcn@latest init

bun add @supabase/supabase-js @supabase/ssr @sb-kit/core @sb-kit/ui

To create a new Next.js app with sb-kit:

npx create-next-app@latest myapp --tailwind --use-npm

cd myapp

npx shadcn@latest init

npm install @supabase/supabase-js @supabase/ssr @sb-kit/core @sb-kit/ui
npx create-next-app@latest myapp --tailwind --use-pnpm

cd myapp

pnpm dlx shadcn@latest init

pnpm add @supabase/supabase-js @supabase/ssr @sb-kit/core @sb-kit/ui
npx create-next-app@latest myapp --tailwind --use-yarn

cd myapp

yarn dlx shadcn@latest init

yarn add @supabase/supabase-js @supabase/ssr @sb-kit/core @sb-kit/ui
npx create-next-app@latest myapp --tailwind --use-bun

cd myapp

bunx shadcn@latest init

bun add @supabase/supabase-js @supabase/ssr @sb-kit/core @sb-kit/ui

Configure global styles

Tailwind CSS v4 requires this to be set in your global CSS file.

app/globals.css
@import 'tailwindcss';
@import 'tw-animate-css';

@import '@sb-kit/ui/styles/default.css';
@source '../../node_modules/@sb-kit';

/* ... rest of the file */

Configure Supabase clients

Option 1: Default Setup

This setup is based on the official Supabase docs and works with any Next.js project.

.env
SUPABASE_URL=<YOUR_SUPABASE_URL>
SUPABASE_ANON_KEY=<YOUR_SUPABASE_ANON_KEY>
/lib/supabase/client/server.ts
import { cookies } from 'next/headers';

import { createServerClient } from '@supabase/ssr';

export async function serverClient() {
  const cookieStore = await cookies();

  return createServerClient(
    process.env.SUPABASE_URL!,
    process.env.SUPABASE_ANON_KEY!,
    {
      cookies: {
        getAll: () => cookieStore.getAll(),
        setAll: (cookiesToSet) => {
          try {
            cookiesToSet.forEach(({ name, value, options }) =>
              cookieStore.set(name, value, options),
            );
          } catch {}
        },
      },
    },
  );
}
/lib/supabase/client/middleware.ts
import { NextRequest, NextResponse } from 'next/server';

import { createServerClient } from '@supabase/ssr';

export async function middlewareClient(request: NextRequest) {
  const supabaseResponse = NextResponse.next();

  const supabase = createServerClient(
    process.env.SUPABASE_URL!,
    process.env.SUPABASE_ANON_KEY!,
    {
      cookies: {
        getAll: () => request.cookies.getAll(),
        setAll: (cookiesToSet) => {
          cookiesToSet.forEach(({ name, value, options }) => {
            supabaseResponse.cookies.set(name, value, options);
          });
        },
      },
    },
  );

  const {
    data: { user },
    error,
  } = await supabase.auth.getUser();

  return {
    supabaseResponse,
    user,
    error,
  };
}

Option 2: Existing Supabase Client

If you’re using your own Supabase client, just make sure your utility functions conform to the following shape:

import type { NextRequest, NextResponse } from 'next/server';

import type { AuthError, SupabaseClient, User } from '@supabase/supabase-js';

/**
 * Server-side Supabase client
 */
async function serverClient(): Promise<SupabaseClient> {
  // return your server client
}

/**
 * Middleware Supabase client
 */
async function middlewareClient(request: NextRequest): Promise<{
  supabaseResponse: NextResponse;
  user: User | null;
  error: AuthError | null;
}> {
  // return your middleware client
}

Initialize sb-kit client

Initialize sb-kit with Supabase clients.

/lib/supabase/sb-kit.ts
import { sbKitClient } from '@sb-kit/core';

import { middlewareClient } from './client/middleware';
import { serverClient } from './client/server';

export const sbKit = sbKitClient({
  supabaseClients: {
    server: serverClient,
    middleware: middlewareClient,
  },
});

Add server-side helpers

Use sbKit.callbackHandler for OAuth callbacks and routeGuard in middleware to protect routes based on authentication state.

/app/api/auth/callback/route.ts
import { sbKit } from '@/lib/supabase/sb-kit';

const callbackHandler = sbKit.callbackHandler;

export { callbackHandler as GET };
/src/middleware.ts
import { type NextRequest, NextResponse } from 'next/server';

import { sbKit } from './lib/supabase/sb-kit';

export async function middleware(request: NextRequest) {
  const routeGuardResponse = await sbKit.routeGuard(request);
  if (routeGuardResponse) return routeGuardResponse;

  return NextResponse.next();
}

export const config = {
  matcher: [
    '/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
  ],
};

Add auth layout and pages

Use sbKit.components to set up the auth layout and pages.

  • AuthWrapper provides the base auth UI along with the SonnerToaster provider.
  • The page components handle the auth flow using server actions.
/app/(auth)/layout.tsx
import { sbKit } from '@/lib/supabase/sb-kit';

type Props = {
  children: React.ReactNode;
};

const AuthWrapper = sbKit.components.AuthWrapper;

const Layout = ({ children }: Props) => {
  return <AuthWrapper>{children}</AuthWrapper>;
};

export default Layout;
/app/(auth)/signin/page.tsx
import type { SearchParams } from 'next/dist/server/request/search-params';
import { sbKit } from '@/lib/supabase/sb-kit';

type Props = {
  searchParams: Promise<SearchParams>;
};

const SignIn = sbKit.components.SignIn;

const Page = ({ searchParams }: Props) => {
  return <SignIn searchParams={searchParams} />;
};

export default Page;
/app/(auth)/signup/page.tsx
import { sbKit } from '@/lib/supabase/sb-kit';

const SignUp = sbKit.components.SignUp;

const Page = () => {
  return <SignUp />;
};

export default Page;
/app/(auth)/forgot-password/page.tsx
import { sbKit } from '@/lib/supabase/sb-kit';

const ForgotPasssword = sbKit.components.ForgotPassword;

const Page = () => {
  return <ForgotPasssword />;
};

export default Page;
/app/(auth)/set-password/page.tsx
import { sbKit } from '@/lib/supabase/sb-kit';

const SetPassword = sbKit.components.SetPassword;

const Page = () => {
  return <SetPassword />;
};

export default Page;

Done.