Astro data-store.json — 삭제한 글이 빌드에 계속 남는 이유

AstroContentLayer빌드캐시정적사이트트러블슈팅

Astro에서 글을 삭제하거나 draft: true로 내렸는데 빌드 결과 dist/와 sitemap에 그 글이 계속 남는다면, 원인은 하나입니다.

node_modules/.astro/data-store.json

Astro의 콘텐츠 레이어(Content Layer)는 글 데이터를 스토리지 레이어에 저장하고 빌드 사이에 캐시합니다. 빌드가 콘텐츠 디렉터리만 읽는 게 아니라 이 스토어를 참조하기 때문에, 파일을 지워도 스토어에 남은 항목이 빌드에 되살아납니다.

문서는 저장 파일의 이름과 경로까지 적어 두지 않으므로 그 위치는 아래 실측입니다.

프로젝트 루트의 .astro/와 dist/를 지워도 소용없는 이유가 그것입니다.

고치는 방법은 둘 중 하나입니다.

npx astro build --force                            # 콘텐츠 레이어 캐시를 지우고 전체 빌드 (v7.2.4 기준 실측)
rm -rf dist node_modules/.astro && npm run build   # 스토어 파일 자체를 지운다

그리고 규칙 하나입니다.

삭제와 철회, draft 처리를 확인하는 빌드는 반드시 클린 빌드로 합니다.

평소 개발 빌드는 캐시 덕을 봐도 됩니다. 다만 “빠졌는지 보는” 빌드가 캐시를 읽으면 그 확인은 무효입니다.

아래는 왜 두 캐시를 지워도 안 되는지, 이 동작이 진짜로 위험한 장면, 그리고 --force가 있는데도 파일을 지우는 이유입니다.

왜 두 캐시를 지워도 안 될까?

정적 사이트 빌더에서 “지웠는데 남는다”면 누구나 캐시를 의심하지요.

Astro 프로젝트에서 눈에 보이는 캐시는 두 곳이고, 저도 거기서 시작했습니다.

rm -rf .astro/    # 프로젝트 루트 — astro sync가 만드는 타입·메타데이터
rm -rf dist/      # 빌드 산출물
npm run build

둘 다 지워도 삭제한 글이 다시 나타났습니다.

이 시점에서 캐시보다 내 착각을 의심하게 됩니다. 파일이 지워지긴 했나, 다른 디렉터리에 사본이 있나, glob 패턴이 이상한가.

전부 아니었습니다.

세 번째 위치가 있었습니다.

$ ls -la node_modules/.astro/
-rw-r--r--  1 user staff  453069  data-store.json
캐시가 세 곳에 있는데 흔히 지우는 두 곳만 사라지고, node_modules 안의 데이터 스토어는 남아서 삭제한 글을 빌드에 되살린다 rm -rf .astro/ rm -rf dist/ .astro/ dist/ node_modules/.astro/ data-store.json 지우는 명령이 없다 — 지워진다 — 지워진다 남는다 — 빌드가 여기서 지운 글을 되살린다
캐시는 세 곳인데 흔히 지우는 명령은 두 곳만 지웁니다.

이 위치가 악랄한 이유는 둘입니다.

① node_modules 안이다

“내 파일”이라는 생각 자체를 안 합니다.

② 이름이 루트의 .astro/와 같다

루트 쪽을 지우고 “.astro는 지웠다”고 믿게 됩니다.

게다가 node_modules 전체 삭제는 무거워서 검증 루프에서 안 씁니다.

rm -rf node_modules && npm install을 매번 할 사람은 없으니, 이 스토어는 사실상 삭제되지 않는 캐시로 살아남습니다.

이 동작이 진짜로 위험한 자리는 어디인가?

이 동작이 물어뜯는 장면은 철회 검증입니다.

잘못 올라간 글을 지우거나 draft: true로 내리고 로컬에서 빌드해 “빠졌는지” 확인합니다. 그런데 빌드가 스토어를 읽으면 확인하려던 바로 그 상태가 캐시에 가려집니다.

반대 방향도 성립합니다. 지운 글이 로컬 빌드에 남아 있으면 멀쩡한 삭제를 의심하며 엉뚱한 곳을 디버깅하게 됩니다.

어느 쪽이든 “빌드 결과를 보고 판단”하는 행위 자체가 오염됩니다.

선을 그어야 할 부분도 있습니다.

배포 환경은 대체로 이 문제의 영향을 받지 않습니다. Cloudflare Pages를 포함한 대부분의 CI/CD는 매 배포마다 새 환경에서 npm ci로 의존성을 새로 설치하는데, npm ci는 node_modules가 이미 있으면 지우고 시작하므로 스토어도 함께 사라집니다. 그래서 증상이 “프로덕션은 멀쩡한데 로컬 빌드만 이상하다”는 비대칭으로 나타나고, 이 비대칭이 진단을 더 헷갈리게 만듭니다.

--force가 있는데 왜 파일을 지울까?

