GitLab Feature Flags

Master GitLab Feature Flags: learn how to roll out features safely, ship experiments, and automate progressive delivery with GitLab's built-in flag management platform.

Table of Contents

1. What Are GitLab Feature Flags?

GitLab Feature Flags are runtime switches that let you enable or disable application functionality without redeploying code. GitLab's built-in service acts as a centralized control plane for progressive delivery, experimentation, and controlled rollouts across environments.

Feature flags wrap new code paths or risky behavior with conditional logic. Teams merge code to production but keep it dark until they're ready to expose it, significantly reducing release risk.

2. Why Use Feature Flags?

  • Safe deploys: decouple deployment from release, allowing instant rollback by toggling the flag.
  • Progressive delivery: release gradually to user cohorts, regions, or environments.
  • Experimentation: A/B test experiences using percentage rollouts.
  • Ops coordination: sync feature availability with marketing launches or maintenance windows.
  • Chaos testing: quickly disable unstable integrations to protect SLAs.
  • Compliance: audit who changed flag states and when, directly in GitLab.

3. Architecture Overview

GitLab's feature flag service uses server-side evaluation backed by a Redis cache and REST API. Applications query the service on startup (or poll periodically) to download flag definitions and strategies.

3.1 High-Level Flow

graph LR subgraph "GitLab UI/API" A[Product Manager] --> B[Create Feature Flag] B --> C[Define Strategy] C --> D[Assign Environments] end subgraph "Flag Service" D --> E[Flag Config Store] E --> F[Evaluation Engine] F --> G[Redis Cache] end subgraph "Application Runtime" H[App Instance] -->|poll/evaluate| F F -->|decision| H end H --> I[Metrics & Logs] I --> A style A fill:#e1f5ff,stroke:#1f78d1,stroke-width:2px style E fill:#fff4e1,stroke:#f57c00,stroke-width:2px style H fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px

This architecture keeps evaluation close to the application while centralizing control, auditing, and automation in GitLab.

4. Core Components

Key building blocks when working with GitLab feature flags:

4.1 Feature Configuration

A flag definition includes a human-readable name, description, boolean default, and a set of environments. You can scope flags to projects or groups and reuse patterns via templates.

4.2 Rollout Strategies

GitLab supports multiple strategies such as All Users, Percentage Rollout, User IDs, and Advanced Group rules. Strategies are evaluated top-down, making it easy to combine gradual rollout with explicit allow/deny lists.

4.3 Environments

Flags can be enabled per environment (development, staging, production). GitLab automatically mirrors your Environments definitions, ensuring deployments and flag states stay in sync.

4.4 Audit & Analytics

Every toggle is recorded in GitLab's audit log. You can integrate with metrics vendors or GitLab Observability to correlate flag changes with error budgets, latency, or user behavior.

5. Project Setup

Feature flags live under Deployments → Feature Flags in each GitLab project. You'll define flags in the UI or via API and evaluate them from your application using the GitLab Feature Flag SDK.

5.1 Enable Feature Flags

  1. Navigate to your project in GitLab.
  2. Go to Deployments → Feature Flags.
  3. Click New feature flag, provide name and description.
  4. Set default state and environment-specific strategies.

5.2 Spring Boot Dependency Setup

Add the GitLab Feature Flags client starter (community-supported) to your build so the client and auto-refresh scheduler are available in the Spring context.

// build.gradle
dependencies {
    implementation "com.gitlab.featureflags:client-spring-boot-starter:1.2.0"
}
<dependency>
    <groupId>com.gitlab.featureflags</groupId>
    <artifactId>client-spring-boot-starter</artifactId>
    <version>1.2.0</version>
</dependency>

The starter provides configuration properties, auto-refresh scheduling, and a type-safe GitlabFeatureFlagClient bean that your services can inject.

6. Configuration

Applications authenticate via personal access tokens or project access tokens. You configure the client with your GitLab instance base URL and token.

6.1 Spring Boot Configuration

# application.yml
gitlab:
  url: https://gitlab.example.com
  project-id: 123
  token: ${GITLAB_FF_TOKEN}
  environment: ${SPRING_PROFILES_ACTIVE:production}
  refresh-interval: 30s

Properties define how the client talks to your GitLab instance, which project owns the flags, and how frequently the local cache refreshes.

6.2 Client Bean (Spring Boot)

@Bean
public GitlabFeatureFlagClient gitlabFeatureFlagClient(
        @Value("${gitlab.url}") String gitlabUrl,
        @Value("${gitlab.project-id}") Integer projectId,
        @Value("${gitlab.token}") String token,
        Environment environment) {
    return GitlabFeatureFlagClient.builder()
        .gitlabUrl(gitlabUrl)
        .projectId(projectId)
        .token(token)
        .environment(environment.getActiveProfiles()[0])
        .build();
}

Clients typically cache flag states locally and refresh every 30 seconds (configurable).

7. Real-World Examples

7.1 Spring Boot Progressive Delivery

Wire GitLab feature flags into a Spring Boot service to gradually roll out a feature to paying customers while keeping it disabled for everyone else.

