Skip to content
NanoFlags
Start free

SDKs

React

Bindings in @nanoflags/sdk/react, built on useSyncExternalStore: components re-render when a new revision arrives or the client status changes. Evaluation stays local.

Set up the provider

Create the client once, outside components, and pass it with the evaluation context to NanoFlagsProvider.

tsx
import { createClient } from "@nanoflags/sdk";
import { NanoFlagsProvider } from "@nanoflags/sdk/react";

const client = createClient({ sdkKey: "nf_pub_…", baseUrl: "https://edge.nanoflags.io", service: "web" });

export function App({ user }: { user: { id: string; plan: string } }) {
  return (
    <NanoFlagsProvider client={client} context={{ key: user.id, plan: user.plan }}>
      <Search />
    </NanoFlagsProvider>
  );
}
PropDescription
clientA client from createClient.
contextEvaluation context shared by every useFlag below the provider. Compared by value (serialized), so a new object with the same content does not re-evaluate.
Use a client key (nf_pub_…) in browser code. Client keys receive only client-exposed flags, and their rules are readable by anyone with the page.

useFlag

tsx
import { useFlag } from "@nanoflags/sdk/react";

function Search() {
  const ranking = useFlag("search-ranking", "relevance-v2");                   // string
  const compact = useFlag("compact-results", false, { device: "mobile" });     // boolean, context override
  const limits = useFlag("result-limits", { page: 20 });                        // json
  …
}
  • The accessor is chosen from the type of the fallback: boolean, string, number, otherwise JSON.
  • The optional third argument is shallow-merged over the provider context for this call.
  • A missing flag, no bundle yet, or a type mismatch returns the fallback.
  • useFlag and useFlagsStatus throw if used outside NanoFlagsProvider.

useFlagsStatus

tsx
const { status, revision, hasBundle } = useFlagsStatus();
// status: "not-ready" | "ready" | "stale"; hasBundle: status !== "not-ready"

Use it to show a neutral state while nothing is loaded, or to surface that the configuration in use is not known to be current. See Status.

Server rendering

Until a bundle is loaded the hooks return fallbacks. To make the first client render match the server, evaluate on the server with a server client and pass the client view of the bundle to the browser client as bootstrap. Never send a server key's full bundle to the browser if it contains flags that are not client-exposed: fetch the bootstrap bundle with a client key, or embed one fetched at build time.

tsx
// browser
const client = createClient({ sdkKey: "nf_pub_…", baseUrl: "https://edge.nanoflags.io", bootstrap: bundleFromServer });

A bootstrap bundle is trusted as given (it is not signature-checked); the client then revalidates with the edge as usual.

Test sessions in the browser

client.useSession(token) routes the client's own accessors, and therefore every hook, through a test session for this tab. The token is kept in sessionStorage; useSession(null) leaves the session.

ts
await client.useSession(tokenFromYourTestTooling); // nf_ts_…
fetch("/api/cart", { headers: { ...client.sessionHeaders() } }); // your backend joins the session