·2 min read

Using Edge Flags in Next.js Middleware

Andreas ThomasAndreas ThomasSoftware Engineer @Upstash

Edge-Flags allow you to easily manage feature flags for your serverless applications. It's built on top of Upstash Redis with powerful geolocation rules. Today I'll show you a very simple example of how you can use Edge-Flags in a Next.js middleware to rewrite requests based on the location of the user.

Create the flag

In our example app we only want to make content available to our users in the EU, so we'll create a new Redis database and then go to the edge-flags page. Select the created database and the production environment.

Then we can create a new flag named eu-countries and add the all countries within the EU.

Edge-Flags

Setup and install the packages

  1. If you don't have an existing Next.js app, you can create one with npx create-next-app and install the @upstash/edge-flags and @upstash/redis packages:
$ npm install @upstash/edge-flags @upstash/redis
$ npm install @upstash/edge-flags @upstash/redis
  1. Create a new file middleware.ts in the root of your project and add the following code:
/middleware.ts
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("eu-countries", req.geo ?? {})
    .catch((err) => {
      console.error(err);
      return false;
    });
 
  if (!enabled) {
    const url = new URL(req.url);
    url.pathname = "/blocked";
    return NextResponse.rewrite(url);
  }
 
  return NextResponse.next();
}
 
export const config = {
  matcher: "/",
};
/middleware.ts
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("eu-countries", req.geo ?? {})
    .catch((err) => {
      console.error(err);
      return false;
    });
 
  if (!enabled) {
    const url = new URL(req.url);
    url.pathname = "/blocked";
    return NextResponse.rewrite(url);
  }
 
  return NextResponse.next();
}
 
export const config = {
  matcher: "/",
};
  1. Create a very sophisticated /blocked page
app/blocked/page.tsx
export default function Page() {
  return <div> You are not in the EU</div>;
}
app/blocked/page.tsx
export default function Page() {
  return <div> You are not in the EU</div>;
}

Now all that's left is to deploy the project to Vercel:

$ npx vercel
$ npx vercel

Make sure to add the environment variables to Vercel either by copying them from the Upstash console or by using the Upstash integration.

Vercel

Test it out

Geolocation in development

Geolocation data is not avaiable when developing locally. You need to actually deploy the app to Vercel to test it out.

Now you can test it out by visiting the index page of your app. If you're in the EU you should see the content, otherwise you'll be redirected to the /blocked page.