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
| Option | Type | Required | Description |
|---|---|---|---|
key | string | Yes | The flag key (kebab-case) |
description | string | No | Human-readable description |
default | T | Yes | Fallback value when the flag doesn’t exist |
options | Array | No | Possible 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:
- Override cookie — dev overrides from the toolbar (highest priority)
- Flagify SDK — evaluated via
@flagify/nodewith local caching - Default value — the
defaultfromdefineFlag()
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 with no per-visitor user context. Since @flagify/astro v1.1.0, the build-time sync runs the targeting engine against the anonymous context, so these work out of the box and reflect the real rule results (not the raw defaultValue):
- Kill switches
- Global catch-all targeting rules
- Percentage-based rollouts (bucketing is deterministic per flag)
Rules that target by user attributes (segments, conditions on role, plan, email, custom attrs, etc.) can’t be evaluated at build time and will miss — for those, use SSR mode and pass the request user to flagify.evaluate(key, user) per request.
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 />}