리소스 힌트(Resource Hints)는 브라우저에 "이 리소스가 곧 필요하다"고 미리 귀띔해서 DNS 조회·TCP 연결·TLS 협상·다운로드를 페이지 파싱과 병렬로 진행하게 만드는 HTML 선언입니다. <link rel="preload">, prefetch, preconnect, dns-prefetch, modulepreload 다섯 가지 표준과 2024년 이후 표준화된 fetchpriority 속성, 그리고 Speculation Rules API를 잘 조합하면 LCP를 200~600ms까지 단축할 수 있죠. 이 글에서는 각 힌트의 정확한 용도, 자주 발생하는 오용 사례, 그리고 2026년 기준으로 제가 실무에서 쓰는 권장 패턴을 코드 예제와 함께 정리했습니다.
preload는 현재 페이지에서 곧 사용할 고우선순위 리소스(LCP 이미지, 중요 폰트, 핵심 스크립트)를 미리 가져오는 용도예요. 무분별하게 쓰면 오히려 LCP를 악화시킵니다.
prefetch는 다음 페이지에 필요할 가능성이 높은 리소스를 저우선순위로 가져오는 용도. 2025년부터는 Speculation Rules API가 사실상 상위 호환입니다.
preconnect는 외부 도메인(CDN, 광고, 분석)에 대한 DNS+TCP+TLS 핸드셰이크를 미리 끝내며, LCP에 영향을 주는 도메인 4~6개까지만 적용하는 것이 안전합니다.
dns-prefetch는 preconnect의 대체재가 아니라 보완재로, 보통 9개 이상의 외부 도메인이 있는 사이트에서 함께 사용합니다.
fetchpriority="high"는 LCP 이미지를 발견 즉시 최우선으로 다운로드하며, 많은 경우 preload를 대체할 수 있습니다.
Speculation Rules API와 103 Early Hints는 2026년 리소스 힌트 생태계의 표준 진화 방향이며, 잘 도입하면 다음 페이지를 사실상 "즉시" 띄울 수 있습니다.
리소스 힌트란 무엇인가요?
리소스 힌트는 W3C에서 표준화한 <link> 기반 선언이에요. 브라우저의 프리로드 스캐너(preload scanner)에 "이 리소스의 네트워크 작업을 미리 시작하라"는 지시를 전달합니다. 일반적인 HTML 파싱은 토큰화 → DOM 구성 → CSSOM 결합 → 렌더 → 리소스 발견 순서로 진행되기 때문에, 페이지 어딘가 깊숙이 위치한 LCP 이미지나 폰트는 파싱이 한참 진행된 뒤에야 다운로드가 시작되죠. 리소스 힌트는 이 순서를 뒤집어, 메인 문서 파싱 초반에 미리 네트워크 핸드셰이크와 다운로드를 트리거합니다.
2026년 기준 모든 모던 브라우저(Chrome 121+, Safari 17.4+, Firefox 125+)는 다섯 가지 핵심 힌트를 안정적으로 지원합니다. 다만 각 힌트는 용도가 명확히 분리되어 있어서, "모든 리소스에 preload를 걸자"는 식의 접근은 오히려 성능을 악화시킵니다. Google web.dev의 preload 가이드도 한 페이지당 preload를 2~3개로 제한할 것을 권장하고 있죠.
실무에서 리소스 힌트의 효과는 LCP(Largest Contentful Paint)와 TTFB(Time to First Byte) 양쪽에서 가장 크게 나타나며, 특히 외부 도메인에 호스팅된 LCP 후보 이미지에는 효과가 즉각적입니다. 자세한 LCP 최적화 흐름은 LCP 최적화 완벽 가이드를 참고하시기 바랍니다.
preload와 prefetch의 차이는 무엇인가요?
가장 자주 혼동되는 두 힌트입니다. 솔직히 저도 처음에는 이름이 비슷해서 헷갈렸어요. 핵심 차이는 "누구를 위한 리소스인가"입니다.
<!-- 사용자가 이동할 가능성이 높은 다음 라우트의 JS -->
<link rel="prefetch"
href="/_next/static/chunks/checkout-page.js"
as="script">
<!-- 카드/링크 hover 시 동적으로 추가하는 패턴 (가장 효율적) -->
<script>
document.querySelectorAll('a.card').forEach(a => {
a.addEventListener('mouseenter', () => {
const link = document.createElement('link');
link.rel = 'prefetch';
link.href = a.href;
link.as = 'document';
document.head.appendChild(link);
}, { once: true });
});
</script>
preconnect는 언제 사용하나요?
preconnect는 특정 외부 도메인에 대해 DNS 조회, TCP 핸드셰이크, 그리고 HTTPS인 경우 TLS 협상까지 미리 수행합니다. 평균적인 모바일 3G/4G 환경에서 외부 도메인 첫 연결은 100~500ms의 비용이 발생하는데, 이 시간을 메인 문서 파싱과 병렬화할 수 있다는 것이 핵심 가치입니다.
외부 폰트 서비스(Google Fonts는 fonts.googleapis.com + fonts.gstatic.com 두 도메인 모두 필요)
외부 자바스크립트 SDK(Stripe, Intercom 등) 도메인
<!-- Google Fonts 표준 패턴 -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<!-- 자체 CDN과 분석 도메인 -->
<link rel="preconnect" href="https://cdn.example.com">
<link rel="preconnect" href="https://www.googletagmanager.com">
dns-prefetch는 2026년에도 여전히 필요한가요?
네, 여전히 필요합니다. dns-prefetch는 DNS 조회만 수행해서 비용이 거의 들지 않으며, preconnect로는 감당할 수 없는 다수의 외부 도메인(광고, A/B 테스트, 분석, 위젯 등)에 효과적입니다. 제가 보통 추천하는 권장 패턴은 다음과 같아요.
Safari는 한때 dns-prefetch를 무시했지만 17.4 이후로 정상 처리하며, 모바일 Safari에서 외부 도메인이 많은 사이트의 TTFB가 측정 가능한 수준으로 개선됩니다. TTFB 자체에 대한 깊은 논의는 TTFB 완벽 가이드에서 다룹니다.
modulepreload로 ES 모듈 트리 단축하기
<link rel="modulepreload">는 ES 모듈 전용 preload입니다. 일반 preload as="script"는 모듈 그래프를 탐색하지 못해서 import한 하위 모듈들을 순차적으로 가져오지만, modulepreload는 모듈 그래프 자체를 인지하기 때문에 의존성도 함께 워밍업할 수 있습니다.
<!-- 진입 모듈과 그 의존성을 한 번에 워밍업 -->
<link rel="modulepreload" href="/app.js">
<link rel="modulepreload" href="/app/router.js">
<link rel="modulepreload" href="/app/store.js">
<script type="module" src="/app.js"></script>
Vite, Rollup, Webpack 5+는 빌드 시 모듈 그래프를 분석해 modulepreload 태그를 자동 주입합니다. Vite의 경우 build.modulePreload 옵션이 기본적으로 활성화되어 있으며, 폴리필이 포함되어 Safari 11~16에서도 동작합니다. 동작 방식은 Vite의 modulePreload 빌드 옵션 공식 문서에 상세히 정리되어 있어요.
fetchpriority 속성과 LCP 최적화
2024년 표준화된 fetchpriority 속성은 솔직히 리소스 힌트 생태계의 가장 큰 패러다임 변화예요. 기존에는 LCP 이미지를 빠르게 가져오려면 반드시 preload를 별도로 선언해야 했지만, 이제는 <img> 태그에 fetchpriority="high" 한 줄만 추가하면 동일한 효과를 얻을 수 있습니다.
<!-- LCP hero 이미지: 더 이상 preload 불필요 -->
<img src="/img/hero.avif"
alt="제품 메인 비주얼"
width="1200" height="630"
fetchpriority="high">
<!-- 반대로 아래쪽 이미지의 우선순위를 낮춰 LCP 경합 줄이기 -->
<img src="/img/decoration.webp"
alt=""
loading="lazy"
fetchpriority="low">
실제 측정 데이터에 따르면 fetchpriority="high"를 LCP 이미지에 적용했을 때 모바일 환경에서 LCP가 평균 10~25% 단축되고, Cloudflare가 자사 블로그에 게시한 측정 결과에서도 일관된 효과가 보고되었습니다. 단, 한 페이지에서 fetchpriority="high"를 가진 이미지는 1개로 제한하세요. 여러 개를 high로 지정하면 우선순위가 분산되어 효과가 사라집니다. (이건 제가 직접 실수해 봤습니다.)
Speculation Rules API와 103 Early Hints
2024년 Chrome 121에서 안정화된 Speculation Rules API는 prefetch와 prerender의 사실상 상위 호환입니다. JSON 기반 선언으로 "사용자가 어떤 링크를 클릭할 가능성이 높은가"를 브라우저에 알려, 메모리·CPU·네트워크 자원을 안전하게 제어합니다.
eagerness 값은 conservative(클릭 직전), moderate(hover/touchstart), eager(즉시), immediate 네 단계로 조절되며, 각 단계마다 동시 prerender 개수가 다릅니다. Chrome의 Speculation Rules 공식 문서에 자세한 가이드라인이 있습니다.
서버 측에서는 HTTP 103 Early Hints를 보조 수단으로 사용할 수 있어요. 메인 응답(200 OK)이 준비되기 전에 103 응답으로 Link: </style.css>; rel=preload; as=style 헤더를 먼저 흘려보내, 서버 처리 시간 동안 브라우저가 리소스를 미리 받도록 만듭니다. Cloudflare, Fastly, Vercel 등 대부분의 엣지 플랫폼이 이미 지원하고 있고, TTFB가 긴 사이트에서 LCP를 300~700ms 개선할 수 있습니다.
자주 발생하는 리소스 힌트 오용 사례
실제 사이트를 진단하면서 가장 흔하게 보이는 실수들을 정리합니다. 제가 컨설팅 다녔던 사이트 중 절반 이상이 한두 개씩 가지고 있던 문제들이에요.
1. 모든 폰트를 preload하는 안티패턴
여러 굵기·기울임·서브셋을 전부 preload하면 LCP 이미지와 대역폭 경합이 생겨 오히려 LCP가 느려집니다. "above the fold에서 즉시 보이는 텍스트의 폰트 1~2개"만 preload하고, 나머지는 font-display: swap으로 처리하세요. 자세한 폰트 최적화 전략은 한국어 웹 폰트 최적화 가이드에 정리되어 있습니다.
2. crossorigin 속성 누락
폰트와 일부 fetch 리소스는 CORS 모드로 요청되므로, preload도 반드시 동일한 CORS 컨텍스트를 가져야 합니다. 누락 시 동일 리소스가 두 번 다운로드됩니다.
3. preload 후 사용하지 않기
preload한 리소스를 3~5초 내에 사용하지 않으면 Chrome DevTools가 콘솔에 경고를 띄웁니다. 이런 리소스는 대부분 prefetch로 바꾸거나 아예 삭제해야 해요.
4. preconnect를 10개 이상 사용
모바일에서 동시 연결 수가 늘어나면 라디오 칩 활성화 시간이 길어져 배터리와 LCP에 모두 악영향을 줍니다. 4~6개를 임계점으로 보고, 나머지는 dns-prefetch로 전환하세요.
5. preload와 fetchpriority의 잘못된 조합
이미지에 이미 fetchpriority="high"가 있는데도 preload를 추가하면, 일부 브라우저 빌드에서는 우선순위가 오히려 떨어지는 경우가 관찰됩니다. fetchpriority가 가능한 경우에는 preload를 생략하는 것이 단순하고 안전합니다.
리소스 힌트 효과 측정하기
리소스 힌트는 "잘 동작하고 있는지" 확인하지 않으면 오히려 발등을 찍는 도구입니다. 측정에는 세 가지 도구를 조합합니다.
Chrome DevTools → Network → Priority 컬럼: 의도한 우선순위(Highest, High, Medium, Low, Lowest)로 다운로드되고 있는지 확인합니다. Priority 컬럼이 보이지 않으면 헤더에서 우클릭으로 추가하세요.
Lighthouse 12 / PageSpeed Insights: "Preconnect to required origins", "Preload key requests" 진단이 자동으로 제안되며, 권장하지 않는 preload는 "Avoid chaining critical requests"에서 경고합니다.
WebPageTest의 Filmstrip & Waterfall: 실제 핸드셰이크 타이밍(파란색 DNS, 주황색 Connect, 보라색 SSL)이 메인 문서와 병렬화되는지 시각적으로 확인할 수 있습니다. MDN의 link 요소 레퍼런스도 함께 참고하세요.
RUM(Real User Monitoring)에서는 Core Web Vitals JS 라이브러리(web-vitals 4.x)로 LCP·INP·CLS를 수집하고, 리소스 힌트 변경 전후의 75퍼센타일 LCP를 비교해야 합니다. A/B 테스트 환경에서는 신뢰구간이 겹치지 않을 만큼의 차이가 나오기까지 보통 1~2주의 트래픽이 필요합니다.
자주 묻는 질문
preload와 prefetch 중 어느 것이 더 빠른가요?
"빠르다"의 의미가 다릅니다. preload는 현재 페이지에서 즉시 사용할 리소스를 높은 우선순위로 가져오므로 LCP·렌더링 속도에 직접 영향을 줍니다. prefetch는 idle 시점에 낮은 우선순위로 다운로드해 다음 페이지를 빠르게 만드는 용도이므로, 현재 페이지 속도에는 거의 영향을 주지 않습니다.
preconnect는 몇 개까지 추가해도 되나요?
일반적으로 4~6개를 권장합니다. 그 이상이 되면 모바일에서 동시 연결로 인한 CPU·배터리·대역폭 부담이 LCP 이득을 상쇄합니다. LCP에 직접 영향을 주는 도메인만 preconnect하고, 나머지는 dns-prefetch로 전환하세요.
fetchpriority="high"가 있으면 preload는 불필요한가요?
대부분의 경우 그렇습니다. LCP 이미지가 HTML 마크업 내에 직접 존재하고 CSS 등으로 가려져 있지 않다면, fetchpriority="high" 한 줄로 충분합니다. 다만 LCP 이미지가 CSS background-image이거나 JS로 동적으로 삽입된다면 preload를 함께 사용해야 합니다.
Speculation Rules API는 모든 브라우저에서 동작하나요?
현재는 Chrome 121+, Edge 121+에서만 동작합니다. Safari와 Firefox는 2026년 6월 기준 미지원이지만, 미지원 브라우저는 단순히 힌트를 무시할 뿐 오류는 발생하지 않으므로 안전하게 추가할 수 있는 점진적 향상(progressive enhancement) 기법입니다.
리소스 힌트가 SEO에 영향을 주나요?
직접적인 SEO 신호는 아닙니다. 하지만 Core Web Vitals(LCP·INP·CLS)는 Google 검색 랭킹 요소이므로 간접적으로 영향을 줍니다. 특히 LCP 단축은 모바일 검색 순위에 측정 가능한 효과가 있어, 리소스 힌트 최적화는 사실상 SEO 작업의 일부로 다뤄집니다.
웹 페이지 용량의 50~70%를 차지하는 이미지, 제대로 최적화하고 계신가요? AVIF·WebP 포맷 전략, srcset과 sizes 반응형 이미지, fetchpriority로 LCP 단축하기, AVIF 모바일 디코딩 함정, 이미지 CDN 자동 최적화까지 2026년 실전 코드와 함께 총정리합니다.