Skip to main content

Getting Started

This guide takes you from zero to your first SDK-powered flag evaluation — with targeting rules, segments, and a real audit trail.

Prerequisites: Docker, Git, and either Node 20+ (for the JS path) or Go 1.24+ (for the Go path). Nothing else.

By the end you will have:

  • A flag evaluating via the JS or Go SDK
  • A targeting rule that enables the flag for a specific user segment
  • An audit trail showing exactly which rule matched

1. Start the stack

Clone the repository and bring up the full stack with Docker Compose:

git clone https://github.com/The127/cuttlegate.git
cd cuttlegate
docker compose up --build
First run takes 2–5 minutes

On a cold Docker cache, docker compose up --build pulls several images before starting. This is normal. Wait for the log line server listening on :8080 before proceeding.

This starts six services:

ServicePortPurpose
db5433PostgreSQL database (Cuttlegate)
migrateApplies database migrations, then exits
server8080Cuttlegate API + embedded web UI
keyline-dbPostgreSQL database (identity provider)
keyline5002Local OIDC identity provider
keyline-ui5003Identity provider admin UI

Wait until you see server listening on :8080 in the compose output before continuing.

2. Log in

Open http://localhost:8080 in your browser. Click Log in and authenticate with the pre-configured test user:

FieldValue
Emailadmin@cuttlegate.local
Passwordpassword

After login you are redirected to the Cuttlegate dashboard. The pre-seeded admin account has admin access.

3. Create a project

In the dashboard, click New Project. Give it a name (e.g. "My App") and a slug (e.g. my-app). The slug is permanent — you will use it in API calls and SDK configuration.

4. Create an environment

Inside your project, navigate to Environments and create one called production with the slug production. Environments let you toggle flags independently per deployment stage.

5. Create a feature flag

Navigate to Flags within your project and create a new flag:

  • Key: dark-mode (this is the identifier you use in code)
  • Type: Boolean

The flag is created in the disabled state. Toggle it on for the production environment before continuing.

6. Create an API key

Navigate to the production environment, then open API Keys. Click Create API Key.

Copy the key immediately — it is shown only once. It looks like cg_....

API keys are scoped to a single project + environment pair and are used by the SDK to authenticate evaluation requests.

7. Create a segment and add members

Segments are named groups of users. Membership is explicit — you add user IDs to a segment, and targeting rules match on whether the evaluating user is in that list.

Navigate to Segments within your project and click New Segment:

  • Name: Pro users
  • Slug: pro-users

Save the segment. Now add the demo user to it. In the UI, open the pro-users segment and click Add Member, entering user-1.

Any SDK call that evaluates with user_id: "user-1" will now match the pro-users segment.

8. Add a targeting rule

Navigate back to the dark-mode flag and open the production environment settings. Click Add Rule:

  • Name: Pro users get dark mode
  • Operator: in_segment
  • Value: pro-users
  • Serve variant: true (Enabled)

Save the rule. The flag now behaves as follows:

  • Users in the pro-users segment (user-1) → enabled, reason rule_match
  • All other users → enabled, reason default (the flag is on; no rule matched their context)
Fallthrough behaviour

When a flag is toggled on and no targeting rule matches a user, the flag falls through to its default state — enabled for everyone. Rules narrow the audience; they do not gate it unless the flag's default is off.

9. Evaluate the flag with SDK

Choose the SDK for your language. Both examples use the cg_... key from step 6 — the field name differs between SDKs (see callout below).

JavaScript / TypeScript

Install the SDK:

npm install @cuttlegate/sdk

Create demo.mjs:

import { createClient } from '@cuttlegate/sdk';

const cg = createClient({
baseUrl: 'http://localhost:8080',
token: 'cg_YOUR_API_KEY_HERE', // paste the key from step 6
project: 'my-app',
environment: 'production',
});

// Evaluate as a segment member — matches the targeting rule
const proResult = await cg.evaluateFlag('dark-mode', {
user_id: 'user-1',
attributes: { plan: 'pro' },
});
console.log('pro user enabled:', proResult.enabled); // true
console.log('reason:', proResult.reason); // rule_match

// Evaluate as a free user — no rule match, falls through to default
const freeResult = await cg.evaluateFlag('dark-mode', {
user_id: 'user-2',
attributes: { plan: 'free' },
});
console.log('free user enabled:', freeResult.enabled); // true
console.log('reason:', freeResult.reason); // default

Run it:

node demo.mjs

Go

Install the SDK:

go get github.com/The127/cuttlegate/sdk/go

Create main.go:

package main

import (
"context"
"fmt"
"log"

cuttlegate "github.com/The127/cuttlegate/sdk/go"
)

func main() {
client, err := cuttlegate.NewClient(cuttlegate.Config{
BaseURL: "http://localhost:8080",
ServiceToken: "cg_YOUR_API_KEY_HERE", // paste the key from step 6
Project: "my-app",
Environment: "production",
})
if err != nil {
log.Fatal(err)
}

ctx := context.Background()

// Bool is the simplest way to evaluate a boolean flag
enabled, err := client.Bool(ctx, "dark-mode", cuttlegate.EvalContext{
UserID: "user-1",
Attributes: map[string]any{"plan": "pro"},
})
if err != nil {
log.Fatal(err)
}
fmt.Println("dark-mode enabled (pro user):", enabled) // true

// Evaluate returns the full result including the reason
result, err := client.Evaluate(ctx, "dark-mode", cuttlegate.EvalContext{
UserID: "user-1",
Attributes: map[string]any{"plan": "pro"},
})
if err != nil {
log.Fatal(err)
}
fmt.Println("reason:", result.Reason) // rule_match
}

Run it:

go run main.go
Same API key, different field name

The cg_... key from step 6 is the same credential in both SDKs. The JS SDK passes it as token; the Go SDK passes it as ServiceToken. If you copy a value from one SDK example into the other, the field name is what changes — not the key itself.

10. View the audit trail

Go back to the Cuttlegate UI. Navigate to the dark-mode flag and open Audit Trail.

You will see the evaluation events from your SDK calls. Each entry shows:

  • The flag key and environment
  • Whether the flag was enabled
  • The reason — one of:
    • rule_match — a targeting rule matched the user
    • default — no rule matched; the flag fell through to its default state
    • segment_deleted — a targeting rule referenced a segment that no longer exists; the rule was skipped and evaluation fell through to the next matching rule or the flag's default
  • The matched rule name — visible for rule_match evaluations; not present for default or segment_deleted

This makes it straightforward to verify that your rules are matching the right users in production.

Stale rule configuration

If you see segment_deleted in the audit trail, a targeting rule is referencing a segment that no longer exists. The evaluation continued — falling through to the next rule or the flag's default — but the stale rule is doing nothing. Navigate to the flag's rules and update or remove any rule that references the deleted segment.

What's next

  • Real-time updates — the SDK supports SSE streaming for instant flag changes without polling. See JS SDK or Go SDK.
  • Testing — use @cuttlegate/sdk/testing (JS) or the cuttlegatetesting package (Go) to mock flags in your test suite without a running server.
  • Multiple environments — create staging and development environments with separate API keys and independent flag states.
  • Percentage rollouts — gradually roll out a flag to a percentage of users without defining a segment.

SDK reference

  • JavaScript / TypeScript SDK — full API, bulk evaluation, SSE streaming, testing utilities
  • Go SDKBool, Evaluate, EvaluateAll, Subscribe, typed errors, testing mock