A modern, full-featured SvelteKit starter template with Supabase integration, authentication, and a comprehensive set of reusable UI components inspired by shadcn/ui.
This starter provides a complete authentication system powered by Supabase, with ready-to-use pages and flows for all common authentication scenarios.
/signup): Create new account with email, password, first name, and last name/login): Sign in with email and password/verify-email): Verify email address after signup/forgot-password): Request password reset link/reset-password): Set new password using reset token/settings): Enable TOTP-based 2FA with QR code/login/2fa): Verify 6-digit code during login/settings): Turn off two-factor authenticationRoutes inside the (authenticated) folder automatically require login. The layout checks for an active session:
// src/routes/(authenticated)/+layout.server.ts
export const load: LayoutServerLoad = async ({ locals: { safeGetSession } }) => {
const { session, user } = await safeGetSession();
if (!session) {
redirect(303, '/login'); // Redirect to login if not authenticated
}
return { user };
};
The hooks.server.ts file sets up Supabase authentication and injects user data into event.locals:
// Supabase client creation and session management
export const handle = sequence(
createSupabaseServerClient, // Creates Supabase client
authorizationHook // Extracts user role from JWT
);
This makes locals.safeGetSession() and locals.userRole available in all server-side code.
event.locals.safeGetSession() to get user and session$lib/supabase.tssrc/hooks.server.ts: Global authentication and authorization hookssrc/lib/supabase.ts: Client-side Supabase client factorysrc/lib/server/supabase.ts: Server-side Supabase client creationsrc/lib/schemas/auth.ts: Zod validation schemas for all auth formssrc/routes/login/, /signup/, etc.: Authentication page implementationsThis starter includes a complete role-based access control system with a 6-tier hierarchy. Each role has a numeric level that determines permissions, with higher numbers granting more access.
| Role | Level | Description |
|---|---|---|
| Guest | 10 | Basic access - default role for new users |
| Contributor | 30 | Can contribute content |
| Author | 50 | Can create and manage own content |
| Editor | 70 | Can edit others' content |
| Admin | 90 | Full administrative access to user management and settings |
| SuperAdmin | 100 | Complete system access with all privileges |
Routes can be protected at different levels depending on your needs.
Protect all routes within a section using +layout.server.ts:
// src/routes/(authenticated)/admin/+layout.server.ts
import { requireRole, ROLE_LEVELS } from '$lib/server/auth-guard';
import type { RequestEvent } from '@sveltejs/kit';
export const load = async (event: RequestEvent) => {
// Require admin role (level 90) to access all /admin routes
requireRole(event.locals, ROLE_LEVELS.ADMIN);
return {};
};
Protect a specific page using +page.server.ts:
// src/routes/(authenticated)/dashboard/+page.server.ts
import { requireRole, ROLE_LEVELS } from '$lib/server/auth-guard';
export const load = async ({ locals }) => {
// Require at least Author role to access this page
requireRole(locals, ROLE_LEVELS.AUTHOR);
// Load page data...
return { data: '...' };
};
For more complex logic, use the hasRole helper:
export const load = async ({ locals }) => {
const isAdmin = locals.hasRole(ROLE_LEVELS.ADMIN);
const isEditor = locals.hasRole(ROLE_LEVELS.EDITOR);
return {
canEdit: isEditor || isAdmin,
canDelete: isAdmin,
userRole: locals.userRole
};
};
Access user role in components for UI customization:
<script lang="ts">
import { ROLE_LEVELS } from '$lib/constants/roles';
let { data } = $props();
const isAdmin = data.userRole?.level >= ROLE_LEVELS.ADMIN;
</script>
{#if isAdmin}
<button>Admin Controls</button>
{/if}
Note: If a user lacks sufficient permissions, requireRole redirects them to /dashboard.
src/lib/constants/roles.ts: Role definitions, levels, and display utilitiessrc/lib/server/auth-guard.ts: Server-side role validationsrc/lib/schemas/roles.ts: Zod schemas for role operationssrc/lib/server/roles.ts: Database operations for role managementWhen running Supabase locally with seed data:
[email protected] / password (SuperAdmin role)[email protected] / password (Guest role)The admin section (/admin) provides comprehensive tools for managing users and monitoring system activity. Access requires Admin role (level 90) or higher.
/admin/users)/admin/audit)The audit system automatically logs all role assignments and changes, providing full accountability and compliance tracking.
src/
lib/
components/
app-sidebar.svelte # Responsive sidebar navigation
navigation.svelte # Navigation menu component
theme-toggle.svelte # Dark/light mode toggle
ui/
alert/ # Alert, AlertTitle, AlertDescription
badge/ # Badge component with variants
button/ # Button
card/ # Card, CardHeader, CardContent, etc.
dropdown-menu/ # Dropdown menu components
field/ # Field, FieldSet, FieldLabel, FieldError, etc.
input/ # Input
input-otp/ # InputOTP, InputOTPGroup, etc.
label/ # Label
navigation-menu/ # Navigation menu components
select/ # Select, SelectContent, SelectItem, etc.
separator/ # Separator
sheet/ # Sheet (side drawer) component
sidebar/ # Sidebar layout components
skeleton/ # Skeleton loading states
sonner/ # Toaster (toast notifications)
table/ # Table, TableHeader, TableBody, etc.
tabs/ # Tabs, TabsList, TabsContent, TabsTrigger
tooltip/ # Tooltip component
constants/
roles.ts # Role levels, names, descriptions, badge variants
hooks/
is-mobile.svelte.ts # Mobile detection hook
schemas/
auth.ts # Authentication schemas (login, signup, etc.)
roles.ts # Role operation schemas
server/
auth-guard.ts # Role-based route protection
roles.ts # Database operations for roles
supabase.ts # Server-side Supabase client
supabase.ts # Client-side Supabase integration
utils.ts # Utility functions
routes/
(authenticated)/ # Authenticated routes (requires login)
admin/ # Admin section (requires Admin role)
users/ # User management page
audit/ # Audit log page
dashboard/ # User dashboard
settings/ # User settings (profile, email, password, 2FA)
login/ # Login page
2fa/ # Two-factor authentication verification
signup/ # Signup page
forgot-password/ # Forgot password page
reset-password/ # Reset password page
verify-email/ # Email verification page
static/ # Static assets (favicon, robots.txt)
supabase/ # Supabase configuration
migrations/ # Database migrations (roles system)
seed/ # Seed data (roles, test users)
git clone <your-repo-url>
cd sveltekit-supabase-starter
yarn install
.env.local.example to .env.local:cp .env.local.example .env.local
PUBLIC_SUPABASE_URL='https://<your-project>.supabase.co'
PUBLIC_SUPABASE_ANON_KEY='<your-anon-key>'
PRIVATE_SUPABASE_SERVICE_ROLE='<your-service-role-key>'
This project is fully integrated with Supabase for authentication, database, and storage. All Supabase logic is located in src/lib/server/supabase.ts and src/lib/supabase.ts. Auth flows use Supabase's email/password and 2FA features. Environment variables configure Supabase endpoints and keys (see the Environment Variables section).
You can run a full Supabase stack (database, authentication, storage, etc.) on your machine for local development. This allows you to develop and test all features locally, just as they would work in production.
yarn global add supabase
supabase start
This will launch the local Supabase stack (Postgres, Auth, Storage, etc.) using the existing supabase/ directory in this project.supabase start, the CLI will print your local project URL and anon/service keys..env.local file with these values:PUBLIC_SUPABASE_URL='http://localhost:54321'
PUBLIC_SUPABASE_ANON_KEY='<your-local-anon-key>'
PRIVATE_SUPABASE_SERVICE_ROLE='<your-local-service-role-key>'
For more details, see the Supabase CLI documentation.
All environment variables should be set in .env.local (never commit secrets to version control).
Start the development server:
yarn dev
http://localhost:5173 (or as shown in the terminal).To start and open the app in your browser automatically:
yarn dev --open
yarn s — Start the dev serveryarn so — Start the dev server and open in browserTo build for production:
yarn build
To preview the production build:
yarn preview
All UI components are located in src/lib/components/ui/ and are inspired by shadcn/ui. Each component is modular, accessible, and themeable with Tailwind CSS.
Alert, AlertTitle, AlertDescriptionBadge with color variantsButton with size and variant optionsCard, CardHeader, CardContent, CardFooter, CardTitle, CardDescription, CardActionDropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuCheckboxItem, etc.Field, FieldSet, FieldLegend, FieldGroup, FieldLabel, FieldTitle, FieldDescription, FieldError, FieldSeparator, FieldContentInput text input componentInputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparatorLabel for form fieldsNavigationMenu, NavigationMenuItem, NavigationMenuLink, etc.Select, SelectTrigger, SelectContent, SelectItemSeparator horizontal/vertical dividerSheet, SheetContent, SheetHeader, SheetTitle (side drawer)Sidebar, SidebarContent, SidebarGroup, SidebarMenu, etc.Skeleton loading placeholderToaster toast notificationsTable, TableHeader, TableBody, TableRow, TableHead, TableCellTabs, TabsList, TabsContent, TabsTriggerTooltip, TooltipTrigger, TooltipContent<script lang="ts">
import { Button } from '$lib/components/ui/button';
import * as Field from '$lib/components/ui/field';
import { Input } from '$lib/components/ui/input';
</script>
<Field.Group>
<Field.Set>
<Field.Legend>Sign In</Field.Legend>
<Field.Group>
<Field.Field>
<Field.Label for="email">Email</Field.Label>
<Input id="email" name="email" />
<Field.Error errors={[{ message: 'Required' }]} />
</Field.Field>
</Field.Group>
</Field.Set>
<Field.Field orientation="horizontal">
<Button type="submit">Submit</Button>
</Field.Field>
</Field.Group>
yarn lint
yarn format
yarn check
MIT