I've been using Vercel for a few years now to host my website(s), but I never really looked into the Vercel Toolbar until now.
I though it was mainly used for leaving comments, but apparently it has evolved a lot, and Vercel added a lot of new capabilities.
One of those caught my eye: the feature flags.
Feature flags is a concept where you can toggle on or off certain functionalities, allowing for controlled release and testing of new features.
Now we know what feature flags are, let's see how to implement them in an Astro website.
Adding the Vercel Toolbar locally
We start by adding the @vercel/toolbar
dependency.
npm i @vercel/toolbar
The use the vercel CLI
to link your local project to your Vercel project
vercel link [path-to-directory]
Vercel injects the Toolbar into your deployment previews automatically, but while developing locally of course this is not available.
That's why I added the check on the NODE_ENV variable, to only add the script when we're developing locally.
So let's add the Toolbar to the Layout
, which is shared by all pages on my website.
We just need to add a <script>
tag to our Astro code.
{
import.meta.env.NODE_ENV === "development" ? (
<script
is:inline
src="https://vercel.live/_next-live/feedback/feedback.js"
data-explicit-opt-in="true"
data-owner-id="team_PK64Z6zzqG3h5W3BmmCZX9aS"
data-project-id="prj_UlaZ1TGeEMBpy8kKmj3wnD7F3M9a"
data-branch="main"
/>
) : null
}
To know what to fill in on the data-owner-id
and data-project-id
, it's best to follow Vercels guide.
Once this is set up, you should see the toolbar appear at the bottom of the page.
Setting up Feature Flags
First we need to set an environment variable called FLAGS_SECRET
inside the Vercel settings for our website, and then pull the environment variable using vercel env pull
.
The FLAGS_SECRET value must have a specific length (32 random bytes encoded in base64) to work as an encryption key.
You can generate this value using nodejs
:
node -e "console.log(crypto.randomBytes(32).toString('base64url'))"
The Vercel Toolbar will send GET requests to an endpoint with the URL .well-known/vercel/flags
on the current domain to retrieve the configuration for the feature flags.
So we should make sure we have an API route which listens on this URL for GET requests, and returns a configuration.
The configuration should have the following shape:
type ApiData = {
definitions: Record<
string,
{
description?: string;
origin?: string;
options?: { value: any; label?: string }[];
}
>;
hints?: { key: string; text: string }[];
overrideEncryptionMode?: "plaintext" | "encrypted";
};
Let's implement this into an API route in our Astro codebase:
export const prerender = false;
import { verifyAccess } from "../../../../lib/vercel-flags-port.mjs";
import type { APIRoute } from "astro";
export const GET: APIRoute = async ({ request }) => {
const access = await verifyAccess(request.headers.get("Authorization"));
if (!access) {
return new Response(null, { status: 401 });
}
return new Response(
JSON.stringify({
definitions: {
newFeature: {
description: "Controls whether the new feature is visible",
options: [
{ value: false, label: "Off" },
{ value: true, label: "On" },
],
},
},
}),
);
};
Note that I added export const prerender = false
at the top of the file, because I'm using hybrid rendering, it's necessary to flag non-static routes.
You can also see I import verifyAccess
from a local file, this is done because I could not get the @vercel/flags
package to work with Astro, because the @vercel/flags
package checks for an environment variable on process.env
, but Astro (actually Vite) uses environment variables on the import.meta.env
property.
Because of this, the package thinks the environment variable is not defined, and throws errors.
Therefore, I ported the file over to my own codebase, and replace process.env
mentions with import.meta.env
, and it works!
The verifyAccess
token will make sure the request to our API route is actually coming from the Vercel Toolbar.
When we click on the feature flags button inside of the toolbar we'll see our newly created feature flag pop up.
Once we select one of the overrides, a cookie with the key vercel-flag-overrides
will be created, containing the encypted value of the flag.
You'll also see the Vercel Toolbar turns purple when you activate a flag.
Now we want to actually read the flag and do something with it.
I decided to use the flag as an indication that the homepage should be redirected to another version of the homepage.
Because I want to redirect as early as possible, I decided to put this logic into a middleware.
In the middleware, we can read the cookies of the incoming request, and execute logic based on that.
import { defineMiddleware } from "astro:middleware";
import { decrypt } from "./lib/vercel-flags-port.mjs";
// `context` and `next` are automatically typed
export const onRequest = defineMiddleware(async (context, next) => {
const response = await next();
const featureFlagOverrideCookie = context.cookies.get(
"vercel-flag-overrides",
)?.value;
if (featureFlagOverrideCookie && context.url.pathname === "/") {
const decryptedFlags = (await decrypt(featureFlagOverrideCookie)) as {
newFeature: boolean;
};
if (decryptedFlags.newFeature) {
return context.redirect("/homepage-alternative-feature-flag");
}
}
return response;
});
So we get the cookies from the context
, check if the requested page is the homepage and read the vercel-flag-overrides
cookie's value.
If there's a cookie and the request is for the homepage, we decrypt
the cookie's value and check if the newFeature
flag is set to true
.
If this is the case, we'll redirect the user (using context.redirect()
) to an alternative homepage.
On more thing that needed to be changed was that I had to change my homepage to also be server rendered (so adding export const prerender = false;
to the top of the file) instead of statically rendered, otherwise it was not possible to read the cookies for the request for that page.
The source code can be found on Github.
Thanks for reading! Hope it helps someone further.
Top comments (0)