Toggly Feature Flags SDK for Gatsby
A comprehensive Gatsby plugin for Toggly feature flags with support for SSR, SSG, build-time page gating, and edge worker filtering.
Features
- 🚀 Gatsby Plugin Integration - Automatic setup via
gatsby-config.js - ⚛️ Modern React Hooks -
useFeatureFlag,useFeatureGate,useToggly - 🧩 React Components -
<Feature>,<FeatureGate>,<TogglyProvider> - 🏗️ Build-Time Page Gating - Extract feature requirements from page frontmatter
- 🌐 Hybrid Approach - Build with all features enabled, filter at edge/runtime
- 🔄 Reactive State - Powered by nanostores for minimal bundle size
- 📦 TypeScript Support - Full type definitions included
- 🎯 User Targeting - Identity-based feature rollouts
- ⚡ Edge Worker Ready - Generate manifests for Cloudflare Workers
Installation
npm install @ops-ai/gatsby-feature-flags-togglyQuick Start
1. Configure the Plugin
Add the plugin to your gatsby-config.js:
module.exports = {
plugins: [
{
resolve: '@ops-ai/gatsby-feature-flags-toggly',
options: {
appKey: 'your-app-key', // Get this from toggly.io
environment: 'Production', // Optional, defaults to 'Production'
allFeaturesEnabledDuringBuild: true, // Optional, for hybrid approach
flagDefaults: {
// Optional fallback values
'my-feature': false,
},
},
},
],
};2. Use in Components
Using Hooks
import { useFeatureFlag } from '@ops-ai/gatsby-feature-flags-toggly';
function MyComponent() {
const { isEnabled, isReady, error } = useFeatureFlag('new-dashboard');
if (!isReady) return <Loading />;
if (error) return <ErrorMessage />;
return isEnabled ? <NewDashboard /> : <OldDashboard />;
}Using Components
import { Feature } from '@ops-ai/gatsby-feature-flags-toggly';
function MyPage() {
return (
<div>
<Feature flag="new-header">
<NewHeader />
</Feature>
<Feature flag="beta-feature" fallback={<ComingSoon />}>
<BetaContent />
</Feature>
</div>
);
}3. Page-Level Gating
Add x-feature to your page frontmatter:
---
title: Beta Features
x-feature: beta-access
---
# Beta Features
This page requires the 'beta-access' feature flag.During build, the plugin generates a toggly-page-features.json manifest that maps pages to required features, enabling edge worker filtering.
Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
appKey |
string |
required | Your Toggly application key |
environment |
string |
'Production' |
Environment name (e.g., ‘Staging’, ‘Dev’) |
baseURI |
string |
'https://client.toggly.io' |
Toggly API base URL |
flagDefaults |
object |
{} |
Default flag values when API unavailable |
featureFlagsRefreshInterval |
number |
180000 |
Client refresh interval (ms) |
allFeaturesEnabledDuringBuild |
boolean |
false |
Enable all features during build |
identity |
string |
undefined |
User identity for targeting |
isDebug |
boolean |
false |
Enable debug logging |
connectTimeout |
number |
5000 |
API connection timeout (ms) |
API Reference
Hooks
useFeatureFlag(flagKey, defaultValue?)
Check if a single feature flag is enabled.
const { isEnabled, isReady, error } = useFeatureFlag('my-feature', false);Parameters:
flagKey(string): Feature flag keydefaultValue(boolean, optional): Default value if flag not found
Returns:
isEnabled(boolean): Whether the flag is enabledisReady(boolean): Whether flags have been loadederror(Error | null): Error if loading failed
useFeatureGate(flagKeys, requirement?, negate?)
Check multiple feature flags with gate logic.
const { isEnabled, isReady, error } = useFeatureGate(
['feature1', 'feature2'],
'all', // or 'any'
false // negate
);Parameters:
flagKeys(string[]): Array of feature flag keysrequirement(‘all’ | ‘any’, optional): Gate requirement (default: ‘all’)negate(boolean, optional): Negate the result (default: false)
Returns:
isEnabled(boolean): Whether the gate condition is metisReady(boolean): Whether flags have been loadederror(Error | null): Error if loading failed
useToggly()
Access the full Toggly store and utilities.
const {
flags,
isReady,
error,
refreshFlags,
setIdentity,
clearIdentity,
} = useToggly();Returns:
flags(object): All feature flagsisReady(boolean): Whether flags have been loadederror(Error | null): Error if loading failedrefreshFlags(function): Manually refresh flagssetIdentity(function): Set user identity for targetingclearIdentity(function): Clear user identity
Components
<Feature>
Conditionally render content based on a feature flag.
<Feature flag="my-feature" fallback={<Loading />}>
<Content />
</Feature>Props:
flag(string): Feature flag keyfallback(ReactNode, optional): Content when flag is disabledchildren(ReactNode): Content when flag is enabled
<FeatureGate>
Conditionally render content based on multiple feature flags.
<FeatureGate
flags={['feature1', 'feature2']}
requirement="all"
negate={false}
fallback={<Restricted />}
>
<Content />
</FeatureGate>Props:
flags(string[]): Array of feature flag keysrequirement(‘all’ | ‘any’, optional): Gate requirement (default: ‘all’)negate(boolean, optional): Negate the result (default: false)fallback(ReactNode, optional): Content when gate is not metchildren(ReactNode): Content when gate is met
<TogglyProvider>
Provider component (automatically wrapped by plugin).
<TogglyProvider config={options}>
<App />
</TogglyProvider>Note: When using the Gatsby plugin, you don’t need to manually wrap your app with
TogglyProvider. The plugin handles this automatically.
Advanced Usage
User Targeting
Set user identity for targeted feature rollouts:
import { useToggly } from '@ops-ai/gatsby-feature-flags-toggly';
function UserProfile({ userId }) {
const { setIdentity } = useToggly();
useEffect(() => {
setIdentity(userId);
}, [userId, setIdentity]);
return <Profile />;
}Manual Flag Refresh
Manually refresh flags without waiting for the refresh interval:
import { useToggly } from '@ops-ai/gatsby-feature-flags-toggly';
function RefreshButton() {
const { refreshFlags } = useToggly();
const handleRefresh = async () => {
await refreshFlags();
};
return <button onClick={handleRefresh}>Refresh Flags</button>;
}Direct Store Access
For advanced use cases, access the nanostores directly:
import { useStore } from '@nanostores/react';
import { $flags, $flag } from '@ops-ai/gatsby-feature-flags-toggly';
function AdvancedComponent() {
// Access all flags
const allFlags = useStore($flags);
// Access specific flag as computed atom
const isEnabled = useStore($flag('my-feature', false));
return <div>{/* ... */}</div>;
}Build-Time Strategy: Hybrid Approach
The recommended approach for Gatsby sites:
1. Enable All Features During Build
// gatsby-config.js
module.exports = {
plugins: [
{
resolve: '@ops-ai/gatsby-feature-flags-toggly',
options: {
appKey: 'your-app-key',
allFeaturesEnabledDuringBuild: true, // ← Enable this
},
},
],
};2. Benefits
- SEO-Friendly: All content is in the static HTML
- No Broken Links: All pages are built and accessible
- Dynamic Control: Features can be toggled without rebuilding
- Edge Enforcement: Use Cloudflare Workers to filter at the edge
3. Edge Worker Filtering
After build, the plugin generates two manifest files in public/:
toggly-page-features.json- Maps pages to required featurestoggly-config.json- Sanitized config for edge workers
Use these with a Cloudflare Worker to enforce feature gates before serving static HTML:
// Example Cloudflare Worker
export default {
async fetch(request, env) {
const url = new URL(request.url);
// Load page features manifest
const manifest = await env.ASSETS.fetch('/toggly-page-features.json');
const pageFeatures = await manifest.json();
// Check if page requires a feature
const requiredFeature = pageFeatures[url.pathname];
if (requiredFeature) {
// Fetch flags from Toggly API
const flags = await fetchTogglyFlags(env.TOGGLY_APP_KEY);
// If feature is disabled, return 404
if (!flags[requiredFeature]) {
return new Response('Not Found', { status: 404 });
}
}
// Serve the static asset
return env.ASSETS.fetch(request);
},
};Page-Level Gating
Using Frontmatter
For MDX or Markdown pages, add x-feature to frontmatter:
---
title: Beta Page
x-feature: beta-access
---
# Beta ContentProgrammatic Pages
When creating pages programmatically, add x-feature to page context:
// gatsby-node.js
exports.createPages = async ({ actions }) => {
actions.createPage({
path: '/beta',
component: require.resolve('./src/templates/beta.js'),
context: {
frontmatter: {
'x-feature': 'beta-access',
},
},
});
};Generated Manifest
The plugin generates toggly-page-features.json:
{
"/beta": "beta-access",
"/premium": "premium-features",
"/new-dashboard": "new-dashboard-feature"
}TypeScript Support
The SDK includes full TypeScript definitions:
import type {
TogglyPluginOptions,
Flags,
GateRequirement,
UseFeatureFlagResult,
UseFeatureGateResult,
UseTogglyResult,
} from '@ops-ai/gatsby-feature-flags-toggly';Examples
Example 1: Feature Toggle
import { useFeatureFlag } from '@ops-ai/gatsby-feature-flags-toggly';
function Dashboard() {
const { isEnabled } = useFeatureFlag('new-dashboard');
return (
<div>
<h1>Dashboard</h1>
{isEnabled ? <NewDashboardWidget /> : <OldDashboardWidget />}
</div>
);
}Example 2: A/B Testing
import { useFeatureFlag } from '@ops-ai/gatsby-feature-flags-toggly';
function Hero() {
const { isEnabled: variantA } = useFeatureFlag('hero-variant-a');
return variantA ? <HeroVariantA /> : <HeroVariantB />;
}Example 3: Gradual Rollout
import { useEffect } from 'react';
import { useToggly } from '@ops-ai/gatsby-feature-flags-toggly';
function App({ user }) {
const { setIdentity } = useToggly();
useEffect(() => {
// Set user ID for gradual rollout
if (user?.id) {
setIdentity(user.id);
}
}, [user, setIdentity]);
return <div>{/* ... */}</div>;
}Example 4: Multiple Flag Gates
import { FeatureGate } from '@ops-ai/gatsby-feature-flags-toggly';
function PremiumContent() {
return (
<FeatureGate
flags={['premium-tier', 'beta-access']}
requirement="any"
fallback={<UpgradePrompt />}
>
<PremiumFeatures />
</FeatureGate>
);
}Example 5: Maintenance Mode
import { Feature } from '@ops-ai/gatsby-feature-flags-toggly';
function App() {
return (
<Feature flag="maintenance-mode" fallback={<MainApp />}>
<MaintenancePage />
</Feature>
);
}Troubleshooting
Flags Not Loading
- Check that
appKeyis correct ingatsby-config.js - Verify network connectivity to
https://client.toggly.io - Enable debug mode:
isDebug: truein plugin options - Check browser console for errors
Build Errors
- Ensure all dependencies are installed:
npm install - Clear Gatsby cache:
gatsby clean - Rebuild:
gatsby build
TypeScript Errors
- Ensure
@types/reactis installed - Check
tsconfig.jsonincludes the SDK types - Restart TypeScript server in your IDE
Contributing
Contributions are welcome! Please open an issue or pull request on GitHub.
License
MIT © Ops.AI
Resources
Related Packages
- @ops-ai/react-feature-flags-toggly - React SDK
- @ops-ai/astro-feature-flags-toggly - Astro SDK
- @ops-ai/ngx-feature-flags-toggly - Angular SDK