Prisma 7 Setup — libSQL / Turso Driver Adapter
Prisma 7 removes the connection string from schema.prisma and moves connection
config into a dedicated prisma.config.ts at the project root. The
@prisma/adapter-libsql package handles both local SQLite files and remote Turso.
<pm> below is the project's package manager: pnpm-lock.yaml → pnpm, yarn.lock → yarn,
package-lock.json → npm, bun.lockb → bun; in a fresh project with no lockfile, use the
packageManager field of package.json or ask. (<pm> add is npm install for npm.)
1. Install packages
<pm> add @prisma/client@^7 @prisma/adapter-libsql@^7
<pm> add -D prisma@^7 dotenv
@libsql/client is not needed — @prisma/adapter-libsql bundles it.
2. prisma/schema.prisma — remove the url field
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
// do NOT add url here — it belongs in prisma.config.ts
}
Also remove previewFeatures = ["driverAdapters"] if present — driver adapters are GA in v7.
3. prisma.config.ts — at the project root (NOT inside prisma/)
Prisma CLI only looks for it at the root.
import path from "node:path"
import { config } from "dotenv"
import { defineConfig } from "prisma/config"
// Prisma CLI runs outside your framework and does not load .env.local by itself.
// override: false keeps a real env var (CI, production) ahead of the file.
config({ path: ".env.local", override: false })
export default defineConfig({
schema: path.join(__dirname, "prisma", "schema.prisma"),
datasource: {
url: process.env.DATABASE_URL!,
},
})
datasource.url is read by the Prisma CLI (migrate dev, studio, …). The runtime
adapter is wired separately in the client module — no migrate.adapter factory is needed.
4. Client module (e.g. src/lib/db.ts) — instantiate PrismaClient with the adapter
PrismaLibSql accepts the connection options directly — no createClient call needed.
import "server-only"
import { PrismaClient } from "@prisma/client"
import { PrismaLibSql } from "@prisma/adapter-libsql"
const globalForPrisma = globalThis as unknown as { prisma: PrismaClient | undefined }
function createPrismaClient(): PrismaClient {
const adapter = new PrismaLibSql({
url: process.env.DATABASE_URL ?? "file:./dev.db",
authToken: process.env.DATABASE_AUTH_TOKEN,
})
return new PrismaClient({
adapter,
log: process.env.LOG_LEVEL === "debug" ? ["query", "error", "warn"] : ["error"],
})
}
export const db = globalForPrisma.prisma ?? createPrismaClient()
if (process.env.NODE_ENV !== "production") {
globalForPrisma.prisma = db
}
(server-only is a Next.js package; drop the import in a plain Node project.)
5. Environment variables
DATABASE_URL / DATABASE_AUTH_TOKEN are conventions, not requirements — keep whatever names
prisma.config.ts and the client module agree on.
# Local dev (SQLite file)
DATABASE_URL="file:./dev.db"
DATABASE_AUTH_TOKEN="" # leave empty for local SQLite
# Production (Turso)
# DATABASE_URL="libsql://<db>-<org>.turso.io"
# DATABASE_AUTH_TOKEN="eyJ..."
DATABASE_AUTH_TOKEN must be an empty string (not omitted) for local SQLite.
6. Run migrations
<pm> exec prisma migrate dev # creates dev.db + applies migrations + regenerates the client
<pm> exec prisma generate # regenerate the client after a schema-only change
From here on, /prisma:prisma-migrate covers day-to-day migration work.
Common errors and fixes
| Error | Cause | Fix |
|---|---|---|
P1012: datasource.url is not allowed |
url = env("DATABASE_URL") still in schema.prisma |
Remove url from the datasource block |
The datasource.url property is required |
prisma.config.ts missing, inside prisma/, or DATABASE_URL unset |
Move it to the project root; make sure dotenv loads your env file |
Cannot find module '@prisma/adapter-libsql' |
Package not installed | <pm> add @prisma/adapter-libsql@^7 |
driverAdapters is not a valid preview feature |
Old previewFeatures = ["driverAdapters"] in schema |
Remove it — GA in Prisma 7 |
Integrating with libraries that expect a Prisma client
Prisma 7's driver-adapter client is shaped differently from v5/v6 clients. Libraries that
auto-detect the adapter kind by inspecting the object may fall through to the wrong path
(BetterAuth, for instance, ends up in its Kysely path and throws Failed to initialize database adapter at startup). Default to the library's explicit Prisma adapter when it
offers one — e.g. prismaAdapter(db, { provider: "sqlite" }) from better-auth/adapters/prisma.
Configuration
This skill reads no keys from .claude/claude-skills.json; the package manager is detected from the lockfile.
To change this skill, do not edit this copy: use /dev-tools:update-skill, or see docs/updating-skills.md in mzvonar/claude-skills-public.