Docs LATEST

Modules

Module structure, manifests, discovery, and dependencies.

Architecture

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:

  1. Config paths - directories listed in config/modules.php
  2. Filesystem globs - patterns like user/modules/*
  3. Composer packages - packages with type velvetcms-module
  4. Tenant paths - when tenancy is enabled, tenant_paths are 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:

  1. Collects all discovered modules
  2. Validates manifests and version constraints
  3. Detects conflicts and missing dependencies
  4. Sorts modules by dependency order
  5. 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