SHIN
Next.js App Router로 풀스택 블로그 만들기
9편□ .env.local에 모든 환경 변수 정의
□ prisma/dev.db가 .gitignore에 포함
□ public/uploads/가 .gitignore에 포함
□ npm run build 로컬 빌드 성공 확인
□ TypeScript 오류 없음 (tsc --noEmit)npm i -g vercel
vercel login
# 프로젝트 연결 및 배포
vercel
# 환경 변수 설정
vercel env add NEXTAUTH_SECRET
vercel env add NEXTAUTH_URL
vercel env add NEXT_PUBLIC_SITE_URL
# 프로덕션 배포
vercel --prodVercel의 서버리스 함수는 읽기 전용 파일시스템을 사용합니다. 따라서 SQLite 파일은 /tmp 디렉토리에서만 쓸 수 있고, 함수 인스턴스가 재시작되면 데이터가 사라집니다.
프로덕션 배포를 위한 선택지:
| 옵션 | 특징 |
|---|---|
| Turso | LibSQL 기반 SQLite 호환, 글로벌 복제 |
| PlanetScale | MySQL 호환, 브랜치 기능 |
| Supabase | PostgreSQL, 오픈소스 |
| Railway | 여러 DB 지원, 단순한 설정 |
Prisma의 datasource만 바꾸면 대부분의 코드는 그대로입니다.
// Turso로 전환 시
datasource db {
provider = "sqlite"
url = env("TURSO_DATABASE_URL")
}import NextImage from 'next/image'
// 외부 도메인 허용 설정 (next.config.ts)
// images: { remotePatterns: [{ hostname: 'example.com' }] }
// 사용
<NextImage
src={post.coverImage}
alt={post.title}
fill // 부모 컨테이너에 맞춤
sizes="(max-width: 768px) 100vw, 700px" // 반응형 힌트
priority={isAboveFold} // LCP 이미지는 priority
className="object-cover"
/>WebP/AVIF 자동 변환, 지연 로딩, 크기 최적화가 내장되어 있습니다.
// 포스트 조회 — 재사용 가능한 캐시
import { cache } from 'react'
const getPost = cache(async (slug: string) =>
prisma.post.findUnique({ where: { slug } })
)
// 같은 요청 내에서 여러 번 호출해도 DB 쿼리 1회// 설정 조회 — Next.js fetch 캐시
export async function getSettings() {
const res = await fetch(`${siteUrl}/api/settings`, {
next: { revalidate: 3600 }, // 1시간 캐시
})
return res.json()
}npm install -D @next/bundle-analyzer
# next.config.ts
import bundleAnalyzer from '@next/bundle-analyzer'
const withBundleAnalyzer = bundleAnalyzer({ enabled: process.env.ANALYZE === 'true' })
export default withBundleAnalyzer(nextConfig)
# 분석 실행
ANALYZE=true npm run build| 지표 | 목표 | 개선 방법 |
|---|---|---|
| LCP | < 2.5s | 커버 이미지 priority, 폰트 preload |
| FID/INP | < 200ms | 클라이언트 컴포넌트 최소화 |
| CLS | < 0.1 | 이미지 크기 고정, 폰트 font-display: swap |
| TTFB | < 800ms | 서버 응답 캐싱, Edge 함수 활용 |
이 시리즈를 통해 처음부터 실제 배포까지 Next.js App Router 기반 풀스택 블로그를 완성했습니다.
핵심 배운 점:
전체 소스는 GitHub 저장소에서 확인할 수 있습니다.