---
title: Custom Adapters
description: Integrate any feature flag provider with the Flags SDK using a custom adapter.
---

# Custom Adapters



Integrate any feature flag provider with the Flags SDK
using an adapter. We publish adapters for the most [common providers](/docs/adapters/supported-providers), but
it is also possible to write a custom adapter in case we don't list
your provider or in case you have an in-house solution for feature
flags.

<CopyPrompt text="Create a custom Flags SDK adapter for my feature flag provider. Implement an adapter factory that initializes or accepts my provider client, define `origin` and `decide` behavior, optionally implement `bulkDecide` (and set `adapterId`) for batch evaluation, expose a default adapter when appropriate, use the adapter from typed flag declarations, preserve Edge Runtime compatibility where possible, and run the relevant tests or build when finished.">
  Create a custom Flags SDK adapter for my feature flag provider. Implement an
  adapter factory that initializes or accepts my provider client, define
  `origin` and `decide` behavior, optionally implement `bulkDecide` (and set
  `adapterId`) for batch evaluation, expose a default adapter when appropriate,
  use the adapter from typed flag declarations, preserve Edge Runtime
  compatibility where possible, and run the relevant tests or build when
  finished.
</CopyPrompt>

Adapters conceptually replace the `decide` and `origin` parts of a flag declaration.

## How to write a custom adapter

Creating custom adapters is possible by creating an adapter factory:

```ts title="example-adapter.ts"
import type { Adapter } from "flags";
import { createClient, EdgeConfigClient } from "@vercel/edge-config";

/**
 * A factory function for your adapter
 */
export function createExampleAdapter(/* options */) {
  // create the client for your provider here, or reuse the one
  // passed in through options

  return function exampleAdapter<ValueType, EntitiesType>(): Adapter<
    ValueType,
    EntitiesType
  > {
    return {
      origin(key) {
        // link to the flag in the provider's dashboard
        return `https://example.com/flags/${key}`;
      },
      async decide({ key }): Promise<ValueType> {
        // use the SDK instance created earlier to evaluate flags here
        return false as ValueType;
      },
    };
  };
}
```

This allows passing the provider in the flag declaration.

```tsx title="flags.tsx#next"
import { flag } from "flags/next";
import { createExampleAdapter } from "./example-adapter";

// create an instance of the adapter
const exampleAdapter = createExampleAdapter();

export const exampleFlag = flag({
  key: "example-flag",
  // use the adapter for many feature flags
  adapter: exampleAdapter,
});
```

## Bulk evaluation

Adapters can implement an optional `bulkDecide` hook to share work when many flags are
evaluated together with [`evaluate`](/frameworks/next/bulk-evaluation). When `bulkDecide` is
implemented and the adapter sets an `adapterId`, `evaluate` calls `bulkDecide` once for each
group of flags that share this adapter and the same `identify` source — instead of calling
`decide` per flag. This lets the provider, for example, resolve many flags through a single
network request.

```ts title="example-adapter.ts"
return {
  // Required for `bulkDecide` to be used by `evaluate`.
  adapterId: "example",
  origin(key) {
    return `https://example.com/flags/${key}`;
  },
  async decide({ key }): Promise<ValueType> {
    return false as ValueType;
  },
  // Called by `evaluate` for a batch of flags sharing this adapter and identify.
  async bulkDecide({ flags, entities, headers, cookies }) {
    // `flags` is `{ key: string; defaultValue?: unknown }[]`.
    // Resolve them however your provider allows — ideally in a single call.
    return Object.fromEntries(
      flags.map(({ key }) => [key, false as ValueType])
    );
  },
};
```

`bulkDecide` must return a record keyed by flag key:

* Missing keys or a `value` of `undefined` fall back to that flag's `defaultValue`.
* Throwing falls back to `defaultValue` per flag (and rejects for flags without a `defaultValue`).
* A flag declared with an inline `decide` takes precedence and is excluded from bulk evaluation.

## Example

Below is an example of an Flags SDK adapter reading Edge Config.

<IframeBrowser src="snippets:/concepts/adapters" codeSrc="https://github.com/vercel/flags/tree/main/examples/snippets/app/concepts/adapters" />

## Exposing default adapters

In the example above, as a user of the adapter, we first needed to
create an instance of the adapter. It is possible to simplify usage
further by exposing a default adapter.

Usage with a default adapter, where we can import a fully configured{" "}
`exampleAdapter`.

```tsx title="flags.tsx#next"
import { flag } from "flags/next";
import { exampleAdapter } from "./example-adapter";

export const exampleFlag = flag({
  key: "example-flag",
  // use the adapter for many feature flags
  adapter: exampleAdapter,
});
```

Many `@flags-sdk/*` adapters will implement this pattern. The
default adapter will get created lazily on first usage, and can
initialize itself based on known environment variables.

```ts title="example-adapter.ts"
// extend the adapter definition to expose a default adapter
let defaultEdgeConfigAdapter:
  | ReturnType<typeof createEdgeConfigAdapter>
  | undefined;

/**
 * A default Vercel adapter for Edge Config
 *
 */
export function edgeConfigAdapter<ValueType, EntitiesType>(): Adapter<
  ValueType,
  EntitiesType
> {
  // Initialized lazily to avoid warning when it is not actually used and env vars are missing.
  if (!defaultEdgeConfigAdapter) {
    if (!process.env.EDGE_CONFIG) {
      throw new Error("Edge Config Adapter: Missing EDGE_CONFIG env var");
    }

    defaultEdgeConfigAdapter = createEdgeConfigAdapter(process.env.EDGE_CONFIG);
  }

  return defaultEdgeConfigAdapter<ValueType, EntitiesType>();
}
```


---

For a semantic overview of all documentation, see [/sitemap.md](/sitemap.md)

For an index of all available documentation, see [/llms.txt](/llms.txt)

For agent-facing discovery, including API and MCP surfaces, see [/agents.md](/agents.md)