Getting Started
Welcome to Toggl, a powerful Laravel feature flag package with a conductor-based API for enterprise applications. This guide will help you install, configure, and create your first feature flag.
Installation
Section titled “Installation”Install Toggl via Composer:
composer require cline/togglConfiguration
Section titled “Configuration”Publish the configuration file:
php artisan vendor:publish --tag=toggl-configThis creates config/toggl.php with the following structure:
return [ 'default' => env('FEATURE_FLAGS_STORE', 'database'),
'stores' => [ 'array' => [ 'driver' => 'array', ],
'database' => [ 'driver' => 'database', 'connection' => env('DB_CONNECTION', null), 'table' => 'features', ], ],
'strategies' => [ 'default' => 'boolean', 'available' => [ 'boolean' => BooleanStrategy::class, 'time_based' => TimeBasedStrategy::class, 'percentage' => PercentageStrategy::class, 'scheduled' => ScheduledStrategy::class, 'conditional' => ConditionalStrategy::class, ], ],];Driver Selection
Section titled “Driver Selection”Array Driver (in-memory)
- Best for: Testing, temporary flags, development
- Data persists only during the current request
- No database required
Database Driver (recommended for production)
- Best for: Production environments, persistent flags
- Data stored in database table
- Survives application restarts
To use the database driver, set your .env:
FEATURE_FLAGS_STORE=databaseDatabase Setup
Section titled “Database Setup”If using the database driver, publish and run the migrations:
php artisan vendor:publish --tag=toggl-migrationsphp artisan migrateThis creates a features table with the following structure:
| Column | Type | Description |
|---|---|---|
id | bigint/ulid/uuid | Primary key (configurable) |
name | string | Feature flag name |
context_type | string | Polymorphic type (e.g., App\Models\User) |
context_id | bigint/ulid/uuid | Polymorphic ID (type configurable) |
value | text | Feature value (boolean, string, array, etc.) |
strategy | string | Strategy class name (optional) |
expires_at | timestamp | Time bomb expiration (optional) |
metadata | json | Strategy-specific configuration (optional) |
The table uses polymorphic columns (context_type, context_id) to support different model types and a unique constraint on (name, context_type, context_id) to ensure each feature flag can only have one value per context.
Your First Feature Flag
Section titled “Your First Feature Flag”Let’s create a simple feature flag to enable a new dashboard for admin users.
1. Define the Feature
Section titled “1. Define the Feature”In your AppServiceProvider or a dedicated FeatureServiceProvider:
use Cline\Toggl\Toggl;
class AppServiceProvider extends ServiceProvider{ public function boot(): void { Toggl::define('new-dashboard', function ($user) { return $user?->isAdmin() ?? false; }); }}2. Check the Feature
Section titled “2. Check the Feature”In your controller:
use Cline\Toggl\Toggl;
class DashboardController extends Controller{ public function index() { if (Toggl::active('new-dashboard')) { return view('dashboard.new'); }
return view('dashboard.legacy'); }}3. Use in Blade Templates
Section titled “3. Use in Blade Templates”@feature('new-dashboard') <div class="new-dashboard"> <!-- New dashboard content --> </div>@else <div class="legacy-dashboard"> <!-- Legacy dashboard content --> </div>@endfeatureUnderstanding Contexts
Section titled “Understanding Contexts”Feature flags in Toggl are context-aware. A context represents the context in which a feature is evaluated - typically a user, team, or organization.
Default Context
Section titled “Default Context”By default, Toggl uses the currently authenticated user as the context:
// These are equivalent when a user is authenticatedToggl::active('new-dashboard');Toggl::for(auth()->user())->active('new-dashboard');Explicit Contexts
Section titled “Explicit Contexts”You can explicitly specify a context:
// Check for specific user$user = User::find(123);if (Toggl::for($user)->active('premium-features')) { // ...}
// Check for team$team = Team::find(456);if (Toggl::for($team)->active('team-analytics')) { // ...}
// String contextif (Toggl::for('admin')->active('debug-mode')) { // ...}
// Numeric contextif (Toggl::for(999)->active('special-offer')) { // ...}Custom Context Resolvers
Section titled “Custom Context Resolvers”You can customize how contexts are resolved by defining a context resolver in your service provider:
use Cline\Toggl\Toggl;
Toggl::resolveContextUsing(function ($driver) { // Return the current tenant instead of user return Tenant::current();});Feature Flag Lifecycle
Section titled “Feature Flag Lifecycle”Here’s a typical lifecycle for a feature flag:
-
Define - Create the feature with a resolver
Toggl::define('new-api', fn($user) => $user->isAdmin()); -
Test - Test with specific users or contexts
Toggl::for($betaTester)->activate('new-api'); -
Rollout - Gradually enable for more users
// Enable for 25% of usersToggl::define('new-api', fn($user) => crc32($user->id) % 100 < 25); -
Full Launch - Enable for everyone
Toggl::activateForEveryone('new-api'); -
Cleanup - Remove flag from code and database
Toggl::purge('new-api');
Common Patterns
Section titled “Common Patterns”Simple Boolean Flag
Section titled “Simple Boolean Flag”// Always onToggl::define('maintenance-mode', true);
// Always offToggl::define('beta-feature', false);User-Based Flag
Section titled “User-Based Flag”Toggl::define('premium-dashboard', function ($user) { return $user->subscription?->plan === 'premium';});Team-Based Flag
Section titled “Team-Based Flag”Toggl::define('team-analytics', function ($team) { return $team->plan === 'enterprise';});Email-Based Flag
Section titled “Email-Based Flag”Toggl::define('early-access', function ($user) { return in_array($user->email, [ 'alice@example.com', 'bob@example.com', ]);});Environment-Based Flag
Section titled “Environment-Based Flag”Toggl::define('debug-toolbar', function () { return app()->environment('local', 'staging');});Best Practices
Section titled “Best Practices”-
Naming Conventions
- Use lowercase with hyphens:
new-dashboard,premium-features - Be descriptive:
ai-chat-assistantinstead offeature-1 - Prefix by area:
api-v2-endpoints,ui-dark-mode
- Use lowercase with hyphens:
-
Organization
- Group related flags in a dedicated service provider
- Document flags in comments explaining purpose and rollout plan
- Remove flags after full rollout
-
Testing
- Always test both active and inactive states
- Use the array driver for unit tests
- Test context variations (different users, teams, etc.)
-
Performance
- Feature checks are cached during request lifecycle
- Database driver is optimized with proper indexing
- Avoid complex resolvers - keep logic simple
Next Steps
Section titled “Next Steps”Now that you have Toggl installed and understand the basics, explore more advanced features:
- Basic Usage - Learn all core operations
- Strategies - Time-based, percentage, and conditional strategies
- Time Bombs - Auto-expiring features
- Feature Groups - Manage related flags together
- Dependencies - Create feature requirements
- Variants - A/B testing with weighted distribution
- Advanced Usage - Events, custom drivers, and more