← All @molecule/* packages · App templates

@molecule/api-resource-feature-flag

API resource · resource-feature-flag · API (Node) · v1.0.1 · Apache-2.0

Feature flags + targeting rules CRUD

npm install @molecule/api-resource-feature-flag

npm · Source on GitHub

How it works

@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

Reference

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.ts JSDoc, 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.

Quick Start

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,
})

Type

resource

Installation

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

API

Interfaces

FeatureFlagRow

Database 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
}

FeatureFlagTargetingRuleRow

Database 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
}

Types

FlagState

Lifecycle state of a feature flag (active, disabled, killed, or time-gated).

type FlagState = 'on' | 'off' | 'killed' | 'scheduled'

FlagType

Discriminates the value type carried by a feature flag.

type FlagType = 'boolean' | 'multivariate' | 'string' | 'number'

Functions

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>

Constants

FLAG_STATES

Allowed lifecycle states for a feature flag.

const FLAG_STATES: readonly ['on', 'off', 'killed', 'scheduled']

FLAG_TYPES

Allowed value types for a feature flag.

const FLAG_TYPES: readonly ['boolean', 'multivariate', 'string', 'number']

flagCreateSchema

Zod 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
>

flagListQuerySchema

Zod 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
>

flagUpdateSchema

Zod 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
>

ruleSchema

Zod 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
>

Injection Notes

Requirements

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.1
  • express ^5.0.0
  • zod ^4.0.0

Runtime Dependencies

  • @molecule/api-bonds-default-express
  • @molecule/api-database
  • @molecule/api-i18n
  • @molecule/api-middleware-validation
  • express
  • zod

Tables: 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.