Using A/BBY with Next.js
A/BBY was built to be the best solution for Feature Flags and A/B Testing in Next.js. It deeply integrates with Next.js and provides a seamless developer experience.
Installation
Install the @tryabby/next
package using your favorite package manager:
npm i @tryabby/next
Configuration
In order to use A/BBY you need to create a free account at tryabby.com (opens in a new tab) first.
You can then use the button in the top right corner of the dashboard to easily copy your A/BBY config.
Create a file called abby.ts
(or whatever you want to call this file) somewhere in your source code. That's it! You're ready to go!
For this example my abby.ts
file looks like this:
// abby.ts
import { createAbby } from "@tryabby/next";
export const { useAbby, AbbyProvider, useFeatureFlag, withAbby } = createAbby({
projectId: "YOUR_PROJECT",
// For testing purposes we only want to use the production environment
currentEnvironment: "production",
tests: {
theme: {
variants: ["light", "dark"],
},
},
flags: ["useDarkmode"],
});
Now you will need to wrap your app with the AbbyProvider
component. This is done in the _app.tsx
file.
If you also wrap your app with withAbby
, you will have access to the Feature Flags for Server Side Rendering or Static Generation as well.
This is highly recommended so that there is no flicker on the inital load of your app. It also allows for proper crawling of your app by search engines.
// _app.tsx
import { AbbyProvider } from "lib/abby";
function MyApp({
Component,
pageProps: { __ABBY_PROJECT_DATA__, ...pageProps },
}) {
return (
<AbbyProvider initialData={__ABBY_PROJECT_DATA__}>
<Component {...pageProps} />
</AbbyProvider>
);
}
export default withAbby(MyApp);
If you only want client side rendering, you can skip the withAbby
part and just wrap your app with the AbbyProvider
(and omit initialData
).
Usage
Hooks
Feature Flags
// index.tsx
import { useFeatureFlag } from "lib/abby";
export function HomePage() {
const useDarkmode = useFeatureFlag("useDarkmode");
return (
<>
<h1>My Homepage</h1>
{useDarkmode && <p>Darkmode is enabled</p>}
</>
);
}
You can now go to the A/BBY dashboard and enable the useDarkmode
flag for your project. You will see the text "Darkmode is enabled" on your homepage.
A/B Tests
// index.tsx
export function HomePage() {
const { variant, onAct } = useAbby("theme");
return (
<>
<h1>My Homepage</h1>
<button
onClick={() => {
onAct();
// React to the user clicking the button
}}
className={`button ${variant === "dark" && "bg-dark"} ${
variant === "light" && "bg-light"
}`}
>
BUY IT
</button>
</>
);
}
This is a simple example of an A/B Test. Once you loaded the page you will get either the "light" or the "dark" variant of the button.
Non-React Context
You might want to use A/BBY outside of React. For example in your app's middleware or in a Next.js API route.
Edge Functions
Edge Functions (opens in a new tab) are Vercel's globally distributed serverless functions. They are a great way to run code on the edge of the Vercel network and use a leaner runtime with less functionality. A/BBY works perfectly with Edge Functions.
The best usecase with Edge Functions and A/BBY is to use them in your middleware, for example to redirect users to a beta version of your app.
// middleware.ts
import { withAbbyEdge } from "lib/abby";
import { NextResponse } from "next/server";
export default withAbbyEdge((req) => {
const myFlag = getFeatureFlagValue("test-flag");
// make sure to use the req object here
const [currentVariant, setCookie] = getABTestValue("test-abtest", req);
if (myFlag && currentVariant === "beta-user") {
const res = NextResponse.redirect("/beta");
// update the user's cookie
setCookie(res);
return res;
}
return NextResponse.next();
});
API Routes
You can access feature flags and A/B tests in your API routes as well.
// /api/test.ts
import { withAbbyApiHandler } from "lib/abby";
export default withAbbyApiHandler((req, res) => {
const myFlag = getFeatureFlagValue("test-flag");
// make sure to use the req object here
const [currentVariant, setCookie] = getABTestValue("test-abtest", req);
if (myFlag && currentVariant === "beta-user") {
// update the user's cookie
setCookie(res);
return res.status(200).end();
}
res.status(404).end();
});