개발 블로그를 운영하다 보면 플랫폼을 이전하거나 기존 글을 백업해야 하는 상황이 찾아옵니다. velog, 티스토리, Dev.to, Hashnode, Medium, 그리고 일본 개발자 생태계의 대표 플랫폼인 Qiita와 Zenn까지, 글을 작성할 때는 대부분 Markdown을 지원하지만 정작 플랫폼을 떠날 때(내보내기) 제공하는 데이터 형식은 제각각입니다.
어떤 플랫폼은 Markdown 원본을 그대로 돌려주고, 어떤 플랫폼은 JSON 데이터로 묶어 내보내며, Medium처럼 HTML 파일이 담긴 ZIP 파일만 제공하는 경우도 있습니다. 이 글에서는 각 개발 블로그 플랫폼에서 글을 추출하는 방법과 데이터 형식 차이, frontmatter 재구성, Qiita에서 Zenn으로의 4단계 이전 절차, 그리고 HTML만 남은 글을 Markdown으로 복원하는 방법까지 전체 흐름을 정리합니다.
만약 이전하려는 기사의 Markdown 원본 파일이 없고 웹에 공개된 HTML 페이지만 남아 있는 경우라면, 해당 HTML을 HTML to Markdown에 붙여넣어 브라우저 안에서 즉시 Markdown으로 복원할 수 있습니다. 변환은 브라우저 내에서 완결되며 외부 서버로 데이터가 전송되지 않습니다.
플랫폼별 기사 추출 방식과 데이터 형식 비교
개발 블로그 플랫폼마다 내보내기 기능이 제공하는 데이터 형식이 다릅니다. 플랫폼 간 이전이나 백업을 계획할 때 참고할 수 있는 형식 대응표입니다.
| 플랫폼 | 기사 추출 방법 | 제공되는 데이터 형식 |
|---|---|---|
| Dev.to | 에디터 가이드새 탭에서 열립니다에 명시된 API를 통해 가져오거나 커뮤니티 내보내기 도구새 탭에서 열립니다 활용 | Markdown + frontmatter |
| Hashnode | 대시보드 일괄 내보내기는 JSON. 단일 기사는 URL 끝에 .md를 추가해 Markdown 원본 취득 가능(공식 변경 내역새 탭에서 열립니다) | JSON / Markdown |
| Medium | "Download your information새 탭에서 열립니다"을 통해 posts/ 폴더가 포함된 ZIP 다운로드 | HTML (Markdown 내보내기 없음) |
| Qiita (일본) | API v2새 탭에서 열립니다를 통해 각 글의 Markdown(body)과 HTML(rendered_body) 취득 | Markdown + HTML |
| Zenn (일본) | 연결된 GitHub 저장소새 탭에서 열립니다를 통해 로컬 Markdown 파일로 관리 | Markdown |
이전 작업은 '어디로 갈 것인가'보다 '지금 어떤 형식의 데이터를 갖고 있는가'에서 시작해야 합니다.
- Markdown 파일이 있는 경우: 본문 문법 차이 점검과 대상 플랫폼에 맞춘 frontmatter 재구성 단계로 바로 진행합니다.
- JSON 파일인 경우: JSON 객체 내부의 Markdown 필드를 추출합니다(Hashnode 내보내기 JSON을
.md파일로 분할해 주는 커뮤니티 도구 등 활용). - HTML 파일인 경우: Markdown으로 먼저 변환해야 합니다. Medium이나 과거 웹페이지 백업이 이에 해당합니다.
Dev.to, Hashnode, Medium에서 글 추출하기
Dev.to에서 기사 가져오기
Dev.to는 에디터 자체가 순수 Markdown 기반이므로 이전이 가장 수월한 플랫폼 중 하나입니다. 각 게시물은 title, published, tags, canonical_url, cover_image, series 등을 포함하는 Jekyll 스타일의 frontmatter를 갖추고 있습니다(Dev.to 에디터 가이드새 탭에서 열립니다).
설정 화면에서 API 키를 발급받은 뒤 API 엔드포인트를 호출하면 본문 Markdown을 포함한 기사 목록을 가져올 수 있습니다. Dev.to-exporter새 탭에서 열립니다 같은 커뮤니티 스크립트를 사용하면 명령어 한 번으로 로컬에 .md 파일로 일괄 저장할 수 있습니다.
Hashnode에서 기사 가져오기
Hashnode는 두 가지 경로를 제공합니다.
- 대시보드의 백업 내보내기 기능은 모든 글을 단일 JSON 파일로 내려받습니다. hashnode-export-to-markdown새 탭에서 열립니다 같은 도구를 사용해 frontmatter가 포함된 개별 Markdown 파일로 분할할 수 있습니다.
- 2026년 6월부터는 개별 기사 URL 끝에
.md를 붙이거나Accept: text/markdown헤더로 요청하면 원본 Markdown을 바로 확인할 수 있습니다(공식 변경 내역새 탭에서 열립니다). 몇 편의 글만 빠르게 옮길 때 편리합니다.
반대로 다른 곳에서 가져온 Markdown 파일을 Hashnode로 옮길 때는 Hashnode 대시보드의 일괄 Markdown 가져오기새 탭에서 열립니다 기능을 통해 ZIP 파일로 한 번에 등록할 수 있습니다.
Medium에서 기사 가져오기
Medium은 내보내기 시 Markdown을 제공하지 않습니다. 계정 설정의 "Download your information새 탭에서 열립니다"에서 내려받는 ZIP 파일의 posts/ 폴더에는 글마다 HTML 파일 하나씩이 들어 있습니다.
이 HTML 파일들을 Markdown으로 변환하는 방법은 두 가지입니다.
mediumexporter나medium-2-md같은 CLI 도구로 일괄 변환- 몇 편의 글이거나 별도 도구 설치 없이 처리하고 싶다면 HTML 파일 내용을 복사해 HTML to Markdown에 붙여넣기
브라우저 내에서 변환하면 비공개 초안이나 미발행 글도 외부 서버로 유출될 염려 없이 안전하게 변환할 수 있습니다.
Qiita에서 Zenn(및 표준 GFM)으로의 이전 4단계
일본의 기술 블로그 생태계를 대표하는 Qiita와 Zenn 간의 이전, 혹은 Qiita 글을 GitHub 기반 블로그로 옮기는 절차는 대표적인 4단계 이전 모델을 보여줍니다.
- API를 통해 원본 글 데이터 추출
- 플랫폼 고유 문법을 대상 문법으로 변환
- frontmatter 구성 및 발행일(
published_at) 유지 - 이미지 및 코드 블록 후처리
단계 1: API를 통한 원본 기사 추출
Qiita는 공식 API v2새 탭에서 열립니다를 제공하여 Markdown 원본을 포함한 기사 데이터를 일괄 취득할 수 있습니다. 설정에서 발급한 개인 액세스 토큰을 헤더에 넣고 인증된 사용자 기사 목록 엔드포인트를 호출합니다.
curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://qiita.com/api/v2/authenticated_user/items?page=1&per_page=100" > items.json
취득 시 확인해야 할 사항 3가지(공식 문서새 탭에서 열립니다 기준):
- 응답의
body필드가 Markdown 원본 소스이고rendered_body가 렌더링된 HTML입니다. 이전에는body를 사용합니다. per_page의 상한은 100입니다. 100건을 넘는다면page번호를 올려 반복 호출합니다.- API 호출 제한은 인증 시 시간당 1,000회, 비인증 시 IP당 시간당 60회입니다. 개인 블로그 이전에는 충분한 용량입니다.
단계 2: 플랫폼 고유 문법 변환과 호환성 검사
기본적인 Markdown 문법(제목, 목록, 링크, 표)은 호환되지만, 각 플랫폼 고유의 컨테이너나 확장 문법은 수정이 필요합니다. 주요 대응 관계는 다음과 같습니다(Qiita 문법 치트시트새 탭에서 열립니다 및 Zenn Markdown 가이드새 탭에서 열립니다 기준).
| 요소 | Qiita 문법 | Zenn 문법 |
|---|---|---|
| 안내 배너 | :::note info | :::message |
| 경고 배너 | :::note warn / :::note alert | :::message alert |
| 접기/펼치기 | <details><summary> 태그 | :::details 제목 |
| 코드 블록 파일명 | ```ruby:qiita.rb | 동일 문법 지원 |
| 수식 블록 | ```math | $$ (앞뒤 빈 줄 필요) |
| 인라인 수식 | $`수식`$ | $수식$ |
주의할 점은 배너 형식이 일대일로 완벽하게 대응하지 않는다는 점입니다. Qiita는 info, warn, alert의 3종류를 제공하는 반면 Zenn은 기본 메시지와 alert의 2종류만 지원합니다. 따라서 warn 배너를 일반 강조(:::message)로 둘지 주의 환기(:::message alert)로 둘지 기준을 정해 치환해야 합니다.
문법 차이를 일일이 수작업으로 찾기 어렵다면 Qiita / Zenn 호환성 검사기에 본문을 붙여넣어 74건의 문법 차이 규칙과 대조할 수 있습니다. 일대일로 결정되는 37건은 즉시 변환되고, 선택이 필요한 14건은 대체 방식을 지정할 수 있으며, 지원되지 않는 23건은 지적 사항으로 안내됩니다. 모든 처리는 브라우저 내에서 완결됩니다.
특히 주의할 점은 Zenn이 본문 내 raw HTML을 렌더링하지 않는다는 점입니다. Qiita에서 지원되던 <details> 태그나 <img width="..."> 태그는 Zenn에서 구문 오류를 내지 않고 태그 문자열 그대로 본문에 노출됩니다. 같은 이유로 :::message warn처럼 지원되지 않는 배너를 적으면 컨테이너가 되지 않고 텍스트 한 줄로 출력됩니다.
변환된 본문의 렌더링 결과를 미리 확인하고 싶다면 Markdown to HTML에 붙여넣어 GFM(GitHub Flavored Markdown) 기준 렌더링을 브라우저에서 바로 확인할 수 있습니다.
단계 3: frontmatter 구성과 공개 일시(published_at) 유지
Zenn 및 정적 사이트 생성기는 문서 시작 부분의 YAML frontmatter로 메타데이터를 관리합니다(Zenn CLI 가이드새 탭에서 열립니다).
---
title: "기사 제목"
emoji: "📘"
type: "tech"
topics: ["rails", "markdown"]
published: true
published_at: "2023-05-10 09:00"
---
Qiita API 응답의 title과 tags를 여기에 매핑합니다. topics에는 최대 5개까지 지정할 수 있으며(Zenn CLI 가이드새 탭에서 열립니다), 파일명이 될 slug는 영문 소문자·숫자·하이픈·언더스코어 조합의 12~50자 제한이 있습니다(Zenn slug 사양새 탭에서 열립니다).
과거 공개 일시를 유지하고 싶다면 frontmatter의 published_at 필드에 과거 날짜를 지정합니다(YYYY-MM-DD 또는 YYYY-MM-DD hh:mm 형식, 일본 시간 기준). Zenn 공식 가이드에서도 다른 플랫폼에서 기사를 이전할 때 공개 일시를 유지하는 용도로 이 필드를 안내하고 있습니다. 단, 공개 일시 설정은 최초 1회만 적용되고 이후에는 수정할 수 없으므로 공개 전에 정확한 값을 확인해야 합니다.
단계 4: 이미지 및 코드 블록 후처리
- 이미지 URL: 이전 직후의 글은 기존 플랫폼의 이미지 CDN 주소를 그대로 참조하고 있어 화면에는 정상 표시됩니다. 하지만 원본 플랫폼을 탈퇴하거나 정책이 변경되면 이미지가 사라질 위험이 있습니다. 장기적으로 보존할 글이라면 이미지를 로컬로 내려받아 새 플랫폼의 저장소에 다시 업로드하고 본문 URL을 교체하는 것이 안전합니다.
- 코드 블록: 파일명 지정 문법(
```ruby:qiita.rb)은 호환되지만, diff 표시나 특정 하이라이팅 표기는 플랫폼마다 다를 수 있으므로(예: Zenn은```diff js처럼 공백 구분) 렌더링 미리보기를 거치는 것이 좋습니다.
중복 콘텐츠 방지와 canonical URL 설정
글을 새 플랫폼으로 이전한 후 기존 플랫폼의 글을 어떻게 처리할지 결정해야 합니다. 선택지는 보통 세 가지입니다.
- 원본 글을 남겨두고 상단에 "새 블로그로 이전했습니다"라는 안내 문구와 링크 추가
- 원본 글의 본문을 요약 및 새 링크로만 간소화
- 원본 글 삭제
검색 엔진(Google 등)은 동일한 내용의 글이 서로 다른 URL에 존재할 때 어느 쪽을 원본으로 취급할지 혼란을 겪을 수 있습니다.
Dev.to는 frontmatter의 canonical_url 필드를 통해 원본 주소를 명시할 수 있고(Dev.to 에디터 가이드새 탭에서 열립니다), Hashnode는 발행 흐름 및 API에서 원문 URL 설정을 지원하며, Medium은 URL 가져오기 기능 사용 시 자동으로 canonical 링크를 원본으로 지정합니다. 이처럼 플랫폼이 지원하는 canonical URL 기능을 적극 활용하면 중복 콘텐츠 불이익 없이 글을 동시 게재하거나 이전할 수 있습니다.
Markdown 소스가 없는 기사 복원 (HTML to Markdown)
Medium의 백업 파일처럼 HTML만 제공되거나, 과거 운영하던 블로그 서비스가 종료되어 웹 아카이브의 HTML 페이지만 남은 경우가 있습니다.
이때는 HTML 코드를 HTML to Markdown에 붙여넣으면 GFM 호환 Markdown으로 변환할 수 있습니다.
예를 들어 다음과 같은 HTML 구조가 있다면,
<h2>설치 및 실행</h2>
<p>먼저 <code>npm install</code> 명령어를 실행합니다.</p>
변환기를 거치면 깔끔한 Markdown으로 바뀝니다.
## 설치 및 실행
먼저 `npm install` 명령어를 실행합니다.
모든 처리가 브라우저 내부에서 실행되므로, 공개되지 않은 사내 기술 문서나 비공개 초안 데이터가 외부 서버에 남지 않습니다. 온라인 변환 도구를 선택할 때는 데이터가 서버로 업로드되는 구조인지, 브라우저 로컬에서 완결되는지 확인하는 것이 보안상 안전합니다. 자세한 보안 점검 기준은 온라인 변환 사이트 보안 검증을 참고하세요. Notion에서 내보낸 HTML 아카이브를 정리할 때도 동일한 방식으로 적용할 수 있습니다. 자세한 변환 절차는 노션 마크다운 내보내기 정리를 참고하세요.
자주 묻는 질문
플랫폼을 이전할 때 원래 발행일을 유지할 수 있나요?
지원 여부는 대상 플랫폼에 따라 다릅니다. Markdown 본문 자체에는 날짜 정보가 없지만 frontmatter를 지원하는 플랫폼 중 일부는 과거 날짜 지정을 허용합니다. 대표적으로 Zenn은 published_at 필드를 통해 과거 발행일 유지를 공식 지원합니다(Zenn CLI 가이드새 탭에서 열립니다). 이전 전에 원본 데이터에서 발행 일시를 미리 기록해 두세요.
이미지는 반드시 새 플랫폼으로 다시 업로드해야 하나요?
이전 직후에는 기존 이미지 URL로도 표시되지만, 기존 계정을 삭제하거나 플랫폼 정책이 변경되면 이미지가 깨질 수 있습니다. 장기적으로 관리할 중요한 기술 글이라면 이미지를 직접 내려받아 새 저장소에 올리고 본문 URL을 수정해 두는 것을 권장합니다.
Dev.to나 Hashnode에서 가장 빠르게 글을 추출하는 방법은 무엇인가요?
Dev.to는 API 키를 이용해 커뮤니티 스크립트(Dev.to-exporter새 탭에서 열립니다)로 일괄 내려받는 것이 가장 빠릅니다. Hashnode는 소량의 글인 경우 기사 URL 끝에 .md를 붙여 원본 Markdown을 바로 복사하는 방식이 가장 간편합니다(공식 변경 내역새 탭에서 열립니다).
Qiita와 Zenn 간 문법 차이를 자동으로 검사할 수 있나요?
Qiita / Zenn 호환성 검사기를 사용하면 74가지 문법 차이점을 자동으로 대조하여 일대일 변환, 선택 치환, 미지원 구문 경고를 브라우저 내에서 즉시 확인할 수 있습니다.
여러 편의 글을 온라인 변환기에 넣어도 안전한가요?
백업 아카이브에는 비공개 초안이나 내부 설정 정보가 섞여 있는 경우가 많습니다. 서버로 파일이나 텍스트를 전송하여 변환하는 도구 대신, 브라우저 내부 JavaScript/Wasm으로만 동작하는 로컬 처리형 도구를 사용하는 것이 안전합니다.
정리
- 블로그 플랫폼 이전은 본질적으로 데이터 형식의 변환 과정입니다(Markdown, JSON, HTML).
- 원본 형식에 따라 추출(API·스크립트) → 문법 정규화 → frontmatter 재구성 → 이미지/코드 후처리의 4단계를 거칩니다.
- Markdown 소스가 없는 HTML 백업 데이터는 HTML to Markdown을 통해 브라우저 내에서 깔끔한 Markdown으로 복원할 수 있습니다.
- 변환된 결과의 렌더링 상태는 Markdown to HTML로 확인하고, Qiita와 Zenn 간 이전에는 Qiita / Zenn 호환성 검사기를 활용해 문법 불일치를 사전에 방지할 수 있습니다.