astro build --force가 콘텐츠 레이어 캐시를 지우고 전체를 다시 빌드하고, astro sync --force도 같은 캐시를 지웁니다. 문서에는 이 플래그가 [email protected]에 들어왔다고 적혀 있고, 이 글의 실측은 v7.2.4입니다. 그런데 왜 제 레포는 파일을 지울까요? 제 레포는 package.json에 rm -rf를 스크립트로 박아뒀습니다.

"build:clean": "rm -rf dist node_modules/.astro && astro build"

스토어 파일의 존재 자체가 사라지므로 “비웠나”를 ls 한 번으로 검증할 수 있기 때문입니다.

플래그는 내부 동작을 믿어야 하지만, 지워진 파일은 믿을 필요가 없습니다.

철회 확인처럼 결과를 확신해야 하는 작업에서는 이 차이가 큽니다.

CI에도 같은 명령을 씁니다. CI는 매 실행마다 npm ci로 새로 시작하니 이론상 불필요하지만, 로컬과 CI의 빌드 명령이 다르면 언젠가 “로컬에선 됐는데” 류의 불일치가 생깁니다. 빌드 명령을 하나로 통일하는 비용이 캐시를 못 쓰는 비용보다 쌉니다. 정적 블로그의 전체 빌드는 어차피 수 초입니다.

자주 묻는 질문

astro build --force 만 쓰면 안 되나요

됩니다. 문서가 콘텐츠 레이어 캐시를 지운다고 적어 두었고, v7.2.4 에서 그렇게 동작하는 것을 확인했습니다. 제가 파일을 지우는 쪽을 택한 건 결과를 ls 한 번으로 검증할 수 있어서입니다.

프로덕션에도 같은 일이 생기나요

대체로 안 생깁니다. npm ci 가 node_modules 를 지우고 시작하므로 스토어도 함께 사라집니다. 그래서 증상이 “프로덕션은 멀쩡한데 로컬만 이상하다”는 비대칭으로 나타나요.

.astro/ 와 node_modules/.astro/ 는 뭐가 다른가요

이름만 같습니다. 루트의 .astro/ 는 astro sync 가 만드는 타입과 메타데이터이고, node_modules/.astro/ 는 콘텐츠 레이어의 데이터 스토어입니다. 루트 쪽을 지우고 「.astro 는 지웠다」고 믿게 되는 자리가 여기입니다.

글을 지우지 않고 draft: true 로 내려도 같나요

같습니다. 스토어에 남은 항목이 되살아나는 것이라 파일 삭제든 draft 든 구분하지 않습니다.

참고 자료

  • Astro — Content Collections, Types of Collections 은 콘텐츠 레이어가 데이터를 스토리지 레이어에 저장하고 빌드 사이에 캐시한다는 근거입니다. 저장 파일의 이름과 경로는 이 문서에 없고 아래 실측입니다.
  • Astro CLI — --force 는 그 플래그가 콘텐츠 레이어 캐시를 지운다는 근거입니다.
  • npm ci 문서 는 node_modules 가 이미 있으면 지우고 시작한다는 근거입니다.

남는 것

“캐시를 지웠다”는 캐시가 몇 곳인지 알 때만 참입니다. 저는 두 곳을 지우고 다 지웠다고 믿었습니다. 세 번째 위치는 이름이 첫 번째와 같고(.astro), 위치는 아무도 안 보는 곳(node_modules)이었습니다. 도구의 캐시 목록을 아는 것과 캐시를 지우는 법을 아는 것은 다른 지식입니다.

검증하는 빌드와 개발하는 빌드는 다른 빌드여야 합니다. 개발 빌드는 빠르라고 캐시를 씁니다. 검증 빌드는 현실을 보라고 존재합니다. 하나의 npm run build로 둘 다 하려는 순간, 검증이 캐시를 읽는 날이 반드시 옵니다.


부록 1: 지금 내 프로젝트가 이 상태인지 확인하기

# 1. 스토어가 존재하는가
ls -la node_modules/.astro/

# 2. 지운 글의 slug가 산출물에 남아 있는가
npm run build
grep -rl "지운-글의-slug" dist/

# 3. 클린 빌드에서는 사라지는가
rm -rf dist node_modules/.astro && npm run build
grep -rl "지운-글의-slug" dist/   # 아무것도 안 나와야 정상

2번에서 나오고 3번에서 안 나오면 정확히 이 문제입니다.

부록 2: CI 설정

# build:clean 을 쓴다. 일반 build 는 node_modules/.astro/data-store.json 의
# 영속 저장 때문에 삭제·draft 처리한 글이 남을 수 있다.
- name: 빌드 (캐시 purge)
  run: npm run build:clean
이 글에서 고친 것 1개
  • 2026-09-27 — 콘텐츠 레이어의 캐시 동작과 --force 플래그, npm ci의 삭제 동작에 공식 문서 링크를 달았습니다. 문서가 적어 두지 않은 것(저장 파일의 이름과 경로)과 적어 둔 것을 문장에서 갈랐습니다.

이 사이트의 수치는 주 1회 DB와 다시 대조하고, 판단이 바뀌면 지우지 않고 글 안에 덧붙입니다. 갱신은 RSS로 받을 수 있습니다.