본문으로 건너뛰기
← 블로그로 돌아가기
튜토리얼 2025년 12월 5일

MDX로 기술 블로그 만들기 — 코드 블록부터 인터랙티브 컴포넌트까지

마크다운에 JSX를 더한 MDX로 기술 블로그를 만드는 실전 가이드.

MDX 블로그 Astro 마크다운

MDX란

MDX는 마크다운 안에서 JSX 컴포넌트를 사용할 수 있게 해주는 포맷이다. 일반 마크다운의 가독성을 유지하면서, 필요한 곳에 인터랙티브 요소를 끼워넣을 수 있다.

# 일반 마크다운 제목

일반 마크다운 문단.

<CustomChart data={chartData} />

다시 일반 마크다운으로 이어진다.

기술 블로그에서 MDX가 유용한 이유: 코드 예제, 비교 테이블, 인터랙티브 데모를 마크다운 글 안에 자연스럽게 배치할 수 있다.

Astro에서 MDX 설정

Astro는 MDX를 공식 지원한다.

npx astro add mdx

astro.config.mjs에 플러그인이 추가된다:

import mdx from '@astrojs/mdx';

export default defineConfig({
  integrations: [mdx()],
});

이후 .mdx 파일을 Content Collection에 넣으면 자동으로 처리된다.

Content Collection으로 글 관리

글마다 필요한 메타데이터를 Zod 스키마로 정의한다.

const blogCollection = defineCollection({
  loader: glob({
    pattern: '**/*.mdx',
    base: './src/content/blog',
  }),
  schema: z.object({
    title: z.string(),
    description: z.string(),
    date: z.string(),
    category: z.enum(['dev', 'tutorial', 'insight']),
    tags: z.array(z.string()),
  }),
});

frontmatter에 필수 필드가 빠지면 빌드가 실패한다. 런타임 에러 대신 빌드 타임에 잡히므로 훨씬 안전하다.

글 작성 패턴

---
title: "Rust로 AES-256 암호화 구현하기"
description: "PBKDF2 키 파생부터 nonce 관리까지."
date: "2026-03-12"
category: "tutorial"
tags: ["Rust", "AES-256", "암호화"]
---

## 왜 AES-256-GCM인가

시크릿 매니저에서 암호화 알고리즘을 고를 때...

## 마스터 패스워드에서 키 파생

PBKDF2로 키를 파생한다.

\`\`\`rust
fn derive_key(password: &str, salt: &[u8]) -> [u8; 32] {
    // 구현
}
\`\`\`

코드 블록에 언어를 명시하면 자동으로 신택스 하이라이팅이 적용된다. Astro는 Shiki를 내장하고 있어 별도 설정 없이 동작한다.

MDX에서 주의할 점

중괄호 이스케이프

MDX는 중괄호를 JSX 표현식으로 해석한다. 일반 텍스트에서 중괄호를 쓰려면 코드 블록 안에 넣거나 백틱으로 감싸야 한다.

<!-- 에러: JSX로 해석됨 -->
fallback 설정은 { en: 'ko' } 형태다.

<!-- 정상: 백틱으로 감싸기 -->
fallback 설정은 `{ en: 'ko' }` 형태다.

HTML 엔티티

<, > 같은 문자도 JSX 태그로 해석될 수 있다. 코드 블록 밖에서는 &lt;, &gt;로 이스케이프하거나 백틱으로 감싼다.

스타일링

글 본문의 스타일은 .prose-custom 클래스로 제어한다.

.prose-custom h2 {
  font-size: 1.25rem;
  font-weight: 700;
  margin-top: 3rem;
  border-bottom: 1px solid var(--color-border);
}

.prose-custom p {
  color: var(--color-text-secondary);
  line-height: 1.9;
}

.prose-custom code {
  font-family: var(--font-mono);
  background: var(--color-bg-elevated);
  padding: 0.2rem 0.5rem;
  border-radius: 4px;
}

Tailwind의 @tailwindcss/typography 플러그인을 쓸 수도 있지만, 디자인 토큰과의 일관성을 위해 직접 정의하는 게 제어하기 쉽다.

이미지 처리

MDX에서 이미지는 마크다운 문법을 그대로 쓴다.

![스크린샷 설명](/images/blog/screenshot.png)

Astro의 Image 컴포넌트를 사용하면 자동 최적화(WebP 변환, 리사이즈)를 적용할 수 있다.

글 목록 페이지

---
import { getCollection } from 'astro:content';

const posts = (await getCollection('blog'))
  .sort((a, b) =>
    new Date(b.data.date).getTime() - new Date(a.data.date).getTime()
  );
---

{posts.map((post) => (
  <article>
    <a href={`/blog/${post.id}/`}>
      <h2>{post.data.title}</h2>
      <p>{post.data.description}</p>
    </a>
  </article>
))}

getCollection으로 모든 글을 가져와서 날짜 역순 정렬. 페이지네이션이 필요하면 Astro의 paginate 함수를 사용한다.

정리

MDX + Astro Content Collection 조합은 기술 블로그의 최적 스택이다. 마크다운의 편리함, JSX의 유연함, Zod의 타입 안전성을 모두 가져갈 수 있다. 글 하나 추가하는 건 MDX 파일 하나 만드는 것으로 끝난다.