Next.js 13 이상에서는 React 서버 컴포넌트(RSC) 덕분에, 별도의 API 서버 없이 서버에서 직접 데이터베이스에 접근할 수 있습니다.
이 글에서는 SQLite와 MySQL을 예시로, 안전하게 서버 컴포넌트에서 DB를 다루는 방법과 장점을 그림과 함께 정리했습니다.
왜 별도 API 서버를 제거해야 할까?
서버를 두 개 운영하는 경우, 특별한 이유(예: 마이크로서비스, 레거시 API 통합)가 없다면 불필요한 HTTP 왕복이 발생하여 성능이 떨어집니다.
| 장점 | 설명 |
| HTTP 왕복 제거 | 서버 → 서버 → DB 요청 없이, 서버 컴포넌트에서 바로 데이터 조회 |
| 코드 단순화 | 데이터 로직이 한 프로젝트 안에서 관리되어 배포와 유지보수가 쉬움 |
단, 외부 API 호출이나 마이크로서비스 구조에서는 여전히 별도의 API 서버가 필요합니다.
서버 컴포넌트에서 DB 직접 접근이 가능한 이유
서버 컴포넌트는 Node.js 환경에서만 실행되며, 클라이언트에는 전송되지 않습니다.
| 구분 | 서버 컴포넌트 | 클라이언트 컴포넌트 |
| 실행 환경 | Node.js (서버) | 브라우저 (클라이언트) |
| 접근 권한 | 로컬 파일, DB, 환경변수 가능 | 서버 자원 접근 불가 |
| 결론 | DB 코드 안전하게 실행 가능 | DB 코드 실행 불가, 보안 위험 |
⚠️ 실제 보안 관점에서는 DB 계정 권한, 환경변수 관리, 인증/권한 처리까지 함께 고려해야 안전합니다.
SQLite vs MySQL 한눈에 비교
| 특징 | SQLite | MySQL |
| 접근 방식 | 파일 기반 (data.db) | 서버 기반 (host, port 필요) |
| API | 동기(synchronous) | 비동기(asynchronous, Promise) |
| 동시 접속 | 제한적, 소규모 적합 | 다중 사용자 지원, 대규모 환경 적합 |
| Next.js 서버 컴포넌트 | 동기 호출 가능 | async/await 필요 |
| 설치 | 가볍고 간단 | 서버 설치 필요 |
💡 요약: SQLite는 로컬/테스트용, MySQL은 프로덕션 환경에서 적합합니다.
구현 예시
a. SQLite (동기 API)
// lib/news.js
import sql from 'better-sqlite3';
import path from 'path';
const dbPath = path.resolve('./data/data.db');
const db = sql(dbPath);
export function getAllNews() {
return db.prepare('SELECT * FROM news').all();
}
// app/news/page.js
import NewsList from '@/components/news-list';
import { getAllNews } from '@/lib/news';
export default function NewsPage() {
const news = getAllNews();
return (
<>
<h1>News Page</h1>
<NewsList news={news} />
</>
);
}
⚠️ 주의: 동기 호출은 대규모 동시 접속 환경에서 블로킹 가능
b. MySQL (비동기 API)
// lib/db-mysql.js
import mysql from 'mysql2/promise';
const pool = mysql.createPool({
host: 'localhost',
user: 'user',
password: 'password',
database: 'nextjs_db'
});
export async function getAllNews() {
const [rows] = await pool.query('SELECT * FROM news');
return rows;
}
// app/news/page.js
import NewsList from '@/components/news-list';
import { getAllNews } from '@/lib/db-mysql';
export default async function NewsPage() {
const news = await getAllNews();
return (
<>
<h1>News Page</h1>
<NewsList news={news} />
</>
);
}
5️⃣ 시각화: 서버 컴포넌트 + DB 직접 접근 구조
┌─────────────────────┐
│ Next.js 서버 컴포넌트 │
│ (NewsPage) │
└─────────┬───────────┘
│ 직접 호출
▼
┌─────────────────────┐
│ DB 로직 (lib/news) │
└─────────┬───────────┘
│ SQLite 파일 / MySQL 서버
▼
┌─────────────────────┐
│ 데이터베이스 │
│ (news 테이블) │
└─────────────────────┘
- 클라이언트에는 완성된 HTML + JSON 데이터만 전달
- DB 접속 정보는 서버 내부에만 존재, 브라우저에 노출되지 않음
장점 요약
| 장점 | 설명 |
| ✅ 최고 성능 | 불필요한 HTTP 요청 제거, 서버에서 바로 렌더링 |
| ✅ SEO 최적화 | 서버에서 HTML 생성 → 검색 엔진에 완전한 콘텐츠 전달 |
| ✅ 코드 단순화 | API 서버 없이 Next.js 프로젝트 내 통합 관리 |
| ✅ 보안 확보 | 서버 컴포넌트에서만 DB 접근, 클라이언트 노출 X |
'NextJS' 카테고리의 다른 글
| [NextJS] SSR과 Hydration 에러 해결 방법 (0) | 2025.10.21 |
|---|---|
| NextJS 로딩 상태 처리 (0) | 2025.10.20 |
| [NextJS] 서버 컴포넌트에서 데이터 직접 가져오기 (Server-Side Fetching) (0) | 2025.10.18 |
| [NextJS] 클라이언트 측에서 백엔드 API 데이터 가져오기 (feat. useEffect) (0) | 2025.10.18 |
| [NextJS] Pre-Renders(사전 랜더링) Page(페이지) (0) | 2024.04.20 |