<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>ETag on StackOnward</title><link>https://stackonward.com/tags/etag/</link><description>Recent content in ETag on StackOnward</description><generator>Hugo</generator><language>en-US</language><lastBuildDate>Fri, 11 Sep 2026 04:20:00 +0800</lastBuildDate><atom:link href="https://stackonward.com/tags/etag/index.xml" rel="self" type="application/rss+xml"/><item><title>Cache-Control for Static Assets: ETag and Fingerprints</title><link>https://stackonward.com/posts/static-asset-cache-control/</link><pubDate>Fri, 11 Sep 2026 04:20:00 +0800</pubDate><guid>https://stackonward.com/posts/static-asset-cache-control/</guid><description>&lt;p&gt;Cache-Control for static assets cannot be one header copied onto every path. Fingerprinted CSS, JavaScript, and fonts can stay cached for a year. HTML has to revalidate so it can pick up new URLs. Images that keep the same filename can stay cached only for as long as outdated bytes are acceptable. Responses that carry account or payment data must not enter a shared cache.&lt;/p&gt;
&lt;figure&gt;
 &lt;img src="https://stackonward.com/images/posts/static-asset-cache-control/en/cache-policy-map.svg" alt="Decision map from public versus sensitive responses to no-store, one-year immutable cache, or short cache and revalidation" loading="lazy" decoding="async"&gt;
 &lt;figcaption&gt;Cache lifetime follows whether the URL changes with the content, whether the response is public, and how long stale copies are allowed to remain.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id="cache-control-for-static-assets-starts-from-whether-the-url-changes"&gt;Cache-Control for static assets starts from whether the URL changes&lt;/h2&gt;
&lt;div class="table-responsive" role="region" aria-label="Scrollable table" tabindex="0"&gt;
 &lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Resource&lt;/th&gt;
					&lt;th&gt;When the URL changes&lt;/th&gt;
					&lt;th&gt;Usual policy&lt;/th&gt;
					&lt;th&gt;Publish requirement&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;HTML&lt;/td&gt;
					&lt;td&gt;The address stays; the document changes&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;no-cache&lt;/code&gt; or a short &lt;code&gt;max-age&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Revalidate or expire in time for the next release&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Fingerprinted CSS, JS, and fonts&lt;/td&gt;
					&lt;td&gt;The filename changes with the bytes&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;public, max-age=31536000, immutable&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;HTML must reference the new URL&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Unversioned images and PDFs&lt;/td&gt;
					&lt;td&gt;The same address may be overwritten&lt;/td&gt;
					&lt;td&gt;Short cache plus ETag&lt;/td&gt;
					&lt;td&gt;Purge that URL or change the URL after a replace&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Public API responses&lt;/td&gt;
					&lt;td&gt;Business semantics decide&lt;/td&gt;
					&lt;td&gt;Explicit &lt;code&gt;public&lt;/code&gt; or &lt;code&gt;private&lt;/code&gt;, &lt;code&gt;s-maxage&lt;/code&gt;, and &lt;code&gt;Vary&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;The cache key must cover every response difference&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Sensitive or one-time responses&lt;/td&gt;
					&lt;td&gt;Reuse is not allowed&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;no-store&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;The CDN must not cache them either&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;app.4f81c9a2.js&lt;/code&gt; can be treated as immutable only because a content change produces a new filename. A directory named &lt;code&gt;/assets/&lt;/code&gt; does not prove that every file inside it is immutable.&lt;/p&gt;</description></item></channel></rss>