Nextjs Middleware Creator

Create optimized Next.js middleware with authentication, rate limiting, and routing logic

Commandnextjs vercelMIT1 source files

Before you use this component

This is a third-party source bundle, not an installation into your account. UI Discovery has checked the available redistribution license evidence; runtime behavior has not been tested. Review all files, use a disposable project first, and do not enable scripts or hooks until you understand their permissions.

Some integrations require separately installed software, API keys or paid services. Credentials and subscriptions are not included. These are Claude Code resources; other clients may require adaptation.

Extract the ZIP into a temporary folder, inspect its entry file and supporting resources, then follow the original instructions. Do not overwrite an existing project configuration blindly. Keep the bundled license and attribution notices.

Source publisher
Claude Code Templates
Creator supplied by source
Not listed in source
Pinned source version
a344359459263d73d8948651c789244093c02e4e
License evidence
LICENSE

Source preview

cli-tool/components/commands/nextjs-vercel/nextjs-middleware-creator.md

---
allowed-tools: Read, Write, Edit
argument-hint: [middleware-type] [--auth] [--rate-limit] [--redirect] [--rewrite]
description: Create optimized Next.js middleware with authentication, rate limiting, and routing logic
---

## Next.js Middleware Creator

**Middleware Type**: $ARGUMENTS

## Current Project Analysis

### Project Structure
- Next.js config: @next.config.js
- Existing middleware: @middleware.ts or @middleware.js (if exists)
- App directory: @app/ (if App Router)
- Auth configuration: @auth.config.ts or @lib/auth/ (if exists)

### Framework Detection
- Package.json: @package.json
- TypeScript config: @tsconfig.json (if exists)
- Authentication libraries: Detect NextAuth.js, Auth0, or custom auth

## Middleware Implementation Strategy

### 1. Middleware File Structure
Create comprehensive middleware at project root:
```
middleware.ts                 # Main middleware file
lib/middleware/              # Middleware utilities
├── auth.ts                  # Authentication middleware
├── rateLimit.ts            # Rate limiting logic
├── redirects.ts            # Redirect rules
├── rewrites.ts             # URL rewriting
├── cors.ts                 # CORS handling
├── security.ts             # Security headers
└── types.ts               # TypeScript types
```

### 2. Base Middleware Template
```typescript
// middleware.ts
import { NextRequest, NextResponse } from 'next/server';
import { authMiddleware } from './lib/middleware/auth';
import { rateLimitMiddleware } from './lib/middleware/rateLimit';
import { securityMiddleware } from './lib/middleware/security';
import { redirectMiddleware } from './lib/middleware/redirects';

export async function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl;
  
  // Apply security headers first
  let response = await securityMiddleware(request);
  
  // Apply rate limiting
  const rateLimitResult = await rateLimitMiddleware(request);
  if (rateLimitResult) return rateLimitResult;
  
  // Handle authentication for protected routes
  if (isProtectedRoute(pathname)) {
    const authResult = await authMiddleware(request);
    if (authResult) return authResult;
  }
  
  // Handle redirects
  const redirectResult = await redirectMiddleware(request);
  if (redirectResult) return redirectResult;
  
  // Apply additional headers to response
  if (response) {
    return response;
  }
  
  return NextResponse.next();
}

function isProtectedRoute(pathname: string): boolean {
  const protectedPaths = ['/dashboard', '/admin', '/api/protected'];
  return protectedPaths.some(path => pathname.startsWith(path));
}

export const config = {
  matcher: [
    // Match all request paths except static files and images
    '/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
  ],
};
```

## Middleware Components

