Skip to main content

Server-Side Usage

Import from @ops-ai/react-router-toggly/server.

Prefer ambient EvalContext — configure getIdentity / getGroups / getClaims (or getContext) once on the loader/action helper. Then isEnabled('X') needs no IdentityContext argument.

Installation

npm install @ops-ai/react-router-toggly

createTogglyLoader

app/utils/toggly.server.ts
import { createTogglyLoader } from '@ops-ai/react-router-toggly/server';

export const togglyLoader = createTogglyLoader({
appKey: process.env.TOGGLY_APP_KEY,
environment: process.env.TOGGLY_ENVIRONMENT,
getIdentity: async (request) => {
const session = await getSession(request.headers.get('Cookie'));
return session.get('userId');
},
getGroups: async (request) => {
const session = await getSession(request.headers.get('Cookie'));
return session.get('roles') ?? [];
},
getClaims: async (request) => {
const session = await getSession(request.headers.get('Cookie'));
return { plan: session.get('plan') ?? '' };
},
});

Feature checks in a loader

app/routes/api.data.tsx
import type { Route } from './+types/api.data';
import { togglyLoader } from '~/utils/toggly.server';

export async function loader({ request }: Route.LoaderArgs) {
return togglyLoader.run({ request }, async ({ client }) => {
if (await client.isEnabled('new-api-v2')) {
return await fetchFromNewAPI();
}
return await fetchFromOldAPI();
});
}

Use args.request for identity. Do not parse React Router’s normalized URL for targeting.

Hydrating the client

export async function loader({ request }: Route.LoaderArgs) {
return togglyLoader.getLoaderData({ request });
}

getLoaderData returns route data that includes the Toggly snapshot under the shared loader key. RouterTogglyProvider reads that key automatically.

Feature-gated actions

import { createFeatureGatedAction } from '@ops-ai/react-router-toggly/server';

export const action = createFeatureGatedAction({
appKey: process.env.TOGGLY_APP_KEY!,
requiredFeatures: 'checkout-v2',
redirectTo: '/upgrade',
async action({ request, client }) {
// Ambient eval context is bound for this action.
return { ok: true };
},
});

When a feature is disabled, the helper redirects (or returns an error Response) instead of running the action body.

Known host floors

  • React Router 8: Node ≥22.22, React ≥19.2.7, Vite ≥7
  • React Router 7: React 18 or 19 with a valid RR7 Node pairing

Package engines.node remains >=18; hosts enforce their own floors.