Database Integration
Powerful database management with Prisma ORM, supporting PostgreSQL, MySQL, SQLite, and MongoDB.
Overview
ShadPanel integrates seamlessly with Prisma to provide:
- ✅ Multi-Database Support - PostgreSQL, MySQL, SQLite, MongoDB
 - ✅ Type-Safe Queries - Auto-generated TypeScript types
 - ✅ Schema Management - Template-based schema generation
 - ✅ Migrations - Track and apply database changes
 - ✅ Prisma Studio - Visual database browser
 - ✅ CLI Commands - Easy database management via 
shadpanel db 
Quick Start
Initialize Database
Run the interactive database setup:
cd my-app
shadpanel db initThis will:
- Prompt for database type (PostgreSQL, MySQL, SQLite, MongoDB)
 - Create 
.envwith connection string template - Create 
prisma/schema.prisma.template - Optionally install Prisma packages
 
Configure Connection
Edit .env with your database credentials:
# PostgreSQL
DATABASE_URL="postgresql://user:password@localhost:5432/mydb?schema=public"
 
# MySQL
DATABASE_URL="mysql://user:password@localhost:3306/mydb"
 
# SQLite
DATABASE_URL="file:./dev.db"
 
# MongoDB
DATABASE_URL="mongodb+srv://user:password@cluster.mongodb.net/mydb"Define Schema
Edit prisma/schema.prisma.template:
datasource db {
  provider = "{{DATABASE_DRIVER}}"
  url      = "{{DATABASE_URL}}"
}
 
generator client {
  provider = "prisma-client-js"
}
 
model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  name      String?
  posts     Post[]
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}
 
model Post {
  id        Int      @id @default(autoincrement())
  title     String
  content   String?
  published Boolean  @default(false)
  authorId  Int
  author    User     @relation(fields: [authorId], references: [id])
  createdAt DateTime @default(now())
}Generate and Migrate
# Generate schema from template and run migration
shadpanel db migrate init --regenerate
 
# Generate Prisma Client
shadpanel db generateUsing Prisma Client
Create Client Instance
// lib/prisma.ts
import { PrismaClient } from '@prisma/client'
 
const globalForPrisma = globalThis as unknown as {
  prisma: PrismaClient | undefined
}
 
export const prisma = globalForPrisma.prisma ?? new PrismaClient()
 
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prismaCRUD Operations
Create
import { prisma } from '@/lib/prisma'
 
// Create a user
const user = await prisma.user.create({
  data: {
    email: 'john@example.com',
    name: 'John Doe',
  },
})
 
// Create with relations
const post = await prisma.post.create({
  data: {
    title: 'Hello World',
    content: 'This is my first post',
    author: {
      connect: { id: user.id },
    },
  },
})Read
// Find all users
const users = await prisma.user.findMany()
 
// Find by ID
const user = await prisma.user.findUnique({
  where: { id: 1 },
})
 
// Find with relations
const userWithPosts = await prisma.user.findUnique({
  where: { id: 1 },
  include: { posts: true },
})
 
// Find with filters
const activeUsers = await prisma.user.findMany({
  where: {
    email: {
      contains: '@example.com',
    },
    posts: {
      some: {
        published: true,
      },
    },
  },
})Update
// Update single record
const updatedUser = await prisma.user.update({
  where: { id: 1 },
  data: {
    name: 'Jane Doe',
  },
})
 
// Update many
const result = await prisma.user.updateMany({
  where: {
    email: {
      contains: '@example.com',
    },
  },
  data: {
    verified: true,
  },
})Delete
// Delete single record
const deletedUser = await prisma.user.delete({
  where: { id: 1 },
})
 
// Delete many
const result = await prisma.user.deleteMany({
  where: {
    createdAt: {
      lt: new Date('2023-01-01'),
    },
  },
})Next.js Integration
Server Components
Use Prisma directly in Server Components:
// app/users/page.tsx
import { prisma } from '@/lib/prisma'
 
