AgentSkillsCN

databuddy-flags

在 React、Node.js 以及 Vue 应用中使用 Databuddy 功能标志。在实施功能标志、A/B 测试、渐进式发布,或针对特定用户群体进行功能开关控制时,可充分发挥其优势。

SKILL.md
--- frontmatter
name: databuddy-flags
description: Use Databuddy feature flags for React, Node.js, and Vue applications. Use when implementing feature flags, A/B testing, gradual rollouts, or user-targeted feature toggles.
metadata:
  author: databuddy
  version: "2.3"

Databuddy Feature Flags

The SDK provides feature flag support across all platforms (React, Node.js, Vue).

External Documentation

For the most up-to-date documentation, fetch: https://databuddy.cc/llms.txt

When to Use This Skill

Use this skill when:

  • Implementing feature flags in React, Next.js, Vue, or Node.js
  • Need A/B testing capabilities
  • Want user-targeted feature toggles
  • Implementing gradual rollouts
  • Need environment-based feature flags

React Feature Flags

Installation

Feature flags are included in the main SDK:

bash
bun add @databuddy/sdk

FlagsProvider

Wrap your app with FlagsProvider:

tsx
import { FlagsProvider } from "@databuddy/sdk/react";

function App() {
  return (
    <FlagsProvider
      clientId={process.env.NEXT_PUBLIC_DATABUDDY_CLIENT_ID}
      user={{ userId: user?.id, email: user?.email }}
      environment="production"
    >
      <YourApp />
    </FlagsProvider>
  );
}

FlagsProvider Props

PropTypeDefaultDescription
clientIdstringrequiredYour project client ID
apiUrlstringAutoCustom API endpoint
userUserContextUser context for targeting
environmentstringEnvironment name
isPendingbooleanfalseShow pending state
disabledbooleanfalseDisable flag fetching
autoFetchbooleantrueAuto-fetch flags on mount
cacheTtlnumberCache TTL in ms
staleTimenumberStale time in ms
skipStoragebooleanfalseSkip local storage

UserContext

typescript
interface UserContext {
  userId?: string;
  email?: string;
  // Additional targeting attributes
  [key: string]: unknown;
}

Hooks

useFlag

Get full flag state with loading/error handling:

tsx
import { useFlag } from "@databuddy/sdk/react";

function MyComponent() {
  const flag = useFlag("my-feature");

  if (flag.loading) {
    return <Skeleton />;
  }

  return flag.on ? <NewFeature /> : <OldFeature />;
}

Returns FlagState:

typescript
interface FlagState {
  on: boolean;           // Is flag enabled
  enabled: boolean;      // Alias for on
  loading: boolean;      // Is loading
  isLoading: boolean;    // Alias for loading
  isReady: boolean;      // Is ready
  status: FlagStatus;    // "pending" | "loading" | "ready" | "error"
  value?: unknown;       // Flag value (for non-boolean flags)
  variant?: string;      // Variant name (for A/B tests)
}

useFeature

Simple feature check with loading state:

tsx
import { useFeature } from "@databuddy/sdk/react";

function MyComponent() {
  const { on, loading, variant } = useFeature("dark-mode");

  if (loading) {
    return <Skeleton />;
  }

  return on ? <DarkTheme /> : <LightTheme />;
}

useFeatureOn

Boolean-only check with default value (SSR-safe):

tsx
import { useFeatureOn } from "@databuddy/sdk/react";

function MyComponent() {
  // Returns false while loading
  const isDarkMode = useFeatureOn("dark-mode", false);

  return isDarkMode ? <DarkTheme /> : <LightTheme />;
}

useFlagValue

Get typed flag value:

tsx
import { useFlagValue } from "@databuddy/sdk/react";

function MyComponent() {
  const maxItems = useFlagValue("max-items", 10);
  const theme = useFlagValue<"light" | "dark">("theme", "light");

  return <ItemList max={maxItems} theme={theme} />;
}

useVariant

Get A/B test variant:

tsx
import { useVariant } from "@databuddy/sdk/react";

function Checkout() {
  const variant = useVariant("checkout-experiment");

  if (variant === "control") {
    return <OldCheckout />;
  }
  if (variant === "treatment-a") {
    return <NewCheckoutA />;
  }
  return <NewCheckoutB />;
}

useFlags

Access the full flags context:

tsx
import { useFlags } from "@databuddy/sdk/react";

function MyComponent() {
  const {
    isOn,
    getFlag,
    getValue,
    fetchFlag,
    fetchAllFlags,
    updateUser,
    refresh,
    isReady,
  } = useFlags();

  // Check if flag is on
  const enabled = isOn("feature-x");

  // Get flag with state
  const flag = getFlag("feature-y");

  // Get typed value
  const limit = getValue<number>("rate-limit", 100);

  // Update user context
  const handleLogin = (user) => {
    updateUser({ userId: user.id, email: user.email });
  };

  // Force refresh flags
  const handleRefresh = () => {
    refresh(true); // true = force clear cache
  };
}

Patterns

Loading States

tsx
function FeatureWithSkeleton() {
  const { on, loading } = useFeature("new-dashboard");

  if (loading) {
    return <DashboardSkeleton />;
  }

  return on ? <NewDashboard /> : <OldDashboard />;
}

Server-Side Rendering

Use isPending during SSR/hydration:

tsx
// In your root layout or app
const [isPending, startTransition] = useTransition();

<FlagsProvider
  clientId="..."
  isPending={isPending}
  user={user}
>
  <App />
</FlagsProvider>

Targeting Rules

Pass user attributes for targeting:

tsx
<FlagsProvider
  clientId="..."
  user={{
    userId: user.id,
    email: user.email,
    plan: user.subscription.plan,
    country: user.address.country,
    createdAt: user.createdAt,
  }}
>
  <App />
</FlagsProvider>

Environment-Based Flags

tsx
<FlagsProvider
  clientId="..."
  environment={process.env.NODE_ENV}
>
  <App />
</FlagsProvider>

Node.js Feature Flags

typescript
import { createFlagsManager } from "@databuddy/sdk/node";

const flags = createFlagsManager({
  clientId: process.env.DATABUDDY_CLIENT_ID,
});

// Check flag
const result = await flags.getFlag("feature-x", {
  userId: "user-123",
  email: "user@example.com",
});

if (result.enabled) {
  // Feature is enabled
}

// Get flag value
const limit = await flags.getValue<number>("rate-limit", {
  userId: "user-123",
}, 100);

Vue Feature Flags

typescript
import { createFlagsPlugin, useFlag, useFeature } from "@databuddy/sdk/vue";

// Install plugin
app.use(createFlagsPlugin({
  clientId: import.meta.env.VITE_DATABUDDY_CLIENT_ID,
}));

// In components
const { on, loading } = useFeature("dark-mode");