개요
이 가이드 에서는 MongoDB 와 통합되는 Next.js 웹 애플리케이션 만드는 방법을 학습 수 있습니다. Next.js는 단일 애플리케이션 에서 서버 측 렌더링, 정적 사이트 생성 및 API 경로를 제공하는 React 프레임워크 입니다. 이 튜토리얼의 애플리케이션 다음과 같은 계층으로 구성되어 있습니다.
데이터베이스 계층: MongoDB 데이터 저장 및 검색을 제공합니다.
API 계층: Next.js API 경로는 서버 측 로직 및 데이터베이스 작업을 처리하다 .
프레젠테이션 계층: React 구성 요소는 사용자 인터페이스와 프론트 엔드 상호 작용을 구현 .
Next.js 애플리케이션에서 MongoDB 사용하는 이유는 무엇인가요?
Next.js는 단일 코드베이스에서 애플리케이션 의 프론트엔드와 백엔드를 모두 빌드 할 수 있는 풀 스택 React 프레임워크 입니다. MongoDB Next.js와 통합하면 다음과 같은 이점을 활용할 수 있습니다.
통합 개발: JavaScript /TypeScript로 클라이언트 및 서버 코드 모두 작성
서버 측 렌더링: 서버 측 렌더링 중에 MongoDB 에서 데이터를 가져와서 검색 엔진 최적화 및 성능 개선
API 경로: MongoDB 에 직접 연결되는 서버리스 API 엔드포인트 생성
유연한 데이터 모델: MongoDB의 문서 모델 JavaScript 객체 및 React 구성 요소 상태 와 자연스럽게 정렬됩니다.
MongoDB 사용하는 Next.js는 동적 콘텐츠, 사용자 인증, 실시간 업데이트 및 복잡한 데이터 관계가 필요한 애플리케이션에 적합합니다.
빠른 시작 튜토리얼
이 튜토리얼에서는 Next.js와 MongoDB 사용하여 웹 애플리케이션 빌드 방법을 보여줍니다. 애플리케이션 샘플 레스토랑 데이터에 액세스하고, 데이터를 쿼리하고, 로컬에서 호스팅되는 사이트 에 결과를 표시합니다. 이 튜토리얼에는 MongoDB Atlas 에서 호스팅되는 MongoDB cluster 에 연결하고 데이터베이스 의 데이터에 액세스하고 표시하는 방법에 대한 지침도 포함되어 있습니다.
팁
Next.js 없이 Node.js 운전자 사용하여 MongoDB 에 연결하려는 경우 Node.js 드라이버 시작하기 가이드 참조하세요.
프로젝트 설정
이 섹션의 단계에 따라 프로젝트 종속성을 설치하고, Atlas 클러스터를 만들고, 애플리케이션 디렉토리를 설정합니다.
전제 조건 확인
애플리케이션 만들려면 개발 환경에 다음이 설치되어 있어야 합니다.
전제 조건 | 참고 사항 |
|---|---|
최신 LTS 또는 최신 릴리스 버전을 다운로드합니다. | |
코드 편집기 | 이 튜토리얼에서는 Visual Studio Code를 사용하지만 원하는 편집기를 사용할 수 있습니다. |
터미널 앱 또는 셸 | MacOS 사용자의 경우 터미널 또는 유사한 앱을 사용하세요. Windows 사용자의 경우 PowerShell을 사용하세요. |
MongoDB Atlas 클러스터 생성
MongoDB Atlas 는 MongoDB 배포서버를 호스팅하는 완전 관리형 클라우드 데이터베이스 서비스입니다. MongoDB 배포서버 없는 경우, MongoDB 시작하기 튜토리얼을 완료하여 무료로 MongoDB 클러스터 생성할 수 있습니다( 크레딧 카드 필요 없음). MongoDB 시작하기 튜토리얼에서는 이 튜토리얼에서 사용되는 sample_restaurants 데이터베이스 포함하여 샘플 데이터 세트를 클러스터 에 로드하는 방법도 보여줍니다.
MongoDB 클러스터에 연결하려면 연결 URI를 사용해야 합니다. 연결 URI를 조회 방법을 학습하려면 MongoDB 시작하기 튜토리얼의 연결 문자열 추가하기 섹션을 참조하세요.
중요
연결 string 을 안전한 위치 에 저장합니다.
데이터베이스 연결 구성
프로젝트 구조 및 종속성을 설정하다 한 후 이 섹션의 단계에 따라 데이터베이스 연결을 구성하세요.
환경 변수 설정
next-quickstart 디렉토리 에서 MongoDB 연결 URI를 저장하는 .env.local 파일 만듭니다.
MONGODB_URI=<connection URI>
<connection URI> 자리 표시자를 이전 단계에서 저장한 연결 URI로 바꿉니다.
참고
Next.js는 .env.local 파일에서 환경 변수를 자동으로 로드합니다. NEXT_PUBLIC_ 접두사가 붙은 변수는 브라우저에 노출되지만 다른 변수는 서버 에서만 사용할 수 있습니다.
데이터베이스 연결 유틸리티 만들기
루트 디렉토리 에서 lib라는 새 디렉토리 만듭니다. 이 디렉토리 에 mongodb.ts 라는 새 파일 추가하고 다음 코드를 붙여넣습니다.
import { MongoClient } from "mongodb"; declare global { var _mongoClientPromise: Promise<MongoClient> | undefined; } const uri = process.env.MONGODB_URI; const options = {}; let client: MongoClient; let clientPromise: Promise<MongoClient>; if (!uri) { throw new Error("Please add your Mongo URI to .env.local"); } client = new MongoClient(uri, options); clientPromise = client.connect(); // Export a module-scoped MongoClient promise. By doing this in a // separate module, the client can be shared across functions. export default clientPromise;
이 파일 애플리케이션 전체에서 공유되는 재사용 가능한 MongoDB 클라이언트 연결을 생성합니다. Next.js가 코드를 핫 리로드할 때 개발 중에 여러 연결이 생성되는 것을 방지하기 위해 연결이 캐시됩니다.
API 경로 만들기
데이터베이스 연결을 설정하다 한 후 이 섹션의 단계에 따라 MongoDB 쿼리 하고 레스토랑 데이터를 반환하는 API 경로를 생성합니다.
레스토랑 API 경로 만들기
app 디렉토리 에서 새 api/restaurants 디렉토리 만듭니다. 이 디렉토리 에 route.ts 라는 새 파일 추가하고 다음 코드를 붙여넣습니다.
import { NextResponse } from "next/server"; import clientPromise from "@/lib/mongodb"; export async function GET() { try { const client = await clientPromise; const db = client.db("sample_restaurants"); const restaurants = await db .collection("restaurants") .find({}) .toArray(); return NextResponse.json(restaurants); } catch { return NextResponse.json( { error: "Failed to fetch restaurants" }, { status: 500 } ); } }
이 파일 /api/restaurants 에서 sample_restaurants 데이터베이스 에서 모든 레스토랑을 검색하는 GET 엔드포인트를 정의합니다.
찾아보기 API 경로 만들기
app/api 디렉토리 에서 browse(이)라는 새 디렉토리 만듭니다. 이 디렉토리 에 route.ts 라는 새 파일 만들고 다음 코드를 붙여넣습니다.
import { NextResponse } from "next/server"; import clientPromise from "@/lib/mongodb"; export async function GET() { try { const client = await clientPromise; const db = client.db("sample_restaurants"); const query = { borough: "Queens", name: { $regex: "Moon", $options: "i" }, }; const restaurants = await db .collection("restaurants") .find(query) .toArray(); return NextResponse.json(restaurants); } catch { return NextResponse.json( { error: "Failed to fetch restaurants" }, { status: 500 } ); } }
이 파일 /api/browse 에서 특정 쿼리 기준과 일치하는 레스토랑을 검색하는 GET 엔드포인트를 정의합니다. 쿼리 이름에 "Moon" 라는 단어가 포함된 퀸즈의 레스토랑을 필터링합니다.
프런트 엔드 구성
API 경로를 설정하다 한 후 이 섹션의 단계에 따라 레스토랑 데이터를 표시하는 React 구성 요소를 만듭니다.
Navbar 구성 요소 만들기
루트 디렉토리 에서 components라는 새 디렉토리 만듭니다. 이 디렉토리 에 Navbar.tsx 라는 새 파일 추가하고 다음 코드를 붙여넣습니다.
import Link from "next/link"; export default function Navbar() { return ( <nav className="bg-gray-800 p-4"> <div className="container mx-auto flex justify-between items-center"> <Link href="/" className="text-white text-xl font-bold"> MongoDB Restaurants </Link> <div className="space-x-4"> <Link href="/" className="text-gray-300 hover:text-white transition-colors" > All Restaurants </Link> <Link href="/browse" className="text-gray-300 hover:text-white transition-colors" > Filtered Restaurants </Link> </div> </div> </nav> ); }
이 구성 요소는 모든 레스토랑과 필터링된 레스토랑을 볼 수 있는 링크가 포함된 탐색 바를 생성합니다.
레스토랑 목록 구성 요소 만들기
components 디렉토리 에서 RestaurantList.tsx 라는 새 파일 만들고 다음 코드를 붙여넣습니다.
"use client"; /* The above directive tells Next.js to render this component on the client side instead of the server side. Client components can use React hooks like useState and useEffect, while server components cannot. */ import { useEffect, useState } from "react"; import { ObjectId } from "mongodb"; interface Restaurant { _id: ObjectId; name: string; borough: string; cuisine: string; } interface RestaurantProps { restaurant: Restaurant; } const Restaurant = (props: RestaurantProps) => ( <tr className="border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted"> <td className="p-4 align-middle [&:has([role=checkbox])]:pr-0"> {props.restaurant.name} </td> <td className="p-4 align-middle [&:has([role=checkbox])]:pr-0"> {props.restaurant.borough} </td> <td className="p-4 align-middle [&:has([role=checkbox])]:pr-0"> {props.restaurant.cuisine} </td> </tr> ); interface RestaurantListProps { endpoint: string; title: string; } export default function RestaurantList({ endpoint, title }: RestaurantListProps) { const [restaurants, setRestaurants] = useState<Restaurant[]>([]); const [loading, setLoading] = useState(true); useEffect(() => { async function getRestaurants() { try { const response = await fetch(endpoint); if (!response.ok) { const message = `An error occurred: ${response.statusText}`; console.error(message); return; } const restaurants = await response.json(); setRestaurants(restaurants); } catch (error) { console.error("Error fetching restaurants:", error); } finally { setLoading(false); } } getRestaurants(); }, [endpoint]); function restaurantList() { return restaurants.map((restaurant) => { return <Restaurant restaurant={restaurant} key={restaurant._id.toString()} />; }); } if (loading) { return <div className="p-4">Loading...</div>; } return ( <> <h3 className="text-lg font-semibold p-4">{title}</h3> <div className="border rounded-lg overflow-hidden"> <div className="relative w-full overflow-auto"> <table className="w-full caption-bottom text-sm"> <thead className="[&_tr]:border-b"> <tr className="border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted"> <th className="h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0"> Name </th> <th className="h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0"> Borough </th> <th className="h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0"> Cuisine </th> </tr> </thead> <tbody className="[&_tr:last-child]:border-0"> {restaurantList()} </tbody> </table> </div> </div> </> ); }
이 구성 요소는 API 경로에서 레스토랑 데이터를 가져오고 표시합니다. React 후크를 사용하여 상태 관리 하고 구성 요소가 마운트될 때 데이터를 가져옵니다.
홈페이지 업데이트
app/page.tsx 파일 로 이동하여 내용을 다음 코드로 바꿉니다.
import RestaurantList from "@/components/RestaurantList"; export default function Home() { return ( <main className="container mx-auto p-4"> <RestaurantList endpoint="/api/restaurants" title="All Restaurants" /> </main> ); }
이 파일 데이터베이스 의 모든 레스토랑을 표시하는 홈페이지를 렌더링합니다.
찾아보기 페이지 만들기
app 디렉토리 에서 browse(이)라는 새 디렉토리 만듭니다. 이 디렉토리 에 page.tsx 라는 새 파일 추가하고 다음 코드를 붙여넣습니다.
import RestaurantList from "@/components/RestaurantList"; export default function Browse() { return ( <main className="container mx-auto p-4"> <RestaurantList endpoint="/api/browse" title='Filtered Restaurants (Queens, containing "Moon")' /> </main> ); }
이 파일 쿼리 기준에 따라 필터링된 레스토랑을 표시하는 찾아보기 페이지를 렌더링합니다.
레이아웃 업데이트
app/layout.tsx 파일 로 이동하여 내용을 다음 코드로 바꿉니다.
import "./globals.css"; import Navbar from "@/components/Navbar"; import { Metadata } from "next"; export const metadata: Metadata = { title: "MongoDB Next.js App", description: "A Next.js application with MongoDB integration", }; export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en"> <body> <Navbar /> {children} </body> </html> ); }
이 파일 탐색 모음을 포함하고 모든 페이지를 래핑하는 애플리케이션 의 루트 레이아웃을 정의합니다.
애플리케이션 실행하기
마지막으로 이 섹션의 단계에 따라 애플리케이션 실행 하고 렌더링된 레스토랑 데이터를 확인합니다.
애플리케이션 사이트 열기
http://localhost:3000/ URL 엽니다. 초기 방문 페이지에는 컬렉션 의 모든 레스토랑 목록이 sample_restaurants.restaurants 표시됩니다.

탐색 모음에서 Filtered Restaurants 링크를 클릭하면 name 및 borough 필드 쿼리 와 일치하는 레스토랑을 볼 수 있습니다.

빠른 시작 튜토리얼을 완료하신 것을 축하드립니다!
이 단계를 완료하면 MongoDB deployment 에 연결하고, 샘플 레스토랑 데이터에 대한 쿼리를 실행하고, 로컬에서 호스팅되는 웹사이트 에 결과를 렌더링하는 Next.js 웹 애플리케이션 이 생성됩니다.
추가 리소스
Next.js 및 MongoDB 에 대해 자세히 학습 다음 리소스를 참조하세요.
Node.js 운전자 문서
Next.js 문서