Basestack Docs
Backend

Vercel Flags SDK

The Basestack Vercel Flags SDK adapter allows you to use Basestack Feature Flags with the Vercel Flags SDK, providing a seamless integration for Next.js applications. This adapter bridges Basestack's feature flag infrastructure with Vercel's type-safe flag system, giving you the best of both worlds.

With this adapter, you can leverage Vercel Flags' excellent developer experience including type safety, server-side rendering support, and a clean API while using Basestack as your feature flag backend. This is perfect if you're already familiar with Vercel Flags or want to use its patterns in your Next.js application.

Preview Status: This provider is currently in preview and still under active development. Basic feature flag functionality is supported, but advanced features like evaluation context and user identity targeting are still in the works. We recommend using this provider if you only need basic feature flag functionality.

Getting started

Examples

Install

Install both the Vercel Flags SDK and the Basestack adapter. The flags package provides the core Vercel Flags functionality, while @basestack/vercel-flags-sdk-adapter connects it to Basestack's API.

Install the SDK
npm install flags @basestack/vercel-flags-sdk-adapter
pnpm install flags @basestack/vercel-flags-sdk-adapter
yarn add flags @basestack/vercel-flags-sdk-adapter
bun add flags @basestack/vercel-flags-sdk-adapter

Environment Variables

Configure your environment variables to connect to your Basestack Feature Flags project. The NEXT_PUBLIC_ prefix makes these variables available in both server and client components.

Make sure to add your .env file to .gitignore to keep your keys secure. Never commit sensitive credentials to version control.

.env
# BASESTACK FEATURE FLAGS
NEXT_PUBLIC_FEATURE_FLAGS_PROJECT_KEY=""
NEXT_PUBLIC_FEATURE_FLAGS_ENVIRONMENT_KEY=""

You can find your project and environment keys in your Basestack Feature Flags Dashboard.

Keep your project and environment keys secure. Never commit them to version control. Use environment variables or secure secret management systems.

Create the Adapter

Create a Basestack adapter instance that connects Vercel Flags to your Basestack project. The adapter handles API communication, caching, and value resolution.

Basic Boolean Flag Adapter:

src/lib/flags.ts
import { flag } from "flags/next";
import { createBasestackAdapter } from "@basestack/vercel-flags-sdk-adapter";

const adapter = createBasestackAdapter<boolean>({
  endpoint: "https://flags-api.basestack.co/v1",
  projectKey: process.env.NEXT_PUBLIC_FEATURE_FLAGS_PROJECT_KEY,
  environmentKey: process.env.NEXT_PUBLIC_FEATURE_FLAGS_ENVIRONMENT_KEY,
  cacheTtlMs: 15_000, // Cache flags for 15 seconds
  requestTimeoutMs: 5_000, // 5 second timeout
  resolveValue: (flag) => flag.enabled, // Return the enabled state for boolean flags
});

export const headerFlag = flag<boolean>({
  key: "header",
  adapter,
  defaultValue: false,
  description: "Shows the next generation header experience",
});

The adapter configuration includes:

  • endpoint: Your Basestack API endpoint
  • projectKey & environmentKey: Your Basestack credentials
  • cacheTtlMs: How long to cache flag values (in milliseconds)
  • requestTimeoutMs: Request timeout duration
  • resolveValue: Function that extracts the flag value from Basestack's response

Use Flags in Your Application

Once configured, you can use flags in your Next.js server components, API routes, and server actions. Flags are fetched server-side, providing excellent performance and SEO benefits.

src/app/page.tsx
import { headerFlag } from "@/lib/flags";

export const dynamic = "force-dynamic";

export default async function HomePage() {
  const showHeader = await headerFlag();

  return (
    <main className="page">
      <section className="card muted">
        <h1>
          {showHeader ? "New header experience" : "Default header experience"}
        </h1>
        <p>Powered by Basestack + Vercel Flags.</p>
      </section>
    </main>
  );
}

The headerFlag() function returns a promise that resolves to the flag's value. Since this is a server component, the flag is evaluated on the server during rendering.

Advanced Usage

String/Variant Flags

For flags that return string values (like A/B test variants), create a string adapter with a custom resolveValue function:

src/lib/flags.ts
import { flag } from "flags/next";
import { createBasestackAdapter } from "@basestack/vercel-flags-sdk-adapter";

const stringAdapter = createBasestackAdapter<string>({
  endpoint: "https://flags-api.basestack.co/v1",
  projectKey: process.env.NEXT_PUBLIC_FEATURE_FLAGS_PROJECT_KEY,
  environmentKey: process.env.NEXT_PUBLIC_FEATURE_FLAGS_ENVIRONMENT_KEY,
  cacheTtlMs: 15_000,
  requestTimeoutMs: 5_000,
  resolveValue: (flag) => flag.payload?.variant as string, // Extract variant from payload
});

export const headerVariantFlag = flag<string>({
  key: "header-variant",
  adapter: stringAdapter,
  defaultValue: "old",
  description: "Header variant for A/B testing",
});

Multiple Adapters

You can create multiple adapters for different flag types or configurations:

src/lib/flags.ts
import { flag } from "flags/next";
import { createBasestackAdapter } from "@basestack/vercel-flags-sdk-adapter";

