The handful of ideas you need to build on the Forge Kernel. The kernel is small by design — the concepts below are the core; everything else is a capability you plug in.
Not on this page: routing, middleware, views, components, and database/ORM are capabilities, not kernel internals. They're summarized under Beyond the Kernel and covered fully on their own pages.
The kernel is a foundation with utilities — you get the structure and plumbing, then decide what to build on top. It boots, loads your app and any capabilities you installed, and hands control to whatever answers the request (usually a routing capability like ForgeRouter).
The kernel component list above is the whole story — there is no router, view engine, or middleware baked in. Those are capabilities you install (ForgeRouter, ForgeView, and so on).
Your front controller calls
Kernel::init(). The bootstrap runs its setup steps (load the
environment, load modules, wire up the container,
handle errors, boot sessions), then the installed
capabilities register themselves. See
Lifecycle
for the full sequence.
The kernel's
Container
resolves the dependencies your code needs. It is
a singleton, so you reach it from anywhere with
Container::getInstance().
Classes you want the container to manage are
marked with a single attribute,
#[Injectable]. You can give it an optional id and choose
whether it is a singleton.
<?php
use Forge\Core\DI\Attributes\Injectable;
#[Injectable] // most services default to a shared (singleton) instance
class UserService
{
public function __construct(
private UserRepository $repository,
) {}
public function createUser(array $data): User
{
return $this->repository->create($data);
}
}
// Non-singleton service
#[Injectable(singleton: false)]
class RequestId
{
public string $id = bin2hex(random_bytes(8));
}
Register a service with
register()
and resolve it with
make()
(or get(), a synonym). Resolution uses reflection for
constructor injection.
<?php
use Forge\Core\DI\Container;
$container = Container::getInstance();
$container->register(UserService::class);
$userService = $container->make(UserService::class);
Registration happens where it makes sense — a module's registration, a service provider, or your bootstrap. The container does not recursively scan every folder for you; you register the services you want it to know about.
Bind an interface to a concrete class with
bind(), or register a shared binding with
singleton(). Group services with
tag()
and pull them back together with
tagged().
<?php
// Interface to implementation
$container->bind(LoggerInterface::class, FileLogger::class, true);
// Tag a group of services
$container->tag('middleware', [
AuthMiddleware::class,
CsrfMiddleware::class,
]);
$middlewares = $container->tagged('middleware');
A capability is a self-contained module you install on top of the kernel. The kernel stays lean; capabilities add what you need — database, routing, views, auth, storage. Install what you use, skip the rest.
Every capability declares itself with the
#[Module]
attribute. Its options control how the kernel
loads it.
name
—
description
—
version
— identity metadata
order
— load order relative to other modules
core: true
— do not auto-load; wire it manually
isCli: true
— load only in CLI context, not web
type
/
category
—
tags
— descriptive metadata
<?php
namespace App\Modules\MyModule;
use Forge\Core\DI\Container;
use Forge\Core\Module\Attributes\Module;
use Forge\Core\Module\Attributes\LifecycleHook;
use Forge\Core\Module\LifecycleHookName;
#[Module(
name: 'MyModule',
description: 'A custom capability for my application',
version: '1.0.0',
order: 100,
core: false, // auto-load
isCli: false, // also load in web context
)]
final class MyModule
{
public function register(Container $container): void
{
// Register the module's services
$container->bind(MyModuleInterface::class, MyModuleService::class);
}
#[LifecycleHook(hook: LifecycleHookName::AFTER_MODULE_REGISTER)]
public function onAfterRegister(): void
{
// Run once the module is registered
}
}
A capability can run code at specific points in
the boot using the
#[LifecycleHook]
attribute. Available moments include
EARLY_BOOT,
BEFORE_MODULE_LOAD,
AFTER_MODULE_LOAD,
AFTER_MODULE_REGISTER,
AFTER_CONFIG_LOADED,
AFTER_BOOT, and
APP_BOOTED. A routing capability, for example, registers
its routes once the app has booted.
Several companion attributes let a capability declare how the kernel should treat it:
#[Compatibility]
— required kernel and PHP versions
#[ConfigDefaults]
— default config without a config file
#[PostInstall]
/
#[PostUninstall]
— CLI commands to run after install or
removal
#[Repository]
—
#[Provides]
/
#[Requires]
— registry and dependency metadata
See Lifecycle and Capabilities for how this all fits together.
Configuration is environment-based and read
through two global helpers. Your secrets live in
.env; the kernel guards it from direct HTTP access.
<?php
// Secrets and environment values
$dbHost = env('DB_HOST', 'localhost');
$debug = env('APP_DEBUG', false);
// Application config (from config/*.php)
$appName = config('app.name', 'Forge App');
Capabilities can ship their own defaults via
#[ConfigDefaults]
and you can override them with a config file.
See
API Reference
for the full helper list.
The kernel ships a command system. Run
php forge.php
to open the interactive command browser, or call
a command directly. Commands come from the kernel
and from installed capabilities.
The kernel itself provides a focused set:
generate:command,
generate:entity,
generate:event,
generate:migration,
generate:module,
generate:seeder,
generate:test
cache:flush,
cache:warm,
cache:rebuild
asset:link,
asset:unlink,
storage:link,
storage:unlink
structure:info,
structure:init
key:generate,
help,
stats
Developer-mode registry commands use the
dev:
prefix (for example
dev:registry:init,
dev:blueprint:list). Many useful commands you will see come from
capabilities — serve
and the
migrate
family are provided by ForgeRouter and
ForgeDatabaseSQL respectively, not the kernel.
A command extends the
Command
base class, is marked with
#[Cli], declares arguments with
#[Arg], and implements
execute(array $args): int. Commands are discovered from
app/Commands/
and from each module's
src/Commands/.
<?php
namespace App\Commands;
use Forge\CLI\Attributes\Arg;
use Forge\CLI\Attributes\Cli;
use Forge\CLI\Command;
#[Cli(
command: 'hello',
description: 'Say hello',
)]
final class HelloCommand extends Command
{
#[Arg(name: 'name', description: 'Who to greet', default: 'world')]
private string $name = 'world';
public function execute(array $args): int
{
$this->info("Hello, {$this->name}!");
return 0;
}
}
Commands can pull in the CLI traits — OutputHelper for colored output, Wizard for interactive prompts, CliGenerator for file generation. See API Reference.
The capabilities below build on the kernel primitives above. Each has its own page with the full picture.
Attribute-based routing, HTTP request and response handling, and middleware groups (CSRF, auth, CORS, and more). Replaces the old routing/middleware sections.
PHP-first templating with layouts, sections, slots, and reusable view components. Replaces the old view engine/components sections.
Implements the kernel's database contracts, the query builder, models, and migrations. Replaces the old database & ORM section.
An event and queue system for pushing slow work out of the request lifecycle. Replaces the old async/queues section.
Browse all the capabilities in the catalog.