MDX와 Next.js로 완전 맞춤형 블로그를 만든 방법

발행: (2026년 4월 24일 PM 07:33 GMT+9)
9 분 소요
원문: Dev.to

I’m happy to translate the article for you, but I’ll need the text you’d like translated. Could you please paste the content (or the portion you want translated) here? I’ll keep the source line exactly as you provided and translate the rest into Korean while preserving all formatting and technical terms.

A Little Back Story

저는 언제나 흥미로운 것들—배운 내용, 관심 있는 주제, 교훈, 교육적인 자료 혹은 그냥 엉뚱한 잡다한 것들—을 포스팅하고 싶었습니다. 만약 실제로 하게 된다면 내 개인 블로그에 올리겠다고 스스로 다짐했죠.

Why a personal blog?

현재의 플랫폼들은 커스터마이징과 기능 면에서 매우 제한적입니다. 일부는 특정 기능을 사용하거나(심지어 기사를 읽기 위해서라도) 구독을 요구합니다. 저는 콘텐츠가 전달되는 방식을 완전히 제어하고 싶었습니다: 디자인, 레이아웃, 폰트, 색상 스키마 등 모든 요소를 말이죠.


직장 생활

저는 최근에 대학을 졸업하고 학교를 마치자마자 바로 채용될 수 있는 행운을 얻었습니다. 몇 달 동안 일을 하면서, 특히 수습 기간이 끝나고 시스템의 매우 복잡한 부분들을 이해해야 할 때 제 역할의 요구가 얼마나 큰지에 적응해야 했습니다.

그때 블로그 아이디어는 머리 뒤쪽으로 밀려났었습니다. 이제 역할에 좀 더 익숙해지고 스트레스와 압박을 더 잘 견디게 되었으며, 제 책임에 대한 시야도 명확해졌으니, 마침내 미완성 상태였던 제 블로그 만들기 아이디어(그리 어렵진 않을 테니까요?)에 다시 착수할 수 있게 되었습니다.

Note: 저는 직장에서 멋진 일들을 많이 했는데, 그 이야기는 또 다른 날에 나누고 싶습니다.

아직 제가 구상하고 있는 “완전 맞춤형” 애플리케이션 수준에 도달하지 못했습니다. 아이디어는 많았지만, 구축을 계속 미루다 보니 원래 원했던 것이 무엇인지 흐려졌습니다. 간단한 버전을 만든 뒤 이제 원래 비전으로 다시 초점을 맞출 수 있게 되었습니다.

학생에서 정규직 직원으로 전환하는 과정은 별도의 글이 필요할 정도입니다—아마 나중에 다루겠습니다.

그럼, 조금 기술적인 이야기를 해볼까요.


기술 스택

이 블로그는 포트폴리오(네, 다소 과한 구성)도 함께 호스팅하는 모노레포의 일부입니다. Next.js 로 구축되었으며 블로그 포스트는 MDX 를 사용합니다. 포스트는 Markdown 으로 작성되고 remark 를 통해 React 컴포넌트로 컴파일됩니다.

  • 스타일링: @tailwindcss/typography 플러그인을 사용한 Tailwind CSS 로 헤딩, 단락, 리스트 등을 스타일링합니다.
  • MDX: 시스템의 핵심 – MDX 가 없었다면 블로그를 구축하고 운영하는 데 훨씬 더 많은 작업이 필요했을 것입니다. 이 훌륭한 도구에 기여해 주신 모든 분들께 큰 감사를 드립니다.
  • 배포: Vercel.

데이터베이스 (또는 그 부재)

저는 데이터베이스를 사용하지 않았습니다(당연히 비용을 피하고 싶었기 때문입니다). SQLite나 무료 호스팅 DB가 적절할 수도 있겠지만, 프로젝트를 복잡하게 만들고 싶지 않았습니다; 단순히 “위시리스트” 버킷에서 꺼내고 싶었습니다.

대신 맞춤 스크립트를 만들었습니다:

  1. MDX 파일들을 순회합니다.
  2. gray‑matter를 사용해 프론트‑머터를 추출합니다.
  3. 수집된 데이터를 TypeScript 파일에 저장합니다.

생성된 파일은 빌드 시 애플리케이션에 import 되므로, 파일을 읽는 등 무거운 런타임 처리가 필요하지 않습니다. 데이터는 앱을 다시 빌드할 때만 변경되므로 이 접근 방식이 합리적입니다.

생성된 객체 예시

// THIS FILE IS AUTO‑GENERATED BY compile‑mdx‑data SCRIPT, DO NOT EDIT

export const blogPostsObject: Record = {
  "mdx-nextjs-blog-setup": {
    title: "My MDX + Next.js Blog Setup",
    description: "This is a description",
    tags: ["nextjs", "mdx", "tailwind"],
    date: "2025-11-21",
    readingTime: "5 min",
  },
};

스크립트는 빌드 스크립트 이전에 실행됩니다.

블로그 메인 페이지

모든 게시물을 나열하는 메인 페이지는 blogPostsObject를 사용합니다. 이렇게 하면 모든 것이 일관성을 유지하고 여러 곳에서 게시물 메타데이터를 수동으로 업데이트할 필요가 없어집니다.


코드 스니펫

저는 Expressive Code를 사용하여 코드 블록을 강조합니다. 구문 강조, 파일 탭, 줄 번호, 그리고 diff 뷰까지 추가해 주는 강력한 플러그인입니다.

  • 파일 탭 예시

    // file: src/components/Button.tsx
    export const Button = () => Click me;
  • 줄 번호 표시 및 특정 줄 강조

    // file: server.ts
    const port = 3000; //  and let me know what you think!

Source:

withTocExport으로 목차 테이블 생성하기

withTocExport 함수가 TOC 데이터를 내보내는 트리거 역할을 합니다.

import withToc from "@stefanprobst/rehype-extract-toc";
import withTocExport from "@stefanprobst/rehype-extract-toc/mdx";

const withMdx = nextMdx({
  options: {
    // …
    rehypePlugins: [
      withToc,
      [withTocExport, { name: "toc" }],
    ],
  },
});

그 후 toc 변수는 MDX import 자체에서 내보내지며, 우리는 이를 Toc 컴포넌트에 전달해 목차 트리를 렌더링합니다.

const { default: Post, toc } = await import(`@/app/(blog)/mdx/${slug}.mdx`);

return (
  <>
    {/* render Post and Toc here */}
  </>
);
  • Post – 블로그 포스트로 렌더링될 컴포넌트.
  • toc – 생성된 목차를 담고 있는 변수.
  • Toc – TOC UI를 렌더링하는 컴포넌트.

마무리 생각

이 블로그가 이렇게 완성된 것이 정말 기쁩니다. 아직 해야 할 일이 많이 남아 있지만, 지금까지 완성한 부분은 그동안의 노력에 감사할 시간을 가질 만합니다.

이 작은 프로젝트에서 앞으로 무엇이 나올지 기대가 되며, 이 글을 읽는 즐거움을 느꼈길 바랍니다! 오타나 실수가 있다면 죄송합니다—아직 이런 글쓰기를 배우는 중이에요 😅

0 조회
Back to Blog

관련 글

더 보기 »

코딩을 배우면서 제가 저지른 가장 큰 실수

실수 당신은 코딩을 배우고 가능한 빨리 직장을 구하기로 결심했습니다. 온라인에서 빠르게 검색한 결과, React 튜토리얼을 찾아냈고, 이 튜토리얼은 J... 를 가르친다고 약속합니다.