Sveltia CMS가 선언 안 한 프론트매터 키를 지운다고 적어뒀는데, 지우는 쪽은 따로 있었습니다
Hugo 블로그에 Sveltia CMS(브라우저에서 글을 고치면 GitHub 저장소에 바로 커밋해 주는 관리 화면)를
붙인 적이 있습니다. 설정 파일 config.yml을 쓰면서 이런 주석을 달아뒀습니다.

# ⚠️ 선언하지 않은 프론트매터 키는 저장할 때 사라진다. 화면에 안 띄울 값도
# 반드시 여기 적어둔다.
프론트매터(글 맨 위 --- 사이에 적는 제목·날짜 같은 설정값)에 있는 키를
fields에 하나라도 빠뜨리면 CMS로 한 번 저장하는 순간 지워진다는 경고입니다.
이 글은 그 경고를 직접 확인해 보니 틀렸다는 이야기이고
대신 값이 정말로 망가지는 경우가 따로 있다는 이야기입니다.
제가 적어둔 경고는 확인한 게 아니었습니다

당시 기록을 다시 읽어봤습니다. 저는 설정 파일을 쓰기 전에 모든 파일의 프론트매터 키를 뽑아서
fields와 대조했습니다. 글 폴더라면 이런 명령입니다.
for f in content/posts/*.md; do awk '/^---$/{n++;next} n==1{print}' "$f"; done \
| grep -oE '^[a-zA-Z_][a-zA-Z0-9_]*:' | LC_ALL=C sort | uniq -c
이 대조에서 개인정보처리방침 페이지의 sitemap.priority가 선언에 빠져 있던 걸 찾아 추가했습니다.
키가 지워지는 걸 본 게 아니라, 지워질까 봐 미리 막은 겁니다.
저장해 보고 키가 사라진 기록은 어디에도 없었습니다.
“사라진다"는 문장은 관측이 아니라 예방 메모였는데, 주석에 단정형으로 적혀 있어서 사실처럼 읽혔습니다.
공식 문서는 반대로 말하고 있었습니다

Sveltia 문서 전체(llms-full.txt, 사이트가 문서를 한 파일로 묶어 주는 것)를 받아 찾아봤습니다.
선언 안 한 키를 지운다는 문장은 없었습니다. 대신 반대 문장이 두 군데 있습니다.
Pages CMS에서 옮겨오는 안내의 설정 비교표 — 「Sveltia CMS always keeps the properties that are not defined in the configuration, placing them after the configured fields」 (Migrating from Pages CMS). 여러 글을 파일 하나에 담는 컬렉션 문서 — 「properties that aren’t defined as fields, are kept as they are」 (Single-File Collections). 둘 다 2026-10-04에 확인했습니다.
선언 안 한 키는 남기고, 선언한 필드 뒤로 보낸다는 겁니다. GitHub 이슈도 키워드를 바꿔 여섯 번 검색했는데 미선언 키가 지워졌다는 보고는 찾지 못했습니다.
제가 쓰던 0.204.0 코드를 직접 돌려봤습니다

문서는 최신판 기준이라 제가 고정해 썼던 v0.204.0에서도 그랬는지는 따로 봐야 했습니다. 저장소를 그 태그로 받아 저장 직전 단계(프론트매터를 다시 조립하는 함수)를 실제 파일로 돌렸습니다.
git clone --depth 1 --branch v0.204.0 https://github.com/sveltia/sveltia-cms.git
pnpm install --frozen-lockfile
조립 함수에는 아예 이런 주석이 있었습니다. 선언한 필드를 먼저 옮기고 나머지를 뒤에 붙입니다.
// Move the remainder, if any, to a new object.
같은 폴더의 기존 테스트 이름도 serializes content with remainder properties not in field list이고 통과합니다.
제 블로그 글 하나를 넣고 publishDate만 빼고 선언해서 돌린 결과입니다.
---
title: 글 목록을 여섯 편씩 끊었습니다 — 틀려도 조용한 것들
description: ...
date: 2026-09-03
slug: pagination-pitfalls
tags:
- Hugo
- 페이징
- SEO
draft: false
narrow: true
publishDate: 2026-09-04
---
publishDate는 사라지지 않고 맨 뒤로 갔습니다. 개인정보처리방침 파일에서 sitemap을 빼고 돌려도
sitemap: priority: 0.3이 그대로 남았습니다. 이 개인정보처리방침 결과는 최신 v0.227.3에서도 같았습니다.
대신 바뀌는 게 두 가지 있었습니다.
- 키 순서 — 선언 안 한 키가 뒤로 밀립니다
- 따옴표와 목록 표기 —
title: "…"의 따옴표가 빠지고,["Hugo", "페이징", "SEO"]한 줄이 여러 줄 목록이 됩니다
값은 같아서 Hugo 빌드 결과는 바뀌지 않습니다. 위 출력으로 프론트매터를 갈아 끼우고 사이트 전체를 빌드해 보니
diff -r로 비교한 결과물 폴더에 차이가 없었습니다(hugo v0.165.0). 다만 처음 저장할 때 diff(변경 내역)는 생각보다 크게 나옵니다.
브라우저에서 GitHub에 실제로 저장한 재현은 아닙니다. 저장 직전 정규화·조립·YAML 출력 함수를 테스트 러너(vitest)로 직접 돌린 것이고, 필드 정보를 찾아주는 부분만 단순화했습니다(2026-10-04).
진짜로 값이 망가지는 건 “잘못 선언"했을 때였습니다

같은 코드를 읽다가 다른 곳에서 삭제를 찾았습니다. 기존 글을 편집 화면에 열 때 선언된 필드의 타입과 파일 속 값의 모양이 다르면 그 값을 버리거나 고칩니다. “안 지워지게 일단 선언해 두자"며 위젯을 대충 고르면 오히려 그때 망가집니다.
같은 입력 sitemap: {priority: 0.3}, tags: [Hugo, 배포]로 여섯 가지 선언을 돌렸습니다.
1. 둘 다 미선언 → sitemap {priority:0.3}, tags [Hugo, 배포]
2. sitemap 을 string 으로 선언 → sitemap "" ← 값 사라짐
3. tags 를 string 으로 선언 → tags "Hugo" ← 두 번째 태그 사라짐
4. sitemap 을 hidden 으로 선언 → sitemap {priority:0.3}
5. sitemap 을 object+number → sitemap {priority:0.3}
6. tags 를 list 로 선언 → tags [Hugo, 배포]
아무것도 안 적은 1번은 멀쩡하고, 틀리게 적은 2·3번에서 값이 날아갑니다. 3번은 목록이 글자 하나로 바뀌는 것이라 diff를 꼼꼼히 보지 않으면 지나치기 쉽습니다. v0.204.0과 v0.227.3 결과가 같았습니다.
화면에 안 보여도 되는 값은 widget: hidden이 가장 안전했습니다. 코드에서 hidden은 code·keyvalue와 함께
값의 모양을 검사하지 않는 타입으로 묶여 있습니다.
- { name: sitemap, widget: hidden }
hidden 필드에는 label을 달면 안 됩니다. Sveltia 공식 JSON 스키마에서 허용하는 키가
widget·default·name·i18n뿐이라 설정이 무효로 잡힙니다. 당시 스키마 검증으로 이 오류를 걸러냈던 기록이 남아 있습니다.
부록 — 버전 숫자만 올리면 흰 화면이 됩니다

관리 화면은 GitHub 쓰기 권한 토큰을 브라우저에 들고 있어서 CDN에서 받는 스크립트에
integrity(받은 파일이 내가 확인한 그 파일인지 해시로 대조하는 속성)를 걸어뒀습니다.
$ curl -sSL https://unpkg.com/@sveltia/cms@0.204.0/dist/sveltia-cms.js \
| openssl dgst -sha384 -binary | openssl base64 -A
kEhdb7fyty++yCu7opXvZVrYC9qbXpjSVinvaDPQ6x3yOCiKdi1gUv3F2jWKW6R3
$ curl -sSL https://unpkg.com/@sveltia/cms@0.227.3/dist/sveltia-cms.js \
| openssl dgst -sha384 -binary | openssl base64 -A
8hMzaf/90SQ5tmWKilMTR2nNU+HEw84lYds8R0eo32rjS6u1h98IrxiM3Jde+XLN
0.204.0 값은 한 달 전 설정에 넣었던 값과 글자 하나까지 같았습니다. 버전이 바뀌면 해시도 당연히 바뀝니다. 그래서 주소의 버전만 0.227.3으로 올리고 해시를 그대로 두면 이렇게 됩니다(Chromium 154).
Failed to find a valid digest in the 'integrity' attribute for resource
'https://unpkg.com/@sveltia/cms@0.227.3/dist/sveltia-cms.js' with computed SHA-384 integrity
'8hMzaf/90SQ…'. The resource has been blocked.
페이지는 200으로 열리고 화면은 완전히 하얗습니다. 오류는 개발자 도구 콘솔에만 찍힙니다. 해시를 맞춘 쪽은 스크립트가 정상적으로 로드돼 Sveltia 화면이 떴습니다. 브라우저가 해시가 다르면 로드를 거부하는 건 정해진 동작입니다 (MDN · Subresource Integrity).
하나 더 고쳐 적습니다. 당시 저는 이 번들이 런타임에 다른 파일을 더 불러오지 않는다고 적었는데,
오늘 0.204.0 파일에서 import(를 세어 보니 5곳이 나왔습니다. 코드 하이라이터와 PDF 워커처럼
필요할 때 CDN에서 따로 받는 모듈이라 진입 파일의 integrity로는 검증되지 않습니다.
다시 설정 파일을 쓴다면

- 프론트매터 키를 전부 뽑아 대조하는 건 그대로 합니다. 다만 목적은 “안 지워지게"가 아니라 각 키의 값 모양(글자·숫자·목록·객체)을 보고 위젯을 맞게 고르기입니다
- 확신이 없는 키는 선언하지 않거나
widget: hidden. 대충string으로 적는 게 가장 위험합니다 - 처음 저장할 때 생기는 diff에서 순서·따옴표 변화는 정상이고 값이 빠졌는지만 봅니다
- 스크립트 버전을 올릴 땐
curl | openssl로 해시를 새로 뽑아 같은 커밋에서 같이 바꿉니다 - 주석에 단정형으로 경고를 적을 땐 직접 본 건지 미리 막은 건지 같이 적습니다. 이번 글은 그걸 안 적어서 생겼습니다