<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Clay Tercek</title><description>Writing about software development. Mostly tooling, caching, and things that bother me.</description><link>https://tercek.me/</link><language>en-us</language><atom:link href="https://tercek.me/blog/rss.xml" rel="self" type="application/rss+xml"/><copyright>© 2026 Clay Tercek</copyright><managingEditor>hello@tercek.me (Clay Tercek)</managingEditor><webMaster>hello@tercek.me (Clay Tercek)</webMaster><ttl>1440</ttl><item><title>Agents Saved React (Unfortunately)</title><link>https://tercek.me/blog/agents-saved-react/</link><guid isPermaLink="true">https://tercek.me/blog/agents-saved-react/</guid><description>We were close to React losing its grip as the default frontend framework. Then AI coding tools arrived and made it permanent.</description><pubDate>Fri, 29 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;There&apos;s &lt;a href=&quot;https://mastrojs.github.io/blog/2026-05-23-is-AI-causing-a-repeat-of-frontends-lost-decade/&quot;&gt;an article making the rounds&lt;/a&gt; about AI causing a repeat of frontend&apos;s &quot;lost decade.&quot; The central claim is that agentic coding tools are &quot;deskilling&quot; developers the way JavaScript frameworks did before them.&lt;/p&gt;
&lt;p&gt;Half of that is right.&lt;/p&gt;
&lt;p&gt;The deskilling argument actually lands for agentic coding. When an AI writes your code and you accept it without reading it, you don&apos;t need to understand what it&apos;s doing to ship something. That&apos;s a real concern.&lt;/p&gt;
&lt;p&gt;But applying &quot;deskilling&quot; to React and the framework era? That&apos;s where I disagree. The article&apos;s own list of lost skills is worth reading back: semantic HTML, CSS, browser differences, accessibility, progressive enhancement, network performance. That&apos;s exactly the list of things a good React developer still has to know. React didn&apos;t remove those requirements. It repackaged them into a component model that&apos;s more portable and easier to reason about at scale. The skills didn&apos;t disappear. The syntax changed. That reads more like &quot;old school dev mad at change&quot; than a real critique.&lt;/p&gt;
&lt;p&gt;Anyway. The bigger thing I&apos;ve been chewing on is React itself.&lt;/p&gt;
&lt;h2&gt;DX rules, UX drools&lt;/h2&gt;
&lt;p&gt;I&apos;ve spent years quietly hoping the frontend world would move on. Not because React is broken. It&apos;s not. The developer experience is genuinely excellent. Component model, unidirectional data flow, a massive library ecosystem. You can build anything with it. Slowly, on a bad connection, but anything.&lt;/p&gt;
&lt;p&gt;But &quot;you can build anything&quot; and &quot;you should build this&quot; aren&apos;t the same claim. The answer to the second one is almost never React.&lt;/p&gt;
&lt;p&gt;The performance story has been bad since the beginning. Shipping a runtime to the browser to reconcile a virtual DOM with the actual one is a strange thing to make the default, especially once browsers got good at the exact job React was hired to do. The virtual DOM was always &lt;a href=&quot;https://svelte.dev/blog/virtual-dom-is-pure-overhead&quot;&gt;a tradeoff, not a free win&lt;/a&gt;. And the framework made that tradeoff on the user&apos;s behalf, not the developer&apos;s. Bundle sizes ballooned. Time to interactive got worse. Developer experience kept improving while user experience slid in the other direction.&lt;/p&gt;
&lt;h2&gt;We were so close&lt;/h2&gt;
&lt;p&gt;Here&apos;s what&apos;s annoying: fine-grained reactivity has existed for years. &lt;a href=&quot;https://svelte.dev/&quot;&gt;Svelte&lt;/a&gt; figured this out. You write components, the compiler produces lean output, there&apos;s no virtual DOM to reconcile. It&apos;s faster. The bundles are smaller. The expensive work happens at build time instead of in the user&apos;s browser. Svelte is excellent, and I genuinely enjoy working with it.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.solidjs.com/&quot;&gt;Solid&lt;/a&gt; went further and asked: what if you got Svelte-level performance but kept React&apos;s mental model? Signals, composable primitives, JSX. Turns out you can have both. Solid routinely lands near the top of the &lt;a href=&quot;https://krausest.github.io/js-framework-benchmark/current.html&quot;&gt;framework benchmarks&lt;/a&gt;, right next to vanilla JavaScript. Solid is a great framework. Nobody uses it.&lt;/p&gt;
&lt;p&gt;Preact &lt;a href=&quot;https://preactjs.com/blog/introducing-signals/&quot;&gt;shipped signals&lt;/a&gt; for the same reason back in 2022. And the &lt;a href=&quot;https://react.dev/blog/2024/10/21/react-compiler-beta-release&quot;&gt;React Compiler&lt;/a&gt; that Meta shipped in late 2024 is trying to automate, at build time, the memoization that compiler-first frameworks made unnecessary half a decade earlier. It doesn&apos;t touch the core issue: the runtime and the reconciler still ship to the browser, and the compiler just re-renders less of the tree. It&apos;s a stopgap with good marketing.&lt;/p&gt;
&lt;p&gt;Around 2023 and into 2024, there was real momentum behind the idea that React would stop being the default. Not die. Just become one tool among several, chosen when it&apos;s actually the right fit. SvelteKit was getting attention. Solid was maturing. The conversation felt like it was actually happening.&lt;/p&gt;
&lt;h2&gt;Then agents happened&lt;/h2&gt;
&lt;p&gt;When an AI is writing your code, it writes what it knows best. Models have more React training data than anything else in the frontend space, the patterns are exhaustively documented, and the community is enormous. Ask an agent to scaffold a component and you&apos;re getting React, a &lt;a href=&quot;https://react.dev/reference/react/StrictMode#fixing-bugs-found-by-double-rendering-in-development&quot;&gt;&lt;code&gt;useEffect&lt;/code&gt; that fires twice in development&lt;/a&gt;, and a &lt;code&gt;package.json&lt;/code&gt; with thirty dependencies. That&apos;s not a criticism, it&apos;s just how it works.&lt;/p&gt;
&lt;p&gt;It&apos;s not even subtle. Someone &lt;a href=&quot;https://saschb2b.com/blog/llm-default-react-stack&quot;&gt;asked eight different models and tools&lt;/a&gt; to build a frontend: Claude, GPT, Gemini, DeepSeek, Qwen, v0, Lovable, Bolt. They all landed on nearly the same answer. React, Next.js, TypeScript, Tailwind, shadcn/ui. The stack is a property of the training corpus, not a choice. And because the next model trains on the code this one generates, the corpus skews further toward React every cycle. The default reinforces itself.&lt;/p&gt;
&lt;p&gt;So instead of the frontend world diversifying, it consolidated. React got a massive tailwind. Not the CSS kind.&lt;/p&gt;
&lt;p&gt;Svelte and Solid are still out there and still measurably faster. They&apos;re just not what the agent defaults to.&lt;/p&gt;
&lt;p&gt;What bothers me most is the timing. &lt;a href=&quot;https://svelte.dev/blog/svelte-5-is-alive&quot;&gt;Svelte 5&lt;/a&gt; shipped with &lt;a href=&quot;https://svelte.dev/blog/runes&quot;&gt;runes&lt;/a&gt; in October 2024. &lt;a href=&quot;https://start.solidjs.com/&quot;&gt;SolidStart hit 1.0&lt;/a&gt; that May. Real alternatives existed with real communities. The moment when developers might have started making deliberate, performance-conscious framework choices arrived right as the era of developers writing code by hand started winding down.&lt;/p&gt;
&lt;p&gt;AI coding tools get marketed as accelerators of innovation. But if you&apos;re generating the same patterns from three years ago at ten times the speed, that&apos;s not innovation. It&apos;s just more of the same, faster.&lt;/p&gt;
&lt;p&gt;The lost decade is here. It just comes with better autocomplete.&lt;/p&gt;
</content:encoded><author>hello@tercek.me (Clay Tercek)</author></item><item><title>AGENTS.md Is Not a README</title><link>https://tercek.me/blog/agents-md-is-not-readme/</link><guid isPermaLink="true">https://tercek.me/blog/agents-md-is-not-readme/</guid><description>Committing agent config files to shared repos quietly imposes one person&apos;s workflow on the whole team. Git figured out the right layering decades ago. We haven&apos;t caught up.</description><pubDate>Wed, 27 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Open source projects are getting plagued by agent files. &lt;code&gt;AGENTS.md&lt;/code&gt;, &lt;code&gt;CLAUDE.md&lt;/code&gt;, &lt;code&gt;.cursor/rules&lt;/code&gt;, &lt;code&gt;.github/copilot-instructions.md&lt;/code&gt;, committed skills, the works. The convention, pushed hard by the people who make these tools, is to commit them. The &lt;a href=&quot;https://agents.md&quot;&gt;agents.md&lt;/a&gt; spec frames the file as &quot;a README for agents,&quot; project infrastructure that belongs in source control next to your CI config. GitHub has written up &lt;a href=&quot;https://github.blog/ai-and-ml/github-copilot/how-to-write-a-great-agents-md-lessons-from-over-2500-repositories/&quot;&gt;lessons from 2,500+ repos&lt;/a&gt; treating it as shared documentation.&lt;/p&gt;
&lt;p&gt;I think this is mostly a mistake.&lt;/p&gt;
&lt;p&gt;These files are inherently personal. The way I drive an agent is not the way you drive an agent, and committing my workflow into a shared repo quietly assumes the whole team should converge on one. I don&apos;t think that&apos;s true, and I don&apos;t think it&apos;s desirable. Your agent workflow can and should be bespoke. It&apos;s closer to your editor config or your shell aliases than to your test suite. Nobody commits their &lt;code&gt;.vimrc&lt;/code&gt; to the project repo and expects everyone to adopt it.&lt;/p&gt;
&lt;p&gt;The usual argument for committing the file is that it documents the architecture, the repo layout, the build and release process, the conventions a new collaborator needs. All of that should be shared. But none of it is &lt;em&gt;agent&lt;/em&gt; information. It&apos;s documentation, and documentation belongs in the README, where humans will actually read it. Putting it in &lt;code&gt;AGENTS.md&lt;/code&gt; just hides your project docs somewhere only the robots look. As &lt;a href=&quot;https://news.ycombinator.com/item?id=44957647&quot;&gt;spawarotti&lt;/a&gt; put it on Hacker News:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;At this point AGENTS.md is a README.md with enough hype behind it to actually motivate people to populate it with contents. People were too lazy to write docs for other people, but funnily enough are ok with doing it for robots.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The shareable content was never agent content. It&apos;s the docs we should have been writing for each other all along.&lt;/p&gt;
&lt;p&gt;This instinct isn&apos;t fringe, but it&apos;s a minority position. You can watch the debate play out in real time: a &lt;a href=&quot;https://news.ycombinator.com/item?id=47975333&quot;&gt;Hacker News commenter&lt;/a&gt; says flatly, &quot;I would .gitignore all of those files. Is this not what is done in industry?&quot; and gets mostly disagreement. The split is always the same: shared rules enforce consistency, but they also flatten everyone into one person&apos;s setup.&lt;/p&gt;
&lt;h2&gt;So why does everyone commit them anyway?&lt;/h2&gt;
&lt;p&gt;Because the alternative is genuinely worse right now.&lt;/p&gt;
&lt;p&gt;The reason to colocate agent instructions with the code is that git gives you branch-awareness for free. Say you&apos;re on a feature branch and you tweak &lt;code&gt;AGENTS.md&lt;/code&gt; to describe a module that only exists on that branch. Then you switch back to &lt;code&gt;main&lt;/code&gt;. Because the file is tracked, your changes travel with the branch, so &lt;code&gt;main&lt;/code&gt;&apos;s agent never sees references to code that doesn&apos;t exist yet. Anyone who has tried git-ignoring their agent files knows the opposite feeling: a single global instruction file that&apos;s perpetually slightly wrong for whatever branch you&apos;re actually on.&lt;/p&gt;
&lt;p&gt;So you&apos;re stuck between two bad options. Commit the file and impose your workflow on the team, or ignore it and lose the branch-awareness that made it useful.&lt;/p&gt;
&lt;h2&gt;What we have today&lt;/h2&gt;
&lt;p&gt;The tools do offer escape hatches, they&apos;re just incomplete.&lt;/p&gt;
&lt;p&gt;Claude Code, for instance, has a real hierarchy (&lt;a href=&quot;https://code.claude.com/docs/en/memory&quot;&gt;documented here&lt;/a&gt;): a user-level &lt;code&gt;~/.claude/CLAUDE.md&lt;/code&gt; that applies across all projects and never gets committed, a team-shared project &lt;code&gt;./CLAUDE.md&lt;/code&gt;, and a personal &lt;code&gt;./CLAUDE.local.md&lt;/code&gt; that you&apos;re meant to add to &lt;code&gt;.gitignore&lt;/code&gt;. AGENTS.md has an &lt;a href=&quot;https://github.com/agentsmd/agents.md/issues/91&quot;&gt;open proposal&lt;/a&gt; to standardize a global &lt;code&gt;~/.config/agents/AGENTS.md&lt;/code&gt;, explicitly modeled on how git handles &lt;code&gt;~/.gitconfig&lt;/code&gt; versus a repo&apos;s &lt;code&gt;.git/config&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That git analogy is the right one. Git solved exactly this problem decades ago: global defaults in &lt;code&gt;~/.gitconfig&lt;/code&gt;, repo overrides in &lt;code&gt;.git/config&lt;/code&gt;, and personal per-repo ignores in &lt;code&gt;.git/info/exclude&lt;/code&gt; that never touch the shared &lt;code&gt;.gitignore&lt;/code&gt;. The local layer is never committed. We just haven&apos;t fully ported that model to agent memory.&lt;/p&gt;
&lt;p&gt;The gap is branch-awareness. &lt;code&gt;CLAUDE.local.md&lt;/code&gt; is per-worktree, not per-branch. None of the personal-config options track your branches the way a committed file does.&lt;/p&gt;
&lt;p&gt;That gap is what pushed me to build &lt;a href=&quot;https://github.com/claytercek/offstage&quot;&gt;offstage&lt;/a&gt;, a small Go CLI that keeps personal files colocated with a project without committing them to the project&apos;s repo. It&apos;s backed by a separate private git repo, and it&apos;s branch-aware: files are stored under &lt;code&gt;&amp;lt;project-id&amp;gt;/&amp;lt;git-branch&amp;gt;&lt;/code&gt;, so each branch gets its own notes, synced across machines via git hooks. It&apos;s been working for me, but I&apos;m floating it as one option, not a recommendation, and your mileage may vary. It&apos;s a partial fix at best: if a branch gets merged via a PR, offstage has no way to know, so you have to manually run &lt;code&gt;offstage merge&lt;/code&gt; to reconcile. The branch lifecycle and the file lifecycle drift apart the moment the merge happens somewhere offstage can&apos;t see.&lt;/p&gt;
&lt;h2&gt;A better solution&lt;/h2&gt;
&lt;p&gt;The real fix is more foundational than a sync tool. A few directions I think are worth exploring:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Native per-branch personal memory in the agent itself.&lt;/strong&gt; The agent already knows what branch you&apos;re on. It could keep personal instructions keyed by branch, stored outside the repo, and reconcile on branch events (merge, delete, rebase) by hooking into git the way it already hooks into everything else. This is offstage&apos;s job, done by something that can actually observe the merge.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A standardized local layer, universally honored.&lt;/strong&gt; If every agent agreed on a &lt;code&gt;~/.config/agents/&lt;/code&gt; global file plus a gitignored local override, and actually merged them at runtime, most of the &quot;personal vs. shared&quot; tension disappears. The committed &lt;code&gt;AGENTS.md&lt;/code&gt; becomes a genuine team README; everything bespoke lives in your local layer.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Treat the shared file as the floor, not the ceiling.&lt;/strong&gt; Commit only the truly project-wide facts (build commands, test runner, deploy steps) and socially discourage stuffing personal workflow into it. Keep the file boring and uncontroversial on purpose.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;None of these fully exist yet. For now I commit a deliberately minimal &lt;code&gt;AGENTS.md&lt;/code&gt; and keep everything bespoke in offstage. But I think the long-term answer is for agents to treat memory the way git treats config: layered, with the personal layer kept firmly off the shared record.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://agents.md&quot;&gt;agents.md&lt;/a&gt; — the open spec, now under the Linux Foundation&apos;s Agentic AI Foundation&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://code.claude.com/docs/en/memory&quot;&gt;Claude Code memory docs&lt;/a&gt; — the user / project / local hierarchy&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/agentsmd/agents.md/issues/91&quot;&gt;agents.md issue #91&lt;/a&gt; — proposal for a global user-level AGENTS.md&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=47975333&quot;&gt;HN: &quot;I would .gitignore all of those files&quot;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=44957647&quot;&gt;HN: spawarotti, &quot;AGENTS.md is a README.md with enough hype&quot;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/docs/gitignore&quot;&gt;git-scm.com/docs/gitignore&lt;/a&gt; — &lt;code&gt;.git/info/exclude&lt;/code&gt; and &lt;code&gt;core.excludesFile&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/claytercek/offstage&quot;&gt;offstage&lt;/a&gt; — my attempt at the branch-aware personal layer&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>hello@tercek.me (Clay Tercek)</author></item><item><title>Cache the HTML Too</title><link>https://tercek.me/blog/cache-html-too/</link><guid isPermaLink="true">https://tercek.me/blog/cache-html-too/</guid><description>The fastest request is the one your server never sees. Most teams cache assets and skip HTML. That&apos;s the part worth fixing.</description><pubDate>Tue, 26 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A lot of web frameworks and platforms bury the single easiest way to make a site faster and cheaper: CDN caching. We spend enormous effort shaving milliseconds off server-side rendering, picking the fastest meta-framework, optimizing database queries, and then skip past the one move that beats all of it. Just save the result. There&apos;s no reason to repeat the same work on every single request.&lt;/p&gt;
&lt;p&gt;The fastest request is the one your server never sees.&lt;/p&gt;
&lt;h2&gt;HTML is cacheable too&lt;/h2&gt;
&lt;p&gt;Most CDNs make this trivial, but the default trips people up. Cloudflare, Fastly, CloudFront, Vercel&apos;s edge: they all cache your static assets (CSS, JS, images, fonts) out of the box. What they do &lt;em&gt;not&lt;/em&gt; cache by default is HTML. As Cloudflare&apos;s docs put it plainly: &lt;a href=&quot;https://developers.cloudflare.com/cache/concepts/default-cache-behavior/&quot;&gt;&quot;The Cloudflare CDN does not cache HTML by default.&quot;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;That&apos;s the part people miss. Caching media feels obvious, but caching pages feels dangerous. Yet a huge fraction of the HTML you serve is identical for every visitor, and there&apos;s no reason to render it fresh each time.&lt;/p&gt;
&lt;p&gt;Turning it on is mostly a one-liner. The mechanism across every CDN is the &lt;code&gt;Cache-Control&lt;/code&gt; header: &lt;code&gt;s-maxage&lt;/code&gt; controls how long the CDN holds the response, and &lt;code&gt;stale-while-revalidate&lt;/code&gt; lets it serve the stale copy instantly while refreshing in the background. On Cloudflare you can also do it without touching your app, via a &lt;a href=&quot;https://developers.cloudflare.com/cache/how-to/cache-rules/examples/cache-everything/&quot;&gt;Cache Rule&lt;/a&gt; that marks matching URLs as eligible for cache.&lt;/p&gt;
&lt;p&gt;One real caveat: &quot;cache everything&quot; means &lt;em&gt;everything&lt;/em&gt;. If you blanket-cache HTML, you can hand one user&apos;s logged-in page to the next visitor. So scope it: exclude anything with an auth cookie, exclude your dashboard, cache the public pages. Anything that sets &lt;code&gt;Set-Cookie&lt;/code&gt;, &lt;code&gt;private&lt;/code&gt;, or &lt;code&gt;no-store&lt;/code&gt; is skipped automatically, but you should still be deliberate about it.&lt;/p&gt;
&lt;h2&gt;How much of your site actually needs to be fresh?&lt;/h2&gt;
&lt;p&gt;This is the question worth asking before you reach for anything fancier. Your blog, your marketing pages, your docs, your product listings... how often do they really change? Sure, modern frameworks render pages fast. But &quot;fast to render on every request&quot; will always lose to &quot;already rendered, sitting at an edge node 20ms from the user.&quot; Static beats dynamic, and a cache turns dynamic into static for the 99% of requests where nothing changed.&lt;/p&gt;
&lt;h2&gt;A note on framework caching&lt;/h2&gt;
&lt;p&gt;Frameworks have their own caching layers, and it&apos;s easy to conflate them with CDN caching. Next.js is the instructive case because its caching model is famously confusing.&lt;/p&gt;
&lt;p&gt;Next.js has &lt;a href=&quot;https://nextjs.org/docs/app/guides/caching&quot;&gt;several distinct caches&lt;/a&gt;: Request Memoization (dedupes calls within a single render), the Data Cache (persists &lt;code&gt;fetch&lt;/code&gt; results across requests), the Full Route Cache (server-side), and the Router Cache (client-side). The Full Route Cache serves fully rendered static pages straight from cache: at build time Next.js renders static routes to HTML plus the RSC payload, and serves that cached output instead of re-rendering per request. That&apos;s exactly the static-serving behavior you want.&lt;/p&gt;
&lt;p&gt;Server Actions are not cached. They use POST and are mutations by design; Next.js only ever memoized GET-style data fetches. Actions can &lt;em&gt;trigger&lt;/em&gt; invalidation via &lt;code&gt;revalidatePath&lt;/code&gt; / &lt;code&gt;revalidateTag&lt;/code&gt;, but they&apos;re never served from cache.&lt;/p&gt;
&lt;p&gt;Worth knowing too: &lt;a href=&quot;https://nextjs.org/blog/next-15&quot;&gt;Next.js 15 flipped the defaults&lt;/a&gt; toward less implicit caching: &lt;code&gt;fetch&lt;/code&gt; is &lt;code&gt;no-store&lt;/code&gt; by default now, and GET route handlers aren&apos;t cached by default. The framework is leaning away from caching-by-magic, which makes the case for owning your caching at the CDN layer even stronger.&lt;/p&gt;
&lt;p&gt;None of this means Next.js is bad at caching. The point is that framework caches and CDN caches solve overlapping but different problems, and the CDN layer is the portable one. It works the same no matter what you build with, and it&apos;s hard to beat for the effort it takes. Reach for it first.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.cloudflare.com/cache/concepts/default-cache-behavior/&quot;&gt;Cloudflare: default cache behavior&lt;/a&gt; — what gets cached out of the box, and what doesn&apos;t&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.cloudflare.com/cache/how-to/cache-rules/examples/cache-everything/&quot;&gt;Cloudflare: &quot;Cache Everything&quot; via Cache Rules&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nextjs.org/docs/app/guides/caching&quot;&gt;Next.js caching guide&lt;/a&gt; — the four cache layers, explained&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nextjs.org/blog/next-15&quot;&gt;Next.js 15 release notes&lt;/a&gt; — the caching default changes&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control&quot;&gt;MDN: &lt;code&gt;Cache-Control&lt;/code&gt;&lt;/a&gt; — &lt;code&gt;s-maxage&lt;/code&gt;, &lt;code&gt;stale-while-revalidate&lt;/code&gt;, and friends&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>hello@tercek.me (Clay Tercek)</author></item></channel></rss>