Claude Skills Guide

Claude Code for Astro Middleware Workflow Guide

Astro middleware enables you to intercept and modify requests and responses at the edge, making it essential for authentication, logging, redirects, and performance optimizations. This guide shows you how to use Claude Code to build, test, and refine Astro middleware efficiently.

Understanding Astro Middleware Fundamentals

Middleware in Astro runs before and after each request is processed. Unlike server-side rendering (SSR) routes that handle the full response, middleware focuses on request/response transformation. This makes it perfect for cross-cutting concerns that affect your entire application.

Astro middleware is defined using the onRequest function, which receives the request and a next function to pass control to the next middleware or route handler:

import type { MiddlewareHandler } from 'astro';

export const onRequest: MiddlewareHandler = async (context, next) => {
  // Process request before it reaches routes
  const start = Date.now();
  
  const response = await next();
  
  // Process response before it's sent
  const duration = Date.now() - start;
  response.headers.set('X-Response-Time', `${duration}ms`);
  
  return response;
};

This pattern allows you to measure and modify response times across your entire site with minimal overhead.

Setting Up Claude Code for Astro Development

Before building middleware, ensure Claude Code is configured for your Astro project. The most effective approach is creating a specialized skill for Astro middleware development.

Create a file named astro-middleware.md in your skills directory with the following structure:

---
name: astro-middleware
description: Expert guidance for building and debugging Astro middleware
---

You are an Astro middleware expert. Help the user build, test, and optimize middleware functions for their Astro project.

This skill gives Claude access to file operations, shell commands, and search capabilities essential for middleware development.

Building Authentication Middleware

One of the most common middleware use cases is protecting routes. Here’s a practical workflow for building authentication middleware with Claude Code:

First, ask Claude to generate the middleware structure:

Create an authentication middleware for Astro that checks for a JWT token in cookies, validates it, and redirects unauthenticated users to /login.

Claude will generate a complete implementation:

import type { MiddlewareHandler } from 'astro';
import { verify } from '@astrojs/auth';

export const authMiddleware: MiddlewareHandler = async (context, next) => {
  const protectedPaths = ['/dashboard', '/settings', '/profile'];
  const isProtectedPath = protectedPaths.some(path => 
    context.url.pathname.startsWith(path)
  );
  
  if (!isProtectedPath) {
    return next();
  }
  
  const token = context.cookies.get('auth_token')?.value;
  
  if (!token) {
    return context.redirect('/login', 302);
  }
  
  try {
    const payload = await verify(token);
    context.locals.user = payload;
    return next();
  } catch (error) {
    context.cookies.delete('auth_token', { path: '/' });
    return context.redirect('/login', 302);
  }
};

Implementing Rate Limiting Middleware

Rate limiting protects your API from abuse. Here’s how to build it with Claude Code’s assistance:

Request the implementation:

Create a rate limiting middleware for Astro that uses an in-memory store with a sliding window algorithm. Limit to 100 requests per minute per IP.

Claude generates efficient middleware code:

import type { MiddlewareHandler } from 'astro';

interface RateLimitEntry {
  count: number;
  resetTime: number;
}

const rateLimitStore = new Map<string, RateLimitEntry>();

export const rateLimitMiddleware: MiddlewareHandler = async (context, next) => {
  const clientIP = context.request.headers.get('x-forwarded-for') || 
                   context.clientAddress || 
                   'unknown';
  
  const now = Date.now();
  const windowMs = 60000; // 1 minute
  const maxRequests = 100;
  
  const entry = rateLimitStore.get(clientIP);
  
  if (!entry || now > entry.resetTime) {
    rateLimitStore.set(clientIP, {
      count: 1,
      resetTime: now + windowMs
    });
    return next();
  }
  
  if (entry.count >= maxRequests) {
    return new Response('Too Many Requests', {
      status: 429,
      headers: {
        'Retry-After': String(Math.ceil((entry.resetTime - now) / 1000)),
        'X-RateLimit-Limit': String(maxRequests),
        'X-RateLimit-Remaining': '0'
      }
    });
  }
  
  entry.count++;
  const response = await next();
  
  response.headers.set('X-RateLimit-Limit', String(maxRequests));
  response.headers.set('X-RateLimit-Remaining', String(maxRequests - entry.count));
  
  return response;
};

Debugging Middleware Issues

When middleware behaves unexpectedly, Claude Code helps diagnose problems quickly. Use the skill to trace through the execution flow:

  1. Check middleware order: Middleware executes in the order it’s defined. Ask Claude to verify your astro.config.mjs includes middleware in the correct sequence.

  2. Inspect locals: Use Claude to add debugging headers:

export const debugMiddleware: MiddlewareHandler = async (context, next) => {
  console.log('Request path:', context.url.pathname);
  console.log('Cookies:', Object.fromEntries(context.cookies));
  console.log('Locals:', context.locals);
  
  const response = await next();
  
  console.log('Response status:', response.status);
  return response;
};
  1. Test edge cases: Ask Claude to generate test cases for various scenarios:
Generate test cases for authentication middleware including: valid token, expired token, missing token, invalid token format, and cookie tampering attempts.

Optimizing Middleware Performance

Middleware runs on every request, so optimization matters. Here are Claude Code’s recommended patterns:

Lazy initialization: Only load heavy dependencies when needed:

export const optimizedMiddleware: MiddlewareHandler = async (context, next) => {
  // Only import heavy library when debugging is enabled
  if (context.url.searchParams.get('debug') === 'true') {
    const { heavyDebugger } = await import('./debugger.js');
    heavyDebugger.log(context);
  }
  
  return next();
};

Early returns: Exit middleware as soon as possible for non-matching routes:

export const efficientMiddleware: MiddlewareHandler = async (context, next) => {
  // Skip all processing for static assets
  if (context.url.pathname.startsWith('/_astro')) {
    return next();
  }
  
  // Continue with middleware logic only for dynamic routes
  // ... rest of middleware
  return next();
};

Integrating Third-Party Services

Claude Code excels at integrating external services into your middleware. For example, adding analytics:

Create middleware that sends request data to Plausible analytics, including page views, referrers, and custom properties for authenticated users.

Testing Middleware in Isolation

Write unit tests for middleware using Vitest and Astro’s testing utilities:

import { describe, it, expect, vi } from 'vitest';
import { authMiddleware } from '../middleware/auth';

describe('authMiddleware', () => {
  it('redirects unauthenticated users to /login', async () => {
    const mockContext = {
      cookies: new Map(),
      url: new URL('/dashboard', 'http://localhost'),
      redirect: vi.fn()
    };
    
    const mockNext = vi.fn();
    
    await authMiddleware(mockContext as any, mockNext);
    
    expect(mockContext.redirect).toHaveBeenCalledWith('/login', 302);
  });
});

Ask Claude to generate comprehensive test suites that cover happy paths, edge cases, and error conditions.

Conclusion

Claude Code transforms Astro middleware development from manual coding to collaborative problem-solving. By creating specialized skills, generating boilerplate code, debugging issues, and creating tests, you build robust middleware faster. The key is treating Claude as a pair programmer who understands Astro’s middleware API and TypeScript patterns.

Start by creating the astro-middleware skill, then iterate on your middleware implementations with Claude’s assistance. Your middleware will be more reliable, better tested, and easier to maintain.

Built by theluckystrike — More at zovo.one