화면을 고치는 일과 내용을 고치는 일은 다릅니다
웹사이트를 운영하다 보면 문구를 자주 바꾸게 됩니다. 공지사항을 추가하고, 상품 가격을 바꾸고, 팀원 소개를 업데이트하고, 고객 후기를 더합니다.
이때 매번 app/page.tsx 전체를 열어 화면 구조를 고치면 위험합니다. 버튼, 카드, 여백, 링크 구조까지 함께 건드리게 되기 때문입니다. 작은 오타 하나로 화면 전체가 깨질 수도 있습니다.
좋은 습관은 화면 구조와 콘텐츠를 분리하는 것입니다.
비유하자면 화면 구조는 진열장이고, 콘텐츠는 진열장 안에 놓는 상품입니다. 상품 이름표를 바꾸려고 진열장 자체를 다시 만들 필요는 없습니다. Next.js에서도 마찬가지입니다. 카드 모양은 그대로 두고, 카드 안에 들어갈 제목·설명·이미지만 따로 관리하면 훨씬 안전합니다.
이번 장의 목표는 간단합니다.
매번 화면 전체를 고치지 않고, 내용만 바꾸는 구조를 만든다.
AI 생성 이미지
배열과 객체를 표처럼 이해하기
콘텐츠를 따로 관리할 때 자주 만나는 단어가 객체와 배열입니다.
객체는 한 사람의 프로필 카드처럼 이해하면 됩니다. 이름, 직무, 소개 문장처럼 서로 관련 있는 정보를 한 묶음으로 담습니다.
{
name: "김하나",
role: "마케팅 매니저",
description: "브랜드 메시지와 콘텐츠 전략을 담당합니다."
}여기서 name, role, description은 항목 이름입니다. 표로 보면 열 제목에 가깝습니다. "김하나", "마케팅 매니저" 같은 값은 실제 내용입니다.
배열은 이런 객체를 여러 줄 모아 놓은 목록입니다. 엑셀이나 구글 스프레드시트의 여러 행을 떠올리면 됩니다.
const teamMembers = [
{
name: "김하나",
role: "마케팅 매니저",
description: "브랜드 메시지와 콘텐츠 전략을 담당합니다."
},
{
name: "이준호",
role: "디자이너",
description: "웹사이트 화면과 시각 자료를 디자인합니다."
}
];처음에는 기호가 낯설 수 있습니다. 하지만 의미만 보면 단순합니다.
{ }는 한 명, 한 상품, 한 글처럼 하나의 묶음입니다.[ ]는 그런 묶음을 여러 개 담는 목록입니다.name: "김하나"는 "이 항목의 이름은 김하나"라는 뜻입니다.각 항목 사이에는 쉼표
,가 필요합니다.
즉 배열과 객체는 개발자만 쓰는 어려운 문법이라기보다, 웹사이트 콘텐츠를 표처럼 정리하는 방법입니다.
상품 목록을 데이터 파일 하나에서 관리하기
이제 실제로 콘텐츠를 분리해 보겠습니다. 예를 들어 상품 소개 카드가 여러 개 있는 페이지를 만든다고 합시다.
먼저 프로젝트의 가장 바깥쪽에 data 폴더를 만들고, 그 안에 products.ts 파일을 만듭니다.
my-next-site
├─ app
├─ components
├─ data
│ └─ products.ts
└─ publicdata/products.ts 파일에는 상품 내용만 적습니다.
export const products = [
{
title: "스타터 패키지",
description: "처음 시작하는 팀을 위한 기본 홈페이지 구성입니다.",
price: "990,000원부터",
image: "/product-starter.jpg"
},
{
title: "브랜드 패키지",
description: "소개 페이지, 서비스 페이지, 문의 페이지를 함께 구성합니다.",
price: "1,900,000원부터",
image: "/product-brand.jpg"
},
{
title: "콘텐츠 패키지",
description: "블로그와 공지사항처럼 꾸준히 쌓이는 콘텐츠 구조를 만듭니다.",
price: "2,500,000원부터",
image: "/product-content.jpg"
}
];이 파일은 화면 디자인을 담당하지 않습니다. 오직 내용만 보관합니다. 그래서 비개발자가 수정해야 할 부분이 훨씬 선명해집니다.
예를 들어 가격이 바뀌면 price 값만 바꾸면 됩니다. 상품 설명이 바뀌면 description만 고치면 됩니다. 새 상품을 추가하려면 { ... } 묶음 하나를 복사해서 아래에 붙이고 내용을 바꾸면 됩니다.
여기서 image 값으로 적은 /product-starter.jpg는 public/product-starter.jpg 파일을 뜻합니다. 앞에서 본 것처럼 public 폴더에 넣은 이미지는 코드에서 /public/product-starter.jpg가 아니라 /product-starter.jpg처럼 씁니다.
이제 app/products/page.tsx에서 이 데이터를 불러와 카드로 보여 줄 수 있습니다. 아직 products 폴더가 없다면 app 폴더 안에 products 폴더를 만들고, 그 안에 page.tsx 파일을 만드세요.
import Image from "next/image";
import { products } from "@/data/products";
export default function ProductsPage() {
return (
<main className="mx-auto max-w-5xl px-6 py-16">
<h1 className="text-3xl font-bold">상품 소개</h1>
<p className="mt-4 text-gray-600">
필요한 상황에 맞춰 선택할 수 있는 패키지입니다.
</p>
<section className="mt-10 grid gap-6 md:grid-cols-3">
{products.map((product) => (
<article key={product.title} className="rounded-2xl border p-6">
<Image
src={product.image}
alt={product.title}
width={800}
height={600}
className="mb-4 h-48 w-full rounded-xl object-cover"
/>
<h2 className="text-xl font-semibold">{product.title}</h2>
<p className="mt-2 text-gray-600">{product.description}</p>
<p className="mt-4 font-bold">{product.price}</p>
</article>
))}
</section>
</main>
);
}여기서 map은 배열 안의 항목을 하나씩 꺼내 반복해서 화면에 그리는 기능입니다. 도장 찍는 기계처럼 생각하면 됩니다. products 안에 상품이 3개 있으면 카드가 3개 생기고, 5개 있으면 카드가 5개 생깁니다.
Image는 앞에서 다룬 Next.js의 이미지 컴포넌트입니다. src에는 데이터 파일에 적어 둔 이미지 경로가 들어가고, alt에는 이미지를 설명하는 글이 들어갑니다. 예시에서는 상품 이름을 alt로 사용했습니다. 실제 운영에서는 이미지 설명을 더 자세히 관리하고 싶을 때 imageAlt 같은 항목을 데이터에 추가할 수도 있습니다.
비개발자가 이 코드를 모두 외울 필요는 없습니다. 중요한 감각은 이것입니다.
카드 모양은
page.tsx가 담당하고, 카드 내용은data/products.ts가 담당한다.
공지사항, 후기, 팀원 목록도 같은 방식입니다
상품 목록만 특별한 것이 아닙니다. 반복되는 콘텐츠는 대부분 같은 방식으로 정리할 수 있습니다.
공지사항이라면 이런 항목이 필요할 수 있습니다.
export const notices = [
{
title: "여름 휴무 안내",
date: "2026-07-29",
category: "운영",
href: "/notices/summer-vacation"
}
];고객 후기라면 이런 항목이 필요할 수 있습니다.
export const reviews = [
{
name: "박소연",
company: "소연스튜디오",
comment: "문의가 들어오기 쉬운 구조로 홈페이지가 정리되었습니다."
}
];팀원 소개라면 이런 항목이 필요할 수 있습니다.
export const members = [
{
name: "정민수",
role: "대표",
photo: "/member-minsu.jpg",
bio: "프로젝트 방향과 고객 커뮤니케이션을 담당합니다."
}
];형태는 조금씩 다르지만 원리는 같습니다.
여러 개 반복된다.
각 항목의 구조가 비슷하다.
화면 모양보다 내용이 자주 바뀐다.
이 세 가지에 해당하면 데이터 파일로 분리하기 좋습니다.
콘텐츠가 많아질수록 규칙이 필요합니다
콘텐츠가 3개일 때는 대충 적어도 큰 문제가 없어 보입니다. 하지만 30개, 100개가 되면 규칙이 없을 때 바로 혼란이 생깁니다.
예를 들어 어떤 글은 날짜를 2026.6.1로 쓰고, 어떤 글은 2026-06-01로 쓰면 정렬이 어려워집니다. 어떤 상품은 image라고 쓰고, 어떤 상품은 thumbnail이라고 쓰면 화면에서 이미지를 제대로 찾지 못할 수 있습니다.
그래서 콘텐츠가 많아질수록 다음 규칙을 정해 두는 것이 좋습니다.
| 항목 | 의미 | 예시 |
|---|---|---|
title | 제목 | "여름 휴무 안내" |
date | 작성일 또는 공개일 | "2026-07-01" |
category | 분류 | "공지", "이벤트" |
image | 대표 이미지 경로 | "/notice-summer.jpg" |
slug | 주소에 쓰는 짧은 이름 | "summer-vacation" |
여기서 slug는 주소용 이름입니다. 글 제목이 "여름 휴무 안내"라면 주소는 /notices/summer-vacation처럼 짧은 영어로 만드는 경우가 많습니다. 사람 이름이 길어도 별명을 부르면 편한 것처럼, slug는 페이지 주소에서 쓰는 별명입니다.
블로그처럼 글이 많아지는 사이트에서는 각 글마다 제목, 발행일, 카테고리 같은 정보를 일정하게 두는 방식이 자주 사용됩니다. 실제 Next.js와 MDX를 함께 쓰는 블로그 구조에서도 글 파일마다 title, publishDate, categories 같은 메타데이터를 두고 목록 정렬이나 분류에 활용하는 예가 많습니다.1
MDX와 CMS는 글쓰기와 개발을 나누는 방법입니다
데이터 파일은 상품, 팀원, 후기처럼 짧고 반복되는 콘텐츠에 좋습니다. 그런데 블로그 글, 도움말 문서, 긴 공지사항처럼 본문이 길어지면 배열 안에 긴 글을 넣는 방식이 불편해집니다.
이때 고려할 수 있는 방법이 MDX와 CMS입니다.
MDX는 Markdown과 JSX를 함께 쓰는 문서 형식입니다. Markdown은 # 제목, - 목록처럼 간단한 표시로 글 구조를 만드는 방식입니다. 여기에 React 컴포넌트도 필요할 때 섞을 수 있습니다. 쉽게 말해 MDX는 "글 문서인데, 중간에 특별한 웹 요소도 넣을 수 있는 파일"입니다.2
예를 들어 개발자가 MDX 설정을 해 두면 비개발자는 이런 식으로 글을 작성할 수 있습니다.
# 여름 휴무 안내
7월 29일부터 8월 2일까지 여름 휴무입니다.
- 문의 답변은 8월 5일부터 순차적으로 진행됩니다.
- 긴급 문의는 이메일로 남겨 주세요.화면 구조를 직접 만지지 않고 글에 집중할 수 있다는 장점이 있습니다. 다만 MDX를 Next.js 프로젝트에서 쓰려면 설정 파일, 라우팅 구조, 문서 위치 같은 준비가 필요합니다. 이 부분은 처음부터 비개발자가 혼자 하기보다 개발자에게 한 번 구조를 잡아 달라고 요청하는 편이 안전합니다.3
CMS는 Content Management System의 줄임말입니다. 한국어로는 콘텐츠 관리 시스템이라고 부릅니다. 워드프레스 관리자 화면처럼 글 제목, 본문, 이미지, 카테고리를 입력하는 별도의 관리 화면을 떠올리면 됩니다.
CMS를 쓰면 비개발자는 코드 편집기 대신 관리자 화면에서 글을 작성할 수 있습니다. 개발자는 CMS에 입력된 내용을 Next.js 화면에 연결합니다.
간단히 구분하면 이렇습니다.
데이터 파일: 작고 반복되는 목록에 적합
MDX: 긴 글과 문서형 콘텐츠에 적합
CMS: 여러 사람이 자주 글을 올리고, 관리자 화면이 필요한 경우에 적합
처음부터 CMS를 붙일 필요는 없습니다. 작은 사이트라면 데이터 파일만으로도 충분합니다. 하지만 글이 자주 쌓이고, 담당자가 여러 명이고, 예약 발행이나 승인 절차가 필요하다면 CMS를 검토할 만합니다.
직접 수정할 영역과 맡기면 좋은 영역
비개발자가 Next.js 사이트를 운영할 때 가장 중요한 것은 "무엇을 직접 바꿔도 되는지"를 아는 것입니다.
| 구분 | 직접 해도 좋은 일 | 개발자에게 맡기면 좋은 일 |
|---|---|---|
| 상품 목록 | 제목, 설명, 가격, 이미지 경로 수정 | 카드 디자인 변경, 결제 연결 |
| 공지사항 | 제목, 날짜, 카테고리, 링크 수정 | 상세 페이지 자동 생성 구조 |
| 팀원 소개 | 이름, 직무, 소개 문장, 사진 교체 | 정렬 방식, 필터 기능 추가 |
| 블로그 글 | MDX 본문 작성, 오타 수정 | MDX 설정, 카테고리 페이지, 검색 기능 |
| CMS | 관리자 화면에서 글 작성 | CMS 선택, API 연결, 권한 설정 |
직접 수정할 수 있는 영역은 보통 data 폴더, content 폴더, 또는 CMS 관리자 화면입니다. 반대로 app/layout.tsx, next.config.js나 next.config.ts, 복잡한 컴포넌트 구조, 외부 서비스 연결은 실수했을 때 영향이 크므로 전문가에게 맡기는 편이 좋습니다.
실습: 상품 하나 추가하기
앞에서 만든 data/products.ts를 열고 마지막 상품 아래에 새 상품을 하나 추가해 보겠습니다.
{
title: "유지보수 패키지",
description: "공개 후 문구 수정, 이미지 교체, 간단한 페이지 업데이트를 지원합니다.",
price: "월 300,000원부터",
image: "/product-care.jpg"
}추가할 때는 바로 위 항목 끝에 쉼표가 있는지 확인하세요.
{
title: "콘텐츠 패키지",
description: "블로그와 공지사항처럼 꾸준히 쌓이는 콘텐츠 구조를 만듭니다.",
price: "2,500,000원부터",
image: "/product-content.jpg"
},
{
title: "유지보수 패키지",
description: "공개 후 문구 수정, 이미지 교체, 간단한 페이지 업데이트를 지원합니다.",
price: "월 300,000원부터",
image: "/product-care.jpg"
}저장한 뒤 브라우저에서 상품 페이지를 확인합니다. 카드가 하나 더 생겼다면 성공입니다. 화면 구조는 건드리지 않았고, 데이터만 추가했는데도 새 카드가 나타났습니다.
문제가 생기면 다음 순서로 확인하세요.
항목 사이에 쉼표
,가 빠지지 않았나요?따옴표
"가 한쪽만 있지 않나요?title,description,price,image이름을 다르게 쓰지 않았나요?이미지 파일이
public폴더 안에 있나요?이미지 경로가
/product-care.jpg처럼/로 시작하나요?Image를 쓴다면import Image from "next/image";가 파일 위쪽에 있나요?Image에width와height가 빠지지 않았나요?
검색할 때는 다음 키워드를 사용하면 좋습니다.
next.js array map render cardsnext.js import data from filenext.js Image public pathtypescript missing comma object array
안전한 운영은 구조에서 시작됩니다
콘텐츠 관리가 편한 사이트는 우연히 만들어지지 않습니다. 처음부터 "자주 바뀌는 내용은 어디에 둘 것인가"를 정해야 합니다.
짧고 반복되는 정보는 데이터 파일로 분리합니다. 긴 글은 MDX를 고려합니다. 여러 사람이 관리해야 하면 CMS를 검토합니다. 그리고 콘텐츠가 많아질수록 제목, 날짜, 카테고리, 대표 이미지, 주소 이름 같은 규칙을 통일합니다.
이 습관이 생기면 Next.js 사이트를 훨씬 덜 무섭게 운영할 수 있습니다. 화면 전체를 고치는 대신, 바꿔도 되는 내용만 안전하게 바꾸면 됩니다.
참고
1Building a blog with Next.js App Router and MDX — Alex Chan
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.