Nextjs Middleware Creator
Create optimized Next.js middleware with authentication, rate limiting, and routing logic
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.