### 1. Authentication Middleware
```typescript
// lib/middleware/auth.ts
import { NextRequest, NextResponse } from 'next/server';
import { jwtVerify } from 'jose';

const JWT_SECRET = new TextEncoder().encode(
  process.env.JWT_SECRET || 'your-secret-key'
);

export async function authMiddleware(request: NextRequest) {
  try {
    // Get token from cookies or Authorization header
    const token = request.cookies.get('auth-token')?.value ||
      request.headers.get('authorization')?.replace('Bearer ', '');

    if (!token) {
      return redirectToLogin(request);
    }

    // Verify JWT token
    const { payload } = await jwtVerify(token, JWT_SECRET);
    
    // Add user info to headers for downstream use
    const response = NextResponse.next();
    response.headers.set('x-user-id', payload.sub as string);
    response.headers.set('x-user-role', payload.role as string);
    
    return response;
    
  } catch (error) {
    console.error('Auth middleware error:', error);
    return redirectToLogin(request);
  }
}

function redirectToLogin(request: NextRequest) {
  const loginUrl = new URL('/login', request.url);
  loginUrl.searchParams.set('callbackUrl', request.url);
  return NextResponse.redirect(loginUrl);
}

// Role-based access control
export function requireRole(allowedRoles: string[]) {
  return async function roleMiddleware(request: NextRequest) {
    const userRole = request.headers.get('x-user-role');
    
    if (!userRole || !allowedRoles.includes(userRole)) {
      return new NextResponse('Forbidden', { status: 403 });
    }
    
    return NextResponse.next();
  };
}
```

### 2. Rate Limiting Middleware
```typescript
// lib/middleware/rateLimit.ts
import { NextRequest, NextResponse } from 'next/server';

// Simple in-memory store (use Redis in production)
const requestCounts = new Map<string, { count: number; resetTime: number }>();

interface RateLimitConfig {
  windowMs: number; // Time window in milliseconds
  maxRequests: number; // Max requests per window
  keyGenerator?: (request: NextRequest) => string;
}

const defaultConfig: RateLimitConfig = {
  windowMs: 15 * 60 * 1000, // 15 minutes
  maxRequests: 100, // 100 requests per 15 minutes
};

export async function rateLimitMiddleware(
  request: NextRequest,
  config: RateLimitConfig = defaultConfig
) {
  const key = config.keyGenerator 
    ? config.keyGenerator(request)
    : getClientIP(request);
  
  const now = Date.now();
  const clientData = requestCounts.get(key);
  
  // Reset window if expired
  if (!clientData || now > clientData.resetTime) {
    requestCounts.set(key, {
      count: 1,
      resetTime: now + config.windowMs
    });
    return null; // Allow request
  }
  
  // Increment counter
  clientData.count++;
  
  // Check if limit exceeded
  if (clientData.count > config.maxRequests) {
    const resetTime = Math.ceil((clientData.resetTime - now) / 1000);
    
    return new NextResponse('Rate limit exceeded', {
      status: 429,
      headers: {
        'X-RateLimit-Limit': config.maxRequests.toString(),
        'X-RateLimit-Remaining': '0',
        'X-RateLimit-Reset': resetTime.toString(),
        'Retry-After': resetTime.toString(),
      },
    });
  }
  
  return null; // Allow request
}

function getClientIP(request: NextRequest): string {
  return request.headers.get('x-forwarded-for') ||
    request.headers.get('x-real-ip') ||
    request.ip ||
    'unknown';
}

// API-specific rate limiting
export const apiRateLimit = (request: NextRequest) =>
  rateLimitMiddleware(request, {
    windowMs: 60 * 1000, // 1 minute
    maxRequests: 60, // 60 requests per minute
    keyGenerator: (req) => `api:${getClientIP(req)}`,
  });
```

### 3. Security Headers Middleware
```typescript
// lib/middleware/security.ts
import { NextRequest, NextResponse } from 'next/server';

export async function securityMiddleware(request: NextRequest) {
  const response = NextResponse.next();
  
  // Security headers
  const securityHeaders = {
    // XSS Protection
    'X-XSS-Protection': '1; mode=block',
    
    // Content Type Options
    'X-Content-Type-Options': 'nosniff',
    
    // Frame Options
    'X-Frame-Options': 'DENY',
    
    // HSTS
    'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
    
    // Referrer Policy
    'Referrer-Policy': 'strict-origin-when-cross-origin',
    
    // Permissions Policy
    'Permissions-Policy': 'camera=(), microphone=(), geolocation=()',
    
    // Content Security Policy
    'Content-Security-Policy': generateCSP(),
  };
  
  // Apply security headers
  Object.entries(securityHeaders).forEach(([key, value]) => {
    response.headers.set(key, value);
  });
  
  return response;
}

function generateCSP(): string {
  const csp = [
    "default-src 'self'",
    "script-src 'self' 'unsafe-eval' 'unsafe-inline'",
    "style-src 'self' 'unsafe-inline'",
    "img-src 'self' data: https:",
    "font-src 'self' data:",
    "connect-src 'self'",
    "frame-ancestors 'none'",
  ];
  
  return csp.join('; ');
}
```

