← All @molecule/* packages · App templates
@molecule/api-resource-feature-flagAPI resource · resource-feature-flag · API (Node) · v1.0.1 · Apache-2.0
Feature flags + targeting rules CRUD
npm install @molecule/api-resource-feature-flag@molecule/api-resource-feature-flag is an API resource: the routes, validation and storage for resource-feature-flag, built on the database and auth cores so it runs on whichever providers your app has bonded.
import { createFeatureFlagRouter } from '@molecule/api-resource-feature-flag'
app.use('/flags', createFeatureFlagRouter())Works with: @molecule/api-bonds-default-express, @molecule/api-database, @molecule/api-i18n, @molecule/api-middleware-validation
Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
@molecule/api-resource-feature-flag — feature-flag CRUD + targeting
rules + environment-scoped rollout state.
Extracted from the feature-flag-manager flagship. Flags carry a
key (e.g. new-checkout-flow), a flag_type (boolean / multivariate
/ string / number), an is_enabled master switch, a rollout_percentage
(0-100), and a state (on / off / killed / scheduled). Targeting rules
attach to a flag and are evaluated in priority order.
import { createFeatureFlagRouter } from '@molecule/api-resource-feature-flag'
app.use('/flags', createFeatureFlagRouter())
import { listFlagsForUser, createFlagForUser } from '@molecule/api-resource-feature-flag'
const flag = await createFlagForUser(userId, {
key: 'new-checkout-flow',
name: 'New checkout flow',
flag_type: 'boolean',
rollout_percentage: 5,
})
resource
npm install @molecule/api-resource-feature-flag @molecule/api-bonds-default-express @molecule/api-database @molecule/api-i18n @molecule/api-middleware-validation express zod
npm install -D @types/express
FeatureFlagRowDatabase row shape for a feature flag definition.
interface FeatureFlagRow {
id: string
user_id: string
project_id: string | null
key: string
name: string
description: string | null
flag_type: FlagType
default_value: unknown
rollout_percentage: number
is_enabled: boolean
state: FlagState
environment: string
stale_days: number
created_at: string | Date
updated_at: string | Date
}
FeatureFlagTargetingRuleRowDatabase row shape for a targeting rule that overrides a flag's value for matching users.
interface FeatureFlagTargetingRuleRow {
id: string
flag_id: string
attribute: string
operator: string
value: unknown
serve_value: unknown
priority: number
description: string | null
created_at: string | Date
}
FlagStateLifecycle state of a feature flag (active, disabled, killed, or time-gated).
type FlagState = 'on' | 'off' | 'killed' | 'scheduled'
FlagTypeDiscriminates the value type carried by a feature flag.
type FlagType = 'boolean' | 'multivariate' | 'string' | 'number'
addRuleToFlag(flagId, userId, data)Appends a new targeting rule to a flag owned by the user and returns the persisted rule row.
function addRuleToFlag(
flagId: string,
userId: string,
data: {
attribute: string
operator: string
value?: unknown
serve_value?: unknown
priority?: number
description?: string
},
): Promise<FeatureFlagTargetingRuleRow | null>
createFeatureFlagRouter()Creates and returns an Express Router with all feature-flag and targeting-rule endpoints.
function createFeatureFlagRouter(): Router
createFlagForUser(userId, data)Creates a new feature flag owned by the given user and returns the persisted row.
function createFlagForUser(
userId: string,
data: {
project_id?: string
key: string
name: string
description?: string
flag_type?: FlagType
default_value?: unknown
rollout_percentage?: number
is_enabled?: boolean
environment?: string
stale_days?: number
},
): Promise<FeatureFlagRow>
deleteFlagForUser(flagId, userId)Deletes a feature flag owned by the user, returning true on success or false if not found.
function deleteFlagForUser(flagId: string, userId: string): Promise<boolean>
deleteRule(ruleId, flagId, userId)Deletes a targeting rule from a flag owned by the user, returning true on success or false if not found.
function deleteRule(ruleId: string, flagId: string, userId: string): Promise<boolean>
getFlagForUser(flagId, userId)Fetches a single feature flag by ID, returning null if it does not exist or is not owned by the user.
function getFlagForUser(flagId: string, userId: string): Promise<FeatureFlagRow | null>
listFlagsForUser(userId, opts?)Returns a paginated list of feature flags owned by the given user, with optional project/environment/state filters.
function listFlagsForUser(
userId: string,
opts?: {
page?: number
limit?: number
project_id?: string
environment?: string
state?: FlagState
},
): Promise<{ data: FeatureFlagRow[]; total: number; page: number; limit: number }>
listRulesForFlag(flagId, userId)Returns all targeting rules for a flag in priority order, or null if the flag is not found or not owned by the user.
function listRulesForFlag(
flagId: string,
userId: string,
): Promise<FeatureFlagTargetingRuleRow[] | null>
updateFlagForUser(flagId, userId, patch)Applies a partial patch to a feature flag owned by the user and returns the updated row, or null if not found.
function updateFlagForUser(
flagId: string,
userId: string,
patch: Partial<{
name: string
description: string
default_value: unknown
rollout_percentage: number
is_enabled: boolean
state: FlagState
environment: string
stale_days: number
}>,
): Promise<FeatureFlagRow | null>
FLAG_STATESAllowed lifecycle states for a feature flag.
const FLAG_STATES: readonly ['on', 'off', 'killed', 'scheduled']
FLAG_TYPESAllowed value types for a feature flag.
const FLAG_TYPES: readonly ['boolean', 'multivariate', 'string', 'number']
flagCreateSchemaZod schema for validating a feature flag creation payload.
const flagCreateSchema: z.ZodObject<
{
project_id: z.ZodOptional<z.ZodString>
key: z.ZodString
name: z.ZodString
description: z.ZodOptional<z.ZodString>
flag_type: z.ZodOptional<
z.ZodEnum<{
string: 'string'
number: 'number'
boolean: 'boolean'
multivariate: 'multivariate'
}>
>
default_value: z.ZodOptional<z.ZodUnknown>
rollout_percentage: z.ZodOptional<z.ZodNumber>
is_enabled: z.ZodOptional<z.ZodBoolean>
environment: z.ZodOptional<z.ZodString>
stale_days: z.ZodOptional<z.ZodNumber>
},
z.core.$strip
>
flagListQuerySchemaZod schema for validating feature flag list query parameters.
const flagListQuerySchema: z.ZodObject<
{
page: z.ZodDefault<z.ZodCoercedNumber<unknown>>
limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>
project_id: z.ZodOptional<z.ZodString>
environment: z.ZodOptional<z.ZodString>
state: z.ZodOptional<
z.ZodEnum<{ on: 'on'; off: 'off'; killed: 'killed'; scheduled: 'scheduled' }>
>
},
z.core.$strip
>
flagUpdateSchemaZod schema for validating a feature flag update payload.
const flagUpdateSchema: z.ZodObject<
{
name: z.ZodOptional<z.ZodString>
description: z.ZodOptional<z.ZodString>
default_value: z.ZodOptional<z.ZodUnknown>
rollout_percentage: z.ZodOptional<z.ZodNumber>
is_enabled: z.ZodOptional<z.ZodBoolean>
state: z.ZodOptional<
z.ZodEnum<{ on: 'on'; off: 'off'; killed: 'killed'; scheduled: 'scheduled' }>
>
environment: z.ZodOptional<z.ZodString>
stale_days: z.ZodOptional<z.ZodNumber>
},
z.core.$strip
>
ruleSchemaZod schema for validating a targeting rule on a feature flag.
const ruleSchema: z.ZodObject<
{
attribute: z.ZodString
operator: z.ZodString
value: z.ZodOptional<z.ZodUnknown>
serve_value: z.ZodOptional<z.ZodUnknown>
priority: z.ZodOptional<z.ZodNumber>
description: z.ZodOptional<z.ZodString>
},
z.core.$strip
>
Peer dependencies:
@molecule/api-bonds-default-express ^1.0.1@molecule/api-database ^1.0.1@molecule/api-i18n ^1.0.1@molecule/api-middleware-validation ^1.0.1express ^5.0.0zod ^4.0.0@molecule/api-bonds-default-express@molecule/api-database@molecule/api-i18n@molecule/api-middleware-validationexpresszodTables: src/__setup__/feature_flags.sql creates feature_flags +
feature_flag_targeting_rules. An mlcl-scaffolded API replays
__setup__/*.sql automatically on migrate; anywhere else run it once —
nothing at runtime creates the tables.
Flags are OWNER-SCOPED rows, not app-global config: every service function
is …ForUser(userId, …) and the router reads the caller from
res.locals.session (mount it behind your global auth middleware — without
a session every request 401s). One user's flags are invisible to another;
for team-/app-wide flags, evaluate against a shared owning account or wrap
the service with your own scoping.
This package STORES flags + targeting rules; it does NOT evaluate them.
There is no /evaluate endpoint or client SDK — resolve a flag for an end
user in your app code: fetch the flag + rules, apply rules in priority
order, and honor is_enabled, state, and rollout_percentage.