Skip to content
Development
Command

/nextjs-migration-helper

Comprehensive Next.js migration assistant for Pages Router to App Router, JavaScript to TypeScript, and modern patterns

From plugin
claude-code-templates
30k200 skills200 agents200 commands2 MCP
Install
$ npx -y skills add davila7/claude-code-templates --agent claude-code

How it fires

How this command gets triggered: by you, by Claude, or both.

  • Fires itselfClaude auto-loads it when your prompt matches the work.
  • You can call itInvoke it directly when you want it.
  • Slash command/nextjs-migration-helper

Context preview

What this command does when you run it.

Comprehensive Next.js migration assistant for Pages Router to App Router, JavaScript to TypeScript, and modern patterns

Command definition

nextjs-migration-helper.md
allowed-tools: Read, Write, Edit, Bash, Grep, Glob
argument-hint: [--pages-to-app] [--js-to-ts] [--class-to-hooks] [--analyze]
description: Comprehensive Next.js migration assistant for Pages Router to App Router, JavaScript to TypeScript, and modern patterns

Next.js Migration Helper

**Migration Type**: $ARGUMENTS

Current Project Analysis

Project Structure Analysis

  • Next.js version: !`grep '"next"' package.json | head -1`
  • Current router: !`ls -la pages/ 2>/dev/null && echo "Pages Router detected" || echo "No pages/ directory found"`
  • App router: !`ls -la app/ 2>/dev/null && echo "App Router detected" || echo "No app/ directory found"`
  • TypeScript: @tsconfig.json (if exists)

File Structure Overview

  • Pages directory: @pages/ (if exists)
  • App directory: @app/ (if exists)
  • Components: @components/ (if exists)
  • API routes: @pages/api/ or @app/api/
  • Styles: @styles/ (if exists)

Migration Strategies

1. Pages Router to App Router Migration

Pre-Migration Analysis

// Migration analysis tool
interface MigrationAnalysis {
  currentStructure: 'pages' | 'app' | 'hybrid';
  pagesCount: number;
  apiRoutesCount: number;
  customApp: boolean;
  customDocument: boolean;
  customError: boolean;
  middlewareExists: boolean;
  complexityScore: number;
}

const analyzeMigrationComplexity = (): MigrationAnalysis => {
  return {
    currentStructure: 'pages', // Detected from file structure
    pagesCount: 0, // Count .js/.tsx files in pages/
    apiRoutesCount: 0, // Count files in pages/api/
    customApp: false, // Check for pages/_app
    customDocument: false, // Check for pages/_document
    customError: false, // Check for pages/_error or 404
    middlewareExists: false, // Check for middleware.ts
    complexityScore: 0, // 1-10 scale
  };
};

Migration Steps

Step 1: Create App Directory Structure

#!/bin/bash
# Create app directory structure

echo "๐Ÿš€ Creating App Router directory structure..."

# Create base app directory
mkdir -p app
mkdir -p app/globals
mkdir -p app/api

# Create layout files
echo "๐Ÿ“ Creating layout structure..."

# Root layout
cat > app/layout.tsx << 'EOF'
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
import './globals.css'

const inter = Inter({ subsets: ['latin'] })

export const metadata: Metadata = {
  title: 'Your App',
  description: 'Migrated to App Router',
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body className={inter.className}>{children}</body>
    </html>
  )
}
EOF

# Global CSS
cat > app/globals.css << 'EOF'
/* Global styles for App Router */
:root {
  --max-width: 1100px;
  --border-radius: 12px;
  --font-mono: ui-monospace, Menlo, Monaco, 'Cascadia Code', 'Segoe UI Mono',
    'Roboto Mono', 'Oxygen Mono', 'Ubuntu Monospace', 'Source Code Pro',
    'Fira Code', 'Droid Sans Mono', 'Courier New', monospace;
}

* {
  box-sizing: border-box;
  padding: 0;
  margin: 0;
}

html,
body {
  max-width: 100vw;
  overflow-x: hidden;
}

body {
  color: rgb(var(--foreground-rgb));
  background: linear-gradient(
      to bottom,
      transparent,
      rgb(var(--background-end-rgb))
    )
    rgb(var(--background-start-rgb));
}

a {
  color: inherit;
  text-decoration: none;
}

@media (prefers-color-scheme: dark) {
  html {
    color-scheme: dark;
  }
}
EOF

echo "โœ… App Router structure created"

Step 2: Migrate Pages to App Router

// Page migration utility
interface PageMigration {
  source: string;
  destination: string;
  type: 'page' | 'api' | 'dynamic' | 'nested';
  hasGetServerSideProps: boolean;
  hasGetStaticProps: boolean;
  hasGetStaticPaths: boolean;
}

const migratePage = async (pagePath: string): Promise<string> => {
  const pageContent = readFileSync(pagePath, 'utf-8');
  
  // Extract page component
  const componentMatch = pageContent.match(/export default function (\w+)/);
  const componentName = componentMatch?.[1] || 'Page';
  
  // Check for data fetching methods
  const hasGetServerSideProps = pageContent.includes('getServerSideProps');
  const hasGetStaticProps = pageContent.includes('getStaticProps');
  const hasGetStaticPaths = pageContent.includes('getStaticPaths');
  
  // Convert to App Router format
  let appRouterCode = '';
  
  // Add metadata if page has Head component
  if (pageContent.includes('from \'next/head\'')) {
    appRouterCode += `import type { Metadata } from 'next'\n\n`;
    appRouterCode += generateMetadata(pageContent);
  }
  
  // Convert data fetching
  if (hasGetServerSideProps) {
    appRouterCode += convertGetServerSideProps(pageContent);
  } else if (hasGetStaticProps) {
    appRouterCode += convertGetStaticProps(pageContent);
  }
  
  // Convert component
  appRouterCode += convertPageComponent(pageContent);
  
  return appRouterCode;
};

const convertGetServerSideProps = (content: string): string => {
  // Extract getServerSideProps logic and convert to Server Component
  const gsspMatch = content.match(/export async function getServerSideProps[\s\S]*?(?=export|$)/);
  
  if (!gsspMatch) return '';
  
  return `
// Server Component with direct data fetching
async function fetchData(context: any) {
  // Converted from getServerSideProps
  // Add your data fetching logic here
  return { data: null };
}
`;
};

const generateMetadata = (content: string): string => {
  // Extract Head component content and convert to metadata
  return `
export const metadata: Metadata = {
  title: 'Page Title',
  description: 'Page description',
}

`;
};

const convertPageComponent = (content: string): string => {
  // Convert page component to App Router format
  return content
    .replace(/import Head from \'next\/head\'/g, '')
    .replace(/<Head>[\s\S]*?<\/Head>/g, '')
    .replace(/export async function getServerSideProps[\s\S]*?(?=export)/g, '')
    .replace(/export async function getStaticProps[\s\S]*?(?=export)
Read more
Ships withclaude-code-templates

Ready-to-use configurations for Anthropic's Claude Code. A comprehensive collection of AI agents, custom commands, settings, hooks, external integrations (MCPs), and project templates to enhance your development workflow.

Get the whole plugin, auto-invoked