Skip to content

Upgrade: v0.1.0-beta to v0.2.0-beta

This guide walks you through every change between Velocity v0.1.0-beta and v0.2.0-beta.

v0.1.0-betav0.2.0-beta
Astro6.0.0-beta.56.0.0-beta.9
Package managernpmpnpm
ZodStandalone zod packageastro/zod (Zod 4)
SEOastro-seo packageNative <meta> tags
CSPNot configuredEnabled with allowlists
Env varsimport.meta.envastro:env (type-safe)
@astrojs/mdxv4v5 beta
@astrojs/reactv4v5 beta
  • Node.js >= 22.12.0
  • pnpm installed globally (npm install -g pnpm)
  1. Switch to pnpm

    Remove package-lock.json and install with pnpm:

    Terminal window
    rm package-lock.json
    pnpm install
  2. Update dependencies

    Bump Astro and integration packages, and remove packages that are no longer needed:

    Terminal window
    pnpm add astro@6.0.0-beta.9 @astrojs/mdx@5.0.0-beta.1 @astrojs/react@5.0.0-beta.1
    pnpm remove zod astro-seo
  3. Remove legacy ESLint --ext flags

    The --ext flag was removed in ESLint v9. Update your package.json scripts:

    "lint": "eslint . --ext .js,.ts,.astro"
    "lint": "eslint ."
  4. Migrate zod imports

    Astro 6 bundles Zod 4 internally. Replace all standalone zod imports:

    import { z } from 'zod';
    import { z } from 'astro/zod';

    This applies to API routes (src/pages/api/*.ts) and anywhere else you import z.

  5. Update Zod 4 API calls

    Zod 4 changed several method signatures:

    // Email validation is now a top-level type
    z.string().email()
    z.email()
    // ZodError property renamed
    error.errors
    error.issues
  6. Remove experimental.contentIntellisense flag

    This flag was stabilized in Astro 6 beta.9. Remove it from astro.config.mjs:

    experimental: {
    contentIntellisense: true,
    },
  7. Fix duplicate canonical URL

    Remove the manual canonical link from BaseLayout.astro — the SEO component now handles it:

    <link rel="canonical" href={canonicalURL} />
  8. Replace astro-seo with native meta tags

    The astro-seo package is replaced with a native SEO.astro component. Update src/components/SEO.astro:

    Before (v0.1.0-beta):

    ---
    import { SEO } from 'astro-seo';
    // ... props
    ---
    <SEO
    title={title}
    description={description}
    openGraph={{ basic: { title, type: "website", image: ogImage } }}
    twitter={{ card: "summary_large_image" }}
    />

    After (v0.2.0-beta):

    ---
    // No external dependency needed
    const { title, description, ogImage, canonicalURL } = Astro.props;
    ---
    <title>{title}</title>
    <meta name="description" content={description} />
    <link rel="canonical" href={canonicalURL} />
    <!-- Open Graph -->
    <meta property="og:title" content={title} />
    <meta property="og:description" content={description} />
    <meta property="og:type" content="website" />
    <meta property="og:image" content={ogImage} />
    <meta property="og:url" content={canonicalURL} />
    <!-- Twitter Card -->
    <meta name="twitter:card" content="summary_large_image" />
    <meta name="twitter:title" content={title} />
    <meta name="twitter:description" content={description} />
    <meta name="twitter:image" content={ogImage} />
  9. Add astro:env configuration

    Replace raw import.meta.env usage with type-safe astro:env. Add the env schema to astro.config.mjs:

    import { defineConfig, envField } from 'astro/config';
    export default defineConfig({
    env: {
    schema: {
    SITE_URL: envField.string({ context: 'server', access: 'public', optional: true }),
    PUBLIC_GA_MEASUREMENT_ID: envField.string({ context: 'client', access: 'public', optional: true }),
    PUBLIC_GTM_ID: envField.string({ context: 'client', access: 'public', optional: true }),
    },
    },
    // ...
    });

    Then update your imports:

    const gaId = import.meta.env.PUBLIC_GA_MEASUREMENT_ID;
    import { PUBLIC_GA_MEASUREMENT_ID } from 'astro:env/client';
  10. Enable CSP with explicit allowlists

    Add Content Security Policy to astro.config.mjs:

    export default defineConfig({
    security: {
    csp: true,
    },
    });

    Astro auto-hashes inline scripts and styles. If you use external resources (Google Fonts, analytics scripts, etc.), add explicit directives:

    security: {
    csp: {
    "script-src": ["https://www.googletagmanager.com"],
    "style-src": ["https://fonts.googleapis.com"],
    "font-src": ["https://fonts.gstatic.com"],
    "connect-src": ["https://www.google-analytics.com"],
    },
    },

Run the full verification suite:

Terminal window
pnpm build && pnpm lint && pnpm check

Also manually verify:

  • Pages render without console errors
  • Contact and newsletter forms still validate correctly
  • Analytics scripts load (if configured)
  • Fonts and external resources load under CSP
PackageReason
zodReplaced by astro/zod (bundled with Astro 6)
astro-seoReplaced by native <meta> tags in SEO.astro
FileReason
package-lock.jsonSwitched to pnpm (pnpm-lock.yaml)
env.d.tsNo longer needed with astro:env