// Boolean adapter for simple on/off flags
const booleanAdapter = createBasestackAdapter<boolean>({
  endpoint: "https://flags-api.basestack.co/v1",
  projectKey: process.env.NEXT_PUBLIC_FEATURE_FLAGS_PROJECT_KEY,
  environmentKey: process.env.NEXT_PUBLIC_FEATURE_FLAGS_ENVIRONMENT_KEY,
  cacheTtlMs: 15_000,
  requestTimeoutMs: 5_000,
  resolveValue: (flag) => flag.enabled,
});

// String adapter for variant flags
const variantAdapter = createBasestackAdapter<string>({
  endpoint: "https://flags-api.basestack.co/v1",
  projectKey: process.env.NEXT_PUBLIC_FEATURE_FLAGS_PROJECT_KEY,
  environmentKey: process.env.NEXT_PUBLIC_FEATURE_FLAGS_ENVIRONMENT_KEY,
  cacheTtlMs: 15_000,
  requestTimeoutMs: 5_000,
  resolveValue: (flag) => flag.payload?.variant as string,
});

// Use boolean adapter
export const headerFlag = flag<boolean>({
  key: "header",
  adapter: booleanAdapter,
  defaultValue: false,
});

// Use variant adapter
export const themeFlag = flag<string>({
  key: "theme",
  adapter: variantAdapter,
  defaultValue: "light",
});

API Routes

Use flags in Next.js API route handlers:

src/app/api/feature/route.ts
import { NextResponse } from "next/server";
import { headerFlag } from "@/lib/flags";

export async function GET() {
  const isEnabled = await headerFlag();
  
  if (isEnabled) {
    return NextResponse.json({ 
      message: "New feature enabled",
      data: { /* new feature data */ }
    });
  }
  
  return NextResponse.json({ 
    message: "Legacy feature",
    data: { /* legacy data */ }
  });
}

Server Actions

Flags work seamlessly with Next.js Server Actions:

src/app/actions.ts
"use server";

import { headerFlag } from "@/lib/flags";

export async function getFeatureData() {
  const showNewFeature = await headerFlag();
  
  if (showNewFeature) {
    return { feature: "new", data: "..." };
  }
  
  return { feature: "legacy", data: "..." };
}

Configuration Options

The createBasestackAdapter function accepts the following configuration:

OptionTypeRequiredDefaultDescription
endpointstringYes-Basestack API endpoint URL
projectKeystringYes-Your Basestack project key
environmentKeystringYes-Your Basestack environment key
cacheTtlMsnumberNo15000Cache time-to-live in milliseconds
requestTimeoutMsnumberNo5000Request timeout in milliseconds
resolveValue(flag: Flag) => TYes-Function to extract the flag value from Basestack's response

Best Practices

1. Organize Flags in a Single File

Keep all your flag definitions in a centralized location for easier management:

// src/lib/flags.ts
export const headerFlag = flag<boolean>({ /* ... */ });
export const footerFlag = flag<boolean>({ /* ... */ });
export const checkoutFlag = flag<string>({ /* ... */ });

2. Use TypeScript Generics

Leverage TypeScript's type system for better type safety:

export const themeFlag = flag<"light" | "dark">({
  key: "theme",
  adapter: variantAdapter,
  defaultValue: "light",
});

3. Set Appropriate Cache TTLs

Balance freshness with performance:

// Short cache for frequently changing flags
const shortCacheAdapter = createBasestackAdapter({
  // ...
  cacheTtlMs: 5_000, // 5 seconds
});

// Longer cache for stable flags
const longCacheAdapter = createBasestackAdapter({
  // ...
  cacheTtlMs: 60_000, // 1 minute
});

4. Handle Errors Gracefully

Always provide sensible default values:

export const criticalFlag = flag<boolean>({
  key: "critical-feature",
  adapter,
  defaultValue: false, // Safe fallback if flag fetch fails
});

5. Use Descriptive Flag Keys

Choose clear, consistent naming for your flags:

// Good
export const newCheckoutFlowFlag = flag<boolean>({ key: "new-checkout-flow", ... });

// Avoid
export const flag1 = flag<boolean>({ key: "f1", ... });

Troubleshooting

Flags Not Updating

If flags aren't updating as expected:

  1. Check Cache TTL: Flags are cached based on cacheTtlMs. Wait for the cache to expire or reduce the TTL
  2. Verify Environment Variables: Ensure NEXT_PUBLIC_ prefixed variables are set correctly
  3. Check Network: Verify your application can reach the Basestack API endpoint
  4. Restart Dev Server: After changing environment variables, restart your Next.js dev server

Type Errors

If you're getting TypeScript errors:

  1. Check Generic Types: Ensure the adapter and flag use matching types
  2. Verify resolveValue: The resolveValue function must return the correct type
  3. Import Types: Make sure you're importing types correctly from flags/next

Flags Returning Default Values

If flags always return default values:

  1. Check Flag Key: Verify the flag key matches what's configured in Basestack
  2. Verify Credentials: Ensure project and environment keys are correct
  3. Check API Response: Inspect the network tab to see if the API is returning data
  4. Review resolveValue: Ensure resolveValue correctly extracts the value from Basestack's response

Performance Issues

If you're experiencing performance problems:

  1. Increase Cache TTL: Reduce API calls by caching longer
  2. Reduce Request Timeout: Set a lower requestTimeoutMs to fail fast
  3. Preload Flags: Consider preloading critical flags at application startup