Master Next.js Edge Middleware patterns for Google Antigravity IDE request handling
# Next.js Edge Middleware Patterns for Google Antigravity IDE
Build fast request handling with Edge Middleware using Google Antigravity IDE. This guide covers authentication, geolocation, A/B testing, and rate limiting patterns.
## Basic Middleware Setup
```typescript
// middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export function middleware(request: NextRequest) {
const response = NextResponse.next();
// Add request timing header
response.headers.set("x-middleware-time", Date.now().toString());
return response;
}
export const config = {
matcher: [
"/((?!api|_next/static|_next/image|favicon.ico).*)",
],
};
```
## Authentication Middleware
```typescript
// middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { getToken } from "next-auth/jwt";
const protectedPaths = ["/dashboard", "/settings", "/profile"];
const authPaths = ["/login", "/signup", "/forgot-password"];
export async function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// Check if path requires authentication
const isProtectedPath = protectedPaths.some((path) => pathname.startsWith(path));
const isAuthPath = authPaths.some((path) => pathname.startsWith(path));
// Get session token
const token = await getToken({ req: request, secret: process.env.NEXTAUTH_SECRET });
// Redirect unauthenticated users from protected routes
if (isProtectedPath && !token) {
const loginUrl = new URL("/login", request.url);
loginUrl.searchParams.set("callbackUrl", pathname);
return NextResponse.redirect(loginUrl);
}
// Redirect authenticated users from auth routes
if (isAuthPath && token) {
return NextResponse.redirect(new URL("/dashboard", request.url));
}
// Role-based access control
if (pathname.startsWith("/admin") && token?.role !== "admin") {
return NextResponse.redirect(new URL("/unauthorized", request.url));
}
return NextResponse.next();
}
```
## Geolocation and Personalization
```typescript
// middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export function middleware(request: NextRequest) {
const response = NextResponse.next();
// Get geolocation data from Vercel
const country = request.geo?.country || "US";
const city = request.geo?.city || "Unknown";
const region = request.geo?.region || "Unknown";
// Set headers for components to access
response.headers.set("x-user-country", country);
response.headers.set("x-user-city", city);
// Redirect based on country
const { pathname } = request.nextUrl;
if (pathname === "/" && country === "DE") {
return NextResponse.redirect(new URL("/de", request.url));
}
// Block certain countries
const blockedCountries = ["CN", "RU"];
if (blockedCountries.includes(country)) {
return NextResponse.redirect(new URL("/blocked", request.url));
}
return response;
}
```
## A/B Testing
```typescript
// middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
const COOKIE_NAME = "ab-experiment";
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// Only apply to specific pages
if (!pathname.startsWith("/pricing")) {
return NextResponse.next();
}
// Check for existing variant
let variant = request.cookies.get(COOKIE_NAME)?.value;
// Assign variant if not set
if (!variant) {
variant = Math.random() < 0.5 ? "control" : "treatment";
}
// Rewrite to variant page
const url = request.nextUrl.clone();
url.pathname = pathname + "/" + variant;
const response = NextResponse.rewrite(url);
// Set cookie for consistent experience
if (!request.cookies.has(COOKIE_NAME)) {
response.cookies.set(COOKIE_NAME, variant, {
maxAge: 60 * 60 * 24 * 30, // 30 days
httpOnly: true,
});
}
return response;
}
```
## Rate Limiting
```typescript
// middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(10, "10 s"),
analytics: true,
});
export async function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// Only rate limit API routes
if (!pathname.startsWith("/api")) {
return NextResponse.next();
}
const ip = request.ip ?? request.headers.get("x-forwarded-for") ?? "127.0.0.1";
const { success, limit, reset, remaining } = await ratelimit.limit(ip);
const response = success ? NextResponse.next() : NextResponse.json({ error: "Too many requests" }, { status: 429 });
response.headers.set("X-RateLimit-Limit", limit.toString());
response.headers.set("X-RateLimit-Remaining", remaining.toString());
response.headers.set("X-RateLimit-Reset", reset.toString());
return response;
}
```
## Best Practices for Google Antigravity IDE
When using Edge Middleware with Google Antigravity, keep middleware fast and lightweight. Use matcher config to limit scope. Handle errors gracefully. Cache expensive operations. Let Gemini 3 generate middleware patterns from your requirements.
Google Antigravity excels at building edge-first request handling.This Next.js prompt is ideal for developers working on:
By using this prompt, you can save hours of manual coding and ensure best practices are followed from the start. It's particularly valuable for teams looking to maintain consistency across their next.js implementations.
Yes! All prompts on Antigravity AI Directory are free to use for both personal and commercial projects. No attribution required, though it's always appreciated.
This prompt works excellently with Claude, ChatGPT, Cursor, GitHub Copilot, and other modern AI coding assistants. For best results, use models with large context windows.
You can modify the prompt by adding specific requirements, constraints, or preferences. For Next.js projects, consider mentioning your framework version, coding style, and any specific libraries you're using.