SvelteKit + Prisma 조합이면 프론트엔드 개발자도 풀스택 앱을 뚝딱 만들 수 있습니다.

개념 정의

Prisma 는 TypeScript/JavaScript를 위한 ORM입니다. 스키마 파일로 데이터 모델을 정의하고, 자동 생성된 타입 안전한 클라이언트로 데이터베이스를 조작합니다.

설정

BASH
npm install prisma @prisma/client
npx prisma init
PRISMA
// prisma/schema.prisma
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model User {
  id        String   @id @default(cuid())
  email     String   @unique
  name      String
  posts     Post[]
  createdAt DateTime @default(now())
}

model Post {
  id        String   @id @default(cuid())
  title     String
  content   String
  published Boolean  @default(false)
  author    User     @relation(fields: [authorId], references: [id])
  authorId  String
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}
BASH
npx prisma migrate dev --name init
npx prisma generate

Prisma 클라이언트 싱글턴

JAVASCRIPT
// src/lib/server/database.js
import { PrismaClient } from '@prisma/client';

// 개발 환경에서 핫 리로드 시 연결 누수 방지
const globalForPrisma = globalThis;

export const db = globalForPrisma.prisma ?? new PrismaClient();

if (process.env.NODE_ENV !== 'production') {
  globalForPrisma.prisma = db;
}

CRUD — 목록 조회

JAVASCRIPT
// src/routes/posts/+page.server.js
import { db } from '$lib/server/database';

export async function load({ url }) {
  const page = Number(url.searchParams.get('page') ?? '1');
  const limit = 10;

  const [posts, total] = await Promise.all([
    db.post.findMany({
      where: { published: true },
      include: { author: { select: { name: true } } },
      orderBy: { createdAt: 'desc' },
      skip: (page - 1) * limit,
      take: limit,
    }),
    db.post.count({ where: { published: true } }),
  ]);

  return {
    posts,
    pagination: { page, limit, total, totalPages: Math.ceil(total / limit) },
  };
}

CRUD — 생성

JAVASCRIPT
// src/routes/posts/new/+page.server.js
import { fail, redirect } from '@sveltejs/kit';
import { db } from '$lib/server/database';

export const actions = {
  default: async ({ request, locals }) => {
    if (!locals.user) redirect(302, '/login');

    const formData = await request.formData();
    const title = formData.get('title')?.toString();
    const content = formData.get('content')?.toString();

    if (!title || title.length < 2) {
      return fail(400, { title, content, error: '제목은 2자 이상이어야 합니다' });
    }

    const post = await db.post.create({
      data: {
        title,
        content: content ?? '',
        authorId: locals.user.id,
      }
    });

    redirect(303, `/posts/${post.id}`);
  }
};

CRUD — 수정/삭제

JAVASCRIPT
// src/routes/posts/[id]/edit/+page.server.js
import { error, fail, redirect } from '@sveltejs/kit';
import { db } from '$lib/server/database';

export async function load({ params, locals }) {
  const post = await db.post.findUnique({ where: { id: params.id } });

  if (!post) error(404, '포스트를 찾을 수 없습니다');
  if (post.authorId !== locals.user?.id) error(403, '권한이 없습니다');

  return { post };
}

export const actions = {
  update: async ({ request, params }) => {
    const formData = await request.formData();
    await db.post.update({
      where: { id: params.id },
      data: {
        title: formData.get('title')?.toString(),
        content: formData.get('content')?.toString(),
      }
    });
    redirect(303, `/posts/${params.id}`);
  },

  delete: async ({ params }) => {
    await db.post.delete({ where: { id: params.id } });
    redirect(303, '/posts');
  },
};

트랜잭션

JAVASCRIPT
// 여러 작업을 하나의 트랜잭션으로
async function transferPost(postId, newAuthorId) {
  await db.$transaction([
    db.post.update({
      where: { id: postId },
      data: { authorId: newAuthorId },
    }),
    db.auditLog.create({
      data: {
        action: 'TRANSFER_POST',
        postId,
        newAuthorId,
      },
    }),
  ]);
}

면접 포인트

  • "ORM을 사용하는 이유는?": 타입 안전한 쿼리, 마이그레이션 관리, SQL 인젝션 방지를 자동으로 제공합니다. Prisma는 스키마에서 TypeScript 타입을 자동 생성하여 개발 경험이 우수합니다.
  • "Prisma 클라이언트 싱글턴이 왜 필요한가요?": 개발 모드에서 핫 리로드 시마다 새 PrismaClient가 생성되면 데이터베이스 연결이 고갈됩니다. 전역 변수에 캐시하여 연결 재사용을 보장합니다.

정리

SvelteKit + Prisma는 풀스택 개발의 가장 생산적인 조합 중 하나입니다. Prisma의 타입 안전한 쿼리와 SvelteKit의 load/actions 패턴이 자연스럽게 결합되어, 보안적이고 타입 안전한 CRUD 앱을 빠르게 구축할 수 있습니다.

댓글 로딩 중...