Extend Forge Kernel with self-contained capability modules. Think of capabilities like modular additions to a house. The kernel gives you the foundation. Capabilities add what you need: database, ORM, authentication, storage, deployment — all optional, all pluggable.
Package functionality into reusable capability modules. Capabilities provide services, controllers, views, CLI commands, and more. Need a database? Install a database capability. Need an ORM? Install an ORM capability. Don't need authentication? Don't install it. The kernel stays lean. You stay in control.
Developer mode unlocks additional CLI commands for managing module registries, creating
versions, and publishing capabilities. These commands replace the old php modules.php tooling.
Enable developer mode by setting FORGE_DEVELOPER_MODE=true in your .env file or config/app.php:
# In .env file
FORGE_DEVELOPER_MODE=true
# Or in config/app.php
return [
'developer_mode' => true,
// ... other config
];
Once enabled, the following commands become available:
dev:registry:init — Initialize a new
module or framework registry. Wizard asks for:
dev:registry:config — Configure
registry settingsdev:module:list —
User-friendly dropdown interface to browse all available modules.
Select any module from an interactive menu to view its versions with the last commit
message for each version.dev:module:version — Create
version wizard that:
--name=ModuleName)modules.json manifest
dev:module:publish — Publish module
registry changes to remote repositorydev:framework:list — List available
framework versionsdev:framework:version — Manage
framework versionsdev:framework:publish — Publish
framework version to registry
Note: All dev:*
commands are only available when developer mode is enabled. This keeps the CLI clean for
regular users while providing powerful tools for developers and maintainers.
Execute code at specific points during application boot.
Executed after the application has booted
Executed after all modules are loaded
Executed after a module is registered
Executed after configuration is loaded
Executed when the application is fully booted
Executed before each HTTP request
Executed after each HTTP request
Executed after HTTP response is sent
use Forge\Core\Module\Attributes\LifecycleHook;
use Forge\Core\Module\LifecycleHookName;
#[LifecycleHook(hook: LifecycleHookName::AFTER_MODULE_REGISTER)]
public function onAfterModuleRegister(): void
{
// Your code here
}
#[LifecycleHook(hook: LifecycleHookName::APP_BOOTED)]
public function onAppBooted(): void
{
// Initialize services, register listeners, etc.
}
Complete authentication system with user registration, login, password management, and session handling. Provides middleware, validation, and user management services. Includes optional JWT support for mobile applications when enabled via configuration.
Complete deployment automation system. Deploy applications to cloud providers (DigitalOcean, custom providers) with automated provisioning, rollback, and zero-downtime deployments. Includes SSH key management, SSL configuration, and deployment state tracking.
Example module demonstrating how to create your own design system as a module capability. Shows that you can package UI components, styles, and design patterns as a reusable module that can be shared across Forge applications.
Reactive protocol for PHP. Build dynamic interfaces with standard PHP controllers, island boundaries, and permission-based attributes. No JavaScript frameworks or separate component classes needed.
Complete deployment automation system. Deploy applications to cloud providers (DigitalOcean, custom providers) with automated provisioning, rollback, and zero-downtime deployments. Includes SSH key management, SSL configuration, and deployment state tracking.
Example module demonstrating how to create your own design system as a module capability. Shows that you can package UI components, styles, and design patterns as a reusable module that can be shared across Forge applications.
Flexible file storage system with multiple driver support. Handles local filesystem, cloud storage providers, and custom storage backends. Includes bucket management and file operations.
Development debugging toolbar with query logging, performance metrics, timeline tracking, memory usage, request/response inspection, and exception details. Only active in development environments.
Complete testing framework with unit tests, integration tests, and test utilities. Supports testing in app, engine, and module scopes with test grouping and filtering capabilities.
Admin dashboard and management interface for your Forge applications.
Markdown processing and rendering with syntax highlighting support. Converts markdown text to HTML with code block highlighting and extended markdown features.
Advanced logging system with multiple drivers (file, database, syslog), log channels, log levels, and structured logging. Supports log rotation and filtering.
Tailwind CSS integration with build tools, asset compilation, and development server support. Provides utilities for managing Tailwind configuration and purging unused styles.
Comprehensive error handling and exception management for production applications. Provides custom error pages, exception logging, error reporting, and graceful error recovery.
Event-driven architecture system with event listeners, event queues, and async event processing. Supports event broadcasting, queued listeners, and event subscribers.
Multi-channel notification system with email, SMS, and push notifications.
Package and capability management system with registry support, integrity verification, and multiple source types (Git, SFTP, FTP, HTTP, Local, Network). Manages capability installation, removal, and project scaffolding.
SQL database support implementing the kernel's DatabaseConnectionInterface. Supports SQLite, MySQL, and PostgreSQL with PDO-based connections, migrations, and seeders.
SQL ORM implementing the kernel's QueryBuilderInterface. Provides attribute-based models, relationships, query builder, and supports SQLite, MySQL, and PostgreSQL. Includes traits like HasTimeStamps and HasMetaData.
Multi-tenant database isolation capability. Automatically resolves tenants by
domain/subdomain, provides separate database connections per tenant, and includes
#[TenantScope] attribute for
controllers. Supports tenant-specific migrations and seeders.
Use Forge CLI or manually place capability modules in the modules directory.
Commands use an interactive wizard by default. You can skip the wizard by providing the
--module= flag or by providing module
names as positional arguments.
Installation Wizard: When installing, you can choose to enter the module name manually or browse available modules. When browsing, you'll select a registry, then choose between single or multiple module selection. In multi-select mode, use checkboxes to select multiple modules (Space to toggle, Enter to confirm) - all will install latest versions. In single-select mode, you'll choose a version (with commit messages for git-based registries), and finally choose whether to force download.
Removal Wizard: When removing, you can choose between single or multiple module selection. You'll see a list of all installed modules with their descriptions. In multi-select mode, use checkboxes to select multiple modules to remove at once.
Multiple Module Support: Both commands support installing or removing multiple modules at once via command-line arguments. For installation, if no version is specified, the latest version is installed automatically.
# Install a capability (wizard-based, interactive)
php forge.php package:install-module
# Skip wizard and install directly
php forge.php package:install-module --module=forge-auth
# Install a specific version (skips version selection in wizard)
php forge.php package:install-module --module=forge-auth@1.2.0
# Install multiple modules (latest versions)
php forge.php package:install-module forge-auth forge-storage forge-logger
# Install multiple modules with mixed versions
php forge.php package:install-module forge-auth@1.2.0 forge-storage forge-logger@0.1.0
# Force download bypassing cache
php forge.php package:install-module --module=forge-auth --force
# List available capabilities
php forge.php package:list-modules
# Remove a capability (wizard-based, shows installed modules with descriptions)
php forge.php package:remove-module
# Skip wizard and remove directly
php forge.php package:remove-module --module=forge-auth
# Remove multiple modules
php forge.php package:remove-module forge-auth forge-storage forge-logger
# Clone capability to modules directory
cd modules/
git clone https://github.com/forge-modules/ForgeAuth.git
# Or download and extract
wget https://github.com/forge-modules/ForgeAuth/archive/main.zip
unzip main.zip -d ForgeAuth/
Auto-Discovery: Capabilities auto-load when placed in the modules directory.
Encapsulate functionality and share across projects as capability modules.
# Generate a new capability module (wizard-based)
php forge.php generate:module
# Skip wizard and generate directly
php forge.php generate:module --name=MyCustomModule
# With description and version
php forge.php generate:module --name=MyCustomModule --description="My custom module" --version=1.0.0
The wizard will prompt you for:
This creates a complete capability module structure in modules/MyCustomModule/:
modules/MyCustomModule/
├── forge.json # Module configuration
├── src/ # Module source code
│ ├── MyCustomModule.php # Module class
│ ├── Controllers/ # Module controllers
│ ├── Services/ # Module services
│ ├── Models/ # Module models
│ ├── Commands/ # CLI commands
│ └── Contracts/ # Interfaces and contracts
├── config/ # Module configuration files
├── resources/ # Module resources
│ ├── views/ # Module views
│ └── assets/ # CSS, JS, images
└── tests/ # Module tests
{
"$schema": "./../../engine/Core/Schema/module-schema.json",
"name": "MyCustomModule",
"version": "1.0.0",
"description": "A custom module for my application",
"type": "generic",
"order": 100,
"cli": {
"commands": []
},
"tags": [],
"config": {
"defaults": {}
},
"author": "Your Name",
"license": ""
}
<?php
declare(strict_types=1);
namespace App\Modules\MyCustomModule;
use Forge\Core\DI\Container;
use Forge\Core\Module\Attributes\Module;
use Forge\Core\Module\Attributes\Service;
use Forge\Core\Module\Attributes\Compatibility;
use Forge\Core\Module\Attributes\ConfigDefaults;
use Forge\Core\Module\Attributes\PostInstall;
use Forge\Core\Module\Attributes\PostUninstall;
use App\Modules\MyCustomModule\Services\CustomService;
use App\Modules\MyCustomModule\Contracts\CustomInterface;
use Forge\Core\Module\Attributes\LifecycleHook;
use Forge\Core\Module\LifecycleHookName;
#[Module(
name: 'MyCustomModule',
description: 'A custom module for my application',
order: 100,
core: false, // Set to true to skip auto-loading (manual wiring required)
isCli: false // Set to true to only load in CLI context
)]
#[Service]
#[Compatibility(framework: '>=0.1.0', php: '>=8.3')]
#[ConfigDefaults(defaults: [
"my_custom_module" => [
"setting1" => "default_value",
"setting2" => true,
]
])]
#[PostInstall(command: 'migrate', args: ['--type=module', '--module=MyCustomModule'])]
#[PostUninstall(command: 'migrate:rollback', args: ['--type=module', '--module=MyCustomModule'])]
final class MyCustomModule
{
public function register(Container $container): void
{
// Register services
$container->bind(CustomInterface::class, CustomService::class);
}
#[LifecycleHook(hook: LifecycleHookName::AFTER_MODULE_REGISTER)]
public function onAfterModuleRegister(): void
{
// Module registration complete
}
}
Module Attributes:
core: true — Module won't be
auto-loaded. You must wire it manually.isCli: true — Module only loads
in CLI context, not in web requests.#[ConfigDefaults] — Define
default configuration directly in the module class. You can still override these in
config/.#[PostInstall] — Automatically
run CLI commands after module installation.#[PostUninstall] — Automatically
run CLI commands after module uninstallation.
Modules can hook into the application lifecycle at various points using the #[LifecycleHook] attribute. The only method
you implement in your module class is register() for service registration.
Executed after the application has booted
Executed after all modules are loaded
Executed after a module is registered
Executed after configuration is loaded
Executed when the application is fully booted
Executed before each HTTP request
Executed after each HTTP request
Executed after HTTP response is sent
<?php
declare(strict_types=1);
namespace App\Modules\MyCustomModule;
use Forge\Core\DI\Container;
use Forge\Core\Module\Attributes\Module;
use Forge\Core\Module\Attributes\LifecycleHook;
use Forge\Core\Module\LifecycleHookName;
#[Module(name: 'MyCustomModule', description: 'A custom module', order: 100)]
final class MyCustomModule
{
public function register(Container $container): void
{
// Register services and bindings here
$container->bind(CustomInterface::class, CustomService::class);
}
#[LifecycleHook(hook: LifecycleHookName::AFTER_MODULE_REGISTER)]
public function onAfterModuleRegister(): void
{
// This hook is called after this module is registered
// Perform initialization logic here
}
#[LifecycleHook(hook: LifecycleHookName::APP_BOOTED)]
public function onAppBooted(): void
{
// This hook is called when the application is fully booted
// Initialize services, register listeners, etc.
}
}
Publish your capabilities to a registry for distribution. This requires Forge developer mode to be enabled.
Before publishing, you need to initialize a registry. Use the dev:registry:init command:
# Initialize a modules registry (wizard-based)
php forge.php dev:registry:init
# Skip wizard
php forge.php dev:registry:init --type=modules
The wizard will ask for:
Use dev:module:list to browse all
available modules in your registry:
# Browse modules with interactive dropdown
php forge.php dev:module:list
This command provides a user-friendly dropdown interface where you can:
Use dev:module:version to create a new
version of your module:
# Create version (wizard-based)
php forge.php dev:module:version
# Skip wizard
php forge.php dev:module:version --name=MyCustomModule --type=minor
php forge.php dev:module:version --name=MyCustomModule --version=1.2.0
The create version wizard will:
--name=ModuleName)forge.json--type=modules.json manifestAfter creating a version, publish it to the remote registry:
# Publish all changes to remote registry
php forge.php dev:module:publish
# Publish specific module
php forge.php dev:module:publish --name=MyCustomModule
forge.json with all
metadata
Registry Workflow: For detailed information about registry structure, integrity hashes, and source types, see the ForgePackageManager documentation.
These are just suggestions based on what tends to work well. You do you. Build modules however makes sense for your project.