Skip to content
This repository was archived by the owner on Dec 12, 2025. It is now read-only.

Commit d50676d

Browse files
committed
mention App Router support in READMEs
1 parent 3119ef2 commit d50676d

File tree

2 files changed

+56
-72
lines changed

2 files changed

+56
-72
lines changed

README.md

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,14 @@ Add Feature Flags to your Next.js application with a single React Hook. This pac
2323
## Key Features
2424

2525
- written for Next.js
26-
- integrate using a simple `useFlags()` hook
26+
- integrate using a simple `useFlags()` hook or `getFlags()` function
27+
- supports App Router (Server Components & Client Components)
2728
- only 2 kB gzipped size
2829
- extremely fast flag responses (~50ms)
29-
- supports *server-side rendering* and *static site generation*
30-
- supports *middleware* and *edge functions*
31-
- supports *user targeting*, *custom rules* and *rollouts*
32-
30+
- supports Server-Side Rendering and Static Site Generation
31+
- supports Middleware and Edge Functions
32+
- supports User Targeting, Custom Rules and Rollouts
33+
3334
<br />
3435

3536
<details>
@@ -56,15 +57,11 @@ import { useFlags } from "flags/client";
5657
export default function IndexPage(props) {
5758
const flagBag = useFlags();
5859

59-
return flagBag.flags.greeting === "dog"
60-
? "Who's a good boye"
61-
: "Hello";
60+
return flagBag.flags.greeting === "dog" ? "Who's a good boye" : "Hello";
6261
}
6362
```
6463

65-
66-
The self documenting examples at [flags.happykit.dev](https://flags.happykit.dev/) show how to use `@happykit/flags` for client-side, static and server-side rendering.
67-
64+
The self documenting examples at [flags.happykit.dev](https://flags.happykit.dev/) show how to use `@happykit/flags` for client-side, static and server-side rendering.
6865

6966
## Full Tutorial
7067

package/README.md

Lines changed: 48 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ Add Feature Flags to your Next.js application with a single React Hook. This pac
2222
**Key Features**
2323

2424
- written for Next.js
25-
- integrate using a simple `useFlags()` hook
25+
- integrate using a simple `useFlags()` hook or `getFlags()` function
26+
- supports App Router (Server Components & Client Components)
2627
- only 2 kB gzipped size
2728
- extremely fast flag responses (~50ms)
28-
- supports *server-side rendering* and *static site generation*
29-
- supports *middleware* and *edge functions*
30-
- supports *user targeting*, *custom rules* and *rollouts*
31-
29+
- supports Server-Side Rendering and Static Site Generation
30+
- supports Middleware and Edge Functions
31+
- supports User Targeting, Custom Rules and Rollouts
3232

3333
<br />
3434

@@ -108,7 +108,7 @@ export const config: Configuration<AppFlags> = {
108108
envKey: process.env.NEXT_PUBLIC_FLAGS_ENV_KEY!,
109109

110110
// You can provide defaults flag values here
111-
defaultFlags: {},
111+
defaultFlags: {},
112112
};
113113
```
114114

@@ -156,16 +156,15 @@ It's recommended to enable [Absolute Imports](https://nextjs.org/docs/advanced-f
156156
This will allow you to later import your flags like
157157

158158
```ts
159-
import { useFlag } from "flags/client"
159+
import { useFlag } from "flags/client";
160160
```
161161

162162
instead of having to use relative imports like
163163

164164
```ts
165-
import { useFlag } from "../../../flags/client"
165+
import { useFlag } from "../../../flags/client";
166166
```
167167

168-
169168
### Setting up the Environment Variable
170169

