๐Ÿš€ ngx-feature-proxy

October 16, 2025 ยท View on GitHub

Icon

npm version npm downloads npm bundle size npm type definitions

GitHub issues GitHub stars GitHub Workflow Status License

๐ŸŽฏ Type-safe Angular Feature Flag Library with Unleash Integration

Reactive programming โ€ข Zero-configuration setup โ€ข Enterprise-ready

๐Ÿ“ฆ NPM โ€ข ๐Ÿš€ Quick Start โ€ข ๐Ÿ’ฌ Discussions

Demo


๐Ÿ“‘ Table of Contents


๐ŸŒŸ Features

FeatureDescription
๐Ÿž Debug ToolBuilt-in debug info for easy troubleshooting
โœจ Type-SafeFull TypeScript support with strict typing
๐Ÿš€ PerformanceOptimized with caching and smart updates
๐Ÿ›ก๏ธ Route ProtectionSupport for guards to protect routes
๐ŸŽจ Template DirectivesDeclarative feature flag usage in templates
๐Ÿ”ง FlexibleSupport for complex feature flag expressions
๐ŸŒ Enterprise ReadyCan be deployed in large-scale applications

๐Ÿ“– What is Unleash?

Unleash is an open-source feature flag management platform that enables you to:

CapabilityBenefit
๐ŸŽ›๏ธ Toggle FeaturesEnable/disable features instantly without deployments
๐ŸŽฏ Targeted RolloutsGradual feature rollouts to specific user segments
๐Ÿงช A/B TestingRun experiments with different feature variants
๐Ÿ“Š AnalyticsTrack feature usage and performance metrics
๐Ÿ”’ Enterprise SecurityRole-based access control and audit logs
๐ŸŒ Multi-EnvironmentSeparate feature configurations for develop/staging/production

๐Ÿ—๏ธ Architecture

graph TB
    subgraph APP["๐Ÿ“ฑ Angular Application (Frontend)"]
        COMP["๐Ÿงฉ Components"]
        SERV["โš™๏ธ FeatureProxyService<br/>- Manage Feature Flags<br/>- Check Access"]
        DIR["โœจ FeatureProxy Directive<br/>- Show/Hide UI based on Flags"]
        GUARD["๐Ÿ” FeatureProxy Guards<br/>- Protect Routes"]
        SIGNAL["๐Ÿ”„ Signal State<br/>- Reactive Updates"]
    end

    subgraph UNLEASH["๐Ÿš€ Unleash Infrastructure"]
        PROXY["๐Ÿ“ก Unleash Proxy<br/>- HTTP/WebSocket<br/>- Real-time Updates"]
        SERVER["๐ŸŽ›๏ธ Unleash Server<br/>- Control Panel<br/>- Manage Features"]
        DB["๐Ÿ’พ PostgreSQL<br/>- Data Storage<br/>- Persistence"]
    end

    subgraph USERS["๐Ÿ‘ฅ Users"]
        ENDUSER["๐Ÿ‘ค End Users<br/>- Use Application"]
        DEVOPS["โš™๏ธ DevOps Team<br/>- Manage Flags"]
    end

    %% Application Internal Flow
    COMP -->|"use"| SERV
    COMP -->|"use"| DIR
    COMP -->|"use"| GUARD
    SERV -->|"update"| SIGNAL
    DIR -->|"check"| SERV
    GUARD -->|"verify"| SERV

    %% Communication with Unleash
    SERV <-->|"๐Ÿ“ก HTTP/WebSocket<br/>- Request Flags<br/>- Real-time Sync"| PROXY
    PROXY <-->|"๐Ÿ”„ Sync Flags<br/>- Pull Configuration"| SERVER
    SERVER <-->|"๐Ÿ’พ Read/Write<br/>- Feature Data"| DB

    %% User Interactions
    ENDUSER -->|"๐Ÿ–ฑ๏ธ Interactions<br/>- Trigger Features"| COMP
    DEVOPS -->|"โš™๏ธ Toggle<br/>- Manage Flags"| SERVER

    %% Styling
    classDef angular fill:#DD0031,stroke:#333,stroke-width:2px,color:#fff,font-size:12px
    classDef unleash fill:#7C3AED,stroke:#333,stroke-width:2px,color:#fff,font-size:12px
    classDef users fill:#059669,stroke:#333,stroke-width:2px,color:#fff,font-size:12px

    class COMP,SERV,DIR,GUARD,SIGNAL angular
    class PROXY,SERVER,DB unleash
    class ENDUSER,DEVOPS users

