Modules
Module structure, manifests, discovery, and dependencies.
Modules are the primary extension mechanism in VelvetCMS. They can add routes, commands, views, services, and configuration.
Module Structure #
Blog/
├── module.json # Required: module manifest
├── src/
│ └── BlogModule.php # Service provider (entry point)
├── routes/
│ └── web.php # Route definitions
├── views/ # Templates
├── database/
│ └── migrations/ # Database migrations
├── config/
│ └── blog.php # Module configuration
└── resources/ # Assets, translations, etc.
Module Manifest #
Every module requires a module.json file:
{
"name": "blog",
"entry": "Vendor\\Blog\\BlogModule",
"version": "1.0.0",
"description": "Blog functionality for VelvetCMS",
"requires": {
"core": ">=1.0.0 <2.0.0"
},
"conflicts": {
"legacy-blog": "*"
}
}
Manifest Fields #
| Field | Required | Description |
|---|---|---|
name |
Yes | Unique module identifier |
entry |
Yes | Fully qualified class name of the service provider |
version |
Yes | SemVer version string |
description |
No | Human-readable description |
requires |
No | Dependencies (module name → version constraint) |
conflicts |
No | Incompatible modules (module name → version constraint) |
Version Constraints #
Supported constraint formats:
>=1.0.0- minimum version<2.0.0- maximum version>=1.0.0 <2.0.0- range^1.0- compatible with 1.x~1.0.0- compatible with 1.0.x*- any version
Service Provider #
The entry class must extend ServiceProvider or BaseModule:
namespace Vendor\Blog;
use VelvetCMS\Core\ServiceProvider;
class BlogModule extends ServiceProvider
{
public function register(): void
{
// Bind services to the container
$this->app->singleton(PostRepository::class);
}
public function boot(): void
{
// Register routes, event listeners, etc.
$this->loadRoutes(__DIR__ . '/../routes/web.php');
$this->loadViews(__DIR__ . '/../views', 'blog');
}
}
Discovery #
Modules are discovered from multiple sources:
- Config paths - directories listed in
config/modules.php - Filesystem globs - patterns like
user/modules/* - Composer packages - packages with type
velvetcms-module - Tenant paths - when tenancy is enabled,
tenant_pathsare scanned
Configuration #
// config/modules.php
return [
'paths' => [
base_path('user/modules/*'),
base_path('modules/*'),
],
'tenant_paths' => [
base_path('user/tenants/{tenant}/modules/*'),
],
'modules' => [
// Explicit module paths
'custom' => base_path('packages/custom-module'),
],
];
Compiled Manifest #
At runtime, modules load from storage/modules-compiled.json for performance. This file is generated during:
- First request (if missing)
- Running
./velvet module:discover
The compiled manifest includes resolved paths, versions, and dependency order.
Load Order #
The module manager:
- Collects all discovered modules
- Validates manifests and version constraints
- Detects conflicts and missing dependencies
- Sorts modules by dependency order
- Registers and boots in sequence
If Module A requires Module B, Module B is registered and booted first.
Module Commands #
./velvet module:list # List all modules
./velvet module:discover # Rebuild module manifest
./velvet make:module Blog # Generate module scaffold