SDK Reference

Server-Side Feature Flags

The Databuddy Node SDK includes a server-side feature flags manager optimized for server environments with request deduplication, batching, and stale-while-revalidate caching.

Installation

bash
bun add @databuddy/sdk

Quick Start

tsx
import { createServerFlagsManager } from "@databuddy/sdk/node";

const flags = createServerFlagsManager({
clientId: process.env.DATABUDDY_CLIENT_ID!,
user: {
  userId: "user-123",
  email: "user@example.com"
}
});

// Wait for initialization
await flags.waitForInit();

// Check a flag
const result = await flags.getFlag("new-feature");
if (result.enabled) {
// Show new feature
}

Creating a Manager

createServerFlagsManager(config)

Creates a new server-side flags manager instance:

tsx
import { createServerFlagsManager } from "@databuddy/sdk/node";

const flags = createServerFlagsManager({
clientId: process.env.DATABUDDY_CLIENT_ID!,
apiUrl: "https://api.databuddy.cc",
user: {
  userId: "user-123",
  email: "user@example.com",
  organizationId: "org-456",
  properties: {
    plan: "premium"
  }
},
environment: "production",
cacheTtl: 60_000,      // 1 minute cache
staleTime: 30_000,     // Revalidate after 30s
debug: false
});

Configuration

OptionTypeDefaultDescription
clientIdstringRequiredYour client ID
apiUrlstringhttps://api.databuddy.ccAPI endpoint
userUserContext-User context for targeting
environmentstring-Environment name
cacheTtlnumber60000Cache TTL in ms
staleTimenumber30000Revalidate after (ms)
autoFetchbooleanfalseFetch all flags on init
debugbooleanfalseEnable debug logging
disabledbooleanfalseDisable flag evaluation

User Context

OptionTypeDescription
userIdstringUser identifier for targeting
emailstringEmail for targeting
organizationIdstringOrganization for group rollouts
teamIdstringTeam for group rollouts
propertiesobjectCustom properties for targeting

Fetching Flags

getFlag(key, user?)

Fetch a single flag with caching and deduplication:

tsx
const result = await flags.getFlag("my-feature");

console.log({
enabled: result.enabled,    // boolean
value: result.value,        // boolean | string | number
variant: result.variant,    // string (for A/B tests)
reason: result.reason       // evaluation reason
});

Override user context for a specific check:

tsx
const result = await flags.getFlag("premium-feature", {
userId: "different-user",
properties: { plan: "enterprise" }
});

fetchAllFlags(user?)

Pre-fetch all flags for a user:

tsx
// Fetch all flags upfront
await flags.fetchAllFlags();

// Now synchronous checks are fast
const state = flags.isEnabled("feature-1");
const value = flags.getValue("max-items", 10);

isEnabled(key)

Synchronous check from cache (call after fetchAllFlags or getFlag):

tsx
const state = flags.isEnabled("my-feature");

if (state.isReady && state.on) {
// Feature is enabled
}

Returns a FlagState object:

tsx
interface FlagState {
on: boolean;          // Is the flag on?
enabled: boolean;     // Alias for on
status: "ready" | "loading" | "error";
loading: boolean;
isLoading: boolean;
isReady: boolean;
value?: boolean | string | number;
variant?: string;
}

getValue(key, defaultValue)

Get a typed value from cache:

tsx
const maxItems = flags.getValue("max-items", 10);
const theme = flags.getValue<"light" | "dark">("theme", "light");

Usage Patterns

Next.js API Routes

app/api/data/route.tstsx
import { createServerFlagsManager } from "@databuddy/sdk/node";
import { NextResponse } from "next/server";

const flags = createServerFlagsManager({
clientId: process.env.DATABUDDY_CLIENT_ID!
});

export async function GET(request: Request) {
const userId = request.headers.get("x-user-id");

const result = await flags.getFlag("new-api-version", {
  userId: userId ?? undefined
});

if (result.enabled) {
  return NextResponse.json({ version: "v2", data: await getNewData() });
}

return NextResponse.json({ version: "v1", data: await getLegacyData() });
}

Next.js Server Components

app/dashboard/page.tsxtsx
import { createServerFlagsManager } from "@databuddy/sdk/node";
import { auth } from "@/lib/auth";

