> ## Documentation Index
> Fetch the complete documentation index at: https://docs.flagkit.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Flags as Code

> Define feature flags as TypeScript code, not runtime configuration

## Philosophy

FlagKit treats feature flags as **first-class TypeScript constructs** rather than runtime configuration. This means your flags are:

* **Type-checked** at compile time
* **Version-controlled** with Git
* **Reviewed** through pull requests
* **Deployed** with your application code

## Traditional vs. FlagKit Approach

<CodeGroup>
  ```typescript Traditional Approach theme={null}
  // Runtime string literals - prone to typos
  const isEnabled = featureFlags.get('new_checkout'); // Typo: should be 'newCheckout'

  // No type safety
  const value: any = featureFlags.get('theme'); // Could be anything!

  // No autocomplete
  featureFlags.get('...') // What flags exist?

  ```

  ```typescript FlagKit Approach theme={null}
  // Type-safe with autocomplete
  import { flags } from './.flagkit/generated/client';

  const isEnabled = flags.get('newCheckout'); // ✅ Autocomplete!
  //                          ^
  //                          │
  //                          └── TypeScript knows all available flags

  // Type-checked values
  const theme: 'light' | 'dark' = flags.get('theme'); // ✅ Type enforced!
  ```
</CodeGroup>

## Defining Flags

Flags are defined in `flags.config.ts` using the FlagKit schema:

```typescript flags.config.ts theme={null}
import { defineFlags, flag } from "@flagkit-io/core";

export const flags = defineFlags({
  // Boolean flag
  newCheckout: flag
    .boolean()
    .description("Enable new checkout flow")
    .default(false)
    .tags(["payments", "ui"]),

  // String flag with validation
  apiEndpoint: flag
    .string()
    .description("API base URL")
    .default("https://api.production.com")
    .pattern(/^https:\/\//), // Must be HTTPS

  // Number flag with constraints
  maxRetries: flag
    .number()
    .description("Maximum retry attempts")
    .min(0)
    .max(10)
    .default(3),

  // Enum flag
  theme: flag
    .enum(["light", "dark", "auto"])
    .description("UI theme")
    .default("auto"),
});
```

## Code Generation

Running `flagkit generate` produces:

<CodeGroup>
  ```typescript .flagkit/generated/types.ts theme={null}
  export type FlagName = 'newCheckout' | 'apiEndpoint' | 'maxRetries' | 'theme';

  export type FlagValues = {
    newCheckout: boolean;
    apiEndpoint: string;
    maxRetries: number;
    theme: 'light' | 'dark' | 'auto';
  };

  export type FlagContext = {
    userId?: string;
    rolloutPercent?: number;
    environment?: string;
    [key: string]: any;
  };
  ```

  ```typescript .flagkit/generated/client.ts theme={null}
  import { evaluate } from "@flagkit-io/core";
  import decisionTree from "./decision-tree.json";

  export const flags = {
    get<K extends FlagName>(name: K, context?: FlagContext): FlagValues[K] {
      return evaluate(name, context, decisionTree);
    },
  };
  ```
</CodeGroup>

## Benefits

<CardGroup cols={2}>
  <Card title="Type Safety" icon="shield-check">
    Catch errors at compile time, not runtime
  </Card>

  <Card title="Autocomplete" icon="sparkles">
    IDE knows all available flags and their types
  </Card>

  <Card title="Refactoring" icon="code-merge">
    Rename flags safely across your codebase
  </Card>

  <Card title="Documentation" icon="book">
    Flags self-document with descriptions and types
  </Card>
</CardGroup>

## Git Workflow

Because flags are code, they follow your normal Git workflow:

```bash theme={null}
# 1. Create feature branch
git checkout -b feature/new-checkout

# 2. Add flag
# Edit flags.config.ts

# 3. Generate types
flagkit generate

# 4. Implement feature using flag
# Edit your application code

# 5. Commit everything together
git add flags.config.ts src/
git commit -m "feat: add new checkout with flag"

# 6. Open PR for review
git push origin feature/new-checkout
```

## Version Control

Flag definitions are **committed to Git**, but generated code typically is not:

```gitignore .gitignore theme={null}
# Don't commit generated code (regenerated on each build)
.flagkit/generated/

# Do commit flag definitions
# flags.config.ts
```

<Tip>
  In CI/CD, run `flagkit generate` as part of your build process to ensure
  generated code is always fresh.
</Tip>

## Schema Validation

FlagKit validates your flag definitions at generation time:

```typescript flags.config.ts theme={null}
export const flags = defineFlags({
  // ❌ Error: Invalid default value
  theme: flag.enum(["light", "dark"]).default("auto"), // 'auto' not in enum!

  // ❌ Error: Invalid number range
  pageSize: flag
    .number()
    .min(10)
    .max(5) // Max can't be less than min!
    .default(20),

  // ❌ Error: Default doesn't match pattern
  email: flag
    .string()
    .pattern(/^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/)
    .default("not-an-email"),
});
```

## Next Steps

<Card title="Local Evaluation" icon="bolt" href="/core-concepts/local-evaluation">
  Learn how FlagKit evaluates flags without API calls
</Card>
