Skip to main content

Getting Started

Installation & Quick Start

Install the package and connect a Prisma or Drizzle adapter to SvelteKit.


This page gets a local admin running with the smallest complete hooks.server.ts. The handler reads your schema once when it is created and serves the admin below /admin by default.

1. Install

npm install sveltekit-admin 
npm install sveltekit-admin 
pnpm add sveltekit-admin 
pnpm add sveltekit-admin 
bun add sveltekit-admin 
bun add sveltekit-admin 
yarn add sveltekit-admin 
yarn add sveltekit-admin 

Install the ORM package and its runtime dependencies in the application as well. For Prisma, run prisma generate after changing the schema. For Drizzle, keep exporting the same table schema object that your application uses.

2. Prisma quick start

// src/hooks.server.ts
import { createAdminHandler } from 'sveltekit-admin';
import { prisma } from '$lib/server/prisma';

export const handle = createAdminHandler({
  prisma,
  authCheck: (event) => event.locals.session?.user?.role === 'admin'
});
// src/hooks.server.ts
import { createAdminHandler } from 'sveltekit-admin';
import { prisma } from '$lib/server/prisma';

export const handle = createAdminHandler({
  prisma,
  authCheck: (event) => event.locals.session?.user?.role === 'admin'
});

The Prisma schema is read from ./prisma/schema.prisma by default. If the app starts from another working directory or uses a non-standard schema location, set prismaSchemaPath explicitly:

export const handle = createAdminHandler({
  prisma,
  prismaSchemaPath: './prisma/admin-schema.prisma'
});
export const handle = createAdminHandler({
  prisma,
  prismaSchemaPath: './prisma/admin-schema.prisma'
});

Run the app and open http://localhost:5173/admin:

pnpm exec prisma generate
pnpm run dev
pnpm exec prisma generate
pnpm run dev

There are no src/routes/admin files to add. The authCheck in the first example assumes an earlier auth hook has populated event.locals.session; see Authentication.

3. Drizzle quick start

Use the dedicated subpath so a Drizzle-only app does not import the Prisma adapter:

// src/hooks.server.ts
import {
  createAdminHandler,
  createDrizzleAdapter
} from 'sveltekit-admin/adapters/drizzle';
import { db } from '$lib/server/db';
import * as schema from '$lib/server/db/schema';

const adapter = createDrizzleAdapter({
  db,
  schema
});

export const handle = createAdminHandler({
  adapter,
  authCheck: (event) => event.locals.session?.user?.role === 'admin'
});
// src/hooks.server.ts
import {
  createAdminHandler,
  createDrizzleAdapter
} from 'sveltekit-admin/adapters/drizzle';
import { db } from '$lib/server/db';
import * as schema from '$lib/server/db/schema';

const adapter = createDrizzleAdapter({
  db,
  schema
});

export const handle = createAdminHandler({
  adapter,
  authCheck: (event) => event.locals.session?.user?.role === 'admin'
});

schema must be the object containing your Drizzle table exports (including relations() exports when your schema uses them). Model keys in models are the schema export keys, such as users, rather than Prisma-style User. If the dialect cannot be inferred, pass dialect: 'postgresql' | 'mysql' | 'sqlite'.

pnpm run dev
pnpm run dev

For SQLite many-to-many writes, the current adapter expects better-sqlite3’s synchronous transaction API. PostgreSQL and MySQL use async transactions; async SQLite drivers are not supported for those writes in this version.

Existing authentication

Compose your auth hook before the admin hook:

import { sequence } from '@sveltejs/kit/hooks';
import { createAdminHandler } from 'sveltekit-admin';
import { prisma } from '$lib/server/prisma';

const authHandle = async ({ event, resolve }) => {
  event.locals.session = await getSession(event);
  return resolve(event);
};

const adminHandle = createAdminHandler({
  prisma,
  authCheck: (event) => event.locals.session?.user?.role === 'admin'
});

export const handle = sequence(authHandle, adminHandle);
import { sequence } from '@sveltejs/kit/hooks';
import { createAdminHandler } from 'sveltekit-admin';
import { prisma } from '$lib/server/prisma';

const authHandle = async ({ event, resolve }) => {
  event.locals.session = await getSession(event);
  return resolve(event);
};

const adminHandle = createAdminHandler({
  prisma,
  authCheck: (event) => event.locals.session?.user?.role === 'admin'
});

export const handle = sequence(authHandle, adminHandle);

First-admin checklist

  • The schema/client exists and is generated.
  • authCheck denies an anonymous request and allows an administrator.
  • models[].scope is present for tenant data.
  • /admin works locally and a create/update/delete has been tested with a non-production database.
  • CSRF and sensitive-field defaults have not been disabled casually.

Continue with Model Configuration, Relations, or Troubleshooting.