Examples
Real-world patterns and recipes for using react-access-engine in production applications.
SaaS Dashboard with Plan Gating
import {
defineAccess,
AccessProvider,
Can,
Feature,
AccessGate,
} from "react-access-engine";
const config = defineAccess({
roles: ["admin", "member", "viewer"] as const,
permissions: {
admin: ["*"],
member: ["projects:read", "projects:write", "billing:read"],
viewer: ["projects:read"],
},
features: {
aiAssistant: { enabled: true, allowedPlans: ["pro", "enterprise"] },
customReports: { enabled: true, allowedPlans: ["enterprise"] },
darkMode: { enabled: true },
},
plans: ["free", "pro", "enterprise"] as const,
});
function Dashboard() {
return (
<AccessProvider config={config} user={currentUser}>
{/* Sidebar: admin-only settings */}
<Can permission="billing:read">
<BillingLink />
</Can>
{/* Plan-gated feature */}
<AccessGate feature="aiAssistant" plan="pro">
<AIAssistantWidget />
</AccessGate>
{/* Universal feature */}
<Feature name="darkMode">
<DarkModeToggle />
</Feature>
</AccessProvider>
);
}Multi-Tenant Application
const config = defineAccess({
roles: ["org-admin", "org-member", "org-guest"] as const,
permissions: {
"org-admin": ["settings:*", "members:*", "projects:*"],
"org-member": ["projects:read", "projects:write"],
"org-guest": ["projects:read"],
},
policies: [
{
id: "same-org-only",
effect: "allow",
permissions: ["projects:read", "projects:write"],
condition: (ctx) => ctx.user.attributes?.orgId === ctx.resource?.orgId,
priority: 10,
},
{
id: "owner-full-access",
effect: "allow",
permissions: ["projects:delete", "projects:transfer"],
condition: (ctx) => ctx.resource?.ownerId === ctx.user.id,
priority: 20,
},
],
});
function ProjectList({ projects }) {
return projects.map((project) => (
<Can
key={project.id}
permission="projects:read"
on={{ orgId: project.orgId }}
>
<ProjectCard project={project} />
</Can>
));
}A/B Testing with Analytics
import { createAnalyticsPlugin, defineAccess } from "react-access-engine";
const analytics = createAnalyticsPlugin({
adapter: {
track: (event, props) => mixpanel.track(event, props),
},
trackExperiments: true,
trackFeatures: true,
});
const config = defineAccess({
roles: ["user"] as const,
permissions: { user: ["read"] },
experiments: {
"checkout-v2": {
active: true,
variants: ["control", "streamlined"],
defaultVariant: "control",
allocation: { control: 50, streamlined: 50 },
},
"onboarding-flow": {
active: true,
variants: ["classic", "guided", "minimal"],
defaultVariant: "classic",
allocation: { classic: 33, guided: 34, minimal: 33 },
},
},
plugins: [analytics],
});
function CheckoutPage() {
const { variant, active } = useExperiment("checkout-v2");
return (
<Experiment
id="checkout-v2"
variants={{
control: <ClassicCheckout />,
streamlined: <StreamlinedCheckout />,
}}
fallback={<ClassicCheckout />}
/>
);
}Next.js App Router Integration
// app/layout.tsx
import { AccessProvider } from "react-access-engine";
import { getUser } from "@/lib/auth";
import { accessConfig } from "@/lib/access-config";
export default async function RootLayout({ children }) {
const user = await getUser();
return (
<html>
<body>
<AccessProvider config={accessConfig} user={user}>
{children}
</AccessProvider>
</body>
</html>
);
}
// app/admin/page.tsx
("use client");
import { PermissionGuard } from "react-access-engine";
export default function AdminPage() {
return (
<PermissionGuard
permissions={["admin:access"]}
fallback={<p>You don't have admin access.</p>}
>
<AdminDashboard />
</PermissionGuard>
);
}Feature Flags with Remote Config
import {
defineAccess,
useRemoteConfig,
AccessProvider,
Feature,
} from "react-access-engine";
const baseConfig = defineAccess({
roles: ["user"] as const,
permissions: { user: ["read"] },
features: {
maintenance: { enabled: false },
newUI: { enabled: false },
},
});
function App({ user }) {
const { config, loading, stale } = useRemoteConfig(baseConfig, {
url: "/api/feature-flags",
pollInterval: 30_000,
});
return (
<AccessProvider config={config} user={user}>
<Feature name="maintenance" fallback={<MainApp />}>
<MaintenancePage />
</Feature>
</AccessProvider>
);
}Custom Plugin for Rate Limiting
const rateLimitPlugin = {
name: "rate-limiter",
onAccessCheck: ({ permission, user, allowed }) => {
if (!allowed) return;
// Track access frequency per user
const key = `${user.id}:${permission}`;
const count = incrementCounter(key);
if (count > 100) {
logWarning(`High access frequency: ${key} (${count} checks)`);
}
},
};