Traffic Management for Next.js Apps Using Vercel Edge and Upstash Edge Flags
In this post, we will show how to block the traffic to your web app from a country. You can apply the same logic to manage traffic with other filters (IP address, user-agent etc). We aim a decoupled, lightweight and dynamic solution:
- I should not need to update and deploy code to update country.
- It should have minimum overhead and cost on my application.
We will use Vercel Edge Middleware and Upstash Edge Flags.
Vercel Edge Middleware
Vercel Edge middleware is a code that intercepts the web requests before being processed by backend. We will use it to check the country and user agent because:
- It is fast and cheap.
- Decoupled from your application.
Upstash Edge Flags
Indeed you can check country and block traffic with a simple if statement in your edge middleware code as below:
const BLOCKED_COUNTRY = "BAD_COUNTRY";
export function middleware(req: NextRequest) {
const country = req.geo.country;
if (country === BLOCKED_COUNTRY) {
return new Response("Blocked ", { status: 451 });
}
return new Response(`Greetings`);
}
const BLOCKED_COUNTRY = "BAD_COUNTRY";
export function middleware(req: NextRequest) {
const country = req.geo.country;
if (country === BLOCKED_COUNTRY) {
return new Response("Blocked ", { status: 451 });
}
return new Response(`Greetings`);
}
So why do we need edge flags? Edge flags will enable us to manage the rules without updating the code.
Let’s start..
Step 1: Redis and Edge Flags Setup
Create a Redis database on Upstash Console. For best performance, select global and the regions that users likely to be.
Go to Edge flags page and select the database you have just created. Create a new flag with a name blockTraffic
. Then add a rule for blocked countries:
Country
is in array
United States
-> on
Save and enable the flag.
The above flag will be enabled if the request is originating from the United States.
Step 2: Next.js Project Setup
Create a Next.js application.
npx create-next-app@latest --typescript
npx create-next-app@latest --typescript
Install @upstash packages:
$ npm install @upstash/edge-flags @upstash/redis
$ npm install @upstash/edge-flags @upstash/redis
Create middleware.ts (top level in your project folder):
import { NextRequest, NextResponse } from "next/server";
import { Client as EdgeFlags } from "@upstash/edge-flags";
import { Redis } from "@upstash/redis";
const edgeFlags = new EdgeFlags({ redis: Redis.fromEnv() });
export default async function middleware(
req: NextRequest,
): Promise<NextResponse> {
const enabled = await edgeFlags.getFlag("blockTraffic", req.geo ?? {});
if (!enabled) {
const url = new URL(req.url);
url.pathname = "/blocked";
return NextResponse.rewrite(url);
}
return NextResponse.next();
}
export const config = {
matcher: "/",
};
import { NextRequest, NextResponse } from "next/server";
import { Client as EdgeFlags } from "@upstash/edge-flags";
import { Redis } from "@upstash/redis";
const edgeFlags = new EdgeFlags({ redis: Redis.fromEnv() });
export default async function middleware(
req: NextRequest,
): Promise<NextResponse> {
const enabled = await edgeFlags.getFlag("blockTraffic", req.geo ?? {});
if (!enabled) {
const url = new URL(req.url);
url.pathname = "/blocked";
return NextResponse.rewrite(url);
}
return NextResponse.next();
}
export const config = {
matcher: "/",
};
Let's create a page for the blocked:
import styles from "@/styles/Home.module.css";
export default function Blocked() {
return (
<div>
<main className={styles.main}>
<h3>Access blocked.</h3>
</main>
</div>
);
}
import styles from "@/styles/Home.module.css";
export default function Blocked() {
return (
<div>
<main className={styles.main}>
<h3>Access blocked.</h3>
</main>
</div>
);
}
That's all! Now you can deploy the app to Vercel:
vercel deploy
Make sure to add the environment variables to Vercel either by copying them from the Upstash console or by using the Upstash integration.
Visit the page, you should be redirected to the blocked page if you are in US. Test different countries using VPN.
Geolocation in development
Geolocation data is not avallable locally. You have to deploy to Vercel to test it the app.