๐Ÿ”„ How it Works:

  1. ๐ŸŽฏ Feature Definition: DevOps team defines feature flags in Unleash Server
  2. ๐Ÿ“ก Real-time Sync: Unleash Proxy pulls configurations and serves them via HTTP/WebSocket
  3. ๐Ÿ”ง Angular Integration: ngx-feature-proxy connects to Unleash Proxy using unleash-proxy-client
  4. ๐Ÿ“Š Reactive Updates: Service uses Angular signals to provide real-time feature flag state
  5. ๐ŸŽจ Template Magic: Directives and guards automatically react to feature flag changes
  6. ๐Ÿ‘ค User Experience: End users see features toggled instantly without page refreshes

๐Ÿš€ Quick Start

๐Ÿ“ฆ Installation

# ๐Ÿš€ Install the library
npm install ngx-feature-proxy

โš™๏ธ Basic Setup

// ๐Ÿ“ src/main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { provideFeatureProxy } from 'ngx-feature-proxy';
import { AppComponent } from './app/app.component';

bootstrapApplication(AppComponent, {
  providers: [
    // ๐ŸŽฏ Configure feature proxy
    provideFeatureProxy({
      url: 'http://localhost:3000/api/proxy', // ๐ŸŒ Your Unleash proxy URL
      clientKey: 'your-client-key', // ๐Ÿ”‘ Your client key
      appName: 'my-angular-app', // ๐Ÿ“ฑ Your app name

      // ๐ŸŽ›๏ธ Optional: Advanced configuration
      context: {
        environment: 'development',
      },
      refreshInterval: 30, // โฑ๏ธ Refresh interval in seconds
      metricsInterval: 60, // ๐Ÿ“Š Metrics interval in seconds
      debug: true, // ๐Ÿž Enable debug mode
    }),
    // ... other providers
  ],
});

๐ŸŽฏ Your First Feature Flag

// ๐Ÿ“ src/app/app.component.ts
import { Component, inject } from '@angular/core';
import { FeatureProxyService } from 'ngx-feature-proxy';

@Component({
  selector: 'app-root',
  template: `
    <div class="container">
      <!-- ๐ŸŽจ Using directive -->
      <div *featureProxy="'newDashboard'">๐Ÿ†• Welcome to the new dashboard!</div>

      <!-- ๐ŸŽฏ Using directive with expression -->
      <div *featureProxy="'premiumUser && (betaAccess || adminMode)'">
        ๐Ÿš€ Access to premium beta features!
      </div>

      <!-- ๐Ÿ”ง Using service -->
      @if (isNewfeatureProxy) {
        <button (click)="tryNewFeature()">โœจ Try New Feature</button>
      }

      <!-- ๐ŸŽญ State information -->
      <div class="debug-info">
        <p>๐Ÿ”„ Ready: {{ $state().ready }}</p>
        <p>โฐ Last Update: {{ $state().lastUpdate | date: 'medium' }}</p>
      </div>
    </div>
  `,
  standalone: true,
  imports: [FeatureProxyDirective],
})
export class AppComponent {
  private featureService = inject(FeatureProxyService);

  // ๐ŸŽฏ Direct feature check
  isNewFeatureEnabled = this.featureService.isEnabled('newFeature');

  // ๐Ÿ“Š Reactive state
  $state = this.featureService.$state;

  tryNewFeature() {
    console.log('๐Ÿš€ New feature activated!');
  }
}

๐ŸŽฎ Usage Guide

๐Ÿ”ง Service Usage

The FeatureProxyService is the core of the library, providing programmatic access to feature flags:

import { Component, inject, computed, effect } from '@angular/core';
import { FeatureProxyService } from 'ngx-feature-proxy';

