skills/astro-v6-upgrade/SKILL.md
Guide for upgrading Astro projects from v5 to v6. Use when users mention upgrading Astro, Astro v6, Astro 6, the Cloudflare adapter v13, or errors related to content collections, ViewTransitions, Astro.glob, Zod schemas, or the Content Layer API.
npx skillsauth add ascorbic/skills astro-v6-upgradeInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill is based on the final Astro v6 upgrade guide and the Cloudflare adapter v13 migration.
22.12.0 or higher. Check with node -v, and update .nvmrc / deployment config if needed. Ensure that you include CI workflows in this update if applicable.npx @astrojs/upgrade # npm
pnpm dlx @astrojs/upgrade # pnpm
yarn dlx @astrojs/upgrade # yarn
@astrojs/cloudflare v13 upgrade has significant changes. Load cloudflare.md.Before upgrading, check if the project needs content-collection migration. Many v5 projects silently relied on legacy backwards-compat (no flag required) and will break on v6.
Decision tree:
src/content/config.{js,ts,mjs,mts} exist?
src/content/ but no config file anywhere?
src/content.config.{js,ts,mjs,mts} for:
loader property → needs migration.type: set → needs migration.getEntryBySlug(), getDataEntryById(), entry.slug, or entry.render()?
If any apply, load content-collections.md.
Temporary escape hatch (if migration can't happen immediately):
export default defineConfig({
legacy: {
collectionsBackwardsCompat: true,
},
});
This preserves the v4-style behavior: src/content/config.ts location, type: 'content'/'data' without loaders, entry.slug, entry.render(), path-based IDs. It is explicitly a migration helper and should be removed as soon as the project moves to the Content Layer API.
Note: The old legacy.collections: true flag is removed. Remove it if present.
These are simple renames/replacements. Apply directly.
---
// Before
import { ViewTransitions } from 'astro:transitions';
// After
import { ClientRouter } from 'astro:transitions';
---
<!-- Before -->
<ViewTransitions />
<!-- After -->
<ClientRouter />
Also remove the handleForms prop if present - it is now removed entirely (form handling has been built in by default since v4).
---
// Before
const posts = await Astro.glob('./posts/*.md');
// After - note: no longer returns a Promise
const posts = Object.values(import.meta.glob('./posts/*.md', { eager: true }));
---
Consider content collections for content, or fast-glob for runtime globbing.
// Before (deprecated)
import { z } from 'astro:content';
import { z } from 'astro:schema';
// After
import { z } from 'astro/zod';
astro:schema and z from astro:content are deprecated - import z from astro/zod directly. For Zod 4 API changes (string formats, error messages, transforms), see zod.md.
// Astro.site in getStaticPaths → import.meta.env.SITE
export function getStaticPaths() {
const site = import.meta.env.SITE; // was Astro.site
}
// Astro.generator in getStaticPaths → just remove it
// import.meta.env.ASSETS_PREFIX → astro:config/server
import { build } from 'astro:config/server';
const prefix = build.assetsPrefix;
// Before
import { emitESMImage } from 'astro/assets/utils';
const result = await emitESMImage(imageId, false, false);
// After
import { emitImageMetadata } from 'astro/assets/utils';
const result = await emitImageMetadata(imageId);
<ClientRouter /> handleForms propForms are handled automatically since v4. Remove the prop:
<!-- Before -->
<ClientRouter handleForms />
<!-- After -->
<ClientRouter />
prefetch() with option// Before
prefetch('/about', { with: 'fetch' });
// After
prefetch('/about');
rewrite() from Actions context// Inside an Action handler - remove any context.rewrite() calls.
// Use custom endpoints instead if you need redirect/rewrite behavior.
astro:transitions internalsIf imported, remove these or use plain string event names:
// Before
import {
createAnimationScope,
isTransitionBeforePreparationEvent,
TRANSITION_AFTER_SWAP,
} from 'astro:transitions/client';
console.log(isTransitionBeforePreparationEvent(event));
console.log(TRANSITION_AFTER_SWAP);
// After
console.log(event.type === 'astro:before-preparation');
console.log('astro:after-swap');
// createAnimationScope has no replacement - remove it.
astro:actions internalsserializeActionResult and deserializeActionResult are no longer exported from astro:actions. Use getActionContext() in middleware:
import { defineMiddleware } from 'astro:middleware';
import { getActionContext } from 'astro:actions';
export const onRequest = defineMiddleware(async (context, next) => {
const { serializeActionResult, deserializeActionResult } = getActionContext(context);
// ...
});
Also remove imports of: ACTION_ERROR_CODES, ActionInputError, appendForwardSlash, astroCalledServerError, callSafely, formDataToObject, getActionQueryString, type Actions, type ActionAccept, type AstroActionContext, type SerializedActionResult.
astro.config.cjs and astro.config.cts are no longer supported. Rename to .mjs, .js, .ts, or .mts.
// Before - numbers were auto-stringified
return [{ params: { id: 1 } }];
// After - must be string or undefined
return [{ params: { id: "1" } }];
// Before
import { defineConfig } from 'astro/config';
export default defineConfig({
session: {
driver: 'redis',
options: { url: process.env.REDIS_URL },
},
});
// After
import { defineConfig, sessionDrivers } from 'astro/config';
export default defineConfig({
session: {
driver: sessionDrivers.redis({ url: process.env.REDIS_URL }),
},
});
%25 is no longer allowed in filenames. Rename any src/pages/test%25file.astro etc.
| Error | Fix |
|-------|-----|
| LegacyContentConfigError | Move src/content/config.ts → src/content.config.ts |
| ContentCollectionMissingALoaderError | Add loader to collection - see content-collections.md |
| ContentCollectionInvalidTypeError | Remove type: 'content' or type: 'data' from collection |
| GetEntryDeprecationError | Replace getEntryBySlug()/getDataEntryById() with getEntry() |
| ContentSchemaContainsSlugError | Replace .slug with .id, use .filePath for filename |
| Cannot find ViewTransitions | Use ClientRouter (see above) |
| Cannot find Astro.glob | Use import.meta.glob() (see above) |
| Node version error | Upgrade to Node 22.12.0+ |
| Zod validation errors | Check zod.md for Zod 4 changes |
| Cloudflare: Astro.locals.runtime is undefined | See cloudflare.md - access moved |
Load these only when needed:
| File | When to load |
|------|--------------|
| content-collections.md | Legacy content collections need migration |
| zod.md | Using Zod schemas with .email(), .url(), custom errors, transforms, or .default() |
| behavior-changes.md | Subtle issues: i18n redirects, script/style order, env vars, image sizing, Vitest, Shiki, SVGs |
| integration-api.md | Building integrations or adapters |
| cloudflare.md | Deploying to Cloudflare Workers / Pages, upgrading @astrojs/cloudflare to v13 |
These flags are now stable, default, or renamed. Remove from config:
export default defineConfig({
experimental: {
// Remove all of these - now stable or default:
csp: true, // stable: use `security.csp`
fonts: true, // stable
liveContentCollections: true, // stable
preserveScriptOrder: true, // now default - see behavior-changes.md
staticImportMetaEnv: true, // now default - see behavior-changes.md
headingIdCompat: true, // now default - see behavior-changes.md
failOnPrerenderConflict: true, // renamed to `prerenderConflictBehavior`
},
});
All official adapters need a major upgrade alongside Astro v6 (to accompany Vite 7 + Environment API):
@astrojs/cloudflare → v13 (significant breaking changes - see cloudflare.md)@astrojs/netlify@astrojs/node@astrojs/verceldevelopment
Maintainer-only workflow for handling GitHub Secret Scanning alerts on OpenClaw. Use when Codex needs to triage, redact, clean up, and resolve secret leakage found in issue comments, issue bodies, PR comments, or other GitHub content.
development
Maintainer workflow for OpenClaw releases, prereleases, changelog release notes, and publish validation. Use when Codex needs to prepare or verify stable or beta release steps, align version naming, assemble release notes, check release auth requirements, or validate publish-time commands and artifacts.
development
Run, watch, debug, and extend OpenClaw QA testing with qa-lab and qa-channel. Use when Codex needs to execute the repo-backed QA suite, inspect live QA artifacts, debug failing scenarios, add new QA scenarios, or explain the OpenClaw QA workflow. Prefer the live OpenAI lane with regular openai/gpt-5.4 in fast mode; do not use gpt-5.4-pro or gpt-5.4-mini unless the user explicitly overrides that policy.
development
End-to-end Parallels smoke, upgrade, and rerun workflow for OpenClaw across macOS, Windows, and Linux guests. Use when Codex needs to run, rerun, debug, or interpret VM-based install, onboarding, gateway smoke tests, latest-release-to-main upgrade checks, fresh snapshot retests, or optional Discord roundtrip verification under Parallels.