Astro SDK

The @flagify/astro package provides a first-class Astro integration for evaluating feature flags in pages and components, with a dev toolbar for overrides.

Installation

npm install @flagify/astro @flagify/node

Setup

1. Add environment variables

FLAGIFY_PROJECT_KEY=your-project-key
FLAGIFY_PUBLIC_KEY=pk_dev_abc123_xxxxxxxx
FLAGIFY_SECRET_KEY=sk_dev_abc123_xxxxxxxx

2. Add the integration

// astro.config.mjs
import { defineConfig } from 'astro/config';
import flagify from '@flagify/astro';

export default defineConfig({
  integrations: [flagify()],
});

This automatically registers:

  • Middleware that initializes the Flagify client and parses override cookies
  • Dev toolbar app for toggling flag overrides during development

Defining flags

Use defineFlag() to create typed flag definitions:

// src/flags.ts
import { defineFlag } from '@flagify/astro';

export const newCheckout = defineFlag({
  key: 'new-checkout-flow',
  description: 'New checkout flow experience',
  default: false,
});

export const heroVariant = defineFlag({
  key: 'hero-variant',
  description: 'A/B test for hero section',
  default: 'control',
  options: [
    { value: 'control', label: 'Control' },
    { value: 'variant-a', label: 'Variant A' },
    { value: 'variant-b', label: 'Variant B' },
  ],
});

defineFlag options

OptionTypeRequiredDescription
keystringYesThe flag key (kebab-case)
descriptionstringNoHuman-readable description
defaultTYesFallback value when the flag doesn’t exist
optionsArrayNoPossible values (for toolbar display)

Evaluating flags

Pass the Astro global to the flag function in your page frontmatter:

---
// src/pages/index.astro
import { newCheckout, heroVariant } from '../flags';

const isNewCheckout = await newCheckout(Astro);
const hero = await heroVariant(Astro);
---

{isNewCheckout && <NewCheckoutBanner />}
<Hero variant={hero} />

Evaluation priority

Flags are resolved in this order:

  1. Override cookie — dev overrides from the toolbar (highest priority)
  2. Flagify SDK — evaluated via @flagify/node with local caching
  3. Default value — the default from defineFlag()

Dev toolbar

In development mode, the Flagify toolbar app appears in the Astro Dev Toolbar. It provides a JSON editor where you can set flag overrides for local testing.

Overrides are stored in a flagify-overrides cookie and persist across page navigations. Click Save & Reload to apply changes, or Clear All to remove all overrides.

{
  "new-checkout-flow": true,
  "hero-variant": "variant-a"
}

Vercel Flags SDK adapter

For projects also using the Flags SDK, @flagify/astro provides a compatible adapter:

import { createFlagifyAdapter } from '@flagify/astro/adapter';
import { flag } from 'flags';

const { adapter } = createFlagifyAdapter();

export const newCheckout = flag({
  key: 'new-checkout-flow',
  adapter: adapter('new-checkout-flow'),
  defaultValue: false,
});

Adapter with custom origin

const { adapter } = createFlagifyAdapter({
  origin: 'https://your-flagify-instance.com',
});

The adapter supports both simple evaluation (getValue) and targeted evaluation with user context (evaluate).

TypeScript

Add type safety for context.locals in your Astro project:

// src/env.d.ts
/// <reference types="astro/client" />

declare namespace App {
  interface Locals {
    flagifyOverrides: Record<string, unknown>;
  }
}

Exported types

import type {
  FlagifyAstroOptions,
  FlagDefinition,
  FlagifyLocals,
  FlagEvaluator,
} from '@flagify/astro';

SSG limitations

In static builds (SSG), flags are evaluated at build time without user context. This works for:

  • Kill switches
  • Global feature rollouts
  • Percentage-based rollouts (without user targeting)

For user-targeted evaluation, use SSR mode.

Using with React islands

For client-side React components (Astro islands), use @flagify/react directly:

---
// src/pages/index.astro
import { newCheckout } from '../flags';
import InteractiveWidget from '../components/InteractiveWidget';

const isNewCheckout = await newCheckout(Astro);
---

<!-- Server-side flag evaluation -->
{isNewCheckout && <InteractiveWidget client:load />}