@Component({
  selector: 'app-feature-demo',
  template: `
    <div class="feature-demo">
      <!-- ๐Ÿ“Š Service state -->
      <div class="status-bar">
        <span
          class="status"
          [class.ready]="$state().ready"
        >
          {{ $state().ready ? '๐ŸŸข Connected' : '๐ŸŸก Connecting...' }}
        </span>
        <span class="last-update"> ๐Ÿ“… Last update: {{ $state().lastUpdate | date: 'short' }} </span>
      </div>

      <!-- ๐ŸŽฏ Feature checks -->
      <div class="features">
        <div class="feature-card">
          <h3>๐Ÿ†• Beta Features</h3>
          <p>Status: {{ betaEnabled ? 'โœ… Enabled' : 'โŒ Disabled' }}</p>
          <button
            [disabled]="!betaEnabled"
            (click)="useBetaFeature()"
          >
            Try Beta Feature
          </button>
        </div>

        <!-- ๐ŸŽญ Variant example -->
        <div
          class="feature-card"
          *ngIf="premiumVariant.enabled"
        >
          <h3>๐Ÿ’Ž Premium Feature</h3>
          <p>Variant: {{ premiumVariant.name }}</p>
          <div [style.background-color]="premiumVariant.payload.value">
            Theme: {{ premiumVariant.payload.value }}
          </div>
        </div>
      </div>
    </div>
  `,
  standalone: true,
})
export class FeatureDemoComponent {
  private featureService = inject(FeatureProxyService);

  // ๐Ÿ“Š Reactive state
  $state = this.featureService.$state;

  // ๐ŸŽฏ Simple feature check
  betaEnabled = computed(() => this.featureService.isEnabled('betaFeatures'));

  // ๐ŸŽญ Get variant with payload
  premiumVariant = computed(() => this.featureService.getVariant('premiumTheme'));

  // ๐Ÿ”„ Complex feature expression
  advancedMode = computed(() =>
    this.featureService.features('premiumUser && (betaAccess || adminMode)')
  );

  constructor() {
    // ๐Ÿ‘‚ React to impression events
    effect(() => {
      const impression = this.featureService.$impression();
      if (impression.eventType === 'isEnabled') {
        console.log('๐ŸŽฏ Feature accessed:', impression.featureName);
      }
    });
  }

  useBetaFeature() {
    console.log('๐Ÿงช Beta feature activated!');
  }

  // ๐Ÿ”„ Update user context
  async updateUserContext(userId: string) {
    await this.featureService.updateContext({ userId }).toPromise();
    console.log('๐Ÿ‘ค User context updated');
  }

  // ๐Ÿ“ก Manual refresh
  async refreshFlags() {
    await this.featureService.refresh().toPromise();
    console.log('๐Ÿ”„ Feature flags refreshed');
  }
}

๐ŸŽจ Directive Usage

The *featureEnabled directive provides declarative feature flag control in templates:

๐ŸŽฏ Simple Feature Check

<div *featureEnabled="'newDashboard'">๐Ÿ†• Welcome to the new dashboard!</div>

๐ŸŽฏ Complex Feature Check

<div *featureEnabled="'premiumUser && (betaAccess || adminMode)'">
  ๐Ÿš€ Access to premium beta features!
</div>

๐Ÿ›ก๏ธ Route Guards

Protect your routes with feature flag-based guards:

import { Routes } from '@angular/router';
import { featureProxyGuard } from 'ngx-feature-proxy';

export const routes: Routes = [
  {
    path: 'dashboard',
    loadComponent: () => import('./dashboard/dashboard.component'),
    canActivate: [
      // ๐ŸŽฏ Simple feature guard
      featureProxyGuard({
        expression: 'newDashboard',
        redirectTo: '/legacy-dashboard',
      }),
    ],
  },
  {
    path: 'admin',
    loadChildren: () => import('./admin/admin.routes'),
    canActivate: [
      // ๐Ÿ›ก๏ธ Complex permission guard
      featureProxyGuard({
        expression: 'adminAccess && (betaTester || superUser)',
        redirectTo: '/not-authorized',
      }),
    ],
  },
  {
    path: 'user',
    loadComponent: () => import('./user/user.component'),
    canActivate: [
      // ๐Ÿ‘ค User-specific feature guard
      featureProxyGuard({
        condition: (service) => service.isEnabled('userFeatures') && service.getVariant('userTier').name === 'gold',
        redirectTo: '/upgrade',
      }),
    ],
  }
  {
    path: 'premium',
    loadChildren: () => import('./premium/premium.routes'),
    canActivateChild: [
      // ๐Ÿ’Ž Premium feature guard for child routes
      featureProxyGuard({
        expression: 'premiumUser && validSubscription',
        redirectTo: '/subscribe',
      }),
    ],
  },
];

๐ŸŽช Advanced Guard Patterns

