CINXE.COM

Caching | Netlify Docs

<!DOCTYPE html> <html lang="en-US"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>Caching | Netlify Docs</title> <meta name="generator" content="VuePress 1.9.9"> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:400,500,700,400italic|Roboto+Mono:400"> <link rel="icon" href="/netlify-icon.svg" type="image/svg+xml"> <link rel="apple-touch-icon" href="/apple-touch-icon.png"> <link rel="icon" href="/favicon-32x32.png" type="image/png" sizes="32x32"> <link rel="icon" href="/favicon-16x16.png" type="image/png" sizes="16x16"> <script>(function (w) { if (!w) return; const darkQuery = w.matchMedia('(prefers-color-scheme: dark)'); const root = document.documentElement; function setTheme(newTheme) { if (newTheme === 'dark' || (newTheme === 'system' && darkQuery.matches)) { root.classList.add('dark-mode'); } else { root.classList.remove('dark-mode'); } w.__theme = newTheme; } w.__setPreferredTheme = function (newTheme) { setTheme(newTheme); try { localStorage.setItem('nf-docs-theme', w.__theme); } catch (err) {} }; // If using system theme, change colors in real time // in response to user settings darkQuery.addEventListener('change', function (event) { if (w.__theme === 'system') { if (event.matches) { root.classList.add('dark-mode'); } else { root.classList.remove('dark-mode'); } } }); let preferredTheme; // Try to get saved theme try { preferredTheme = localStorage.getItem('nf-docs-theme') || 'system'; } catch (err) {} // Initialize preferredTheme setTheme(preferredTheme); })(window);</script> <script src="/rum.js" data-application-id="ededf59a-7705-4933-b2a0-5efa8b35b293" data-client-token="pub1b84fc7c7429f37e025e8160c02da8bb" data-service="docs" data-env="production" defer="true"></script> <meta name="description" content="Customize cache key variations and set Cache-Control headers to control the granularity and freshness of your cache. Purge the cache by site or cache tag."> <meta property="og:title" content="Caching"> <meta property="og:url" content="https://docs.netlify.com/platform/caching/"> <meta property="og:description" content="Customize cache key variations and set Cache-Control headers to control the granularity and freshness of your cache. Purge the cache by site or cache tag."> <meta property="og:image" content="https://docs.netlify.com/og-image.png"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta prefix="og: http://ogp.me/ns#" property="og:type" content="article"> <meta prefix="og: http://ogp.me/ns#" property="og:article:author" content="Netlify"> <meta name="google-site-verification" content="G4JqDTXMHpDyWoqIRwgw8PBqg-AncXqtdkHehcOR7kc"> <meta name="slack-app-id" content="A05P27DR8C8"> <link href="https://docs.netlify.com/platform/caching/" rel="canonical" /> <link rel="preload" href="/assets/css/0.styles.d221ae53.css" as="style"><link rel="preload" href="/assets/js/app.1a68918d.js" as="script"><link rel="preload" href="/assets/js/10.a8fb7bb3.js" as="script"><link rel="preload" href="/assets/js/2.f24e0879.js" as="script"><link rel="preload" href="/assets/js/178.c0517fab.js" as="script"><link rel="preload" href="/assets/js/21.29480efd.js" as="script"><link rel="preload" href="/assets/js/11.470e17cb.js" as="script"><link rel="preload" href="/assets/js/16.dc8f34ea.js" as="script"><link rel="preload" href="/assets/js/15.6d589b72.js" as="script"><link rel="preload" href="/assets/js/9.01fad13a.js" as="script"><link rel="preload" href="/assets/js/3.be674a14.js" as="script"> <link rel="stylesheet" href="/assets/css/0.styles.d221ae53.css"> </head> <body> <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-NMKKF2M" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript> <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar-header"><div class="navbar"><div class="navbar__logo-link"><a href="/" class="router-link-active"><span class="visuallyhidden">Netlify Docs</span> <svg width="146" height="40" viewBox="0 0 146 40" fill="none" xmlns="http://www.w3.org/2000/svg" class="netlify-lockup" data-v-4ee6c329><path d="M22.794 39.79V29.687l.21-.21h2.526l.21.21V39.79l-.21.209h-2.527l-.209-.21ZM22.794 10.314V.21l.21-.209h2.526l.21.21v10.104l-.21.21h-2.527l-.209-.21ZM14.1 32.687h-.347l-1.738-1.738v-.347l3.256-3.26 1.84.004.245.242v1.84L14.1 32.686ZM12.015 9.49v-.35l1.738-1.735h.347l3.256 3.256v1.836l-.246.248h-1.839L12.015 9.49ZM.582 18.524h14.316l.21.21v2.53l-.21.209H.582l-.21-.21v-2.53l.21-.209Z" fill="var(--lockup-lines-fill)" data-v-4ee6c329></path> <path d="M29.005 25.265h-2.526l-.21-.21v-5.912c0-1.054-.412-1.869-1.682-1.895-.654-.016-1.4 0-2.199.033l-.12.12v7.651l-.21.21h-2.526l-.21-.21V14.948l.21-.21h5.684a3.998 3.998 0 0 1 3.998 3.999v6.315l-.21.21v.003ZM41.24 20.841l-.21.21H34.5l-.21.209c0 .422.423 1.685 2.108 1.685.631 0 1.263-.21 1.476-.631l.21-.21h2.525l.21.21c-.21 1.263-1.263 3.16-4.424 3.16-3.58 0-5.265-2.526-5.265-5.477 0-2.952 1.685-5.478 5.055-5.478 3.37 0 5.056 2.526 5.056 5.478v.844Zm-3.161-2.107c0-.21-.21-1.686-1.895-1.686s-1.895 1.476-1.895 1.686l.21.21h3.37l.21-.21ZM47.136 22.104c0 .422.21.632.632.632h1.895l.209.209v2.107l-.21.21h-1.894c-1.895 0-3.58-.845-3.58-3.161v-4.634l-.21-.21h-1.475l-.21-.209v-2.107l.21-.21h1.476l.21-.209v-1.894l.209-.21h2.526l.21.21v1.894l.209.21h2.316l.21.21v2.106l-.21.21h-2.316l-.21.21V22.1l.003.003ZM54.93 25.265h-2.525l-.21-.21V10.73l.21-.21h2.526l.21.21v14.322l-.21.21v.003ZM60.618 13.046h-2.526l-.21-.209V10.73l.21-.21h2.526l.21.21v2.107l-.21.21Zm0 12.22h-2.526l-.21-.21V14.944l.21-.21h2.526l.21.21v10.112l-.21.21ZM70.52 10.73v2.107l-.21.21h-1.894c-.422 0-.632.209-.632.631v.844l.21.21H70.1l.21.21v2.106l-.21.21h-2.107l-.21.21v7.581l-.21.21H65.05l-.21-.21v-7.582l-.21-.21h-1.475l-.21-.209v-2.107l.21-.21h1.476l.21-.209v-.844c0-2.317 1.684-3.161 3.58-3.161h1.894l.21.21-.004.003ZM78.311 25.474c-.844 2.108-1.685 3.37-4.633 3.37h-1.054l-.21-.209v-2.107l.21-.21h1.054c1.053 0 1.263-.209 1.475-.84v-.21l-3.37-8.216v-2.108l.21-.21h1.894l.21.21 2.526 7.163h.21l2.525-7.163.21-.21h1.894l.21.21v2.108l-3.37 8.426.01-.004Z" fill="var(--lockup-wordmark-fill)" data-v-4ee6c329></path> <path d="M94.699 25.205V10.707l-.213-.214H92.78l-.213.214v5.117h-.213c-.661-.853-1.706-1.28-2.772-1.28-2.985 0-4.69 2.346-4.69 5.544 0 3.198 1.705 5.543 4.69 5.543 1.13 0 2.132-.469 2.772-1.28h.213l.213.854.213.213h1.493l.213-.213Zm-2.132-5.117c0 2.558-1.066 3.624-2.772 3.624-1.705 0-2.771-1.258-2.771-3.624 0-2.367 1.066-3.625 2.771-3.625 1.706 0 2.772 1.066 2.772 3.625ZM96.614 20.088c0 3.411 1.918 5.543 5.117 5.543 3.198 0 5.117-2.132 5.117-5.543 0-3.412-1.919-5.544-5.117-5.544s-5.117 2.133-5.117 5.544Zm2.132 0c0-2.346 1.066-3.625 2.985-3.625 1.918 0 2.985 1.28 2.985 3.625 0 2.345-1.067 3.624-2.985 3.624-1.92 0-2.985-1.279-2.985-3.624ZM110.26 20.088c0-2.346 1.066-3.625 2.985-3.625 1.705 0 2.345.853 2.558 1.706l.213.213h1.706l.213-.213c-.213-1.919-1.706-3.625-4.69-3.625-3.199 0-5.117 2.133-5.117 5.544 0 3.411 1.918 5.543 5.117 5.543 2.984 0 4.477-1.706 4.69-3.624l-.213-.213h-1.706l-.213.213c-.213.852-.853 1.705-2.558 1.705-1.919 0-2.985-1.279-2.985-3.624ZM127.733 22.433c0-1.919-1.066-2.772-3.199-3.198-2.132-.426-2.984-.64-2.984-1.706 0-.852.852-1.066 1.918-1.066 1.493 0 1.919.64 1.919 1.28l.214.213h1.705l.213-.213c0-2.132-1.705-3.198-4.051-3.198-2.984 0-4.05 1.492-4.05 2.984 0 1.92 1.279 2.772 3.411 3.198 2.132.427 2.772.64 2.772 1.706 0 .853-.64 1.28-2.133 1.28-1.492 0-2.132-.64-2.132-1.706l-.213-.213h-1.705l-.214.213c0 2.345 1.493 3.624 4.264 3.624 2.985 0 4.265-1.492 4.265-3.198Z" fill="var(--lockup-secondary-text-fill)" data-v-4ee6c329></path> <path d="M131.138 18.524h14.316l.209.21v2.53l-.209.209h-14.316l-.21-.21v-2.53l.21-.209Z" fill="var(--lockup-lines-fill)" data-v-4ee6c329></path></svg></a></div> <div class="navbar__actions-wrapper"><form id="search-form" role="search" class="algolia-search-wrapper search-form"><label class="search-form__label"><svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 32 32" class="search-form__label-icon-search"><path d="M20.571 15.143c0-4.411-3.589-8-8-8s-8 3.589-8 8 3.589 8 8 8 8-3.589 8-8zM29.714 30c0 1.25-1.036 2.286-2.286 2.286-0.607 0-1.196-0.25-1.607-0.679l-6.125-6.107c-2.089 1.446-4.589 2.214-7.125 2.214-6.946 0-12.571-5.625-12.571-12.571s5.625-12.571 12.571-12.571 12.571 5.625 12.571 12.571c0 2.536-0.768 5.036-2.214 7.125l6.125 6.125c0.411 0.411 0.661 1 0.661 1.607z" fill="rgba(175, 180, 182, 0.87)"></path></svg> <input id="algolia-search-input" placeholder="Search our docs by topic..." class="search-form__input"></label> <button tabindex="-1" type="reset" class="search-form__label-icon-close"><span class="visuallyhidden">Close search</span> <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 18 18"><g fill="#A3A9AC" transform="scale(-1 1) rotate(45 .571 -12.959)"><rect width="2.333" height="18.667" x="8.164" y=".003"></rect> <polygon points="8.164 .003 10.497 .003 10.497 18.67 8.164 18.67" transform="rotate(-90 9.33 9.336)"></polygon></g></svg></button> <div class="search-form__content-overlay"></div></form> <div class="navbar__right-actions"><a href="/ask-netlify/" aria-label="ask netlify" class="navbar__ask-netlify-link"><span class="navbar__ask-netlify-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 44 44" class="wrapper__icon-ask-netlify"><path fill="currentColor" d="M18.77 23.56a1.8 1.8 0 1 1-3.6 0 1.8 1.8 0 0 1 3.6 0Zm8.26 1.8a1.8 1.8 0 1 0 0-3.6 1.8 1.8 0 0 0 0 3.6Zm-3.86-1.54.03.07v.38l-.03.07-.87 1.77-.12.09h-.32l-.13-.1-.9-1.76-.03-.07v-.38l.03-.07 1-.66h.31l1.03.66Z"></path> <path fill="currentColor" fill-rule="evenodd" d="M22.32 13C28.77 13 34 17.22 34 23.67a6.97 6.97 0 0 1-6.97 6.97H10v-6.97C10 17.22 15.23 13 21.68 13h.64ZM11.55 23.16a5.24 5.24 0 0 1 10.07-2.05h.76l.01-.03a5.24 5.24 0 0 1 10.06 2.08c0 2.65-2.13 5.17-4.53 5.23H16.5a5.24 5.24 0 0 1-4.95-5.23Z" clip-rule="evenodd"></path> <path fill="currentColor" d="m24.47 8.12.07-.16 1.16-.4.15.08.63 1.95-.4.82-.16.06-.82-.4-.63-1.95Zm9.88 3.27.16.06.48 1.13-.07.16-1.9.76-.85-.34-.07-.16.35-.85 1.9-.76ZM30.04 8l.16-.06 1.1.54.05.16-1.14 2.43-.87.3-.15-.08-.3-.86L30.04 8Z" class="ask-netlify-flair"></path></svg></span> <span class="navbar__ask-netlify-label">Ask Netlify</span></a> <div class="user-menu"><!----> <button href="#menu" aria-label="menu" class="menu-trigger is-not-visible-mamabear"><svg viewBox="0 0 31 25" xmlns="http://www.w3.org/2000/svg" class="wrapper__icon-menu"><rect x="0.581177" y="0.71875" width="30" height="4" fill="currentcolor"></rect> <rect x="0.581177" y="10.7188" width="30" height="4" fill="currentcolor"></rect> <rect x="0.581177" y="20.7188" width="30" height="4" fill="currentcolor"></rect></svg></button> <nav aria-label="Netlify navigation" class="navbar__nav is-visible-mamabear navbar__authlinks" data-v-1733a580><div class="navbar__nav-list" data-v-1733a580><a href="https://app.netlify.com/login" rel="noopener noreferrer" class="navbar__nav-link" data-v-1733a580> Log in </a> <a href="https://app.netlify.com/signup" target="self" rel="noopener noreferrer" class="navbar__nav-link signup-button" data-v-1733a580> Sign up </a></div></nav></div></div></div></div></header> <main class="wrapper wrapper--main"><div class="wrapper__sidebar wrapper__navigation"><a class="button button--icon button--close is-not-visible-mamabear"><svg aria-hidden="true" width="24" height="24" viewBox="0 0 16 16" class="icon"><path d="M8,15 C4.13400675,15 1,11.8659932 1,8 C1,4.13400675 4.13400675,1 8,1 C11.8659932,1 15,4.13400675 15,8 C15,11.8659932 11.8659932,15 8,15 Z M10.44352,10.7233105 L10.4528296,10.7326201 L10.7326201,10.4528296 C11.0310632,10.1543865 11.0314986,9.66985171 10.7335912,9.37194437 L9.36507937,8.0034325 L10.7360526,6.63245928 C11.0344957,6.33401613 11.0349311,5.84948135 10.7370237,5.55157401 L10.448426,5.26297627 C10.1505186,4.96506892 9.66598387,4.96550426 9.36754072,5.26394741 L8.00589385,6.62559428 L6.63738198,5.25708241 C6.33947464,4.95917507 5.85493986,4.95961041 5.55649671,5.25805356 L5.26737991,5.54717036 C4.96893676,5.84561351 4.96850142,6.33014829 5.26640876,6.62805563 L6.62561103,7.9872579 L5.25463781,9.35823112 C4.95619466,9.65667427 4.95575932,10.141209 5.25366666,10.4391164 L5.5422644,10.7277141 C5.84017175,11.0256215 6.32470652,11.0251861 6.62314967,10.726743 L7.99412289,9.35576976 L9.36263476,10.7242816 C9.66054211,11.022189 10.1450769,11.0217536 10.44352,10.7233105 Z"></path></svg></a> <div aria-label="Docs" class="sidebar wrapper__sidebar-interior"><nav aria-label="Docs"><div><div class="sidebar__section"><span class="sidebar__section-label">Welcome</span> <ul class="sidebar__links"><li class="sidebar__link-item"><div><a href="/" aria-current="page" class="sidebar__link">Home</a></div></li><li class="sidebar__link-item"><div><a href="/get-started/" class="sidebar__link">Get started</a></div></li><li class="sidebar__link-item"><div><a href="/welcome/add-new-site/" class="sidebar__link">Add new site</a></div></li><li class="sidebar__link-item"><section tabIndex="-1" class="sidebar__group collapsable is-sub-group"><button tabIndex="-1" class="sidebar__group-heading"> Get help </button> <!----> <!----></section></li></ul></div><div class="sidebar__section"><span class="sidebar__section-label">Platform</span> <ul class="sidebar__links"><li class="sidebar__link-item"><div><a href="/platform/what-is-netlify/" class="sidebar__link">What is Netlify?</a></div></li><li class="sidebar__link-item"><div><a href="/platform/who-is-netlify-for/" class="sidebar__link">Who is Netlify for?</a></div></li><li class="sidebar__link-item"><section tabIndex="-1" class="sidebar__group collapsable is-sub-group"><button tabIndex="-1" class="sidebar__group-heading"> Checklists </button> <!----> <!----></section></li><li class="sidebar__link-item"><section tabIndex="-1" class="sidebar__group collapsable is-sub-group"><button tabIndex="-1" class="sidebar__group-heading"> How we release </button> <!----> <!----></section></li></ul></div><div class="sidebar__section"><span class="sidebar__section-label">Platform primitives</span> <ul class="sidebar__links"><li class="sidebar__link-item"><div><a href="/platform/primitives/" class="sidebar__link">Overview</a></div></li><li class="sidebar__link-item"><section tabIndex="-1" class="sidebar__group collapsable is-sub-group"><button tabIndex="-1" class="sidebar__group-heading"> Functions </button> <!----> <!----></section></li><li class="sidebar__link-item"><section tabIndex="-1" class="sidebar__group collapsable is-sub-group"><button tabIndex="-1" class="sidebar__group-heading"> Edge Functions </button> <!----> <!----></section></li><li class="sidebar__link-item"><section tabIndex="-1" class="sidebar__group collapsable is-sub-group"><button tabIndex="-1" class="sidebar__group-heading"> Image CDN </button> <!----> <!----></section></li><li class="sidebar__link-item"><div><a href="/blobs/overview/" class="sidebar__link">Blobs</a></div></li><li class="sidebar__link-item"><div><a href="/platform/caching/" aria-current="page" class="active sidebar__link">Caching</a></div></li><li class="sidebar__link-item"><div><a href="/platform/dev-server/" class="sidebar__link">Dev Server</a></div></li><li class="sidebar__link-item"><section tabIndex="-1" class="sidebar__group collapsable is-sub-group"><button tabIndex="-1" class="sidebar__group-heading"> Platform extensions </button> <!----> <!----></section></li></ul></div><div class="sidebar__section"><span class="sidebar__section-label">Frameworks</span> <ul class="sidebar__links"><li class="sidebar__link-item"><div><a href="/frameworks/" class="sidebar__link">Overview</a></div></li><li class="sidebar__link-item"><section tabIndex="-1" class="sidebar__group collapsable is-sub-group"><button tabIndex="-1" class="sidebar__group-heading"> Framework support </button> <!----> <!----></section></li><li class="sidebar__link-item"><div><a href="/frameworks/environment-variables/" class="sidebar__link">Use environment variables with frameworks</a></div></li><li class="sidebar__link-item"><div><a href="/frameworks-api/" class="sidebar__link">Frameworks API</a></div></li></ul></div><div class="sidebar__section"><span class="sidebar__section-label">Developer tools</span> <ul class="sidebar__links"><li class="sidebar__link-item"><section tabIndex="-1" class="sidebar__group collapsable is-sub-group"><button tabIndex="-1" class="sidebar__group-heading"> CLI </button> <!----> <!----></section></li><li class="sidebar__link-item"><section tabIndex="-1" class="sidebar__group collapsable is-sub-group"><button tabIndex="-1" class="sidebar__group-heading"> API </button> <!----> <!----></section></li><li class="sidebar__link-item"><div><a href="/terraform-provider/" class="sidebar__link">Terraform Provider</a></div></li><li class="sidebar__link-item"><div><a href="https://developers.netlify.app/sdk/get-started/introduction/" target="_blank" rel="noopener noreferrer" class="sidebar__link">Netlify SDK</a></div></li><li class="sidebar__link-item"><div><a href="/welcome/command-palette/" class="sidebar__link">Command Palette</a></div></li></ul></div><div class="sidebar__section"><span class="sidebar__section-label">Integrate &amp; extend</span> <ul class="sidebar__links"><li class="sidebar__link-item"><div><a href="/integrations/overview/" class="sidebar__link">Overview</a></div></li><li class="sidebar__link-item"><section tabIndex="-1" class="sidebar__group collapsable is-sub-group"><button tabIndex="-1" class="sidebar__group-heading"> Integrations </button> <!----> <!----></section></li><li class="sidebar__link-item"><section tabIndex="-1" class="sidebar__group collapsable is-sub-group"><button tabIndex="-1" class="sidebar__group-heading"> Build Plugins </button> <!----> <!----></section></li><li class="sidebar__link-item"><div><a href="/slack-app/" class="sidebar__link">Netlify App for Slack</a></div></li><li class="sidebar__link-item"><div><a href="/integrations/extend-netlify/" class="sidebar__link">Extend Netlify</a></div></li></ul></div><div class="sidebar__section"><span class="sidebar__section-label">Configure &amp; deploy site</span> <ul class="sidebar__links"><li class="sidebar__link-item"><section tabIndex="-1" class="sidebar__group collapsable is-sub-group"><button tabIndex="-1" class="sidebar__group-heading"> Git </button> <!----> <!----></section></li><li class="sidebar__link-item"><section tabIndex="-1" class="sidebar__group collapsable is-sub-group"><button tabIndex="-1" class="sidebar__group-heading"> Environment聽variables </button> <!----> <!----></section></li><li class="sidebar__link-item"><section tabIndex="-1" class="sidebar__group collapsable is-sub-group"><button tabIndex="-1" class="sidebar__group-heading"> Configure builds </button> <!----> <!----></section></li><li class="sidebar__link-item"><section tabIndex="-1" class="sidebar__group collapsable is-sub-group"><button tabIndex="-1" class="sidebar__group-heading"> Site deploys </button> <!----> <!----></section></li><li class="sidebar__link-item"><section tabIndex="-1" class="sidebar__group collapsable is-sub-group"><button tabIndex="-1" class="sidebar__group-heading"> Domains &amp; HTTPS </button> <!----> <!----></section></li><li class="sidebar__link-item"><section tabIndex="-1" class="sidebar__group collapsable is-sub-group"><button tabIndex="-1" class="sidebar__group-heading"> Static routing </button> <!----> <!----></section></li><li class="sidebar__link-item"><section tabIndex="-1" class="sidebar__group collapsable is-sub-group"><button tabIndex="-1" class="sidebar__group-heading"> Forms </button> <!----> <!----></section></li></ul></div><div class="sidebar__section"><span class="sidebar__section-label">Visual editing</span> <ul class="sidebar__links"><li class="sidebar__link-item"><section tabIndex="-1" class="sidebar__group collapsable is-sub-group"><button tabIndex="-1" class="sidebar__group-heading"> Visual Editor </button> <!----> <!----></section></li><li class="sidebar__link-item"><div><a href="/ai-assisted-publishing/" class="sidebar__link">AI-Assisted Publishing</a></div></li><li class="sidebar__link-item"><div><a href="https://visual-editor-reference.netlify.com/" target="_blank" rel="noopener noreferrer" class="sidebar__link">Visual editor reference</a></div></li></ul></div><div class="sidebar__section"><span class="sidebar__section-label">Manage data</span> <ul class="sidebar__links"><li class="sidebar__link-item"><section tabIndex="-1" class="sidebar__group collapsable is-sub-group"><button tabIndex="-1" class="sidebar__group-heading"> Connect </button> <!----> <!----></section></li></ul></div><div class="sidebar__section"><span class="sidebar__section-label">Site &amp; team management</span> <ul class="sidebar__links"><li class="sidebar__link-item"><section tabIndex="-1" class="sidebar__group collapsable is-sub-group"><button tabIndex="-1" class="sidebar__group-heading"> Accounts &amp; billing </button> <!----> <!----></section></li><li class="sidebar__link-item"><section tabIndex="-1" class="sidebar__group collapsable is-sub-group"><button tabIndex="-1" class="sidebar__group-heading"> Security </button> <!----> <!----></section></li><li class="sidebar__link-item"><section tabIndex="-1" class="sidebar__group collapsable is-sub-group"><button tabIndex="-1" class="sidebar__group-heading"> Monitor sites </button> <!----> <!----></section></li></ul></div></div></nav> <div aria-labelledby="#external-link__header" class="external-links" data-v-bad94b42><p id="external-link__header" class="external-links__header" data-v-bad94b42> Contact </p> <ul class="external-links__list" data-v-bad94b42><li class="external-links__item" data-v-bad94b42><a href="https://answers.netlify.com" target="_blank" rel="noopener noreferrer" class="external-links__link" data-v-bad94b42> Forums </a></li> <li class="external-links__item" data-v-bad94b42><a href="https://www.netlify.com/support/" target="_blank" rel="noopener noreferrer" class="external-links__link" data-v-bad94b42> Contact support </a></li></ul></div> <nav aria-label="Netlify navigation" class="navbar__nav is-visible-mamabear navbar__authlinks is-not-visible-mamabear" data-v-1733a580><div class="navbar__nav-list" data-v-1733a580><a href="https://app.netlify.com/login" rel="noopener noreferrer" class="navbar__nav-link" data-v-1733a580> Log in </a> <a href="https://app.netlify.com/signup" target="self" rel="noopener noreferrer" class="navbar__nav-link signup-button" data-v-1733a580> Sign up </a></div></nav></div></div> <div class="wrapper__sidebar wrapper__toc"><nav aria-label="On this page" data-toc="" class="contents wrapper__sidebar-interior"> <details><summary class="contents__header">On this page</summary> <ol><li><a href="/platform/caching/#default-caching-behavior" data-slug="default-caching-behavior">Default caching behavior</a> <!----></li><li><a href="/platform/caching/#cache-key-variation" data-slug="cache-key-variation">Cache key variation</a> <ul><li><a href="/platform/caching/#vary-by-query-parameter" data-slug="vary-by-query-parameter">Vary by query parameter</a> <!----></li><li><a href="/platform/caching/#vary-by-header" data-slug="vary-by-header">Vary by header</a> <!----></li><li><a href="/platform/caching/#vary-by-language" data-slug="vary-by-language">Vary by language</a> <!----></li><li><a href="/platform/caching/#vary-by-country" data-slug="vary-by-country">Vary by country</a> <!----></li><li><a href="/platform/caching/#vary-by-cookie" data-slug="vary-by-cookie">Vary by cookie</a> <!----></li><li><a href="/platform/caching/#combine-variations" data-slug="combine-variations">Combine variations</a> <!----></li></ul></li><li><a href="/platform/caching/#supported-cache-control-headers" data-slug="supported-cache-control-headers">Supported cache control headers</a> <ul><li><a href="/platform/caching/#stale-while-revalidate-directive" data-slug="stale-while-revalidate-directive">Stale while revalidate directive</a> <!----></li><li><a href="/platform/caching/#durable-directive" data-slug="durable-directive">Durable directive</a> <!----></li><li><a href="/platform/caching/#framework-support" data-slug="framework-support">Framework support</a> <!----></li><li><a href="/platform/caching/#default-values" data-slug="default-values">Default values</a> <!----></li><li><a href="/platform/caching/#header-precedence" data-slug="header-precedence">Header precedence</a> <!----></li></ul></li><li><a href="/platform/caching/#automatic-invalidation-with-atomic-deploys" data-slug="automatic-invalidation-with-atomic-deploys">Automatic invalidation with atomic deploys</a> <ul><li><a href="/platform/caching/#opt-out-of-automatic-invalidation" data-slug="opt-out-of-automatic-invalidation">Opt out of automatic invalidation</a> <ul></ul></li></ul></li><li><a href="/platform/caching/#on-demand-invalidation" data-slug="on-demand-invalidation">On-demand invalidation</a> <ul><li><a href="/platform/caching/#purge-by-site" data-slug="purge-by-site">Purge by site</a> <!----></li><li><a href="/platform/caching/#purge-by-cache-tag" data-slug="purge-by-cache-tag">Purge by cache tag</a> <ul></ul></li></ul></li><li><a href="/platform/caching/#debug-with-cache-status" data-slug="debug-with-cache-status">Debug with Cache-Status</a> <ul><li><a href="/platform/caching/#example-cache-status-values" data-slug="example-cache-status-values">Example Cache-Status values</a> <!----></li><li><a href="/platform/caching/#troubleshooting-tips" data-slug="troubleshooting-tips">Troubleshooting tips</a> <!----></li></ul></li><li><a href="/platform/caching/#more-resources" data-slug="more-resources">More resources</a> <!----></li></ol></details></nav></div> <section class="wrapper__content"><header class="content__default"><div class="wrapper__breadcrumbs"><span class="breadcrumb__item"><span>Platform primitives</span> <span class="breadcrumb__break">/</span></span></div> <h1>Caching</h1></header> <div class="content__default"><p>Netlify鈥檚 global caching infrastructure is built to provide stellar performance without any stale pages or broken assets for your visitors.</p> <h2 id="default-caching-behavior"><a href="#default-caching-behavior" class="header-anchor">#</a> Default caching behavior</h2> <p>Static asset responses on Netlify are cached on Netlify鈥檚 global edge nodes and <a href="#automatic-invalidation-with-atomic-deploys">automatically invalidated</a> whenever a deploy changes the content. Static asset responses can only change with new deploys. So, unless there is a new deploy or <a href="#on-demand-invalidation">manual purge</a>, we treat static asset responses as fresh for up to one year and ignore any attempts to set cache control headers with a shorter <code>max-age</code>.</p> <p>However, responses coming from <a href="/functions/overview/">Netlify Functions</a>, <a href="/edge-functions/overview/">Edge Functions</a>, and <a href="/routing/redirects/rewrites-proxies/">proxies</a> are not cached by default. Because these responses are dynamic, they may change without a new deploy and we don鈥檛 want to risk serving stale content. If you would like to cache responses from functions, edge functions, or proxies, you can <a href="#supported-cache-control-headers">add cache control headers</a> to customize the caching.</p> <p>When cached, different types of responses have different default cache key considerations that determine whether a request reuses an existing cache object or creates a new one.</p> <ul><li>values for header names sent with the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Vary" target="_blank" rel="noopener noreferrer">standard <code>Vary</code> HTTP response header</a> are factored into cache keys for all response types</li> <li>query parameters are additionally factored into cache keys by default for the following: <ul><li>responses from <a href="/functions/overview/">serverless functions</a> except for <a href="/configure-builds/on-demand-builders/">On-demand Builders</a></li> <li>responses from <a href="/edge-functions/overview/">edge functions</a> when <a href="/edge-functions/optional-configuration/#configure-an-edge-function-for-caching">opting into manual caching</a></li> <li>static assets served from a <a href="/routing/redirects/redirect-options/#query-parameters">redirect with a query parameter condition</a></li></ul></li></ul> <p>This default cache key behavior optimizes the cache hit rate for the majority of use cases. You can customize the behavior with <a href="#cache-key-variation">cache key variations</a> that take different aspects of a request into account.</p> <h2 id="cache-key-variation"><a href="#cache-key-variation" class="header-anchor">#</a> Cache key variation</h2> <p>Cache keys determine whether a request reuses an existing cache object or creates a new one. Our defaults for creating cache keys optimize the cache hit rate for the majority of use cases. However, your particular use case may have opportunities for further improvement.</p> <p>For example, if your site uses an edge function to <a href="https://edge-functions-examples.netlify.app/example/localized-content" target="_blank" rel="noopener noreferrer">localize content</a> based on user location, you may want to cache responses based on location to balance the cache hit rate with accurate localization. Or, if your site uses a serverless function where the response depends on only one query parameter, you may want to cache responses based on just that one query parameter and ignore the others to increase the cache hit rate.</p> <p>You can customize how cache key variations are created for your responses by <a href="#more-resources">setting the <code>Netlify-Vary</code> response header</a>. This gives you fine-grained control over which parts of a request are taken into consideration for matching cache objects. The <code>Netlify-Vary</code> header takes a set of comma-delimited instructions for what parts of the request to vary cache keys on. Possible instructions are as follows:</p> <ul><li><strong><a href="#vary-by-query-parameter"><code>query</code></a>:</strong> vary by the value of some or all request URL query parameters</li> <li><strong><a href="#vary-by-header"><code>header</code></a>:</strong> vary by the value of one or more request headers</li> <li><strong><a href="#vary-by-language"><code>language</code></a>:</strong> vary by the languages from the <code>Accept-Language</code> request header</li> <li><strong><a href="#vary-by-country"><code>country</code></a>:</strong> vary by the country inferred from a GeoIP lookup on the request IP address</li> <li><strong><a href="#vary-by-cookie"><code>cookie</code></a>:</strong> vary by the value of one or more request cookie keys</li></ul> <div class="custom-block netlify-tip"><p class="custom-block-title">On-demand Builders don鈥檛 support cache key variation</p> <p>On-demand Builders don鈥檛 support the <code>Netlify-Vary</code> header. They use the request鈥檚 URL path to determine whether to create a new cache object or reuse an existing one. This approach can鈥檛 be customized.</p></div> <p>Different cache objects are created for different matches to the instructions. A single additional cache object is created for all non-matches. For example, consider a response with <code>Netlify-Vary: query=style|season</code>.</p> <ul><li>All of the following matches are cached under different cache keys: <ul><li><code>/shirts?style=casual&amp;season=summer</code></li> <li><code>/shirts?style=casual&amp;season=winter</code></li> <li><code>/shirts?style=casual</code></li></ul></li> <li>Meanwhile, all of the following non-matches are cached under the same cache key. Requests to these and any other non-matches return the same response: <ul><li><code>/shirts</code></li> <li><code>/shirts?price=low</code></li> <li><code>/shirts?price=sale&amp;delivery=true</code></li></ul></li></ul> <div class="custom-block netlify-warning"><p class="custom-block-title"><span>Use the same <code>Netlify-Vary</code> header for all responses from a URL</span></p> <p>Any given URL should return the same <code>Netlify-Vary</code> header across all responses. If different resources for the same URL return different <code>Netlify-Vary</code> settings, the instructions for the first resource cached for that URL are used and the subsequent instructions are ignored.</p></div> <p>If a response includes both the <code>Netlify-Vary</code> and <code>Vary</code> headers, we respect both when creating cache keys and returning cached responses. In general, you should use <code>Netlify-Vary</code> for your custom business logic and <code>Vary</code> for content format and encoding negotiation. If you use a service like Cloudflare in front of Netlify, you should use the standard <code>Vary</code> header to pass any desired instructions to Cloudflare since <code>Netlify-Vary</code> is a Netlify-specific feature for increased customization of cache keys on Netlify.</p> <h3 id="vary-by-query-parameter"><a href="#vary-by-query-parameter" class="header-anchor">#</a> Vary by query parameter</h3> <p>You can create cache key variations based on a specific subset of query parameters included with a request or all request query parameters. The former is helpful when some query parameters do not affect the response or are unique for each request, such as analytics tracking parameters. The latter is helpful when all query parameters affect the response, such as query parameters that display variations of a product listing.</p> <ul><li><p>To create cache key variations for a subset of query parameters, specify one or more keys in a pipe-delimited list. For example:</p> <div class="language- extra-class"><pre class="language-text"><code>Netlify-Vary: query=item_id|page|per_page </code></pre></div></li> <li><p>To create cache key variations for all query parameters, include the following response header:</p> <div class="language- extra-class"><pre class="language-text"><code>Netlify-Vary: query </code></pre></div></li></ul> <p>The query parameter instruction is case-sensitive. However, the order in which parameters are specified on a given request does not affect how they are matched. For example, consider a <code>/shirts</code> path with a <code>Netlify-Vary: query</code> header to vary on all query parameters. A response for <code>/shirts?color=red&amp;size=large</code> is cached under the same key as <code>/shirts?size=large&amp;color=red</code> but a different key than <code>/shirts?Color=Red&amp;Size=Large</code>.</p> <h3 id="vary-by-header"><a href="#vary-by-header" class="header-anchor">#</a> Vary by header</h3> <p>You can create cache key variations based on your custom request headers and most <a href="https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Standard_request_fields" target="_blank" rel="noopener noreferrer">standard request headers</a>. This is helpful for custom business logic like caching different responses based on which version of your app a visitor uses.</p> <div data-v-b31881da><details class="item" data-v-6824795a><summary class="header" data-v-6824795a><svg width="21" height="13" viewBox="0 0 21 13" fill="none" xmlns="http://www.w3.org/2000/svg" class="icon-arrow-down icon-arrow-down" data-v-6824795a><path d="M20.7656 1.82812C21.0156 2.10938 21.0156 2.375 20.7656 2.625L10.9219 12.4688C10.6719 12.7188 10.4219 12.7188 10.1719 12.4688L0.328125 2.625C0.078125 2.375 0.078125 2.10938 0.328125 1.82812L1.26562 0.9375C1.51562 0.65625 1.78125 0.65625 2.0625 0.9375L10.5469 9.375L19.0312 0.9375C19.3125 0.65625 19.5781 0.65625 19.8281 0.9375L20.7656 1.82812Z"></path></svg> <span data-v-6824795a>Standard request header limitations</span></summary> <div class="content" data-v-6824795a><p data-v-6824795a>The following standard request headers can not be used with <code data-v-6824795a>Netlify-Vary</code> because they either have high cardinality that risks degraded performance or are the basis of other caching features on Netlify.</p> <ul data-v-6824795a><li data-v-6824795a><code data-v-6824795a>Accept</code></li> <li data-v-6824795a><code data-v-6824795a>Accept-Charset</code></li> <li data-v-6824795a><code data-v-6824795a>Accept-Datetime</code></li> <li data-v-6824795a><code data-v-6824795a>Accept-Encoding</code></li> <li data-v-6824795a><code data-v-6824795a>Accept-Language</code> - use <code data-v-6824795a>Vary: Accept-Language</code> or <code data-v-6824795a>Netlify-Vary</code> with a list of specific languages instead.</li> <li data-v-6824795a><code data-v-6824795a>Cache-Control</code></li> <li data-v-6824795a><code data-v-6824795a>Connection</code></li> <li data-v-6824795a><code data-v-6824795a>Content-Length</code></li> <li data-v-6824795a><code data-v-6824795a>Cookie</code> - use <code data-v-6824795a>Vary: Cookie</code> or <code data-v-6824795a>Netlify-Vary</code> with a list of specific cookie keys instead.</li> <li data-v-6824795a><code data-v-6824795a>Host</code></li> <li data-v-6824795a><code data-v-6824795a>If-Match</code></li> <li data-v-6824795a><code data-v-6824795a>If-Modified-Since</code></li> <li data-v-6824795a><code data-v-6824795a>If-None-Match</code></li> <li data-v-6824795a><code data-v-6824795a>If-Unmodified-Since</code></li> <li data-v-6824795a><code data-v-6824795a>Range</code></li> <li data-v-6824795a><code data-v-6824795a>Referer</code></li> <li data-v-6824795a><code data-v-6824795a>Upgrade</code></li> <li data-v-6824795a><code data-v-6824795a>User-Agent</code></li></ul></div></details></div> <p>To create cache key variations based on request headers, specify one or more headers in a pipe-delimited list. For example:</p> <div class="language- extra-class"><pre class="language-text"><code>Netlify-Vary: header=Device-Type|App-Version </code></pre></div><h3 id="vary-by-language"><a href="#vary-by-language" class="header-anchor">#</a> Vary by language</h3> <p>You can create cache key variations for one or more individual languages or custom language groups. These are checked against the <code>Accept-Language</code> header from the request using <a href="https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes" target="_blank" rel="noopener noreferrer">standard browser language identification codes</a>. This can be helpful for caching localized content.</p> <ul><li><p>To create cache key variations based on one or more individual languages, use a pipe-delimited list. For example:</p> <div class="language- extra-class"><pre class="language-text"><code>Netlify-Vary: language=en|de </code></pre></div></li> <li><p>To group multiple languages together, use <code>+</code>. For example:</p> <div class="language- extra-class"><pre class="language-text"><code>Netlify-Vary: language=en|es+pt|da+nl+de </code></pre></div></li></ul> <p>The language instruction respects the quality parameter from the <code>Accept-Language</code> header. This means, for example, that a request with <code>Accept-Language: fr-CH, fr;q=0.9, en;q=0.7, de;q=0.8, *;q=0.5</code> and a response with <code>Netlify-Vary: language=de+nl|en</code> use a cache object under the <code>de+nl</code> variation.</p> <div class="custom-block netlify-tip"><p class="custom-block-title"><span>Use the standard <code>Vary</code> header to vary on all languages</span></p> <p>To create cache key variations for all possible individual languages, you can use <code>Vary: Accept-Language</code> rather than listing all the options in a <code>Netlify-Vary: language</code> instruction.</p></div> <h3 id="vary-by-country"><a href="#vary-by-country" class="header-anchor">#</a> Vary by country</h3> <p>You can create cache key variations based on the geographical origin of the request. You can specify individual countries or custom country groups. These are checked against a GeoIP lookup of the request IP address using <a href="https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2" target="_blank" rel="noopener noreferrer">ISO 3166-1 two-letter codes</a>. This can be helpful for caching content about products whose availability varies by region.</p> <ul><li><p>To create cache key variations based on one or more individual countries, use a pipe-delimited list. For example:</p> <div class="language- extra-class"><pre class="language-text"><code>Netlify-Vary: country=es|de </code></pre></div></li> <li><p>To group multiple countries together, use <code>+</code>. For example:</p> <div class="language- extra-class"><pre class="language-text"><code>Netlify-Vary: country=us|es+pt|dk+nl+de </code></pre></div></li></ul> <h3 id="vary-by-cookie"><a href="#vary-by-cookie" class="header-anchor">#</a> Vary by cookie</h3> <p>You can create cache key variations based on a subset of cookie keys. This is helpful for things like cookie-based A/B testing. It鈥檚 typically bad for cache hit rate to create variations based on the entirety of the <code>Cookie</code> header value as this may include authentication details that vary for each user. So, you should instead target specific cookie keys to vary on.</p> <p>To create cache key variations based on one or more cookie keys, use a pipe-delimited list. For example:</p> <div class="language- extra-class"><pre class="language-text"><code>Netlify-Vary: cookie=ab_test|is_logged_in </code></pre></div><p>The cookie instruction is case-sensitive. However, the order that cookie keys are specified on a given response does not affect how they are matched. For example, consider a path with a <code>Netlify-Vary: cookie=ab_test|is_logged_in</code> header. A response with <code>Cookie: ab_test=new; is_logged_in=no</code> is cached under the same key as <code>Cookie: is_logged_in=no; ab_test=new</code> but a different key than <code>Cookie: AB_test=New; is_logged_in=NO</code>.</p> <h3 id="combine-variations"><a href="#combine-variations" class="header-anchor">#</a> Combine variations</h3> <p>You can use any combination of the above instructions to vary your cached content.</p> <p>To combine multiple instructions, separate them with a comma. For example:</p> <div class="language- extra-class"><pre class="language-text"><code>Netlify-Vary: query,country=es+de|us </code></pre></div><p>This tells Netlify to take both the entire query into account for cached objects, as well as the request鈥檚 country of origin.</p> <h2 id="supported-cache-control-headers"><a href="#supported-cache-control-headers" class="header-anchor">#</a> Supported cache control headers</h2> <p>Netlify supports the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control" target="_blank" rel="noopener noreferrer">standard caching directives</a> with the following cache control headers:</p> <ul><li><strong><code>Netlify-CDN-Cache-Control</code>:</strong> targeted field that applies to only Netlify鈥檚 CDN</li> <li><strong><code>CDN-Cache-Control</code>:</strong> targeted field that applies to all CDNs that support it</li> <li><strong><code>Cache-Control</code>:</strong> general field that can apply to any CDN or a visitor鈥檚 browser</li></ul> <div class="custom-block netlify-tip"><p class="custom-block-title">On-demand Builders use time to live</p> <p>On-demand Builders don鈥檛 support these cache control headers. They instead support an optional <a href="/configure-builds/on-demand-builders/#time-to-live-ttl">time to live (TTL)</a> pattern that allows you to set a fixed duration of time after which a cached builder response is invalidated.</p></div> <p>The following directives affect response caching as described below.</p> <ul><li><code>public</code>: cache the response.</li> <li><code>private</code>: Netlify鈥檚 cache is a shared cache, so using <code>private</code> means we don鈥檛 cache the response in our network and can鈥檛 reuse it for multiple clients. However, the response will be cached in the local cache for each client.</li> <li><code>no-store</code>: do not cache the response.</li> <li><code>s-maxage</code>: store and reuse the cached response in Netlify鈥檚 shared cache for this many seconds.</li> <li><code>max-age</code>: store and reuse the cached response in any cache for this many seconds. If <code>s-maxage</code> is also set, Netlify鈥檚 shared cache will use <code>s-maxage</code> instead.</li> <li><a href="#stale-while-revalidate-directive"><code>stale-while-revalidate</code></a>: keep serving a stale object out of the cache for this many seconds while the object is revalidated in the background.</li> <li><a href="#durable-directive"><code>durable</code></a>: for serverless functions only. Use to reduce function invocations and response latency. When a response is generated and cached for one edge node, store the response in Netlify鈥檚 durable cache so that other edge nodes can reuse it instead of invoking the function again.</li></ul> <h3 id="stale-while-revalidate-directive"><a href="#stale-while-revalidate-directive" class="header-anchor">#</a> Stale while revalidate directive</h3> <p>Stale while revalidate is a caching pattern that allows the cache to keep serving a stale object out of the cache while the object is revalidated in the background. This can be impactful for implementing API caching or patterns like incremental static regeneration (ISR).</p> <p>As an example use case, imagine you have a slow API endpoint that takes 5 seconds to respond. You can wrap it in a function that adds the following cache header:</p> <div class="language- extra-class"><pre class="language-text"><code>Netlify-CDN-Cache-Control: public, max-age=60, stale-while-revalidate=120 </code></pre></div><p>Here鈥檚 what this header does:</p> <ul><li><code>public</code> instructs Netlify鈥檚 edge to cache the first response.</li> <li><code>max-age=60</code> instructs the cache to continue serving the cached response for 60 seconds after the initial request. After 60 seconds, the cache is considered stale.</li> <li><code>stale-while-revalidate=120</code> instructs the cache how long it can serve stale content. If a request arrives within this specified duration after the content expired, the stale content is served while the cache revalidates the content in the background.</li></ul> <p>If there鈥檚 a steady stream of requests, visitors will get recently refreshed results from the API without having to wait 5 seconds for the API response.</p> <p>Here鈥檚 a timeline to illustrate how this works:</p> <ol><li>An initial request generates a response that gets cached (consider this to be t = 0).</li> <li>A new request is made 30 seconds later (t = 30). The cache is still fresh, so the edge serves the cached response.</li> <li>Another request is made 100 seconds later (t = 130). The cache is now stale, but the time is within the 120 <em>additional</em> seconds allotted to serve stale content. So, the edge serves the stale cached response while the cache revalidates the content in the background. Time is reset (t = 0) when the revalidated response is cached.</li> <li>Another new request is made 4 minutes later (t = 240). The cache is stale again and the time is outside the allotment for serving stale content (which ended at t = 60 + 120 = 180). The edge waits for a new response to be generated before serving and caching it. Time is reset (t = 0) when the new response is cached.</li></ol> <h3 id="durable-directive"><a href="#durable-directive" class="header-anchor">#</a> Durable directive</h3> <p>By default, when a site visitor makes a request to Netlify for content that is generated by a function, the specific edge node the visitor connects to checks its own local cache. If fresh content is not found in that node鈥檚 cache, the node invokes the function to generate a new response. This means the function is typically invoked multiple times for the same content.</p> <p>When you use the <code>durable</code> directive for a function鈥檚 response, that response is not only returned to the edge node that invoked the function but also stored in a shared cache called the <em>durable cache</em>. Whenever that content is requested, edge nodes that don鈥檛 have the response locally cached check the durable cache, and only invoke the function if the response is not found there.</p> <p><img src="/images/caching-durable.png" alt=""></p> <p>You can expect the following benefits when you add the <code>durable</code> directive to your serverless functions:</p> <ul><li><strong>Better response times and more reliable performance for edge cache misses.</strong> Without the durable cache, an edge cache miss for a serverless function always leads to a function invocation. Function invocations have variable performance and increased latency because of factors like warm vs. cold starts, the time it takes the function logic to run, and calls to third-party APIs that have their own latency profile. With the <code>durable</code> directive, many of these edge cache misses are backed by a response stored in the durable cache, so an additional function invocation isn鈥檛 required. This can also mitigate issues related to high-volume function usage with third-party providers, such as rate-limiting.</li> <li><strong>Fewer function invocations, which can lead to a reduced bill.</strong> The durable cache allows edge nodes to share a cached response, so edge nodes don鈥檛 have to invoke the function individually when they don鈥檛 already have a cached response. This reduces the number of function invocations, typically by a significant amount, and decreased usage can mean decreased costs. This can also mitigate issues with third-party providers that can occur with a high volume of function usage, such as third-party API quotas being exhausted. Note that while we aim to minimize function invocations, we do not guarantee that there鈥檚 always only a single function call for each version of a generated page. Multiple requests across different regions in a short time frame might invoke a function multiple times because the cache is eventually consistent.</li></ul> <p>Here鈥檚 an example of a serverless function using the <code>durable</code> directive:</p> <div class="language-ts extra-class"><pre class="language-ts"><code><span class="token keyword">import</span> <span class="token keyword">type</span> <span class="token punctuation">{</span> Context <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;@netlify/functions&quot;</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">async</span> <span class="token punctuation">(</span>req<span class="token operator">:</span> Request<span class="token punctuation">,</span> context<span class="token operator">:</span> Context<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Response</span><span class="token punctuation">(</span><span class="token string">&quot;Hello world&quot;</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> headers<span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string-property property">'Netlify-CDN-Cache-Control'</span><span class="token operator">:</span> <span class="token string">'public, durable, max-age=60, stale-while-revalidate=120'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre></div><p>The durable cache is compatible with all other fine-grained cache controls including cache key variations, stale while revalidate, and on-demand invalidation. This means if you鈥檙e already using the edge cache to cache function responses, adding the durable cache requires minimal code changes. Using the durable cache doesn鈥檛 add significant latency to function invocations. This is because we automatically co-locate the durable cache for a site with the site鈥檚 <a href="/functions/optional-configuration/?fn-language=ts#region">functions region</a> to minimize cross-region hops for a request.</p> <div class="custom-block netlify-warning"><p class="custom-block-title">Not yet supported on Edge Function responses</p> <p>The durable cache is currently only compatible with Netlify Function responses. The <code>durable</code> directive has no effect on responses from Netlify Edge Functions. If you would like to see this feature added, please <a href="https://www.netlify.com/support/" target="_blank" rel="noopener noreferrer">tell us more about your use case</a>.</p></div> <h3 id="framework-support"><a href="#framework-support" class="header-anchor">#</a> Framework support</h3> <p>Your ability to control caching headers varies by web framework.</p> <p>Some web frameworks give developers full control of caching headers. For example, check out our developer guides on how to use our caching primitives with the following frameworks:</p> <ul><li><a href="https://developers.netlify.com/guides/how-to-do-advanced-caching-and-isr-with-astro/" target="_blank" rel="noopener noreferrer">Astro</a></li> <li><a href="https://developers.netlify.com/guides/how-to-do-isr-and-advanced-caching-with-remix/" target="_blank" rel="noopener noreferrer">Remix</a></li></ul> <p>However, other frameworks control some or all caching headers on behalf of developers. Note the following framework-specific limitations:</p> <ul><li><p>Next.js</p> <ul><li>On Netlify, cacheable responses on sites using the Next Runtime 5.5.0 or later automatically use the durable cache</li> <li>You can override this behavior in your <a href="https://nextjs.org/docs/app/api-reference/next-config-js/headers#cache-control" target="_blank" rel="noopener noreferrer">next config file</a>, but note that Next.js did not support this before 14.2.10.</li></ul></li> <li><p><a href="/frameworks/nuxt/">Nuxt</a> v3 apps using the default <code>netlify</code> Nitro preset can鈥檛 set cache control headers on ISR routes.</p> <div class="custom-block netlify-note"><p class="custom-block-title">Automatic durable cache for Nuxt and more coming soon</p> <p>We are working on updating our framework support for Nuxt (and other frameworks powered by Nitro, such as Analog, SolidStart, and TanStack Start) to automatically use the durable cache.</p></div></li></ul> <h3 id="default-values"><a href="#default-values" class="header-anchor">#</a> Default values</h3> <p>If you don鈥檛 specify any of the supported cache control headers, we use the following default values.</p> <p>For static assets:</p> <div class="language- extra-class"><pre class="language-text"><code>Netlify-CDN-Cache-Control: public, s-maxage=31536000, must-revalidate Cache-Control: public, max-age=0, must-revalidate </code></pre></div><p>For dynamic responses:</p> <div class="language- extra-class"><pre class="language-text"><code>Cache-Control: public, max-age=0, must-revalidate </code></pre></div><h3 id="header-precedence"><a href="#header-precedence" class="header-anchor">#</a> Header precedence</h3> <p>If you specify more than one of the supported headers, Netlify will respect the most specific one. Netlify always passes <code>CDN-Cache-Control</code> and <code>Cache-Control</code> downstream so that other caches can use them. Here are some examples:</p> <ul><li>Response includes both <code>Netlify-CDN-Cache-Control</code> and <code>CDN-Cache-Control</code> <ul><li>Netlify uses the settings from <code>Netlify-CDN-Cache-Control</code></li> <li><code>CDN-Cache-Control</code> will be passed downstream for other caches to use</li></ul></li> <li>Response includes both <code>CDN-Cache-Control</code> and <code>Cache-Control</code> <ul><li>Netlify uses the settings from <code>CDN-Cache-Control</code></li> <li>Both <code>CDN-Cache-Control</code> and <code>Cache-Control</code> are passed downstream for other caches to use</li></ul></li></ul> <h2 id="automatic-invalidation-with-atomic-deploys"><a href="#automatic-invalidation-with-atomic-deploys" class="header-anchor">#</a> Automatic invalidation with atomic deploys</h2> <p>To support <a href="/site-deploys/overview/">atomic deploys</a>, all new deploys invalidate the cache for the given <a href="/site-deploys/overview/#deploy-contexts">deploy context</a> by default. For example, a new deploy of a Deploy Preview will invalidate the cache for that specific Deploy Preview number while all other Deploy Previews for the site will remain cached as is. This automation means that a cached asset may be invalidated despite the cache control headers indicating that the asset should still be considered fresh. This override guarantees that we never accidentally serve stale content.</p> <p>Automatic invalidation relies on an internal cache ID that we apply automatically to all objects on our CDN. The ID indicates both the site and the deploy context that an object belongs to.</p> <h3 id="opt-out-of-automatic-invalidation"><a href="#opt-out-of-automatic-invalidation" class="header-anchor">#</a> Opt out of automatic invalidation</h3> <p>If you want some of your cached responses from functions or proxies to persist across atomic deploys, you can opt them out of automatic invalidation.</p> <p>As an example use case, imagine a site that proxies to a CMS server that has a weekly release cycle. Any site deploy in between the weekly CMS releases invalidates the whole cache for that deploy context causing Netlify to revalidate all objects. This includes assets cached from the CMS even though they haven鈥檛 changed. This can affect performance, increase bandwidth spend, and put unnecessary strain on the CMS server. In this scenario, you can opt out of automatic invalidation for responses proxied from the CMS server to avoid these issues.</p> <p>To opt an object out of automatic cache invalidation, set the <code>Netlify-Cache-ID</code> response header with one or more custom cache IDs. To set multiple IDs, use a comma-separated list.</p> <div class="theme-code-group" data-v-5f0a03e0><div class="theme-code-group__nav" data-v-5f0a03e0><ul role="tablist" class="theme-code-group__ul" data-v-5f0a03e0><li class="theme-code-group__li" data-v-5f0a03e0><button class="theme-code-group__nav-tab" data-v-5f0a03e0> Loading error: Refresh the page to access this code sample </button></li></ul></div> <div role="tabpanel" id="one-id-tab" tabindex="0" class="theme-code-block" data-v-12d54b40><div class="language- extra-class" data-v-12d54b40><pre class="language-text" data-v-12d54b40><code data-v-12d54b40>Netlify-Cache-ID: cms-proxy </code></pre></div></div> <div role="tabpanel" id="multiple-i-ds-tab" tabindex="0" class="theme-code-block" data-v-12d54b40><div class="language- extra-class" data-v-12d54b40><pre class="language-text" data-v-12d54b40><code data-v-12d54b40>Netlify-Cache-ID: cms-proxy,product,image </code></pre></div></div></div> <p>The custom cache ID overrides the internal cache ID making it so that automatic invalidation with atomic deploys does not apply to the object. However, any <code>Cache-Control</code>聽directives for an object are still respected so you can control how long the object stays cached.</p> <p>To support granular <a href="#on-demand-invalidation">on-demand invalidation</a> of cached objects that are opted out of automatic invalidation, your custom <code>Netlify-Cache-ID</code> values are automatically registered as cache tags that you can use to purge the object by tag.</p> <p>Keep the following in mind when setting <code>Netlify-Cache-ID</code></p> <ul><li>cache IDs are case insensitive</li> <li>cache ID response headers must contain only UTF-8 encoded characters</li> <li>a single cache ID can be up to 1024 characters long</li> <li>a single response can have up to 500 cache IDs</li></ul> <h4 id="best-practices"><a href="#best-practices" class="header-anchor">#</a> Best practices</h4> <p>After you鈥檝e opted out of automatic invalidation, some site updates might not propagate as you expect them to. This is more common when your <code>Cache-Control</code> configuration keeps assets fresh for a long time. If this happens, we recommend that you use <a href="#on-demand-invalidation">on-demand invalidation</a> to purge the cache so that you don鈥檛 have to wait for revalidation based on the <code>Cache-Control</code> directives to take effect. After a manual purge, your changes should propagate fully across our CDN as requests are made to your site.</p> <p>Here are some scenarios where it鈥檚 a best practice to manually purge the cache after making changes:</p> <ul><li>Changing a redirect rule that configures a proxy to a page with a <code>Netlify-Cache-ID</code> header. The update might not propagate to all routes, since the proxied content stays in the cache.</li> <li>Changing a function that generated a response with a <code>Netlify-Cache-ID</code> header. The updated function won鈥檛 run since the previously generated response stays in the cache.</li></ul> <p>If you have sensitive content, we recommend that you don鈥檛 opt out of automatic invalidation for it. This is because we don鈥檛 want to risk your sensitive content becoming more widely available than it should be. Take the following scenario for example:</p> <ul><li>A site with sensitive content is using <a href="/security/secure-access-to-sites/traffic-rules/">Firewall Traffic Rules</a>.</li> <li>The sensitive content has been opted out of automatic invalidation.</li> <li>A new deploy is made that doesn鈥檛 include the sensitive content.</li> <li>Someone removes the Firewall Traffic Rules thinking the site doesn鈥檛 need them anymore now that the project no longer contains sensitive content.</li> <li>However, the sensitive content remains cached. The cached content is publicly available to everyone until responses are revalidated based on <code>Cache-Control</code> directives which could potentially be long-lived.</li></ul> <h2 id="on-demand-invalidation"><a href="#on-demand-invalidation" class="header-anchor">#</a> On-demand invalidation</h2> <p>If you want to invalidate cached objects while their cache control headers indicate they鈥檙e still fresh, you can purge the cache by <a href="/platform/caching/#purge-by-site">site</a> or <a href="/platform/caching/#purge-by-cache-tag">cache tag</a>. These granular options for refreshing your cache without redeploying your entire site optimize developer productivity for your team and site performance for your customers. On-demand invalidation across the entire network takes just a few seconds, even if you鈥檙e purging a tag associated with thousands of cached objects.</p> <p>You can use the following to invalidate cached objects:</p> <ul><li>a <a href="/functions/get-started/">serverless function</a> with the <code>purgeCache</code> helper</li> <li>a direct call to the <a href="https://open-api.netlify.com/#tag/purge" target="_blank" rel="noopener noreferrer"><code>purge</code> API endpoint</a> with a <a href="/api/get-started/#authentication">personal access token</a></li></ul> <p>You can use either to purge by site or by tag as demonstrated in the examples in the next sections.</p> <div data-v-b31881da><details class="item" data-v-6824795a><summary class="header" data-v-6824795a><svg width="21" height="13" viewBox="0 0 21 13" fill="none" xmlns="http://www.w3.org/2000/svg" class="icon-arrow-down icon-arrow-down" data-v-6824795a><path d="M20.7656 1.82812C21.0156 2.10938 21.0156 2.375 20.7656 2.625L10.9219 12.4688C10.6719 12.7188 10.4219 12.7188 10.1719 12.4688L0.328125 2.625C0.078125 2.375 0.078125 2.10938 0.328125 1.82812L1.26562 0.9375C1.51562 0.65625 1.78125 0.65625 2.0625 0.9375L10.5469 9.375L19.0312 0.9375C19.3125 0.65625 19.5781 0.65625 19.8281 0.9375L20.7656 1.82812Z"></path></svg> <span data-v-6824795a>Extra step for Lambda-compatible serverless functions</span></summary> <div class="content" data-v-6824795a><p data-v-6824795a>To purge the cache from a <a href="/functions/lambda-compatibility/">Lambda-compatible serverless function</a>, you must pass the <code data-v-6824795a>purge_api_token</code> value provided automatically by Netlify. This keeps your Lambda-compatible function secure.</p> <div class="language-ts extra-class" data-v-6824795a><pre class="language-ts" data-v-6824795a><code data-v-6824795a><span class="token comment" data-v-6824795a>// purge a cache tag passed by query parameter across all deploys of a site</span> <span class="token comment" data-v-6824795a>// no need to specify site ID as it is passed automatically by the purgeCache helper </span> <span class="token keyword" data-v-6824795a>import</span> <span class="token punctuation" data-v-6824795a>{</span> purgeCache <span class="token punctuation" data-v-6824795a>}</span> <span class="token keyword" data-v-6824795a>from</span> <span class="token string" data-v-6824795a>&quot;@netlify/functions&quot;</span> module<span class="token punctuation" data-v-6824795a>.</span>exports<span class="token punctuation" data-v-6824795a>.</span><span class="token function-variable function" data-v-6824795a>handler</span> <span class="token operator" data-v-6824795a>=</span> <span class="token keyword" data-v-6824795a>async</span> <span class="token punctuation" data-v-6824795a>(</span>event<span class="token punctuation" data-v-6824795a>,</span> context<span class="token punctuation" data-v-6824795a>)</span> <span class="token operator" data-v-6824795a>=&gt;</span> <span class="token punctuation" data-v-6824795a>{</span> <span class="token keyword" data-v-6824795a>const</span> token <span class="token operator" data-v-6824795a>=</span> context<span class="token punctuation" data-v-6824795a>.</span>clientContext<span class="token punctuation" data-v-6824795a>.</span>custom<span class="token punctuation" data-v-6824795a>.</span>purge_api_token<span class="token punctuation" data-v-6824795a>;</span> <span class="token keyword" data-v-6824795a>await</span> <span class="token function" data-v-6824795a>purgeCache</span><span class="token punctuation" data-v-6824795a>(</span><span class="token punctuation" data-v-6824795a>{</span> tags<span class="token operator" data-v-6824795a>:</span> <span class="token punctuation" data-v-6824795a>[</span><span class="token string" data-v-6824795a>&quot;tag1&quot;</span><span class="token punctuation" data-v-6824795a>,</span> <span class="token string" data-v-6824795a>&quot;tag2&quot;</span><span class="token punctuation" data-v-6824795a>]</span><span class="token punctuation" data-v-6824795a>,</span> token <span class="token punctuation" data-v-6824795a>}</span><span class="token punctuation" data-v-6824795a>)</span> <span class="token keyword" data-v-6824795a>return</span> <span class="token punctuation" data-v-6824795a>{</span> body<span class="token operator" data-v-6824795a>:</span> <span class="token string" data-v-6824795a>&quot;Purged!&quot;</span><span class="token punctuation" data-v-6824795a>,</span> statusCode<span class="token operator" data-v-6824795a>:</span> <span class="token number" data-v-6824795a>202</span> <span class="token punctuation" data-v-6824795a>}</span> <span class="token punctuation" data-v-6824795a>}</span> </code></pre></div></div></details></div> <h3 id="purge-by-site"><a href="#purge-by-site" class="header-anchor">#</a> Purge by site</h3> <p>Purging by site invalidates all cached assets across all deploys for the site.</p> <p>As an example use case, imagine a site that uses branch deploys for A/B testing, is backed by a content API, and needs to be automatically refreshed every hour with new content. Purging the cache by site is useful in this scenario because it keeps the content refresh in sync across all branch deploys.</p> <h5 id="use-a-function-with-the-purgecache-helper-to-purge-by-site"><a href="#use-a-function-with-the-purgecache-helper-to-purge-by-site" class="header-anchor">#</a> Use a function with the <code>purgeCache</code> helper to purge by site</h5> <p>When you use a function with the <code>purgeCache</code> helper, the site ID is passed automatically so you don鈥檛 need to specify the site.</p> <div class="language-ts extra-class"><pre class="language-ts"><code><span class="token comment">// purge all objects across all deploys for this site</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> purgeCache <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;@netlify/functions&quot;</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;Purging everything&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">await</span> <span class="token function">purgeCache</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Response</span><span class="token punctuation">(</span><span class="token string">&quot;Purged!&quot;</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> status<span class="token operator">:</span> <span class="token number">202</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> </code></pre></div><h5 id="use-a-direct-call-to-the-purge-api-to-purge-by-site"><a href="#use-a-direct-call-to-the-purge-api-to-purge-by-site" class="header-anchor">#</a> Use a direct call to the <code>purge</code> API to purge by site</h5> <p>To purge by site with a direct API call, specify the site with one of the following</p> <ul><li><strong><code>site_id</code>:</strong> for example, <code>3970e0fe-8564-4903-9a55-c5f8de49fb8b</code></li> <li><strong><code>site_slug</code>:</strong> for example, <code>mysitename</code></li></ul> <p>You can find these values for your site by visiting the Netlify UI at <div aria-label="Navigation path" class="nav-path-container"><strong>Site configuration <span aria-hidden="true">></span> General <span aria-hidden="true">></span> Site details <span aria-hidden="true">></span> Site information</strong></div> and checking the <strong>Site ID</strong> or <strong>Site name</strong>.</p> <div class="language-sh extra-class"><pre class="language-sh"><code><span class="token function">curl</span> <span class="token parameter variable">-X</span> POST <span class="token punctuation">\</span> <span class="token parameter variable">-H</span> <span class="token string">&quot;Content-Type: application/json&quot;</span> <span class="token punctuation">\</span> <span class="token parameter variable">-H</span> <span class="token string">&quot;Authorization: Bearer &lt;personal_access_token&gt;&quot;</span> <span class="token punctuation">\</span> <span class="token parameter variable">--data</span> <span class="token string">'{&quot;site_id&quot;: &quot;3970e0fe-8564-4903-9a55-c5f8de49fb8b&quot;}'</span> <span class="token punctuation">\</span> <span class="token string">'https://api.netlify.com/api/v1/purge'</span> </code></pre></div><h3 id="purge-by-cache-tag"><a href="#purge-by-cache-tag" class="header-anchor">#</a> Purge by cache tag</h3> <p>Purging by cache tag invalidates specified cached assets. You can purge by tag across all deploys of a site or only within a specific deploy context.</p> <p>As an example use case, imagine a high-traffic e-commerce site where products routinely sell out. You may want to purge promotions for products when they sell out so that customers aren鈥檛 disappointed when they follow an old cached promotion link only to find that the product isn鈥檛 currently available. Purging by cache tag is useful in this scenario because it can refresh assets related to the sold-out product without impacting performance for items that are still available.</p> <p>To purge by cache tag you must first <a href="#add-cache-tags">add cache tag response headers</a>. Then you can <a href="#invalidate-tagged-objects">invalidate tagged objects</a>.</p> <p>Keep the following in mind when purging by cache tag</p> <ul><li>cache tags are case insensitive</li> <li>cache tag response headers must contain only UTF-8 encoded characters</li> <li>a single tag can be up to 1024 characters long</li> <li>a single response can have up to 500 cache tags</li></ul> <h4 id="add-cache-tags"><a href="#add-cache-tags" class="header-anchor">#</a> Add cache tags</h4> <p>Netlify supports the following cache tag response headers</p> <ul><li><strong><code>Netlify-Cache-Tag</code>:</strong> targeted field that applies to only Netlify鈥檚 CDN</li> <li><strong><code>Cache-Tag</code>:</strong> general field that can apply to any CDN</li></ul> <p>You can specify one or more cache tags for a response. For multiple tags, use a comma-separated list:</p> <div class="theme-code-group" data-v-5f0a03e0><div class="theme-code-group__nav" data-v-5f0a03e0><ul role="tablist" class="theme-code-group__ul" data-v-5f0a03e0><li class="theme-code-group__li" data-v-5f0a03e0><button class="theme-code-group__nav-tab" data-v-5f0a03e0> Loading error: Refresh the page to access this code sample </button></li></ul></div> <div role="tabpanel" id="cache-tag-tab" tabindex="0" class="theme-code-block" data-v-12d54b40><div class="language- extra-class" data-v-12d54b40><pre class="language-text" data-v-12d54b40><code data-v-12d54b40>Cache-Tag: tag1,tag2,tag3 </code></pre></div></div> <div role="tabpanel" id="netlify-cache-tag-tab" tabindex="0" class="theme-code-block" data-v-12d54b40><div class="language- extra-class" data-v-12d54b40><pre class="language-text" data-v-12d54b40><code data-v-12d54b40>Netlify-Cache-Tag: tag1,tag2,tag3 </code></pre></div></div></div> <p>Additionally, if you鈥檝e <a href="#opt-out-of-automatic-invalidation">opted out of automatic invalidation</a> for an object, any custom cache IDs you set with the <code>Netlify-Cache-ID</code> response header are registered as tags for that cached object. This prevents cached objects from getting stuck on our CDN with no way to purge them.</p> <p>These 3 response headers work together in the following ways:</p> <ul><li>If you specify both <code>Netlify-Cache-Tag</code> and <code>Cache-Tag</code>, Netlify uses the values from <code>Netlify-Cache-Tag</code>. Netlify always passes <code>Cache-Tag</code> values downstream so other caches can use them.</li> <li>Setting <code>Netlify-Cache-Tag</code> to a value already set for <code>Netlify-Cache-ID</code> is redundant and has no extra effect on your site. If however you want to send your custom <code>Netlify-Cache-ID</code> tags downstream so other caches can use them, you must set <code>Cache-Tag</code> with the same values you鈥檝e set for <code>Netlify-Cache-ID</code>.</li> <li>Tags automatically registered based on <code>Netlify-Cache-ID</code> values do not contribute to the limit of 500 cache tags per response. They have their own separate limit of 500 cache IDs per response.</li></ul> <p>Here are some examples:</p> <ul><li>Response includes <code>Netlify-Cache-Tag: cms-proxy</code> and <code>Cache-Tag: cms-asset</code>: <ul><li>Netlify tags the cached object with the value from <code>Netlify-Cache-Tag</code>.</li> <li>You can purge the object from Netlify鈥檚 cache using the <code>cms-proxy</code> tag.</li> <li>Attempts to purge the <code>cms-asset</code> tag on Netlify鈥檚 CDN do not affect the cached object.</li> <li><code>Cache-Tag: cms-asset</code> is passed downstream for other caches to use.</li> <li>The cached object is automatically invalidated by new deploys.</li></ul></li> <li>Response includes <code>Netlify-Cache-ID: product</code> and <code>Cache-Tag: image</code>: <ul><li>Netlify tags the cached object with both <code>product</code> and <code>image</code>.</li> <li>You can purge the object from Netlify鈥檚 cache using either tag.</li> <li><code>Cache-Tag: image</code> is passed downstream for other caches to use. However, the <code>product</code> tag is not sent downstream.</li> <li>The cached object persists after new deploys until its <code>Cache-Control</code> directives indicate it鈥檚 stale or until you purge it manually.</li></ul></li> <li>Response includes <code>Netlify-Cache-ID</code> with 500 values and <code>Cache-Tag</code> with 500 different values: <ul><li>Netlify tags the cached object with the values from both headers.</li> <li>You can purge the object from Netlify鈥檚 cache with any of the 1000 different tags on the object.</li></ul></li></ul> <div class="custom-block netlify-tip"><p class="custom-block-title"><span>Other providers may strip <code>Cache-Tag</code> before it reaches Netlify</span></p> <p>Some providers remove <code>Cache-Tag</code> from their responses. If you are proxying to a provider that does this, you should use both <code>Netlify-Cache-Tag</code> and <code>Cache-Tag</code> so that your cache tags are applied to both Netlify and the proxy.</p></div> <h4 id="invalidate-tagged-objects"><a href="#invalidate-tagged-objects" class="header-anchor">#</a> Invalidate tagged objects</h4> <p>As mentioned above, you can use either a function or a direct API call to invalidate cached objects by tag.</p> <h5 id="use-a-function-with-the-purgecache-helper-to-purge-by-cache-tag"><a href="#use-a-function-with-the-purgecache-helper-to-purge-by-cache-tag" class="header-anchor">#</a> Use a function with the <code>purgeCache</code> helper to purge by cache tag</h5> <p>When you use a function with the <code>purgeCache</code> helper, the site ID is passed automatically so you don鈥檛 need to specify the site.</p> <p>By default, tag-based purges apply to all of the site鈥檚 deploys. To target a specific deploy, specify one or more of the following</p> <ul><li><strong><code>deployAlias</code></strong> (optional)<strong>:</strong> for example, <code>deploy-preview-11</code>. On its own, targets the specified alias on the primary domain.</li> <li><strong><code>domain</code></strong> (optional)<strong>:</strong> for example, <code>early-access.company.com</code>. On its own, targets the currently published production deploy on the specified domain.</li></ul> <div class="language-ts extra-class"><pre class="language-ts"><code><span class="token comment">// purge a cache tag passed by query parameter</span> <span class="token comment">// applies to a specific Deploy Preview of a specific subdomain</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> purgeCache <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;@netlify/functions&quot;</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">async</span> <span class="token punctuation">(</span>req<span class="token operator">:</span> Request<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> url <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name"><span class="token constant">URL</span></span><span class="token punctuation">(</span>req<span class="token punctuation">.</span>url<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> cacheTag <span class="token operator">=</span> url<span class="token punctuation">.</span>searchParams<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">&quot;tag&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>cacheTag<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> deployAlias <span class="token operator">=</span> <span class="token string">&quot;deploy-preview-11&quot;</span><span class="token punctuation">;</span> <span class="token keyword">const</span> domain <span class="token operator">=</span> <span class="token string">&quot;early-access.company.com&quot;</span><span class="token punctuation">;</span> <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;Purging tag: &quot;</span><span class="token punctuation">,</span> cacheTag<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">await</span> <span class="token function">purgeCache</span><span class="token punctuation">(</span><span class="token punctuation">{</span> tags<span class="token operator">:</span> <span class="token punctuation">[</span>cacheTag<span class="token punctuation">]</span><span class="token punctuation">,</span> deployAlias<span class="token punctuation">,</span> domain<span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Response</span><span class="token punctuation">(</span><span class="token string">&quot;Purged!&quot;</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> status<span class="token operator">:</span> <span class="token number">202</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> </code></pre></div><h5 id="use-a-direct-call-to-the-purge-api-to-purge-by-cache-tag"><a href="#use-a-direct-call-to-the-purge-api-to-purge-by-cache-tag" class="header-anchor">#</a> Use a direct call to the <code>purge</code> API to purge by cache tag</h5> <p>To purge by cache tag with a direct API call, specify the following</p> <ul><li><p><strong><code>cache_tags</code>:</strong> for example <code>news</code> or <code>blog,sale</code></p></li> <li><p>the site with either of the following:</p> <ul><li><strong><code>site_id</code>:</strong> for example, <code>3970e0fe-8564-4903-9a55-c5f8de49fb8b</code></li> <li><strong><code>site_slug</code>:</strong> for example, <code>mysitename</code></li></ul> <p>You can find these values for your site by visiting the Netlify UI at <div aria-label="Navigation path" class="nav-path-container"><strong>Site configuration <span aria-hidden="true">></span> General <span aria-hidden="true">></span> Site details <span aria-hidden="true">></span> Site information</strong></div> and checking the <strong>Site ID</strong> or <strong>Site name</strong>.</p></li></ul> <p>By default, tag-based purges apply to all of the site鈥檚 deploys. To target a specific deploy, specify one or more of the following</p> <ul><li><strong><code>deploy_alias</code></strong> (optional)<strong>:</strong> for example, <code>deploy-preview-11</code>. On its own, targets the specified alias on the primary domain.</li> <li><strong><code>domain</code></strong> (optional)<strong>:</strong> for example, <code>early-access.company.com</code>. On its own, targets the currently published production deploy on the specified domain.</li></ul> <div class="language-bash extra-class"><pre class="language-bash"><code><span class="token comment"># applies to a specific Deploy Preview of a specific subdomain</span> <span class="token function">curl</span> <span class="token parameter variable">-X</span> POST <span class="token punctuation">\</span> <span class="token parameter variable">-H</span> <span class="token string">&quot;Content-Type: application/json&quot;</span> <span class="token punctuation">\</span> <span class="token parameter variable">-H</span> <span class="token string">&quot;Authorization: Bearer &lt;personal_access_token&gt;&quot;</span> <span class="token punctuation">\</span> <span class="token parameter variable">--data</span> <span class="token string">'{&quot;site_slug&quot;: &quot;mysitename&quot;, &quot;cache_tags&quot;: [&quot;news&quot;], &quot;deploy_alias&quot;: &quot;deploy-preview-11&quot;, &quot;domain&quot;: &quot;early-access.company.com&quot;}'</span> <span class="token punctuation">\</span> <span class="token string">'https://api.netlify.com/api/v1/purge'</span> </code></pre></div><h2 id="debug-with-cache-status"><a href="#debug-with-cache-status" class="header-anchor">#</a> Debug with <code>Cache-Status</code></h2> <p>Netlify sets a <code>Cache-Status</code> header on all responses. This header contains information about how different cache layers handled each response and follows <a href="https://httpwg.org/specs/rfc9211.html" target="_blank" rel="noopener noreferrer">RFC 9211</a>.</p> <p>The <code>Cache-Status</code> header is useful for troubleshooting and monitoring. For example, you can use it for the following:</p> <ul><li>checking if you received a cached response</li> <li>finding out why you received an uncached response</li> <li>differentiating cached and uncached responses when measuring performance</li></ul> <p>To troubleshoot, examine the <code>Cache-Status</code> header on your responses and check how our network handled a request.</p> <p>If you use a frontend monitoring tool to collect performance metrics, we recommend that you record this header so that you can differentiate cached and uncached responses when analyzing your site鈥檚 performance.</p> <h3 id="example-cache-status-values"><a href="#example-cache-status-values" class="header-anchor">#</a> Example <code>Cache-Status</code> values</h3> <p>Here are some examples of common response patterns:</p> <ul><li><strong>No response found in the cache:</strong><br> <code>Cache-Status: &quot;Netlify Edge&quot;; fwd=miss</code></li> <li><strong>Cached response found and served:</strong><br> <code>Cache-Status: &quot;Netlify Edge&quot;; hit</code></li> <li><strong>Outdated response found and not served:</strong><br> <code>Cache-Status: &quot;Netlify Edge&quot;; fwd=stale</code></li> <li><strong>Outdated response found and served while we refresh in the background because the <a href="#stale-while-revalidate-directive">stale while revalidate</a> directive was used:</strong><br> <code>Cache-Status: &quot;Netlify Edge&quot;; hit; fwd=stale</code></li></ul> <p>For serverless functions with the <a href="#durable-directive"><code>durable</code> directive</a>, some common response patterns include a <code>Cache-Status</code> from the durable cache.</p> <ul><li><strong>No response found in the edge cache or durable cache:</strong><br> <code>Cache-Status: &quot;Netlify Edge&quot;; fwd=miss</code><br> <code>Cache-Status: &quot;Netlify Durable&quot;; fwd=miss; stored=true; ttl=3600</code></li> <li><strong>No response found in the edge cache; cached response found in the durable cache and served:</strong><br> <code>Cache-Status: &quot;Netlify Edge&quot;; fwd=miss</code><br> <code>Cache-Status: &quot;Netlify Durable&quot;; hit; ttl=1234</code></li> <li><strong>Outdated response found in the edge cache and not served; fresh response found in the durable cache and served:</strong><br> <code>Cache-Status: &quot;Netlify Edge&quot;; fwd=stale</code><br> <code>Cache-Status: &quot;Netlify Durable&quot;; hit; ttl=1234</code></li> <li><strong>No response found in the edge cache; outdated response found in the durable cache and not served:</strong><br> <code>Cache-Status: &quot;Netlify Edge&quot;; fwd=miss</code><br> <code>Cache-Status: &quot;Netlify Durable&quot;; fwd=stale; stored=false; ttl=-600</code></li> <li><strong>No response found in the edge cache; outdated response found in the durable cache and served while we refresh in the background because the <a href="#stale-while-revalidate-directive">stale while revalidate</a>聽directive was used:</strong><br> <code>Cache-Status: &quot;Netlify Edge&quot;; fwd=miss</code><br> <code>Cache-Status: &quot;Netlify Durable&quot;; hit; fwd=stale; stored=true; ttl=-600</code></li></ul> <h3 id="troubleshooting-tips"><a href="#troubleshooting-tips" class="header-anchor">#</a> Troubleshooting tips</h3> <ul><li>A response might have multiple <code>Cache-Status</code> headers if multiple caches were involved in serving the response. For information about Netlify cache behavior, find values that start with <code>&quot;Netlify Edge&quot;</code> or <code>&quot;Netlify Durable&quot;</code>.</li> <li>Each request you make could land on a different instance of the cache that has different content stored. If your site does not receive production traffic that warms the cache and you鈥檙e not using the <a href="#durable-directive"><code>durable</code> directive</a> for serverless functions, you will likely land on multiple caches that don鈥檛 have a cached response before getting a cache hit. Try making multiple requests when debugging caching issues to ensure you make repeat requests to the same instance of the cache.</li></ul> <h2 id="more-resources"><a href="#more-resources" class="header-anchor">#</a> More resources</h2> <p>Refer to the following resources for how to set caching headers for different types of responses</p> <ul><li><strong><a href="/functions/get-started/#synchronous-function">Get started with functions</a>:</strong> include caching headers in a function鈥檚 response object.</li> <li><strong><a href="/edge-functions/optional-configuration/#response-caching">Optional configuration for edge functions</a>:</strong> opt in to caching and customize cache behavior for an edge function.</li> <li><strong><a href="/image-cdn/overview/#custom-headers">Netlify Image CDN</a>:</strong> set headers on source images to control caching for Netlify Image CDN.</li> <li><strong><a href="/routing/headers/">Custom headers</a>:</strong> set caching headers that are sent downstream for static assets.</li> <li><strong><a href="/connect/access-data/#use-the-connect-client">Connect JavaScript client</a>:</strong> use the Connect client to query your data layer and it will automatically add cache tags and manage invalidation for you.</li></ul></div> <!----> <div class="content__default wrapper__last_updated"><time datetime="2024-10-15"> Last updated: October 15, 2024 </time></div> <!----> <div class="feedback"><div class="media"><div class="media__body"><h4 class="media__title"> Did you find this doc useful? </h4> <!----> <p class="media__copy"> Your feedback helps us improve our docs. </p> <!----> <!----></div> <div class="media__figure"><button aria-label="upvote" class="feedback__vote feedback__vote--upvote"><svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" aria-hidden="true"><g fill="none" fill-rule="evenodd"><circle cx="32" cy="32" r="32" fill="none" fill-rule="nonzero"></circle> <g stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="M40 29h-7.645l1.473-3.889c.377-.996.042-2.135-.803-2.73-.963-.679-2.263-.427-2.936.569L26 29v9a4 4 0 0 0 4 4h6.517c1.51 0 2.893-.852 3.573-2.203L42 36v-5a2 2 0 0 0-2-2zM22 29v12"></path></g></g></svg></button><button aria-label="downvote" class="feedback__vote feedback__vote--downvote"><svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" aria-hidden="true"><g fill="none" fill-rule="evenodd"><circle cx="32" cy="32" r="32" fill="none" fill-rule="nonzero"></circle> <g stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="M23 35h7.645l-1.473 3.889c-.377.996-.042 2.135.803 2.73.963.679 2.263.427 2.936-.569l4.09-6.05v-9a4 4 0 0 0-4-4h-6.518c-1.51 0-2.893.852-3.573 2.202L21 28v5a2 2 0 0 0 2 2zM41 35V23"></path></g></g></svg></button></div></div> <div><form class='form form--floating-labels feedback__form--appear' method='post' name='feedback'><input type="hidden" name="form-name" value="feedback"> <input type="hidden" name="path" value="/platform/caching/"> <input type="hidden" name="vote" value=""> <label class="visuallyhidden"> Do not fill in this field <input name="verification" value=""></label> <div class="form__field"><label><div class="form__label"> What else would you like to tell us about this doc? </div> <textarea name="feedback" class="form__textarea"></textarea></label></div> <div class="btn-group"><button disabled="disabled" class="btn"> Send </button></div></form></div></div> <footer class="footer"><div class="footer-wrapper"><nav aria-label="Footer navigation" class="footer-nav"><ul class="footer__nav"><li class="footer__nav-item"><a href="https://netlify.com/" class="footer__nav-link"> Netlify </a></li> <li class="footer__nav-item"><a href="https://netlify.com/careers/" class="footer__nav-link"> Careers </a></li> <li class="footer__nav-item"><a href="https://netlify.com/blog/" class="footer__nav-link"> Blog </a></li> <li class="footer__nav-item"><a href="https://www.netlify.com/legal/terms-of-use/" class="footer__nav-link"> Terms </a></li> <li class="footer__nav-item"><a href="https://www.netlify.com/privacy/" class="footer__nav-link"> Privacy </a></li></ul></nav> <div class="dark-mode-widget footer__theme-toggle" data-v-0d17f8d5><label for="theme-select" class="visuallyhidden" data-v-0d17f8d5>Select a theme</label> <div class="forms-select-c" data-v-0d17f8d5><div class="theme-toggle-icon" data-v-0d17f8d5><svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" data-v-0d17f8d5><path fill-rule="evenodd" clip-rule="evenodd" d="M14 7C14 10.866 10.866 14 7 14C3.13401 14 0 10.866 0 7C0 3.13401 3.13401 0 7 0C10.866 0 14 3.13401 14 7ZM7 12.2C6.99999 12.2 7.00001 12.2 7 12.2C4.12812 12.2 1.8 9.87188 1.8 7C1.8 4.12812 4.12812 1.8 7 1.8C7.00001 1.8 6.99999 1.8 7 1.8V12.2Z" fill="currentColor"></path></svg> <!----> <!----></div> <select value="system" name="theme-select" id="theme-select" class="forms-input"> <option value="system" data-v-0d17f8d5>System</option><option value="light" data-v-0d17f8d5>Light</option><option value="dark" data-v-0d17f8d5>Dark</option></select> <svg width="21" height="13" viewBox="0 0 21 13" fill="none" xmlns="http://www.w3.org/2000/svg" class="icon-arrow-down forms-select-c-arrow"><path d="M20.7656 1.82812C21.0156 2.10938 21.0156 2.375 20.7656 2.625L10.9219 12.4688C10.6719 12.7188 10.4219 12.7188 10.1719 12.4688L0.328125 2.625C0.078125 2.375 0.078125 2.10938 0.328125 1.82812L1.26562 0.9375C1.51562 0.65625 1.78125 0.65625 2.0625 0.9375L10.5469 9.375L19.0312 0.9375C19.3125 0.65625 19.5781 0.65625 19.8281 0.9375L20.7656 1.82812Z"></path></svg></div></div></div> <p class="footer__copyright">漏 2024 Netlify</p></footer></section></main></div><div class="global-ui"></div></div> <script src="/assets/js/app.1a68918d.js" defer></script><script src="/assets/js/10.a8fb7bb3.js" defer></script><script src="/assets/js/2.f24e0879.js" defer></script><script src="/assets/js/178.c0517fab.js" defer></script><script src="/assets/js/21.29480efd.js" defer></script><script src="/assets/js/11.470e17cb.js" defer></script><script src="/assets/js/16.dc8f34ea.js" defer></script><script src="/assets/js/15.6d589b72.js" defer></script><script src="/assets/js/9.01fad13a.js" defer></script><script src="/assets/js/3.be674a14.js" defer></script> <script src="/netlify-cnm/cnm.js" async defer></script> <script async id="netlify-rum-container" src="/.netlify/scripts/rum" data-netlify-rum-site-id="90a54386-9477-4113-bd6a-b9227b573d00" data-netlify-deploy-branch="main" data-netlify-deploy-context="production" data-netlify-cwv-token="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzaXRlX2lkIjoiOTBhNTQzODYtOTQ3Ny00MTEzLWJkNmEtYjkyMjdiNTczZDAwIiwiYWNjb3VudF9pZCI6IjU4ZGE4ODkzZDY4NjVkMzVjOTJhNzJiOCIsImRlcGxveV9pZCI6IjY3NDBmMzNkOTdmMTdiMDAwODkyNzMyMCIsImlzc3VlciI6Im5mc2VydmVyIn0.w3RbnVlZywFu8_P7X1si0AcznAHq7JlUzsxOj5i3olQ"></script><script type="text/javascript"> if (window.location.host === "docs.netlify.com") { !function(){var analytics=window.analytics=window.analytics||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","debug","page","once","off","on","addSourceMiddleware","addIntegrationMiddleware","setAnonymousId","addDestinationMiddleware"];analytics.factory=function(e){return function(){var t=Array.prototype.slice.call(arguments);t.unshift(e);analytics.push(t);return analytics}};for(var e=0;e<analytics.methods.length;e++){var key=analytics.methods[e];analytics[key]=analytics.factory(key)}analytics.load=function(key,e){var t=document.createElement("script");t.type="text/javascript";t.async=!0;t.src="https://cdn.segment.com/analytics.js/v1/" + key + "/analytics.min.js";var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(t,n);analytics._loadOptions=e};analytics.SNIPPET_VERSION="4.13.1"; analytics.load("kjz0qkJslzzHMcNGI3GkDb9HDZ6vspYZ"); }}(); } </script></body> </html>

Pages: 1 2 3 4 5 6 7 8 9 10