# Migrate

> Guide migration to Astro from other frameworks or between Astro versions. Use when converting Next.js, Nuxt, Gatsby projects or upgrading Astro.

- Skill: `incluud/migrate` (Agent Skill)
- Install (CLI): `npx skillmds@latest add incluud/migrate`
- Raw SKILL.md: https://api.skillmd.com/api/skills/incluud/migrate/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: incluud (https://skillmd.com/u/incluud)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/incluud/migrate

---


# Migrate to Astro

## When to Use

- Migrating from Next.js, Nuxt, Gatsby, or other frameworks
- Upgrading between major Astro versions
- Converting a static HTML site to Astro
- Moving from Create React App to Astro

## Instructions

### 1. Identify Migration Path

| From | Complexity | Key Changes |
|------|------------|-------------|
| **Static HTML** | Low | Wrap in `.astro`, add layouts |
| **Next.js (Pages)** | Medium | Route structure similar, convert JSX |
| **Next.js (App)** | Medium-High | Server components map well to Astro |
| **Nuxt** | Medium | Vue components work with integration |
| **Gatsby** | Medium | GraphQL → Content Collections |
| **Create React App** | Medium | Add routing, convert to islands |
| **Astro v4 → v5** | Low-Medium | Content Layer changes begin |
| **Astro v5 → v6** | Medium | Content collections, `Astro.glob()`, and runtime changes |

### 2. Project Setup

Create new Astro project alongside existing:

```bash
npm create astro@latest my-astro-site
```

Or convert in-place by installing Astro:

```bash
npm install astro
```

Update `package.json` scripts:

```json
{
  "scripts": {
    "dev": "astro dev",
    "build": "astro build",
    "preview": "astro preview"
  }
}
```

If upgrading to Astro 6, verify the runtime first:

```bash
node --version
```

Astro 6 requires Node 22.12.0 or newer. Also upgrade official integrations and adapters alongside Astro to avoid version skew.

### 3. Migration Patterns

#### Static HTML → Astro

1. Rename `.html` to `.astro`
2. Move to `src/pages/`
3. Extract repeated sections to `src/layouts/`
4. Convert to components as needed

```astro
---
// src/layouts/Layout.astro
const { title } = Astro.props
---
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>{title}</title>
  </head>
  <body>
    <slot />
  </body>
</html>
```

#### Next.js → Astro

**Pages Router:**

| Next.js | Astro |
|---------|-------|
| `pages/index.js` | `src/pages/index.astro` |
| `pages/blog/[slug].js` | `src/pages/blog/[slug].astro` |
| `getStaticProps` | Frontmatter code block |
| `getStaticPaths` | `getStaticPaths()` export |
| `_app.js` | `src/layouts/Layout.astro` |
| `next/image` | `astro:assets` Image component |
| `next/link` | Standard `<a>` tags |

**Convert a Next.js page:**

```jsx
// Next.js: pages/blog/[slug].js
export async function getStaticPaths() {
  const posts = await getPosts()
  return { paths: posts.map(p => ({ params: { slug: p.slug } })) }
}

export async function getStaticProps({ params }) {
  const post = await getPost(params.slug)
  return { props: { post } }
}

export default function Post({ post }) {
  return <article><h1>{post.title}</h1></article>
}
```

```astro
---
// Astro: src/pages/blog/[slug].astro
import { getCollection, render } from 'astro:content'

export async function getStaticPaths() {
  const posts = await getCollection('blog')
  return posts.map(post => ({
    params: { slug: post.id },
    props: { post },
  }))
}

const { post } = Astro.props
const { Content } = await render(post)
---

<article>
  <h1>{post.data.title}</h1>
  <Content />
</article>
```

**Keep React components:**

```bash
npx astro add react
```

Then use with client directives:

```astro
---
import InteractiveWidget from '../components/InteractiveWidget.tsx'
---

<InteractiveWidget client:visible />
```

#### Nuxt → Astro

```bash
npx astro add vue
```

| Nuxt | Astro |
|------|-------|
| `pages/` | `src/pages/` (similar) |
| `components/` | `src/components/` |
| `layouts/` | `src/layouts/` |
| `nuxt.config.ts` | `astro.config.mjs` |
| Auto-imports | Explicit imports |

Vue components work directly:

```astro
---
import MyVueComponent from '../components/MyVueComponent.vue'
---

<MyVueComponent client:load />
```

