← 전체 글로 돌아가기

웹 개발

새로고침해도 변경이 안 보일 때 — 브라우저 캐시와 hard reload

일반 새로고침은 캐시된 파일을 그대로 쓴다. 배포 직후 변경이 반영되지 않아 보인다면 hard reload로 캐시를 건너뛰어야 한다.

배포를 마쳤는데 브라우저에서 새로고침해도 바뀐 내용이 안 보이는 경우가 있다. 서버 로그를 보면 요청도 잘 오고 있고, 다른 기기에서는 바뀐 버전이 보인다. 범인은 브라우저 캐시다.

일반 새로고침과 hard reload의 차이

일반 새로고침 (F5 / Cmd+R): 브라우저가 캐시에 있는 JS, CSS, 이미지 파일을 그대로 쓴다. HTML만 서버에서 새로 받아오고 나머지는 캐시에서 꺼낸다.

Hard reload (Ctrl+Shift+R / Cmd+Shift+R): 캐시를 무시하고 모든 리소스를 서버에서 새로 요청한다. 응답 헤더에 캐시가 있어도 무조건 재요청한다.

캐시 비우기 + 강력 새로고침: Chrome DevTools를 열어놓은 상태에서 새로고침 버튼을 길게 누르면 나오는 메뉴. Cache-Control과 관계없이 캐시를 완전히 비운다.

언제 어떤 방법을 쓰나

개발 중에 CSS나 JS를 바꿨는데 반영이 안 보이면 hard reload(Ctrl+Shift+R)부터 해본다. 그래도 안 보이면 DevTools → Network 탭 → "Disable cache" 체크박스를 켜고 다시 로드한다. DevTools가 열려 있는 동안 캐시를 쓰지 않아 개발할 때 편하다.

운영 배포 후 사용자가 변경 사항을 못 본다고 하면, hard reload 가이드를 먼저 안내하되 근본 해결은 캐시 전략에 있다.

근본 해결: 파일명에 해시를 붙인다

Vite, Next.js, Webpack 같은 번들러는 기본적으로 JS/CSS 파일명에 콘텐츠 해시를 붙인다.

# 변경 전
/assets/main-abc123.js

# 코드 변경 후 빌드
/assets/main-def456.js

HTML이 새 파일명을 참조하면 브라우저는 캐시에 해당 파일이 없으니 서버에서 받아온다. 사용자가 hard reload를 할 필요가 없다. 이게 제대로 동작하려면 HTML 자체는 캐시되면 안 된다.

nginx에서 HTML만 캐시 안 하는 설정:

location ~* \.html$ {
    add_header Cache-Control "no-cache, no-store, must-revalidate";
}

location ~* \.(js|css|png|jpg|woff2)$ {
    add_header Cache-Control "public, max-age=31536000, immutable";
}

HTML은 항상 최신, 해시가 붙은 정적 파일은 1년 캐시. 이 조합이면 배포 직후 사용자가 자동으로 새 버전을 받는다.

개발 중 캐시를 아예 끄고 싶다면

Chrome 기준으로 DevTools(F12)를 열고 Network 탭에서 "Disable cache" 를 체크해두면 DevTools가 열려 있는 동안 캐시를 쓰지 않는다. 개발 중에 이 옵션을 켜두면 hard reload를 반복할 필요가 없다.