### 4. CORS Middleware
```typescript
// lib/middleware/cors.ts
import { NextRequest, NextResponse } from 'next/server';

interface CorsOptions {
  origin: string | string[] | boolean;
  methods: string[];
  allowedHeaders: string[];
  credentials: boolean;
}

const defaultCorsOptions: CorsOptions = {
  origin: true, // Allow all origins in development
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
  allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'],
  credentials: true,
};

export function corsMiddleware(options: Partial<CorsOptions> = {}) {
  const config = { ...defaultCorsOptions, ...options };
  
  return function cors(request: NextRequest) {
    const response = NextResponse.next();
    const origin = request.headers.get('origin');
    
    // Handle preflight requests
    if (request.method === 'OPTIONS') {
      return handlePreflight(request, config);
    }
    
    // Set CORS headers
    if (shouldAllowOrigin(origin, config.origin)) {
      response.headers.set('Access-Control-Allow-Origin', origin || '*');
    }
    
    if (config.credentials) {
      response.headers.set('Access-Control-Allow-Credentials', 'true');
    }
    
    response.headers.set(
      'Access-Control-Allow-Methods',
      config.methods.join(', ')
    );
    
    response.headers.set(
      'Access-Control-Allow-Headers',
      config.allowedHeaders.join(', ')
    );
    
    return response;
  };
}

function handlePreflight(request: NextRequest, config: CorsOptions) {
  const headers = new Headers();
  const origin = request.headers.get('origin');
  
  if (shouldAllowOrigin(origin, config.origin)) {
    headers.set('Access-Control-Allow-Origin', origin || '*');
  }
  
  if (config.credentials) {
    headers.set('Access-Control-Allow-Credentials', 'true');
  }
  
  headers.set('Access-Control-Allow-Methods', config.methods.join(', '));
  headers.set('Access-Control-Allow-Headers', config.allowedHeaders.join(', '));
  headers.set('Access-Control-Max-Age', '86400'); // 24 hours
  
  return new NextResponse(null, { status: 200, headers });
}

function shouldAllowOrigin(
  origin: string | null,
  allowedOrigin: string | string[] | boolean
): boolean {
  if (allowedOrigin === true) return true;
  if (allowedOrigin === false) return false;
  if (typeof allowedOrigin === 'string') return origin === allowedOrigin;
  if (Array.isArray(allowedOrigin)) return allowedOrigin.includes(origin || '');
  return false;
}
```

