#MVP
#monorepo
#Fastify
#react
#react native
#Prisma ORM
#Supabase
Korean
Written by Paul
December 8, 2025
보일러 플레이트 템플릿 생성 CLIpackages/prisma-schemabinaryTargetsenv 설정apps/server폴더 구조 안내로컬환경에서 실행하기배포하기배포 명령어hoist 환경 주의사항Layer 구성packages/api-sdk환경변수 설정코드 생성 실행활용 방식apps/RNApp마치며
COLDSURF. 1년여의 기록을 마무리하며.
이번 글에서는 지난 시간 동안 운영해 온 제품 실험의 끝자락에서, 지속 가능성을 갖춘 MVP를 구현하기 위해 어떤 기술 스택을 선택해야 하며, 또한 그에 맞는 보일러플레이트 구성은 어떠해야 하는지에 대해 정리해보고자 합니다.
무리한 확장보다는 유지 가능한 설계, 불필요한 복잡성보다는 운영 가능한 단순성을 중심에 둔 접근을 다루겠습니다.
보일러 플레이트 템플릿 생성 CLI
본격적인 설명에 앞서, 지속 가능한 MVP를 빠르게 시작할 수 있도록 준비해 둔 보일러플레이트 템플릿을 먼저 소개합니다.
위 명령어로 프로젝트를 생성하면, 운영 가능한 수준의 기술 스택과 기본 구조가 갖춰진 템플릿이 자동으로 세팅됩니다.
템플릿의 전체 구성은 아래 레포지토리에서 확인하실 수 있습니다.
https://github.com/coldsurfers/create-mvp-surf-cli
해당 CLI는 다음 레포지토리의 main 브랜치를 그대로 가져오도록 설정되어 있습니다.
https://github.com/coldsurfers/create-mvp-surf
이제부터 이 템플릿에 포함된 요소들을 하나씩 살펴보며, 각각이 어떤 역할을 수행하는지 정리해보겠습니다.
packages/prisma-schema
첫 번째로 살펴볼 모노레포 패키지는 prisma-schema입니다.
비즈니스 데이터의 중심이 되는 모델을 정의하고 있으므로, 템플릿 구성 설명에서도 가장 먼저 짚고 넘어가야 할 영역입니다.
아래는 템플릿에 기본 설정으로 포함된 schema.prisma 예시입니다.
binaryTargets
binaryTargets는 실제 배포 환경에서 Prisma Client가 동작하기 위한 런타임 타겟을 지정하는 옵션입니다.
AWS Lambda 배포를 고려한다면, Linux 환경 기반의 OpenSSL 설정이 필수이므로 아래와 같이 포함해두었습니다.
- rhel-openssl-3.0.x
- debian-openssl-3.0.x
이를 통해 로컬(Mac)과 서버(Linux) 간 바이너리 불일치로 인한 libquery-engine 오류를 예방할 수 있습니다.
env 설정
이 템플릿은 기본적으로 Supabase PostgreSQL과 연결되도록 구성되어 있습니다.
연동을 위해서는 .env.sample을 참고해 .env 파일을 생성한 뒤 다음 값을 채워 넣으면 됩니다.
- DATABASE_URL
- DIRECT_URL
필요한 연결 정보는 Supabase 프로젝트의 Connection Settings에서 확인하실 수 있습니다.
apps/server
prisma-schema 패키지를 살펴보았으니, 이제 이를 실제로 활용하는 Node.js 기반 서버 구성으로 넘어가겠습니다.
템플릿에서는 apps/server 디렉터리에 Fastify 기반 서버 보일러플레이트가 준비되어 있습니다.
이 서버는 Fastify를 중심으로 구성되며, 기본적인 실행 환경에 필요한 모듈들은 모두 package.json에 사전 정의되어 있으므로 아래 명령어만 실행하면 됩니다.
또한 추후 React Native App 및 Next.js Web 클라이언트에서 공용으로 사용할 api-sdk 자동 코드 생성을 대비하여,
zod 스키마 기반의 Swagger 설정도 포함해두었습니다.
즉, 서버에서 정의한 타입과 DTO 구조를 SDK 형태로 안전하게 공유할 수 있는 준비가 되어 있습니다.
폴더 구조 안내
Fastify 서버는 Controller → Service → Repository 구조로 명확히 구분되어 있어,
역할 단위 확장과 유지보수에 적합한 형태로 설계되어 있습니다.
로컬환경에서 실행하기
명령어 실행 후 http://localhost:3001 에서 개발 서버를 확인하실 수 있습니다.
API 문서는 아래 경로에서 Swagger UI로 제공됩니다.
- http://localhost:3001/docs
로컬 개발 환경은 tsup을 통해 Node 서버를 번들링하여 구동하는 방식이며,
아직 hot reload는 적용되어 있지 않습니다.
따라서 서버 관련 파일 변경 후에는 한 번 더 아래 명령어로 재실행해 주세요.
배포하기
템플릿에는 AWS Lambda 기반 서버 배포 설정이 기본 탑재되어 있으며,
serverless 프레임워크를 사용해 손쉽게 프로덕션 및 개발 환경을 구성할 수 있습니다.
우선 .env에 serverless 관련 환경 변수를 먼저 세팅해 주세요.
(예: AWS 자격 정보, STAGE, REGION 등)
배포 명령어
Turbo를 사용 중이라면:
일반 pnpm 환경이라면:
hoist 환경 주의사항
본 템플릿은 pnpm 기반 monorepo이면서 .npmrc에 hoist 설정이 활성화되어 있습니다.
따라서 서버를 Lambda로 패키징하기 전, apps/server/node_modules 하위에 필요한 의존성을 모아야 합니다.
이를 자동화하기 위해 serverless-pre-build.mjs 스크립트가 포함되어 있으며,
package.json에는 다음과 같이 설정되어 있습니다.
Layer 구성
Lambda는 일정 용량 이상 zip 패키지가 초과되면 배포가 불가능하기 때문에
Layer 기반 의존성 분리가 필수적입니다.
해당 설정은 아래에서 확인할 수 있습니다.
- serverless.yml
- scripts/serverless-pre-build.mjs
이 스크립트는 다음 역할을 수행합니다.
- hoist된 모듈 정리
- Layer 전용 디렉터리 생성
- 배포 패키지 최소화
- Prisma 엔진 등 런타임 바이너리 동작 환경 맞춤 구성
packages/api-sdk
서버 구성이 완료되었다면, 이제 서버에서 노출되는 Swagger 기반 API 스펙을 토대로 자동 코드 생성(codegen)을 진행할 차례입니다.
환경변수 설정
먼저 아래 파일을 준비해주세요.
.env.sample 을 참고하여 동일한 키 구조로 값을 채우면 됩니다.
(여기에는 Swagger 문서 URL 및 스키마 다운로드 경로가 포함됩니다.)
코드 생성 실행
명령어 실행 후, 서버에 배포되어 있는 Swagger 스펙을 기반으로 타입이 자동 생성됩니다.
생성 결과는 다음 경로에서 확인할 수 있습니다.
types/api.ts활용 방식
생성된 API 타입 파일은 이후 다음과 같은 용도로 사용됩니다.
- 클라이언트 앱(RN, Next.js 등)에서 공용 타입 참조
- fetcher SDK 구성 시 기반 타입 제공
- DTO 및 응답 타입 안전성 보장
- 중복 선언 없이 서버–클라이언트 간 스펙 싱크 유지
즉, 서버에서 스키마가 변경되더라도 swagger:dev만 다시 실행하면 클라이언트 타입도 자동 갱신되므로,
운영 과정에서 스키마 불일치로 인한 오류를 크게 줄일 수 있습니다.
apps/RNApp
RNApp은 기본적으로 React Native 0.81.4 버전을 기반으로 구성되어 있습니다.
필요하지 않다면 해당 앱을 제거해도 무방하며, 웹 중심 구조를 원하신다면 apps 디렉터리 아래에 Next.js 앱을 추가해도 됩니다.
모노레포 환경에 따른 설정은 아래 파일에서 확인할 수 있습니다.
- babel.config.js
- metro.config.js
두 설정 파일에는 워크스페이스 패키지 참조, alias 경로, shared 모듈 로딩 등을 위한 설정이 포함되어 있습니다.
또한 Android 네이티브 관련 초기 세팅은 다음 위치에서 확인하실 수 있습니다.
- android/build.gradle
- android/app/build.gradle
React Native 환경 특성상, 네이티브 단의 빌드 스펙이나 SDK 버전, JDK 설정 등이 이 두 파일에서 관리되므로, 패키지 업데이트나 네이티브 모듈 추가 시 참고해 주세요.
마치며
이번 글에서는 CLI를 활용한 템플릿 설치와 구조 소개까지, 비교적 가벼운 범위만 함께 살펴보았습니다.
전체 내용을 글로 모두 담기에는 분량이 방대해질 수 있어, 심화된 주제(배포 자동화, Lambda 최적화, Codegen 파이프라인, RN/Next 공용 SDK 활용 등)는 추후 영상 형태로 다뤄볼 예정입니다.
이 시리즈는 COLDSURF와 함께한 1년여의 빌드 여정을 되돌아보는 기록이기도 합니다.
짧지 않은 시간 동안 프로덕트를 실험하고, 쌓인 문제들을 해소하며 얻어낸 통찰을 정리하는 과정이기도 했습니다.
단순히 MVP 하나를 구성하는 데 이렇게 많은 공수가 필요한가 의문이 들 수 있습니다.
하지만 앞서 언급했던
에서 다뤘듯이, 모든 프로덕트에는 수면 아래 숨겨진 거대한 얼음층이 존재합니다.
이 빙하층은 첫 설계부터 차곡차곡 쌓이며, 운영과 피벗, 확장과 축소의 모든 지점에 영향을 줍니다.
처음부터 과도한 스펙으로 MVP를 구성하면, 어느 순간 마이그레이션 자체가 프로덕트 운영을 마비시키는 일이 벌어질 수 있습니다.
반대로 너무 가벼워도 확장 단계에서 모든 기반을 다시 설계해야 하는 상황이 찾아옵니다.
결국 중요한 것은 “확장 가능하지만, 무리하지 않는 시작”이며, 이번 템플릿은 그 균형에 맞춰 설계되었습니다.
이 글이 지금 각자의 자리에서 MVP를 구축하고 있는 팀과 창작자에게 작은 방향성이 되어 주길 바랍니다.
수많은 오류 수정과 리팩터링, 배포 실패와 재시도, 그 속에서 작게 쌓인 경험이 결국 빙하 아래를 단단하게 다지는 시간이라고 믿습니다.
끝으로, 오늘도 자신만의 프로덕트를 실제로 만들어내고 있는 모든 팀과 빌더에게 아낌없는 응원을 보냅니다.
감사합니다.