Migrate to Netlify Today

Netlify announces the next evolution of Gatsby Cloud. Learn more

ContactSign Up
Community Plugin
View plugin on GitHub

Toggly Feature Flags SDK for Gatsby

npm version License: MIT

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-toggly

Quick 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 key
  • defaultValue (boolean, optional): Default value if flag not found

Returns:

  • isEnabled (boolean): Whether the flag is enabled
  • isReady (boolean): Whether flags have been loaded
  • error (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 keys
  • requirement (‘all’ | ‘any’, optional): Gate requirement (default: ‘all’)
  • negate (boolean, optional): Negate the result (default: false)

Returns:

  • isEnabled (boolean): Whether the gate condition is met
  • isReady (boolean): Whether flags have been loaded
  • error (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 flags
  • isReady (boolean): Whether flags have been loaded
  • error (Error | null): Error if loading failed
  • refreshFlags (function): Manually refresh flags
  • setIdentity (function): Set user identity for targeting
  • clearIdentity (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 key
  • fallback (ReactNode, optional): Content when flag is disabled
  • children (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 keys
  • requirement (‘all’ | ‘any’, optional): Gate requirement (default: ‘all’)
  • negate (boolean, optional): Negate the result (default: false)
  • fallback (ReactNode, optional): Content when gate is not met
  • children (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 features
  • toggly-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 Content

Programmatic 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

  1. Check that appKey is correct in gatsby-config.js
  2. Verify network connectivity to https://client.toggly.io
  3. Enable debug mode: isDebug: true in plugin options
  4. Check browser console for errors

Build Errors

  1. Ensure all dependencies are installed: npm install
  2. Clear Gatsby cache: gatsby clean
  3. Rebuild: gatsby build

TypeScript Errors

  1. Ensure @types/react is installed
  2. Check tsconfig.json includes the SDK types
  3. Restart TypeScript server in your IDE

Contributing

Contributions are welcome! Please open an issue or pull request on GitHub.

License

MIT © Ops.AI

Resources

© 2026 Gatsby, Inc.