@Configuration
public class FeatureFlagConfig {

    @Bean
    GitlabFeatureFlagClient gitlabFeatureFlagClient(GitlabProperties props) {
        return GitlabFeatureFlagClient.builder()
            .gitlabUrl(props.url())
            .projectId(props.projectId())
            .token(props.token())
            .environment(props.environment())
            .refreshInterval(Duration.ofSeconds(30))
            .build();
    }
}

@Service
public class ProgressiveDeliveryService {

    private final GitlabFeatureFlagClient flags;

    public ProgressiveDeliveryService(GitlabFeatureFlagClient flags) {
        this.flags = flags;
    }

    public String getNavigationVariant(Customer customer) {
        boolean enabled = flags.isEnabled("new_navbar", customer.id());
        return enabled && customer.plan().equals("PRO")
            ? "new-navigation"
            : "classic-navigation";
    }
}

@RestController
@RequestMapping("/ui")
public class NavigationController {

    private final ProgressiveDeliveryService service;

    public NavigationController(ProgressiveDeliveryService service) {
        this.service = service;
    }

    @GetMapping("/navigation")
    public ResponseEntity<NavigationResponse> navigation(@AuthenticationPrincipal Customer customer) {
        String variant = service.getNavigationVariant(customer);
        return ResponseEntity.ok(new NavigationResponse(variant));
    }

    public record NavigationResponse(String variant) {}
}

7.2 Backend Kill Switch

@RestController
public class PaymentsController {
    private final GitlabFeatureFlagClient flags;

    public PaymentsController(GitlabFeatureFlagClient flags) {
        this.flags = flags;
    }

    @PostMapping("/payments")
    public ResponseEntity<?> charge(@RequestBody PaymentRequest request) {
        if (!flags.isEnabled("payments_v2", request.customerId())) {
            return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE)
                .body("Payments temporarily disabled");
        }
        return paymentService.charge(request);
    }
}

7.3 GitLab CI Toggle

Use the API within CI/CD pipelines to flip a flag after a successful deployment:

feature_toggle:
  stage: deploy
  script:
    - |
      curl --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
        --data "active=true" \
        "https://gitlab.com/api/v4/projects/${CI_PROJECT_ID}/feature_flags/new_navbar"
  when: manual
  environment: production

8. Best Practices

  • Name carefully: use consistent prefixes (e.g., checkout_) to keep flags searchable.
  • Document intent: include links to issues, epics, or experiments directly in the description.
  • Set expiry dates: schedule cleanup tasks so flags do not accumulate technical debt.
  • Automate toggles: combine with GitLab Deployments or incident automations.
  • Observe impact: wire flag state to metrics (errors, conversions) to catch regressions fast.
  • Limit scope: avoid wrapping entire applications; keep flag conditions close to the smallest affected component.

9. Testing Feature Flags

Treat flag states as part of your test matrix. GitLab clients expose APIs you can stub or override in tests.

9.1 Unit Testing

@Test
void rendersNewNavbarWhenFlagEnabled() {
    when(flags.isEnabled("new_navbar", "user-1")).thenReturn(true);
    assertTrue(component.shouldRenderNewNavbar("user-1"));
}

9.2 Integration Testing

Use GitLab's Test Environment feature to create ephemeral environments with known flag states. Seed flags through the API in your test jobs before running end-to-end suites.

10. Advanced Concepts

10.1 Percentage Rollouts

Deterministic hashing ensures the same user ID consistently receives the same variation. Adjust the percentage to expand coverage without shifting existing cohorts.

10.2 Segmentation

Combine User IDs, IP ranges, or Custom contexts (e.g., subscription tiers) for precise control. GitLab evaluates the first matching rule, so order rules from most specific to least specific.

10.3 Multi-Project Flags

Create group-level feature flag templates for cross-project consistency. Templates standardize naming, strategy defaults, and documentation.

10.4 Cleanup Automation

Use the /feature_flags/:id API to archive flags after the code paths are fully rolled out. Pair with Danger or custom linting to alert when a flag exists longer than its expiry date.

11. Production Considerations

  • Latency: cache flag evaluations in-memory and refresh asynchronously to avoid blocking requests.
  • Fail-open vs fail-closed: decide what happens if the flag service is unreachable; most teams prefer defaults that keep core functionality available.
  • Secrets: store API tokens in GitLab CI/CD variables or secret managers; rotate regularly.
  • Monitoring: alert when a flag toggles outside approved change windows.
  • Cost: each flag adds complexity—budget cleanup time on your roadmap.

12. Conclusion

GitLab Feature Flags bring progressive delivery, experimentation, and operational safety to the same platform you already use for source control and CI/CD. By codifying rollouts, tying toggles to issues and pipelines, and instrumenting their impact, teams can ship faster with less risk.

Start with a single kill switch, then evolve toward automated percentage rollouts, experiment tracking, and cross-project governance. Explore the GitLab Feature Flags documentation for SDK references and advanced configuration tips.

Post a Comment

0 Comments