/nextjs-migration-helper
Comprehensive Next.js migration assistant for Pages Router to App Router, JavaScript to TypeScript, and modern patterns
$ npx -y skills add davila7/claude-code-templates --agent claude-codeHow 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.mdallowed-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
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)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.
Repo: davila7/claude-code-templates
Other commands on claude-code-templates.
- /cleanup-cache
Clean system caches (npm, Homebrew, Yarn, browsers, Python/ML) to free disk space
Open command - /create-blog-article
Create an SEO-optimized blog article for a Claude Code component with AI-generated cover image
Open command - /lint
Run Python code linting and formatting tools.
Open command - /test
Run Python tests with pytest, unittest, or other testing frameworks.
Open command - /worktree-check
Check current worktree status, branch, and assigned task
Open command - /worktree-cleanup
Clean up merged worktrees and their branches
Open command

