When building a fast-growing web application, hitting unexpected cloud tier limits is a rite of passage.
Recently, on our platform CardCheck—a web app designed to help Indian consumers compare credit card reward rates, lounge perks, and forex fees—we received a warning alert from Vercel:
- Fluid Active CPU: 9.3 hours consumed (vs. 4.0 hours included on the Hobby tier — over 230% of our limit).
- Edge Requests: Surging past 980,000+ requests per month (approaching the 1M limit).
Our traffic was growing, but our serverless usage was growing exponentially faster. Here is how we pinpointed the root causes, optimized our Next.js App Router codebase, and slashed our daily resource burn by over 80% in under an hour.
The Root Causes
After analyzing our route traffic and execution logs, we discovered three main culprits:
1. Auth Middleware Running on Guest Traffic
Like many Next.js applications, we use middleware for session handling. However, our middleware function was refreshing authentication state on every single incoming HTTP request.
Since 95%+ of visitors browsing credit card comparisons are unauthenticated guests, our serverless middleware was making unnecessary remote authentication checks on every page hit.
2. Over-using export const dynamic = 'force-dynamic'
To ensure card comparison tools and public wallet routes showed fresh data, several pages were explicitly configured with export const dynamic = 'force-dynamic'.
This completely bypassed Vercel’s Edge CDN cache, forcing Next.js to execute a serverless function render on every request—including search engine crawlers and automated bots.
3. Middleware Matcher Sweeping Up Static & Metadata Assets
Our middleware matcher pattern wasn't explicitly excluding metadata assets like robots.txt, sitemap.xml, and static media files. Every time a web crawler indexed our sitemap, it triggered a middleware serverless invocation.
The 3-Step Fix
Here is the exact code pattern we implemented to solve these bottlenecks:
Step 1: Add a Cookie Guard to Middleware
Instead of triggering session verification for every visitor, we added a lightweight cookie check. If no authentication cookies are present on the incoming request, we skip the remote auth check entirely and return the response immediately.
// middleware.ts
export async function updateSession(request: NextRequest) {
let response = NextResponse.next({ request });
// Guard: Only verify session if auth cookies actually exist on the request
const hasAuthCookie = request.cookies.getAll().some((c) => c.name.startsWith('sb-'));
if (hasAuthCookie) {
// Refresh session for logged-in user
await refreshUserSession(request, response);
}
return response;
}
Result: Unauthenticated visitors now get instant responses without waiting on external network hops inside middleware.
Step 2: Refactor Middleware Matcher Rules
We updated our middleware.ts configuration matcher to strictly exclude static assets, sitemaps, and robots.txt:
export const config = {
matcher: [
'/((?!_next/static|_next/image|favicon.ico|robots.txt|sitemap.*\\.xml|.*\\.(?:svg|png|jpg|jpeg|gif|webp|css|js|woff|woff2|ttf|txt|xml|json)$).*)',
],
};
Step 3: Replace force-dynamic with Incremental Static Regeneration (ISR)
Instead of forcing dynamic SSR on public comparison routes and sitemaps, we switched to Incremental Static Regeneration using revalidate.
Before:
// Forces full SSR execution on every request
export const dynamic = 'force-dynamic';
After:
// Pre-renders page at Edge CDN and revalidates in background every 60 seconds
export const revalidate = 60;
export const dynamicParams = true;
For sitemaps and metadata files that change infrequently, we set revalidate = 86400 (24 hours).
The Results
Within 24 hours of deploying these changes to production on CardCheck:
- Daily Edge Requests dropped by ~80% (from ~89,000 requests/day down to ~12,000 requests/day).
- Fluid CPU hours stabilized well within normal limits.
- Time to First Byte (TTFB) for guest visitors improved by 150–400ms because requests no longer stall in auth middleware.
Key Takeaways for Next.js Developers
- Check your Middleware Matcher: Ensure static assets and sitemaps aren't silently triggering serverless function invocations.
- Guard your Auth Checks: Don't hit external auth services in middleware if the user doesn't even have a session cookie.
-
Embrace ISR: Unless a page requires real-time user-specific data, prefer
revalidateoverforce-dynamic.
This optimization was built and tested live for CardCheck.in, an unbiased credit card comparison engine for India.
Top comments (0)