// ๐Ÿ”ง Custom guard with complex logic
export const premiumGuard = featureProxyGuard({
  condition: (service) => {
    const isPremium = service.isEnabled('premiumUser');
    const isValidSubscription = service.isEnabled('validSubscription');
    const variant = service.getVariant('premiumTier');

    return isPremium && isValidSubscription && ['gold', 'platinum'].includes(variant.name);
  },
  redirectTo: '/upgrade',
});

// ๐ŸŒ Geo-based feature guard
export const geoFeatureGuard = featureProxyGuard({
  condition: (service) => {
    return service.features('featureEnabled && (region_US || region_EU)');
  },
  redirectTo: '/geo-restricted',
});

// ๐Ÿ“ฑ Device-specific guard
export const mobileFeatureGuard = featureProxyGuard({
  condition: (service) => {
    const isMobile = service.getVariant('deviceType').name === 'mobile';
    return isMobile && service.isEnabled('mobileFeatures');
  },
  redirectTo: '/desktop-only',
});

๐Ÿณ Docker Setup with Unleash

๐Ÿณ Complete Docker Compose Setup

Create a docker-compose.yml file for a complete Unleash setup:

# ๐Ÿณ docker-compose.yml
services:
  unleash:
    image: unleashorg/unleash-server:${UNLEASH_VERSION:-6}
    container_name: unleash
    restart: ${RESTART_POLICY:-unless-stopped}
    ports:
      - '4242:4242'
    networks:
      - unleash_net
    environment:
      # ๐Ÿ—„๏ธ Database configuration
      DATABASE_URL: 'postgres://postgres:${UNLEASH_DATABASE_PASSWORD:-unleash}@unleash-db/postgres'
      DATABASE_SSL: 'false'

      # ๐Ÿ“Š Logging and performance
      LOG_LEVEL: 'warn'

      # ๐Ÿ”‘ API tokens (generate secure tokens for production)
      INIT_FRONTEND_API_TOKENS: ${INIT_FRONTEND_API_TOKENS:-*:*.unleash-insecure-frontend-api-token}
      INIT_BACKEND_API_TOKENS: ${INIT_BACKEND_API_TOKENS:-*:*.unleash-insecure-api-token}

      # ๐ŸŒ Server configuration
      UNLEASH_URL: 'https://${UNLEASH_DOMAIN:-localhost:4242}'

      # ๐Ÿ‘ค Default admin credentials
      UNLEASH_DEFAULT_ADMIN_PASSWORD: ${UNLEASH_DEFAULT_ADMIN_PASSWORD:-admin123}
      UNLEASH_DEFAULT_ADMIN_USERNAME: ${UNLEASH_DEFAULT_ADMIN_USERNAME:-admin}

      # โšก Performance optimizations
      UNLEASH_PROXY_SECRETS: ${UNLEASH_PROXY_SECRETS:-some-secret}
    depends_on:
      unleash-db:
        condition: service_healthy
    healthcheck:
      test: wget --no-verbose --tries=1 --spider http://localhost:4242/health || exit 1
      interval: 1s
      timeout: 1m
      retries: 5
      start_period: 15s
    volumes:
      # ๐Ÿ“ Optional: Custom configuration
      - ./unleash-config:/opt/unleash/config:ro

  unleash-db:
    image: postgres:17-alpine
    container_name: unleash-db
    restart: ${RESTART_POLICY:-unless-stopped}
    volumes:
      - ${DATA_PATH:-./data}/unleash/postgresql/data:/var/lib/postgresql/data
    expose:
      - '5432'
    networks:
      - unleash_net
    environment:
      - POSTGRES_DB=postgres
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=${UNLEASH_DATABASE_PASSWORD:-unleash123}
    healthcheck:
      test: ['CMD', 'pg_isready', '--username=postgres', '--host=127.0.0.1', '--port=5432']
      interval: 2s
      timeout: 1m
      retries: 5
      start_period: 10s

  # ๐Ÿš€ Optional: Unleash Proxy (for better performance)
  unleash-proxy:
    image: unleashorg/unleash-proxy:latest
    container_name: unleash-proxy
    restart: ${RESTART_POLICY:-unless-stopped}
    ports:
      - '3000:3000'
    networks:
      - unleash_net
    environment:
      UNLEASH_URL: 'http://unleash:4242/api'
      UNLEASH_API_TOKEN: ${INIT_BACKEND_API_TOKENS:-*:*.unleash-insecure-api-token}
      UNLEASH_APP_NAME: 'unleash-proxy'
      UNLEASH_INSTANCE_ID: 'unleash-proxy-1'
    depends_on:
      unleash:
        condition: service_healthy