export default async function UsersPage() {
  const users = await prisma.user.findMany({
    orderBy: { createdAt: 'desc' },
  })
 
  return (
    <div>
      <h1>Users</h1>
      <ul>
        {users.map((user) => (
          <li key={user.id}>
            {user.name} ({user.email})
          </li>
        ))}
      </ul>
    </div>
  )
}API Routes
Use Prisma in API routes:
// app/api/users/route.ts
import { NextResponse } from 'next/server'
import { prisma } from '@/lib/prisma'
 
export async function GET() {
  const users = await prisma.user.findMany()
  return NextResponse.json(users)
}
 
export async function POST(request: Request) {
  const body = await request.json()
 
  const user = await prisma.user.create({
    data: {
      email: body.email,
      name: body.name,
    },
  })
 
  return NextResponse.json(user)
}Server Actions
Use Prisma in Server Actions:
// app/actions/users.ts
'use server'
 
import { prisma } from '@/lib/prisma'
import { revalidatePath } from 'next/cache'
 
export async function createUser(formData: FormData) {
  const user = await prisma.user.create({
    data: {
      email: formData.get('email') as string,
      name: formData.get('name') as string,
    },
  })
 
  revalidatePath('/users')
  return user
}
 
export async function deleteUser(id: number) {
  await prisma.user.delete({
    where: { id },
  })
 
  revalidatePath('/users')
}Schema Management
Note: The
shadpanel db generate-schemacommand was removed — define your schema manually inprisma/schema.prisma(or render your template intoprisma/schema.prisma). After updating the schema, run migrations or push and then runshadpanel db generateto update the Prisma Client.
Template Workflow
ShadPanel supports template-based schemas for reusability:
- 
Edit template:
# Edit prisma/schema.prisma.template - 
Render or update schema:
 
- Edit 
prisma/schema.prisma.templateand render or copy the result toprisma/schema.prismaas part of your workflow. 
- Migrate:
 
# Create and apply a migration (template regeneration supported)
shadpanel db migrate update --regenerateBenefits:
- Version controlled template
 - Reusable across environments
 - Consistent team setup
 
Direct Editing Workflow
For simple projects:
- Edit schema directly:
 
# Edit prisma/schema.prisma- Apply changes and generate client:
 
- Create a migration and apply it:
shadpanel db migrate [name] - Or, for quick prototyping without migration history:
shadpanel db push 
After applying changes, regenerate the Prisma Client:
shadpanel db generateMigrations
Creating Migrations
# Create migration from schema changes
shadpanel db migrate add_users_table
 
# With template regeneration
shadpanel db migrate add_users_table --regenerateApplying Migrations
Migrations are applied automatically when created. To apply pending migrations:
npx prisma migrate deployMigration History
View migrations:
ls prisma/migrations/Each migration folder contains:
migration.sql- SQL statements- Migration timestamp in folder name
 
Reset Database
Reset and reapply all migrations:
shadpanel db resetWarning: This deletes all data!
Prisma Studio
Visual database browser:
shadpanel db studioOpens at http://localhost:5555
Features:
- Browse all tables
 - Create, edit, delete records
 - Filter and search
 - View relations
 
Seeding
Create Seed Script
// prisma/seed.ts
import { PrismaClient } from '@prisma/client'
 
const prisma = new PrismaClient()
 
async function main() {
  // Delete existing data
  await prisma.post.deleteMany()
  await prisma.user.deleteMany()
 
  // Create users
  const alice = await prisma.user.create({
    data: {
      email: 'alice@example.com',
      name: 'Alice',
      posts: {
        create: [
          {
            title: 'First Post',
            content: 'Hello World!',
            published: true,
          },
        ],
      },
    },
  })
 
  const bob = await prisma.user.create({
    data: {
      email: 'bob@example.com',
      name: 'Bob',
      posts: {
        create: [
          {
            title: 'Second Post',
            content: 'Learning Prisma',
            published: false,
          },
        ],
      },
    },
  })
 
  console.log({ alice, bob })
}
 
