vercel/next.js/next-cache-components-optimizer
Claude Code and agent skill by vercel/next.js
- vendor
Checking that the SKILL.md file is still in the repository.
Optimize the meaningful UI available immediately from a Next.js route on an initial load (hard navigation) or named client-side navigation (soft navigation). Encode the goal as a failing @next/playwright instant() e2e and work it to green, one verified route and entry point at a time; the shipped test then guards against regression. Use when asked to grow a static shell, fix a slow first paint or non-instant navigation, diagnose which Suspense boundary blocks useful UI, or add instant() regress…
Install
npx vskill@latest install vercel/next.js/next-cache-components-optimizerSKILL.md
next-cache-components-optimizer
Set up an agentic optimization loop that drives a Next.js route from "not instant" to "instant" and keeps it there. The loop is test-driven: encode the goal as a failing @next/playwright instant() test, work it to green, and ship the test as the regression guard. Run it once per target route and entry point. Work the phases P → G in order; each ends in a gate.
Before changing the route, read the bundled Optimizing the static shell guide at node_modules/next/dist/docs/01-app/02-guides/optimizing-the-static-shell.md. If it is unavailable, use the online guide. The guide owns the framework behavior and implementation patterns. This skill owns the navigation contract, production rig, trustworthy RED-to-GREEN loop, parity check, differential, and report.
What is invariant, and what is yours
One thing here is fixed. The rest is yours. Read this before treating any command, platform, or env var below as a requirement.
- Invariant: the verification loop. Maximizing the shell is worthless
unless you can prove it. The proof is an automated check: under a lock that gates dynamic data, the static shell still commits. RED shows the gap, GREEN shows it closed, the test ships as the regression guard. It must run on a production-like build and must not be able to pass vacuously. Stand the loop up once; every later optimization is then verifiable by construction. The loop is the deliverable, not any one route.
- The mechanism: `@next/playwright` `instant()`. This skill uses
`instant()` as a ruler, not a stopwatch (phase A). It comes from @next/playwright (installed alongside @playwright/test, on the same release line as next), so it isn't tied to any host. Keep it. Timing a navigation by hand is too flaky to trust, and is the failure mode this skill exists to prevent.
- Yours: the rig. How you build, deploy, authenticate, configure
Playwright, and loop belongs to your stack, not to this skill. A local next build && next start, a CI/staging container, and a per-push preview deploy are equally valid rigs; the verdict comes from the build, never the platform. Phase 0 maps the invariant onto your repo. Read every platform name, env-var spelling, and command below as an example to translate, not a requirement.
Two entry points, two instant UI contracts
A route reaches the user two ways:
- Initial load (hard navigation) commits the route's prerendered static
shell; deferred parts stream in behind their loading skeletons (Suspense fallbacks, loading.tsx).
- Client-side navigation (soft navigation) reuses shared layouts and
commits the available App Shell for the destination segments that change.
The same implementation patterns can make either entry point instant. The test differs only in how the navigation is driven ("Driving the navigation in tests" below), and the available UI can differ because a soft navigation reuses layouts above the source and destination's divergence point. Guard the entry point the user named, and both when both matter. See What "instant" means.
This skill is therefore not limited to increasing the direct-load static shell. It can also fix a non-instant client navigation when caching reusable work or moving request-time work behind a focused boundary makes the destination's available App Shell commit immediately. When that App Shell is already instant and the goal is to fetch additional URL-specific content before the click, hand off to next-partial-prefetching-optimizer.
Goal
Make the most meaningful available App Shell UI commit immediately, and let only genuinely request-time work stream afterward. The shipped test deterministically encodes present ∧ instant. Non-blank is the additional bar the workflow enforces by judgment because an instant() pass alone is satisfied by an empty shell.
instant() is a ruler, not a stopwatch: assert that the shell appears under the lock; do not time it. A trustworthy verdict requires a production build (phase A).
The GREEN under the lock is the deterministic verdict; each gate keeps it trustworthy.
Reporting to the user
This loop is meant to run unattended, so it doesn't stop to ask between steps. Work the navigation the user named, finish it, and stop. What matters is how you word and present the results, not how often you interrupt. The mechanics below — the rig, RED, GREEN, the gates — are your scaffolding; the user never needs to hear those words.
- Speak their language. Describe the gap and the result in terms of what the
user sees: "navigating to the dashboard waited on the charts query before anything painted; now the layout and skeletons paint instantly and the charts stream in" — not RED/GREEN, the lock, or the phase letters.
- Show, don't tell. When you report a route, drive the browser (or attach
before/after screenshots) so the user watches the shell commit immediately and the data stream in, rather than reading a claim. Identical before and after means the fix did nothing — roll it back.
- Present a run as a list of results the user can click through — one line
per navigation: the route, what commits instantly, and what streams in — not a transcript of the loop.
- Only surface a question for a genuine fork: a fix that would change
behavior, a security-sensitive read, or a route that's dynamic by design (a per-link-prefetch candidate, not a shell to grow). A clean instant fix is not a fork — keep going. With no one to ask (an unattended run), don't block: take the safe default and note the assumption — for a cache-freshness choice, defer the read behind <Suspense> (always fresh, still instant) rather than guess a cacheLife.
The workflow
Phases B and C build the test; only the locked test from C ships.
P. PREREQUISITES: current Next.js with Cache Components
The workflow depends on framework capabilities that ship with current Next.js:
- Next.js 16.3+ with `cacheComponents: true` in
next.config.ts. Without
Cache Components there is no static shell to optimize.
- `@next/playwright` on the same release line as the project's
next; it
provides instant(). Verify with npm ls next @next/playwright (or the project's package manager) and align them if they differ. The matching testing API is in the next runtime, gated by the `experimental.exposeTestingApiInProductionBuild` config flag (phase A).
If the project does not meet these, upgrade first (npx @next/codemod upgrade automates most of it), then enable Cache Components in next.config.ts:
Enabling the flag surfaces the blocking routes to resolve first; the `next-cache-components-adoption` skill drives that adoption. Reach for this optimizer once the app builds under Cache Components.
This gate is deliberate: the skill targets current Next.js, and none of the verdicts below are meaningful on older versions.
0. SETUP: discover this project's rig, once per repo
The principles in this skill are fixed; the infrastructure they run on is yours. On first use in a repository, discover how the project builds, deploys, authenticates, and tests (inspect the repository first, and ask the user only what it cannot answer), then write the answers to a committed instant-nav.rig.md. Every later run reads that file instead of rediscovering. The required build, test context, navigation contracts, iteration loop, and file template are in `rig-template.md`.
If the repo has no Playwright e2e harness yet, standing up a minimal one (@next/playwright, a config with baseURL, one authenticated path) is part of this step; the loop does not assume a pre-existing suite.
A. RIG: a production build with the testing API exposed
Stand up the rig described by instant-nav.rig.md. Two invariants hold on every platform:
- Never measure on `next dev`. It does not prefetch, and its lock is
unreliable for blocking routes, so a dev instant() result is not a valid RED or GREEN.
- The measured build must expose the testing API. Otherwise
instant()
silently no-ops and the test passes vacuously (see reference/red-test-robustness.md). The lock-engagement proof is the phase-C RED itself: the unfixed target route is the known-blocking route, and its RED under the lock shows the lock engages on this build (C-gate); the self-validating variant in test-template.md is the in-band guarantee. Wire experimental.exposeTestingApiInProductionBuild to a condition that is true for every build you measure and never true in production:
``ts experimental: { // Use the condition your platform provides, and record it in the rig file: // local: an explicit opt-in, as below // generic CI: process.env.DEPLOY_ENV === 'staging' // Vercel: process.env.VERCEL_ENV === 'preview' exposeTestingApiInProductionBuild: process.env.EXPOSE_TESTING_API === '1', } ``
The rig is any production-like build that exposes the testing API: a local next build && next start, a CI/staging container, and a preview deploy are all equally valid; the verdict comes from the build, not the platform. See rig-template.md for the setup requirements.
For any deployed or remote build, poll the rig's LIVENESS probe to confirm the artifact contains HEAD before trusting a verdict (a stale deploy reads as a false RED or GREEN); a local next build && next start needs none. The probe mechanism is in rig-template.md.
B. BASELINE (unlocked): development scaffold, do not ship
Drive the real navigation with no instant() lock and assert that the destination's SHELL_MARKER renders as the test user: the account the e2e suite authenticates as (in CI, the CI account; locally, your e2e login fixture), with its flags, plan, role, and data. This establishes that the marker is real and reachable: not flag-gated, not redirected away, not a guessed selector. The suite runs as the test account, not the author's session; that environment drift (the rig DRIFT list) is a common source of untrustworthy REDs. Scaffold and run command: `test-template.md`. Delete this baseline before the PR.
C. RED (locked) + the VERIFY-RED gate
Wrap the same navigation in instant(); assert the shell commits under the lock. A RED here is the gap. This is the test that ships (test-template.md).
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files. Certified 14 Nov 2026.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/next-cache-components-optimizer/SKILL.md
Popularity
- Repository stars
- 142,332
- Repository forks
- 32,047
- 7-day trend score
- 59
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/vercel/next.js/next-cache-components-optimizer)