### 5. Redirect and Rewrite Middleware
```typescript
// lib/middleware/redirects.ts
import { NextRequest, NextResponse } from 'next/server';

interface RedirectRule {
  source: string | RegExp;
  destination: string;
  permanent?: boolean;
  conditions?: (request: NextRequest) => boolean;
}

const redirectRules: RedirectRule[] = [
  // Legacy URL redirects
  {
    source: '/old-page',
    destination: '/new-page',
    permanent: true,
  },
  
  // Dynamic redirects
  {
    source: /^\/user\/(.+)$/,
    destination: '/profile/$1',
    permanent: false,
  },
  
  // Conditional redirects
  {
    source: '/admin',
    destination: '/admin/dashboard',
    conditions: (request) => {
      const userRole = request.headers.get('x-user-role');
      return userRole === 'admin';
    },
  },
  
  // Maintenance mode
  {
    source: /.*/,
    destination: '/maintenance',
    conditions: (request) => {
      return process.env.MAINTENANCE_MODE === 'true' &&
        !request.nextUrl.pathname.startsWith('/maintenance');
    },
  },
];

export async function redirectMiddleware(request: NextRequest) {
  const { pathname } = request.nextUrl;
  
  for (const rule of redirectRules) {
    if (shouldApplyRule(rule, pathname, request)) {
      const destination = resolveDestination(rule.destination, pathname);
      const url = new URL(destination, request.url);
      
      return NextResponse.redirect(url, {
        status: rule.permanent ? 301 : 302,
      });
    }
  }
  
  return null; // No redirect needed
}

function shouldApplyRule(
  rule: RedirectRule,
  pathname: string,
  request: NextRequest
): boolean {
  // Check pattern match
  const matches = typeof rule.source === 'string'
    ? pathname === rule.source
    : rule.source.test(pathname);
  
  if (!matches) return false;
  
  // Check additional conditions
  if (rule.conditions) {
    return rule.conditions(request);
  }
  
  return true;
}

function resolveDestination(destination: string, pathname: string): string {
  // Handle dynamic replacements
  return destination.replace(/\$(\d+)/g, (match, num) => {
    // Extract from regex matches
    return pathname; // Simplified - would need actual regex matching
  });
}
```

### 6. A/B Testing Middleware
```typescript
// lib/middleware/abTest.ts
import { NextRequest, NextResponse } from 'next/server';

interface ABTest {
  name: string;
  variants: string[];
  traffic: number; // Percentage of traffic to include (0-100)
  condition?: (request: NextRequest) => boolean;
}

const activeTests: ABTest[] = [
  {
    name: 'homepage-design',
    variants: ['control', 'variant-a', 'variant-b'],
    traffic: 50,
  },
  {
    name: 'checkout-flow',
    variants: ['old-checkout', 'new-checkout'],
    traffic: 100,
    condition: (req) => req.nextUrl.pathname.startsWith('/checkout'),
  },
];

export function abTestMiddleware(request: NextRequest) {
  const response = NextResponse.next();
  
  for (const test of activeTests) {
    // Check if user should be included in test
    if (test.condition && !test.condition(request)) continue;
    
    // Check traffic allocation
    const userId = getUserId(request);
    const hash = hashString(userId + test.name);
    const bucket = hash % 100;
    
    if (bucket >= test.traffic) continue;
    
    // Assign variant
    const variantIndex = hash % test.variants.length;
    const variant = test.variants[variantIndex];
    
    // Set cookie for consistent experience
    response.cookies.set(`ab_${test.name}`, variant, {
      maxAge: 30 * 24 * 60 * 60, // 30 days
      httpOnly: false, // Allow client-side access
    });
    
    // Set header for server-side use
    response.headers.set(`x-ab-${test.name}`, variant);
  }
  
  return response;
}

function getUserId(request: NextRequest): string {
  // Get user ID from cookie, or generate anonymous ID
  return request.cookies.get('user-id')?.value ||
    request.headers.get('x-forwarded-for') ||
    'anonymous';
}

function hashString(str: string): number {
  let hash = 0;
  for (let i = 0; i < str.length; i++) {
    const char = str.charCodeAt(i);
    hash = ((hash << 5) - hash) + char;
    hash = hash & hash; // Convert to 32-bit integer
  }
  return Math.abs(hash);
}
```

## Advanced Middleware Patterns

### 1. Middleware Composition
```typescript
// lib/middleware/compose.ts
import { NextRequest, NextResponse } from 'next/server';

type MiddlewareFunction = (
  request: NextRequest,
  response?: NextResponse
) => NextResponse | Promise<NextResponse> | null;

export function composeMiddleware(...middlewares: MiddlewareFunction[]) {
  return async function composedMiddleware(request: NextRequest) {
    let response: NextResponse | null = null;
    
    for (const middleware of middlewares) {
      const result = await middleware(request, response || undefined);
      
      if (result && result.status >= 300 && result.status < 400) {
        // Handle redirects immediately
        return result;
      }
      
      if (result && result.status >= 400) {
        // Handle errors immediately  
        return result;
      }
      
      if (result) {
        response = result;
      }
    }
    
    return response || NextResponse.next();
  };
}
```