#### Gatsby → Astro

| Gatsby | Astro |
|--------|-------|
| GraphQL queries | Content Collections |
| `gatsby-image` | `astro:assets` Image |
| `gatsby-plugin-*` | Astro integrations |
| MDX pages | MDX in content collections |

**Convert GraphQL to Content Collections:**

```typescript
// Gatsby: gatsby-node.js with GraphQL
// → Astro: src/content.config.ts with a loader and schema

import { defineCollection } from 'astro:content'
import { glob } from 'astro/loaders'
import { z } from 'astro/zod'

const blog = defineCollection({
  loader: glob({ base: './src/content/blog', pattern: '**/*.{md,mdx}' }),
  schema: z.object({
    title: z.string(),
    date: z.coerce.date(),
    // Match your Gatsby frontmatter fields
  }),
})

export const collections = { blog }
```

### 4. Astro Version Upgrades

**Upgrade command:**

```bash
npx @astrojs/upgrade
```

**v5 → v6 Key Changes:**

- Node 22.12.0+ is required
- Legacy content collections support is removed
- `src/content/config.ts` moves to `src/content.config.ts`
- Each collection now needs a `loader`
- `z` should come from `astro/zod`
- `entry.id` replaces legacy `slug` usage in collection routing
- `entry.render()` becomes `render(entry)`
- `Astro.glob()` is removed in favor of `import.meta.glob()` or `getCollection()`
- `<ViewTransitions />` is removed; use `<ClientRouter />`
- `Astro.site` inside `getStaticPaths()` should become `import.meta.env.SITE`

**Astro 6 upgrade checklist:**

1. Upgrade Astro and official integrations/adapters together
2. Verify Node 22.12.0+ locally and in CI/deployment
3. Move `src/content/config.ts` to `src/content.config.ts`
4. Add a `loader` to every collection
5. Replace `import { defineCollection, z } from 'astro:content'` with `import { defineCollection } from 'astro:content'` and `import { z } from 'astro/zod'`
6. Replace `post.slug` with `post.id`
7. Replace `post.render()` with `render(post)`
8. Replace `Astro.glob()` with `import.meta.glob()` or `getCollection()`
9. Replace `<ViewTransitions />` with `<ClientRouter />`

Check migration guide: [docs.astro.build/guides/upgrade-to/v6](https://docs.astro.build/en/guides/upgrade-to/v6/)

### 5. Common Migration Tasks

#### Move static assets

```text
public/images/ → public/images/  (same)
src/assets/   → src/assets/      (processed by Vite)
```

#### Update image imports

```astro
---
import { Image } from 'astro:assets'
import heroImage from '../assets/hero.jpg'
---

<Image src={heroImage} alt="Hero" width={800} height={400} />
```

#### Convert CSS

- Global CSS → Import in layout
- CSS Modules → Work as-is
- Styled Components → Use with React integration
- Tailwind → `npx astro add tailwind`

#### Environment variables

```text
// Next.js
NEXT_PUBLIC_API_URL

// Astro
PUBLIC_API_URL  // Client-side
API_SECRET      // Server-side only
```

#### Replace Astro.glob()

```astro
---
// Before
const posts = await Astro.glob('./posts/*.md')

// After
const posts = Object.values(import.meta.glob('./posts/*.md', { eager: true }))
---
```

For content collections, prefer `getCollection()` instead of raw globs.

### 6. Verification Checklist

- [ ] Local and deployment environments meet the required Node version
- [ ] All routes render correctly
- [ ] Content collections build without warnings
- [ ] Images load and are optimized
- [ ] Interactive components hydrate
- [ ] SEO meta tags present
- [ ] Build completes without errors
- [ ] Links work (no 404s)
- [ ] Forms submit correctly
- [ ] Performance improved or maintained

## Resources

- [Official Migration Guides](https://docs.astro.build/en/guides/migrate-to-astro/)
- [Upgrade to Astro v6](https://docs.astro.build/en/guides/upgrade-to/v6/)
- [From Next.js](https://docs.astro.build/en/guides/migrate-to-astro/from-nextjs/)
- [From Nuxt](https://docs.astro.build/en/guides/migrate-to-astro/from-nuxt/)
- [From Gatsby](https://docs.astro.build/en/guides/migrate-to-astro/from-gatsby/)