export default async function DashboardPage() {
const session = await auth();

const flags = createServerFlagsManager({
  clientId: process.env.DATABUDDY_CLIENT_ID!,
  user: session?.user ? {
    userId: session.user.id,
    email: session.user.email,
    properties: { plan: session.user.plan }
  } : undefined
});

const newDashboard = await flags.getFlag("new-dashboard");

if (newDashboard.enabled) {
  return <NewDashboard />;
}

return <LegacyDashboard />;
}

Express Middleware

tsx
import express from "express";
import { createServerFlagsManager } from "@databuddy/sdk/node";

const app = express();

// Create a shared manager
const flags = createServerFlagsManager({
clientId: process.env.DATABUDDY_CLIENT_ID!,
autoFetch: true
});

// Wait for init
await flags.waitForInit();

// Middleware to attach flags to request
app.use(async (req, res, next) => {
const userId = req.headers["x-user-id"] as string;

req.flags = {
  isEnabled: async (key: string) => {
    const result = await flags.getFlag(key, { userId });
    return result.enabled;
  }
};

next();
});

app.get("/api/feature", async (req, res) => {
const enabled = await req.flags.isEnabled("my-feature");
res.json({ enabled });
});

Serverless Functions

tsx
import { createServerFlagsManager } from "@databuddy/sdk/node";

// Create manager outside handler for reuse
const flags = createServerFlagsManager({
clientId: process.env.DATABUDDY_CLIENT_ID!
});

export async function handler(event: any) {
const userId = event.headers["x-user-id"];

const result = await flags.getFlag("feature", { userId });

return {
  statusCode: 200,
  body: JSON.stringify({
    enabled: result.enabled,
    variant: result.variant
  })
};
}

Caching Behavior

The server manager uses stale-while-revalidate caching:

  1. Fresh cache: Returns immediately
  2. Stale cache: Returns immediately, revalidates in background
  3. No cache: Fetches from API
tsx
const flags = createServerFlagsManager({
clientId: process.env.DATABUDDY_CLIENT_ID!,
cacheTtl: 60_000,      // Cache valid for 1 minute
staleTime: 30_000      // Revalidate after 30 seconds
});

// First call: fetches from API
const result1 = await flags.getFlag("my-feature");

// Within 30s: returns cached value (fresh)
const result2 = await flags.getFlag("my-feature");

// After 30s but within 60s: returns cached, revalidates in background
const result3 = await flags.getFlag("my-feature");

// After 60s: fetches from API
const result4 = await flags.getFlag("my-feature");

Request Batching

Multiple concurrent flag requests are batched automatically:

tsx
// These 3 concurrent requests become 1 API call
const [flag1, flag2, flag3] = await Promise.all([
flags.getFlag("feature-1"),
flags.getFlag("feature-2"),
flags.getFlag("feature-3")
]);

Request Deduplication

Identical concurrent requests are deduplicated:

tsx
// Only 1 API call is made
const [result1, result2] = await Promise.all([
flags.getFlag("same-feature"),
flags.getFlag("same-feature")
]);

Updating User Context

tsx
// Update user for subsequent calls
flags.updateUser({
userId: "new-user",
properties: { plan: "enterprise" }
});

// Refresh flags for new user
await flags.refresh();

Manager Lifecycle

waitForInit()

Wait for the manager to initialize:

tsx
const flags = createServerFlagsManager({
clientId: process.env.DATABUDDY_CLIENT_ID!,
autoFetch: true
});

await flags.waitForInit();
// Now all flags are cached

isReady()

Check if the manager is ready:

tsx
if (flags.isReady()) {
// Safe to use synchronous methods
const state = flags.isEnabled("my-feature");
}

destroy()

Clean up resources:

tsx
flags.destroy();

Singleton Pattern

For most applications, create a single manager instance:

lib/flags.tstsx
import { createServerFlagsManager } from "@databuddy/sdk/node";

let flagsManager: ReturnType<typeof createServerFlagsManager> | null = null;

export function getFlags() {
if (!flagsManager) {
  flagsManager = createServerFlagsManager({
    clientId: process.env.DATABUDDY_CLIENT_ID!,
    autoFetch: true
  });
}
return flagsManager;
}
In your routestsx
import { getFlags } from "@/lib/flags";

const flags = getFlags();
const result = await flags.getFlag("my-feature", { userId });

TypeScript Types

tsx
import {
createServerFlagsManager,
ServerFlagsManager,
type FlagsConfig,
type FlagResult,
type FlagState,
type UserContext
} from "@databuddy/sdk/node";

How is this guide?