### 2. Feature Flag Middleware
```typescript
// lib/middleware/featureFlags.ts
import { NextRequest, NextResponse } from 'next/server';

interface FeatureFlag {
  name: string;
  enabled: boolean;
  percentage?: number;
  userGroups?: string[];
  geoRegions?: string[];
}

const featureFlags: FeatureFlag[] = [
  {
    name: 'new-dashboard',
    enabled: true,
    percentage: 25,
  },
  {
    name: 'premium-features',
    enabled: true,
    userGroups: ['premium', 'admin'],
  },
];

export function featureFlagMiddleware(request: NextRequest) {
  const response = NextResponse.next();
  const activeFlags: Record<string, boolean> = {};
  
  for (const flag of featureFlags) {
    if (!flag.enabled) {
      activeFlags[flag.name] = false;
      continue;
    }
    
    // Check percentage rollout
    if (flag.percentage) {
      const userId = getUserId(request);
      const hash = hashString(userId + flag.name) % 100;
      if (hash >= flag.percentage) {
        activeFlags[flag.name] = false;
        continue;
      }
    }
    
    // Check user groups
    if (flag.userGroups) {
      const userRole = request.headers.get('x-user-role');
      if (!userRole || !flag.userGroups.includes(userRole)) {
        activeFlags[flag.name] = false;
        continue;
      }
    }
    
    activeFlags[flag.name] = true;
  }
  
  // Set feature flags in headers
  response.headers.set('x-feature-flags', JSON.stringify(activeFlags));
  
  return response;
}
```

## Middleware Testing

### 1. Unit Tests
```typescript
// __tests__/middleware.test.ts
import { NextRequest } from 'next/server';
import { middleware } from '../middleware';

describe('Middleware', () => {
  it('should add security headers', async () => {
    const request = new NextRequest('http://localhost:3000/');
    const response = await middleware(request);
    
    expect(response.headers.get('X-Frame-Options')).toBe('DENY');
    expect(response.headers.get('X-Content-Type-Options')).toBe('nosniff');
  });

  it('should redirect unauthenticated users from protected routes', async () => {
    const request = new NextRequest('http://localhost:3000/dashboard');
    const response = await middleware(request);
    
    expect(response.status).toBe(302);
    expect(response.headers.get('location')).toContain('/login');
  });
});
```

### 2. Integration Tests
```typescript
// __tests__/middleware.integration.test.ts
describe('Middleware Integration', () => {
  it('should handle complete authentication flow', async () => {
    // Test login -> dashboard -> logout flow
  });
  
  it('should respect rate limiting', async () => {
    // Test multiple requests hitting rate limit
  });
});
```

## Deployment and Monitoring

### 1. Performance Monitoring
```typescript
// lib/middleware/monitoring.ts
export function monitoringMiddleware(request: NextRequest) {
  const start = Date.now();
  
  return new Response(JSON.stringify({}), {
    status: 200,
    headers: {
      'x-response-time': `${Date.now() - start}ms`,
    },
  });
}
```

### 2. Error Handling
```typescript
// lib/middleware/errorHandler.ts
export function errorHandlerMiddleware(
  error: Error,
  request: NextRequest
): NextResponse {
  console.error('Middleware error:', error);
  
  // Log to monitoring service
  // logError(error, request);
  
  return new NextResponse('Internal Server Error', { status: 500 });
}
```

Generate comprehensive middleware implementation with all requested features, proper TypeScript types, and production-ready patterns.

Preview capped at 60,000 characters. Download the bundle for every original file and notice.

Read the redistribution license
MIT License

Copyright (c) 2025 Daniel (San) Ávila

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Bundle SHA-256: 2da21fcd8c7afd99e86ec1038fc8bc32d9d6aada04e1cddbcfebb270f8e28f19. Files are served as downloads and are never executed by this page.