React
@shipos/react wraps @shipos/sdk in hooks. It's SSR-safe with no hydration mismatch, and components re-render live when flag config changes.
Install
npm i @shipos/reactQuickstart
Wrap your tree in the provider, then read flags with useFlag:
import { ShipOSProvider, useFlag } from "@shipos/react";
function App() {
return (
<ShipOSProvider clientKey="sos_sdk_..." user={{ userId: "u_42" }}>
<Checkout />
</ShipOSProvider>
);
}
function Checkout() {
const newCheckout = useFlag("new-checkout", false);
return newCheckout ? <CheckoutV2 /> : <CheckoutV1 />;
}Hydration-safe by design
Next.js App Router
The provider is client-only. Create a providers.tsx with "use client" and a public key:
"use client";
import { ShipOSProvider } from "@shipos/react";
export function Providers({ children }: { children: React.ReactNode }) {
return (
<ShipOSProvider
clientKey={process.env.NEXT_PUBLIC_SHIPOS_SDK_KEY!}
user={{ userId: "u_42" }}
>
{children}
</ShipOSProvider>
);
}Use the hook in a client component:
"use client";
import { useFlag } from "@shipos/react";
export function CheckoutButton() {
const newCheckout = useFlag("new-checkout", false);
return <button>{newCheckout ? "Checkout v2" : "Checkout"}</button>;
}In server components, route handlers, and server actions, use @shipos/sdk directly:
import { createClient } from "@shipos/sdk";
const shipos = createClient({ key: process.env.SHIPOS_SDK_KEY! });
export default async function Page() {
const banner = await shipos.flag("promo-banner", { default: false });
return <main>{banner && <PromoBanner />}</main>;
}Seed the first render with bootstrap
API
| Hook | Returns | Description |
|---|---|---|
| useFlag(key, default, overrides?) | T | The flag value. Returns default on the server and first client render, evaluates on mount, re-evaluates on config change. overrides { userId?, attributes? } replaces the provider user for this call. |
| useFlagDetail(key, default, overrides?) | { value, reason, loading } | Value plus reason; loading stays true until the first evaluation settles. |
| useShipOS() | ShipOSClient | The underlying client, an escape hatch. Throws if called outside the provider. |
| createFlagStore(client, key, default, context?, bootstrap?) | FlagStore | Advanced / testing, a standalone store for a single flag. |
Provider props
ShipOSProvider takes either a ready-made client, or clientKey plus optional baseUrl, defaults, and refreshInterval. Both forms also accept user and bootstrap.
Who owns the client
Re-exports
createClient, ShipOSClient, and the wire types are re-exported from @shipos/sdk, so you can import everything from @shipos/react when you need both.