main()
  .then(async () => {
    await prisma.$disconnect()
  })
  .catch(async (e) => {
    console.error(e)
    await prisma.$disconnect()
    process.exit(1)
  })Configure Seed Command
// package.json
{
  "prisma": {
    "seed": "tsx prisma/seed.ts"
  }
}Run Seed
shadpanel db seedAdvanced Patterns
Transactions
const [user, post] = await prisma.$transaction([
  prisma.user.create({
    data: { email: 'user@example.com', name: 'User' },
  }),
  prisma.post.create({
    data: { title: 'Post', content: 'Content' },
  }),
])Raw Queries
// Raw SQL
const users = await prisma.$queryRaw`
  SELECT * FROM "User" WHERE "email" LIKE ${pattern}
`
 
// Execute SQL
await prisma.$executeRaw`
  UPDATE "User" SET "verified" = true WHERE "email" = ${email}
`Middleware
const prisma = new PrismaClient()
 
prisma.$use(async (params, next) => {
  const before = Date.now()
  const result = await next(params)
  const after = Date.now()
 
  console.log(`Query ${params.model}.${params.action} took ${after - before}ms`)
 
  return result
})Soft Deletes
model User {
  id        Int       @id @default(autoincrement())
  email     String    @unique
  name      String?
  deletedAt DateTime?
}// Soft delete
await prisma.user.update({
  where: { id: 1 },
  data: { deletedAt: new Date() },
})
 
// Query only non-deleted
const activeUsers = await prisma.user.findMany({
  where: { deletedAt: null },
})Database-Specific Features
PostgreSQL
model User {
  id    Int    @id @default(autoincrement())
  email String @unique
  data  Json   // JSON field
  tags  String[] // Array field
}MySQL
model Post {
  id      Int      @id @default(autoincrement())
  title   String   @db.VarChar(255)
  content String   @db.Text
  views   Int      @default(0) @db.UnsignedInt
}MongoDB
model User {
  id    String @id @default(auto()) @map("_id") @db.ObjectId
  email String @unique
  posts Post[]
}
 
model Post {
  id       String @id @default(auto()) @map("_id") @db.ObjectId
  title    String
  authorId String @db.ObjectId
  author   User   @relation(fields: [authorId], references: [id])
}Best Practices
1. Connection Pooling
// lib/prisma.ts - Singleton pattern
const prisma = globalForPrisma.prisma ?? new PrismaClient({
  log: ['query', 'error', 'warn'],
})2. Error Handling
try {
  const user = await prisma.user.create({ data })
} catch (error) {
  if (error instanceof Prisma.PrismaClientKnownRequestError) {
    if (error.code === 'P2002') {
      console.error('Unique constraint violation')
    }
  }
  throw error
}3. Indexing
model User {
  email String @unique
  name  String
 
  @@index([name])
  @@index([email, name])
}4. Pagination
const page = 1
const pageSize = 10
 
const users = await prisma.user.findMany({
  skip: (page - 1) * pageSize,
  take: pageSize,
})5. Select Only Needed Fields
const users = await prisma.user.findMany({
  select: {
    id: true,
    email: true,
    name: true,
    // Don't include password
  },
})Troubleshooting
Migration Conflicts
# Mark migration as rolled back
npx prisma migrate resolve --rolled-back migration_name
 
# Mark migration as applied
npx prisma migrate resolve --applied migration_nameSchema Out of Sync
# Pull schema from database
shadpanel db pull
 
# Push schema to database (no migrations)
shadpanel db pushConnection Issues
Check .env configuration:
echo $DATABASE_URLTest connection:
npx prisma db execute --stdin <<< "SELECT 1"Next Steps
- CLI Database Commands - Complete command reference
 - Prisma Documentation - Official Prisma docs
 - Authentication - Integrate auth with database