171170
You might have noticed that `flags/config.ts` uses an Environment Variable called `
@@ -186,7 +185,6 @@ Later on, don't forget to also provide the environment variable in production.
186185

187186
> There's also [a full walkthrough of the setup](https://medium.com/frontend-digest/using-feature-flags-in-next-js-c5c8d0795a2?source=friends_link&sk=d846a29f376acf9cfa41e926883923ab), which explains the setup in your project and in HappyKit Flags itself.
188187
189-
190188
That's it. You're now ready to use your first feature flag.
191189

192190
## Basic Usage
@@ -199,7 +197,7 @@ import { useFlags } from "flags/client";
199197

200198
export default function FooPage(props) {
201199
const { flags } = useFlags();
202-
return flags?.xzibit ? 'Yo dawg' : 'Hello';
200+
return flags?.xzibit ? "Yo dawg" : "Hello";
203201
}
204202
```
205203
@@ -217,18 +215,18 @@ export const getServerSideProps = async (context) => {
217215

218216
export default function FooPage(props) {
219217
const { flags } = useFlags({ initialState: props.initialFlagState });
220-
return flags?.xzibit ? 'Yo dawg' : 'Hello';
218+
return flags?.xzibit ? "Yo dawg" : "Hello";
221219
}
222220
```
223221
224222
> Note that you should only ever call `useFlags()` once per Next.js page to avoid causing multiple requests and inconsistent flags.
225223
>
226224
> See more about this in the [FAQs](#why-should-i-only-ever-render-the-useflags-hook-once-per-page).
227225
228-
229226
## Exports
230227
231228
`@happykit/flags` offers multiple entrypoints:
229+
232230
- `@happykit/flags/config`: Configuration functions
233231
- `@happykit/flags/server`: Use flags in `getServerSideProps` & `getStaticProps`
234232
- `@happykit/flags/client`: Use flags on the client
@@ -245,7 +243,7 @@ This section describes the exports of your `flags` folder.
245243
246244
### `config`
247245
248-
*exported from `flags/config`*
246+
_exported from `flags/config`_
249247
250248
Exports a `config` object which is shared across all runtimes (server, client, edge).
251249
@@ -254,10 +252,9 @@ Exports a `config` object which is shared across all runtimes (server, client, e
254252
- `config.defaultFlags = undefined` _(object)_ _optional_: Key-value pairs of flags and their values. These values are used as fallbacks in `useFlags` and `getFlags`. The fallbacks are used while the actual flags are loaded, in case a flag is missing or when the request loading the flags fails for unexpected reasons. If you don't declare `defaultFlags`, then the flag values will be `undefined`.
255253
- `config.endpoint = "https://happykit.dev/api/flags"` _(string)_ _optional_: The endpoint to load flags from. This does not usually need to be changed.
256254
257-
258255
### `useFlags`
259256
260-
*exported from `flags/client`*
257+
_exported from `flags/client`_
261258
262259
This hook loads the flags on the client.
263260
@@ -271,7 +268,6 @@ This hook loads the flags on the client.
271268
- `options.pause` _(boolean)_ _optional_: Set this to `true` to delay fetching of the passed inputs. This is useful in case you need to wait for your `user` or `traits` to be loaded before kicking off the feature flag evaluation request.
272269
- `options.clientLoadingTimeout = 3000` _(number)_ _optional_: A timeout in milliseconds after which any client-side evaluation requests will be aborted. Pass `false` to disable this feature. This feature is only supported in [browsers which support](https://caniuse.com/abortcontroller) the [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController). Overwrites `config.clientLoadingTimeout`.
273270
274-
275271
The `useFlags` function returns an object called [`flagBag`](#flagBag). The returned `flagBag` is described [below](#flagbag).
276272
277273
#### `flagBag`
@@ -296,10 +292,9 @@ Provide any of these attributes to store them in HappyKit. You will be able to u
296292
- `avatar` _(string)_: URL to users profile picture
297293
- `country` _(string)_: Two-letter uppercase country-code of user's county, see [ISO 3166-1](https://en.wikipedia.org/wiki/ISO_3166-1)
298294
299-
300295
#### `getFlags`
301296
302-
*exported from `flags/server`*
297+
_exported from `flags/server`_
303298
304299
- `getFlags(options)`
305300
- `options.context` _(object)_ _required_: The context which you receive from `getStaticProps` or `getServerSideProps`.
@@ -324,17 +319,16 @@ This function returns a promise resolving to an object that looks like this:
324319
325320
### `getEdgeFlags`
326321
327-
*exported from `flags/edge`*
322+
_exported from `flags/edge`_
328323
329324
This function is meant to be used from [Next.js Middleware](https://nextjs.org/docs/middleware) (`middleware` files) and [Edge API Routes](https://nextjs.org/docs/api-routes/edge-api-routes).
330325
331-
*exported from `@happykit/flags/edge`*
326+
_exported from `@happykit/flags/edge`_
332327
333328
- `getEdgeFlags(options)`
334329
- `options.request` _(NextRequest)_ _required_: The Next.js Request.
335330
- `options.user` _(object)_ _optional_: Same as `user` in `useFlags()`. If pass a user here, make sure to pass the same user to `useFlags({ user })`.
336331
- `options.traits` _(object)_ _optional_: Same as `traits` in `useFlags()`. If pass traits here, make sure to pass the same traits to `useFlags({ traits })`.
337-
338332
339333
This function returns a promise resolving to an object that looks like this:
340334
@@ -348,7 +342,7 @@ This function returns a promise resolving to an object that looks like this:
348342
error: string | null,
349343
// The preloaded state, which can be provided to useFlags({ initialState })
350344
initialFlagState: object,
351-
// Use this to set the response cookie from the middleware
345+
// Use this to set the response cookie from the middleware
352346
// with `response.cookie(...cookie.args)`
353347
cookie: null | {
354348
name: string;
@@ -359,7 +353,6 @@ This function returns a promise resolving to an object that looks like this:
359353
}
360354
```
361355
362-
363356
## Advanced Usage
364357
365358
### With user targeting
@@ -371,7 +364,7 @@ You can provide a `user` as the first argument. Use this to enable per-user targ
371364
import { useFlags } from "flags/client";
372365

373366
export default function FooPage(props) {
374-
const flagBag = useFlags({ user: { key: 'user-id' } });
367+
const flagBag = useFlags({ user: { key: "user-id" } });
375368
return flagBag.flags.greeting === "dog" ? "Woof" : "Hello";
376369
}
377370
```
@@ -387,7 +380,7 @@ import { useFlags } from "flags/client";
387380
import { getFlags } from "flags/server";
388381

389382
export const getServerSideProps = async (context) => {
390-
const user = { key: 'user-id' };
383+
const user = { key: "user-id" };
391384
const { initialFlagState } = await getFlags({ context, user });
392385
return { props: { user, initialFlagState } };
393386
};
@@ -423,7 +416,7 @@ export const config: Configuration<AppFlags> = {
423416
defaultFlags: {
424417
greeting: "dog",
425418
// .. more defaults ..
426-
},
419+
},
427420
// .. other settings ..
428421
});
429422
```
@@ -464,7 +457,7 @@ export const getServerSideProps = async (context) => {
464457
};
465458

466459
export default function FooPage(props) {
467-
return props.flags.greeting === "dog" ? 'Woof' : 'Hello';
460+
return props.flags.greeting === "dog" ? "Woof" : "Hello";
468461
}
469462
```
470463
@@ -610,9 +603,9 @@ And make this change in `flags/edge.ts`
610603
611604
Now `@happykit/flags` will load your feature flag definitions from your own storage every time you use `getFlags` or `getEdgeFlags`.
612605
613-
*In theory you could commit a file to your own repository containing HappyKit's feature flag definitions and load this json from `getDefinitions`. This would give you feature flags at 0 latency.*
606+
_In theory you could commit a file to your own repository containing HappyKit's feature flag definitions and load this json from `getDefinitions`. This would give you feature flags at 0 latency._
614607
615-
*The downside would be that updates to your flags would require a redeployment, and that changes would not affect other preview deployments.*
608+
_The downside would be that updates to your flags would require a redeployment, and that changes would not affect other preview deployments._
616609
617610
### With same domain evaluations
618611
@@ -663,17 +656,15 @@ You can use a property called `settled` which turns `true` once the flags are fr
663656
664657
> Note: This example does not include the setup of your `flags` folder.
665658
666-
667659
```js
668660
// pages/profile.js
669-
import * as React from 'react';
661+
import * as React from "react";
670662
import { useFlags } from "flags/client";
671663
import { getFlags } from "flags/server";
672-
import dynamic from 'next/dynamic';
673-
674-
const ProfileVariantA = dynamic(() => import('components/profile-a'));
675-
const ProfileVariantB = dynamic(() => import('components/profile-b'));
664+
import dynamic from "next/dynamic";
676665

666+
const ProfileVariantA = dynamic(() => import("components/profile-a"));
667+
const ProfileVariantB = dynamic(() => import("components/profile-b"));
677668

678669
export const getServerSideProps = async (context) => {
679670
// preload your user somehow
@@ -699,9 +690,9 @@ export default function Page(props) {
699690
//
700691
// So the check for "settled" is unnecessary in this example,
701692
// but useful if you want to use `getStaticProps`.
702-
if (!flagBag.settled) return null
693+
if (!flagBag.settled) return null;
703694

704-
return flagBag.flags?.profileVariant === 'A' ? (
695+
return flagBag.flags?.profileVariant === "A" ? (
705696
<ProfileVariantA user={props.user} />
706697
) : (
707698
<ProfileVariantB user={props.user} />
@@ -741,7 +732,7 @@ export type AppFlags = {
741732
```
742733
743734
When you open your project on [happykit.dev](https://happykit.dev/),
744-
you can go to Flags > Types to generate your `AppFlags` types.
735+
you can go to Flags > Types to generate your `AppFlags` types.
745736
746737
### Code splitting
747738
@@ -751,21 +742,21 @@ When you open your project on [happykit.dev](https://happykit.dev/),
751742
If you have two variants of a page and you only want to render one depending on a feature flag, you're able to keep the client-side bundle small by using dynamic imports.
752743
753744
```js
754-
import * as React from 'react';
745+
import * as React from "react";
755746
import { useFlags } from "flags/client";
756747
import { getFlags } from "flags/server";
757-
import dynamic from 'next/dynamic';
748+
import dynamic from "next/dynamic";
758749

759-
const ProfileVariantA = dynamic(() => import('../components/profile-a'));
760-
const ProfileVariantB = dynamic(() => import('../components/profile-b'));
750+
const ProfileVariantA = dynamic(() => import("../components/profile-a"));
751+
const ProfileVariantB = dynamic(() => import("../components/profile-b"));
761752

762753
export default function Page(props) {
763-
const flagBag = useFlags({ user: { key: 'user_id_1' } });
754+
const flagBag = useFlags({ user: { key: "user_id_1" } });
764755

765756
// display nothing until we know for sure which variants the flags resolve to
766757
if (!flagBag.settled) return null;
767758

768-
return flagBag.flags?.profileVariant === 'A' ? (
759+
return flagBag.flags?.profileVariant === "A" ? (
769760
<ProfileVariantA user={props.user} />
770761
) : (
771762
<ProfileVariantB user={props.user} />
@@ -779,14 +770,13 @@ Notice that the loading state is gone with that as well, since the flags are ava
779770
780771
```js
781772
// with server-side flag preloading
782-
import * as React from 'react';
783-
import { useFlags } from 'flags/client';
784-
import { getFlags } from 'flags/server';
785-
import dynamic from 'next/dynamic';
786-
787-
const ProfileVariantA = dynamic(() => import('components/profile-a'));
788-
const ProfileVariantB = dynamic(() => import('components/profile-b'));
773+
import * as React from "react";
774+
import { useFlags } from "flags/client";
775+
import { getFlags } from "flags/server";
776+
import dynamic from "next/dynamic";
789777

778+
const ProfileVariantA = dynamic(() => import("components/profile-a"));
779+
const ProfileVariantB = dynamic(() => import("components/profile-b"));
790780

791781
export const getServerSideProps = async (context) => {
792782
// preload your user somehow
@@ -803,17 +793,15 @@ export default function Page(props) {
803793
initialState: props.initialFlagState,
804794
});
805795

806-
return flagBag.flags?.profileVariant === 'A' ? (
796+
return flagBag.flags?.profileVariant === "A" ? (
807797
<ProfileVariantA user={props.user} />
808798
) : (
809799
<ProfileVariantB user={props.user} />
810800
);
811801
}
812802
```
813803
814-
*This technique of removing the loading state works only with `getServerSideProps`. If you use `getStaticProps`, the server has no concept of the current visitor, but a visitor could influence flag rollouts. The client thus needs to reevaluate the flags and will only settle (pass `settled: true`) once the client-side reevaluation has completed.*
815-
816-
804+
_This technique of removing the loading state works only with `getServerSideProps`. If you use `getStaticProps`, the server has no concept of the current visitor, but a visitor could influence flag rollouts. The client thus needs to reevaluate the flags and will only settle (pass `settled: true`) once the client-side reevaluation has completed._
817805
818806
### Middleware example
819807
@@ -848,15 +836,15 @@ if (flagBag.cookie) {
848836
response.cookie(
849837
flagBag.cookie.name,
850838
flagBag.cookie.value,
851-
flagBag.cookie.options,
852-
)
839+
flagBag.cookie.options
840+
);
853841
}
854842
```
855843
856844
There is a shortcut to make this more concise:
857845
858846
```ts
859-
if (flagBag.cookie) response.cookie(...flagBag.cookie.args)
847+
if (flagBag.cookie) response.cookie(...flagBag.cookie.args);
860848
```
861849
862850
`flagBag.cookie.args` is an array that contains `[cookie.name, cookie.value, cookie.options]`, so `cookie.args` can simply be applied onto `response.cookie`.
@@ -865,7 +853,6 @@ Both of these methods of using `flagBag.cookie` set a cookie called `hkvk` on th
865853
866854
You can see this example in action at [flags.happykit.dev/demo/middleware](https://flags.happykit.dev/demo/middleware).
867855
868-
869856
## FAQs
870857
871858
### Why should I only ever render the `useFlags` hook once per page?
@@ -878,6 +865,6 @@ Depending on the rendering mode, you might need to pass some `initialState` to t
878865
879866
From there it's best to pass the returned `flagBag` to each component that needs it.
880867
881-
You can do so directly or by using `@happykit/flags/context`.
868+
You can do so directly or by using `@happykit/flags/context`.
882869
883870
This allows you to switch between flags, and prevents you from calling `useFlags()` with inconsistent values on the same page. Only calling `useFlags()` once per page ensures you'll see the same feature flags on the whole page.

0 commit comments

Comments
 (0)