Amba
SDKsFeatures

Feature flags

Server-evaluated boolean and multi-variant flags. One fetch per session, hooks for React.

Feature flags let you ship code dark and turn it on for a slice of users without a deploy. The SDK fetches the full flag set in one call, then resolves each flag's value per-user against rules you define in the console.

Two flag types:

  • Boolean flags — on / off per user. Read with useFlag(name) or flags.fetch().then(...).
  • Multi-variant flags — return a string (e.g. 'control' / 'short' / 'long') for A/B/n testing. Read with useVariant(name) or the returned variant field on each assignment.

Each flag can also carry a payload JSON value — useful for config-driven feature gates ({ "max_items": 25 }).

Quick start

import { Amba } from '@layers/amba-web';
 
const flags = await Amba.flags.fetch();
const newUi = flags.find((f) => f.name === 'new_ui')?.enabled ?? false;
const copy = flags.find((f) => f.name === 'signup_copy')?.variant ?? 'control';

Operations

fetch()

Returns the full flag set for the signed-in user. Each entry has the shape:

{
  name: 'new_onboarding',     // flag name
  enabled: true,               // boolean evaluation
  variant: 'short',            // optional, for multi-variant flags
  payload: { max_items: 25 },  // optional, attached JSON config
}

The SDK caches the response for the lifetime of the session — subsequent fetch() calls within ~60 seconds return the cache. Force a refresh by signing the user out and back in (e.g. after a server-side rule change).

React hooks

useFlag(name) returns a boolean. useVariant(name) returns the variant string (or null if unset / not loaded).

import { useFlag, useVariant } from '@layers/amba-react';
 
function NewFeature() {
  const enabled = useFlag('new_feature');
  if (!enabled) return null;
 
  const layout = useVariant('new_feature_layout'); // 'horizontal' | 'vertical' | null
  return layout === 'horizontal' ? <Horizontal /> : <Vertical />;
}

Both hooks default to safe values (false / null) while the initial fetch is in flight — render without an explicit loading guard.

Patterns

Gate render at module scope

For flags that gate large slabs of the UI, prefer fetching once at app start and stashing the result:

let flagsCache: Awaited<ReturnType<typeof Amba.flags.fetch>> | null = null;
 
export async function getFlag(name: string): Promise<boolean> {
  flagsCache ??= await Amba.flags.fetch();
  return flagsCache.find((f) => f.name === name)?.enabled ?? false;
}

Config-driven gates

For A/B tests with parameterized behavior, attach a payload to the variant in the console and read it on the client:

function PaginatedList() {
  const flags = await Amba.flags.fetch();
  const flag = flags.find((f) => f.name === 'pagination_size');
  const limit = (flag?.payload as { limit?: number })?.limit ?? 20;
  const { data } = await Amba.collections.find('posts', { limit });
  return <List items={data} />;
}

Server-side parity

Server functions can read the same flags for the same user via ctx.flags.fetch() (or amba.asUser(uid).flags.fetch() from a Node server). Useful for gating server logic on the same assignment as the UI:

// Server function
export default defineFunction(async (req, ctx) => {
  const flags = await ctx.flags.fetch();
  const newPipeline = flags.find((f) => f.name === 'new_processing_pipeline')?.enabled ?? false;
  return newPipeline ? newImpl() : oldImpl();
});

Limits

  • Flag count: up to 100 flags per project visible to a single fetch.
  • Variant count: up to 8 variants per multi-variant flag (control + 7 treatments is a common ceiling).
  • Payload size: up to 8 KB JSON per flag.
  • Cache TTL: ~60 seconds per session, then a server round-trip on next fetch(). To deliberately re-evaluate (e.g. after a permission change), sign the user out and back in.

Reference

On this page