networks:
  unleash_net:
    driver: bridge

volumes:
  unleash_data:
    driver: local

Create a .env file for easy configuration:

# ๐Ÿ“ .env
# ๐Ÿณ Docker configuration
UNLEASH_VERSION=5.7
RESTART_POLICY=unless-stopped
DATA_PATH=./data

# ๐ŸŒ Domain and URLs
UNLEASH_DOMAIN=localhost:4242

# ๐Ÿ—„๏ธ Database
UNLEASH_DATABASE_PASSWORD=unleash123

# ๐Ÿ‘ค Admin credentials (CHANGE IN PRODUCTION!)
UNLEASH_DEFAULT_ADMIN_USERNAME=admin
UNLEASH_DEFAULT_ADMIN_PASSWORD=admin123

# ๐Ÿ”‘ API Tokens (GENERATE SECURE TOKENS FOR PRODUCTION!)
INIT_FRONTEND_API_TOKENS=*:development.unleash-insecure-frontend-api-token
INIT_BACKEND_API_TOKENS=*:development.unleash-insecure-api-token
UNLEASH_PROXY_SECRETS=proxy-secret-123

# ๐ŸŽฏ Optional: Context fields
UNLEASH_CONTEXT_FIELDS=userId,sessionId,environment,region

Commands to manage the Docker setup:

# ๐Ÿƒ Start the stack
docker-compose up -d

# ๐Ÿ“Š View logs
docker-compose logs -f unleash

# ๐Ÿ” Check health
docker-compose ps

# ๐Ÿ—‘๏ธ Clean up
docker-compose down -v

# ๐Ÿ“ˆ Scale proxy (for high traffic)
docker-compose up -d --scale unleash-proxy=3

๐ŸŒ Access Your Unleash

After running docker-compose up -d:


๐Ÿค Contributing

We welcome contributions! Here's how you can help:

๐Ÿ› Bug Reports

  1. ๐Ÿ” Search existing issues
  2. ๐Ÿ“ Create detailed bug report
  3. ๐Ÿท๏ธ Use appropriate labels

โœจ Feature Requests

  1. ๐Ÿ’ก Discuss in GitHub Discussions
  2. ๐Ÿ“‹ Create feature request issue
  3. ๐Ÿš€ Submit pull request

๐Ÿ› ๏ธ Development Workflow

# ๐Ÿด Fork and clone
git clone https://github.com/your-username/ngx-feature-proxy.git
cd ngx-feature-proxy

# ๐ŸŒฟ Create feature branch
git checkout -b feat/amazing-feature

# โœ… Commit changes
git commit -m "โœจ Add amazing feature"

# ๐Ÿš€ Push and create PR
git push origin feat/amazing-feature

๐Ÿ“ Commit Convention

We use Conventional Commits:

  • โœจ feat: New features
  • ๐Ÿ› fix: Bug fixes
  • ๐Ÿ“š docs: Documentation
  • ๐ŸŽจ style: Code formatting
  • โ™ป๏ธ refactor: Code restructuring
  • ๐Ÿš€ perf: Performance improvements
  • ๐Ÿšจ test: Testing
  • ๐Ÿ”ง chore: Maintenance

๐Ÿ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

MIT License

Copyright (c) 2025 Kiet Le

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

๐Ÿ™ Acknowledgments

This project wouldn't be possible without these amazing technologies:

Angular
Angular
The best Framework ever
RxJS
RxJS
Reactive Programming
Unleash
Unleash
Feature Flag Management
Docker
Docker
Containerization

๐Ÿ“ž Support

๐Ÿค Get Help & Connect

Email GitHub Issues Discussions Docker Hub

๐Ÿ“Š Project Stats

GitHub contributors GitHub last commit GitHub repo size


๐ŸŒŸ Ready to get started?

๐Ÿ“ฆ Install Now โ€ข ๐Ÿ“– View Docs โ€ข ๐Ÿ’ฌ Join Discussion


โญ If this project helped you, please consider giving it a star! โญ

Made with โค๏ธ by ZenKiet