Installation
Install the engine and optional admin UI, run the migration, and wire up the context resolver.
Installation
Engine
composer require vortos/vortos-feature-flagsRun the module migration to create the flags tables:
php vortos vortos:migrateThe migration lives in Resources/migrations/ inside the package. vortos:migrate discovers and runs it automatically.
The engine self-registers via extra.vortos.package in its composer.json. No manual service registration is needed.
Wiring up the context resolver
The engine ships with an anonymous context resolver — every request is treated as an unauthenticated user with no attributes. This means percentage rollout and attribute rules will not work until you override it.
Create a resolver in your application:
use Vortos\FeatureFlags\FlagContext;
use Vortos\FeatureFlags\Resolver\FlagContextResolverInterface;
use Vortos\Http\Request;
final class UserFlagContextResolver implements FlagContextResolverInterface
{
public function __construct(private readonly CurrentUserProvider $auth) {}
public function resolve(Request $request): FlagContext
{
$user = $this->auth->current();
if (!$user->isAuthenticated()) {
return new FlagContext();
}
return new FlagContext(
userId: (string) $user->getId(),
tenantId: (string) $user->getTenantId(),
attributes: [
'plan' => $user->plan,
'role' => $user->role,
'region' => $user->region,
],
);
}
}$services->alias(FlagContextResolverInterface::class, UserFlagContextResolver::class);Register once. Everything that evaluates flags uses this resolver automatically — the built-in /api/flags endpoint, #[RequiresFlag] on controllers, and any call to FlagRegistry::isEnabled() or FlagRegistry::variant() without an explicit context.
Admin UI (optional)
composer require vortos/vortos-feature-flags-adminThe admin UI ships with pre-built JavaScript assets inside the package. Copy them into your application's public directory:
php vortos vortos:assets:publishThis reads every installed Vortos package that declares a public-dir in its composer.json and copies the assets to public/bundles/{package-name}/. For the admin UI, this creates public/bundles/feature-flags-admin/.
Symlink mode for development
Use --symlink during development to avoid re-running the command after a rebuild:
php vortos vortos:assets:publish --symlinkAssets served from packages/feature-flags-admin/ via a symlink update immediately when you rebuild. Use copy mode in production.
Configure your web server to serve the public/ directory. No additional Nginx or Caddy rules are needed — the assets are ordinary static files at /bundles/feature-flags-admin/.
Required roles
The admin UI checks flags.read and flags.write permissions on every request. Configure your authorization layer to grant these to the appropriate roles:
$catalog->define('flags.read', 'View feature flags and their state');
$catalog->define('flags.write', 'Create, update, enable, and disable feature flags');Users without flags.read receive a 403 when accessing the admin UI. Users with flags.read but not flags.write see the dashboard in read-only mode.
Verifying the installation
# Should show the flags table and an empty list
php vortos vortos:flags:list
# Create a test flag, check it appears
php vortos vortos:flags:create test-flag --description="Installation check"
php vortos vortos:flags:list
php vortos vortos:flags:delete test-flag --forceFor the admin UI, navigate to /admin/flags in your browser. You should see the dashboard with an environment selector and an empty flag list.