PHPackages                             happenv-com/laravel-true-modular - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. happenv-com/laravel-true-modular

ActiveLibrary[Framework](/categories/framework)

happenv-com/laravel-true-modular
================================

v1.1.0(3w ago)211.5k↑100%22MITPHPPHP ^8.3CI passing

Since Apr 29Pushed 3w agoCompare

[ Source](https://github.com/happenv-com/laravel-true-modular)[ Packagist](https://packagist.org/packages/happenv-com/laravel-true-modular)[ RSS](/packages/happenv-com-laravel-true-modular/feed)WikiDiscussions 1.x Synced 1w ago

READMEChangelog (8)Dependencies (17)Versions (14)Used By (2)

True Modular for Laravel
========================

[](#true-modular-for-laravel)

  ![Laravel True Modular](https://camo.githubusercontent.com/cd56e07e2fb74b255e4de28a71ba6e6cef24533b52297c6d159e2a2adc291e6a/68747470733a2f2f62616e6e6572732e6265796f6e64636f2e64652f4c61726176656c253230547275652532304d6f64756c61722e706e673f7468656d653d6c69676874267061636b6167654d616e616765723d636f6d706f7365722b72657175697265267061636b6167654e616d653d68617070656e762d636f6d2532466c61726176656c2d747275652d6d6f64756c6172267061747465726e3d617263686974656374267374796c653d7374796c655f31266465736372697074696f6e3d4d616b652b796f75722b4c61726176656c2b6172636869746563747572652b6578706c696369742532432b64657465726d696e69737469632b616e642b616e616c797a61626c65266d643d312673686f7757617465726d61726b3d3026666f6e7453697a653d313030707826696d616765733d68747470732533412532462532466c61726176656c2e636f6d253246696d672532466c6f676f6d61726b2e6d696e2e737667)[![Latest Version on Packagist](https://camo.githubusercontent.com/1007470d9a7108e335954d2864806b3ce646236ba6f057e22e4b077eb127720e/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f68617070656e762d636f6d2f6c61726176656c2d747275652d6d6f64756c61722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/happenv-com/laravel-true-modular)[![Total Downloads](https://camo.githubusercontent.com/e0ab4cdf8c6db36028f45326316fc9bf4e878cc9276c582a10f99a67a2d984bf/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f68617070656e762d636f6d2f6c61726176656c2d747275652d6d6f64756c61722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/happenv-com/laravel-true-modular)[![Tests](https://camo.githubusercontent.com/0d9f17280ef77a1f2462036a62ad978cd21ad6afabe83cf001a567f7c155e93c/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f68617070656e762d636f6d2f6c61726176656c2d747275652d6d6f64756c61722f74657374732e796d6c3f6272616e63683d302e78267374796c653d666c61742d737175617265266c6162656c3d7465737473)](https://github.com/happenv-com/laravel-true-modular/actions/workflows/tests.yml)[![PHPStan](https://camo.githubusercontent.com/a20752aad99e92137a4ececa212b8bc85ccf043a04a3e683e36d96e7288c0993/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f68617070656e762d636f6d2f6c61726176656c2d747275652d6d6f64756c61722f7068707374616e2e796d6c3f6272616e63683d302e78267374796c653d666c61742d737175617265266c6162656c3d7068707374616e)](https://github.com/happenv-com/laravel-true-modular/actions/workflows/phpstan.yml)[![Zizmor](https://camo.githubusercontent.com/28d65e0ff7a2a608099052ecba5fd3eed516b3c7c51ff4038f0b8a0b4bc71fb0/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f68617070656e762d636f6d2f6c61726176656c2d747275652d6d6f64756c61722f7a697a6d6f722e796d6c3f6272616e63683d302e78267374796c653d666c61742d737175617265266c6162656c3d7a697a6d6f72)](https://github.com/happenv-com/laravel-true-modular/actions/workflows/zizmor.yml)[![Code Style](https://camo.githubusercontent.com/f498f15191fd27e286d8192eee0e459cc30dca5e3a59942caa6e07b13fc5f5c1/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f68617070656e762d636f6d2f6c61726176656c2d747275652d6d6f64756c61722f6669782d636f64652d7374796c652e796d6c3f6272616e63683d302e78267374796c653d666c61742d737175617265266c6162656c3d636f64652532307374796c65)](https://github.com/happenv-com/laravel-true-modular/actions/workflows/fix-code-style.yml)

**Make your Laravel architecture explicit, deterministic, and analyzable.**

Modules are first-class Composer packages with deterministic dependency ordering, an extended lifecycle, and a built-in architecture runtime. Instead of an architecture that lives only in your team's heads, you get one you can query, graph, and reason about.

```
php artisan module:impact acme/catalog

acme/catalog

Direct:
  acme/checkout
  acme/pricing

Indirect:
  acme/storefront

Total affected: 3

```

> **Ask the codebase what a change touches before you make it.**

Contents
--------

[](#contents)

- [Why](#why)
- [Where modules live](#where-modules-live)
- [The module graph](#the-module-graph)
- [Enforcing boundaries (static analysis)](#enforcing-boundaries-static-analysis)
- [Built for agentic coding](#built-for-agentic-coding)
- [Defining a module](#defining-a-module)
- [Extending existing modules](#extending-existing-modules)
- [Extending the framework](#extending-the-framework)
- [Production notes](#production-notes)
- [Install](#install)
- [Documentation](#documentation)
- [Development](#development)
- [License](#license)

Why
---

[](#why)

Large Laravel applications get harder to evolve over time. Modules end up depending on each other silently, boot order becomes implicit, cross-module initialization is fragile, and the real shape of the architecture survives only in the heads of the people who wrote it.

True Modular for Laravel makes that shape explicit, and builds three guarantees on top of it:

1. **Topological provider ordering** - module service providers are sorted by their `composer.json`dependencies, so a module always boots after the modules it depends on. Cycles are detected and reported, not silently mis-ordered.
2. **Enhanced lifecycle** - `register() → initialize() → boot()`. The `initialize()` phase runs after every provider is registered but before *anything* boots - including third-party package providers. So your cross-module wiring (morph maps, permissions, drivers, Livewire/Filament hooks) is in place before any package's `boot()` reads it.
3. **Architecture runtime** - `module:graph`, `module:impact`, `module:why`, `module:list`, with `--format=json` so you can wire blast-radius checks into CI, and `--format=mermaid`/`dot` to render the graph.

Where modules live
------------------

[](#where-modules-live)

A module is just a Composer package whose `composer.json` declares `type: "true-module"`. That means a module can live in either place:

- **Local to your app** - under the `app-modules/` directory, versioned alongside the rest of your code. This is where most modules start.
- **An external Composer package** - pulled in via `composer require` and resolved from `vendor/`like any dependency, so a module can be shared across applications or published privately.

Both are discovered the same way and take part in the same dependency ordering and tooling - there's no difference in how they behave at runtime. The modules directory (default `app-modules`) and the module type (default `true-module`) are configurable in `bootstrap/app.php` via `Application::modulesDirectory()` and `Application::moduleComposerType()`.

The module graph
----------------

[](#the-module-graph)

Modules declare their dependencies in `composer.json` like any other Composer package. The package reads those edges and derives both the **shape** of your system and the **exact order** things run. Real graphs aren't a straight line - modules fan out and share dependencies. The number on each node is its position in the deterministic boot order:

 ```
graph TD
    core["1 · core"] --> auth["2 · auth"]
    core --> product["3 · product"]
    product --> inventory["4 · inventory"]
    product --> pricing["5 · pricing"]
    auth --> sale
    inventory --> sale["6 · sale"]
    pricing --> sale
    sale --> amazon["7 · amazon"]
    sale --> ebay["8 · ebay"]
```

      Loading `module:graph` renders that as a tree - each module sits under the one it depends on. A module with two dependencies (here `sale`) appears under each path that reaches it:

```
php artisan module:graph

core
├── auth
│   └── sale
│       ├── amazon
│       └── ebay
└── product
    ├── inventory
    │   └── sale
    │       ├── amazon
    │       └── ebay
    └── pricing
        └── sale
            ├── amazon
            └── ebay

```

`module:list` flattens it into the **deterministic execution order** - the exact, numbered sequence in which providers `register()`, `initialize()`, and `boot()`, dependencies first:

```
php artisan module:list --simple

Modules in order (dependencies first):

  1. core
  2. auth
  3. product
  4. inventory
  5. pricing
  6. sale
  7. amazon
  8. ebay

```

No module ever boots before the modules it depends on - and a cycle is a hard error, not a race condition. Other views of the same graph:

```
php artisan module:graph --format=mermaid # paste straight into a doc
php artisan module:graph --format=dot     # pipe into Graphviz
php artisan module:graph --root=sale      # restrict to one subtree
php artisan module:why amazon core        # shortest path: why does Amazon depend on Core?
```

Local modules are referenced by their short name (`amazon`) — the package qualifies them with your default vendor (derived from `modulesNamespace`, e.g. `happenv/amazon`). External packages keep their full `vendor/name` (`acme/catalog`), which signals they aren't part of the local system. Resolution is case-insensitive.

Output mirrors this: local modules print by short name, external packages by full `vendor/name`. Pass `--with-vendor` to any of these commands to print every module with its full `vendor/name`; `--format=json`always uses full names.

Enforcing boundaries (static analysis)
--------------------------------------

[](#enforcing-boundaries-static-analysis)

[![Latest Version on Packagist](https://camo.githubusercontent.com/396d1044add4b4eff8551823b0949d5691f41356d7f4872bc8a36a46dcd1f358/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f68617070656e762d636f6d2f6c61726176656c2d747275652d6d6f64756c61722d7068707374616e2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/happenv-com/laravel-true-modular-phpstan)[![Total Downloads](https://camo.githubusercontent.com/866fe8446c55433204b1009372818440c44da1279dfd49859ebb286b8af83ccc/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f68617070656e762d636f6d2f6c61726176656c2d747275652d6d6f64756c61722d7068707374616e2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/happenv-com/laravel-true-modular-phpstan)

The runtime *discovers* and *explains* the architecture; a companion package [**`happenv-com/laravel-true-modular-phpstan`**](https://github.com/happenv-com/laravel-true-modular-phpstan)*enforces* it. It ships two zero-config PHPStan extensions:

- **Module Boundary Enforcer** - fails analysis when a module references a class from another module that isn't declared in its `composer.json` `require`, and detects circular dependencies between modules. It reads the same `composer.json` edges the framework uses to order providers, so there's nothing to configure.
- **Dynamic Relation Resolver** - types Eloquent relations registered at runtime (e.g. relations one module adds to another module's model via [model extensions](docs/model-extensions.md)), which are otherwise invisible to static analysis.

```
composer require --dev happenv-com/laravel-true-modular-phpstan
```

With [`phpstan/extension-installer`](https://github.com/phpstan/phpstan-extension-installer) both extensions register automatically. See the [package README](https://github.com/happenv-com/laravel-true-modular-phpstan) for details.

Built for agentic coding
------------------------

[](#built-for-agentic-coding)

Explicit boundaries aren't only good for humans — they're what makes a codebase legible to an AI coding agent, and one of the biggest reasons to adopt this architecture today.

- **Smaller context, faster iterations.** A module is a self-contained package with an explicit dependency list, so an agent loads just that module and the few it depends on — not the whole app.
- **The agent knows where it's allowed to work.** `module:impact`, `module:why`, and `module:graph --root=` let it ask *"what does this affect, and what does it depend on?"* — so it moves inside well-defined boundaries instead of grepping and guessing across the whole system.
- **Guardrails it gets feedback from.** The PHPStan [Module Boundary Enforcer](#enforcing-boundaries-static-analysis) fails the moment generated code crosses a boundary not declared in `composer.json` — immediate, machine-readable feedback, not a reviewer catching it later.
- **It already knows the conventions.** The package ships [Laravel Boost](https://laravel.com/docs/boost) resources auto-installed by `boost:install`, so an agent picks up the lifecycle, the `Module` builder, and the rules without docs in the prompt.

See [docs/agentic-coding.md](docs/agentic-coding.md) for the full agent workflow.

Defining a module
-----------------

[](#defining-a-module)

A module is a Composer package (`type: "true-module"`) whose service provider extends `ModuleProvider` and declares its features fluently:

```
class CatalogServiceProvider extends ModuleProvider
{
    public function configureModule(Module $module): void
    {
        $module
            ->name('acme/catalog')
            ->hasConfig('catalog')
            ->hasRoutes('web', 'api')
            ->hasViews()
            ->hasMigrations()
            ->runsMigrations();
    }
}
```

> The `ModuleProvider` / `Module` fluent API is heavily inspired by [spatie/laravel-package-tools](https://github.com/spatie/laravel-package-tools). Many thanks to Spatie and its contributors for their hard work — this package builds on the patterns they pioneered.

Extending existing modules
--------------------------

[](#extending-existing-modules)

Modules don't only talk to each other through services - they can extend the **domain model itself**. A downstream module adds attributes and relations to an upstream module's Eloquent model without touching that model's class, so the dependency arrow stays pointed the right way.

The `billing` module declares the extension:

```
$module->hasModelExtensions([
    Product::class => ProductBillingExtension::class,
]);
```

```
/**
 * @property Product $model
 */
final class ProductBillingExtension extends ModelExtension
{
    public function invoices(): HasMany
    {
        return $this->model->hasMany(Invoice::class);
    }
}
```

And `Product` gains the relation as if it were defined on it:

```
Product::query()->with('invoices');
```

A sibling, `hasModelBuilderExtensions()`, does the same for an Eloquent **query builder** - the key is the builder class to mix new query methods into, so a downstream module can teach an upstream model's builder new scopes:

```
$module->hasModelBuilderExtensions([
    ProductBuilder::class => ProductBillingQueries::class,
]);

Product::query()->withOutstandingInvoices()->get();
```

The `catalog` module that owns `Product` is never modified - `billing` contributes new attributes, relations, and query methods to it. Each module composes the shared domain model instead of forking or patching it. (Static analysis still sees these runtime additions, thanks to the [PHPStan extension](#enforcing-boundaries-static-analysis) above.)

Extending the framework
-----------------------

[](#extending-the-framework)

The extensions above aren't a custom trick — they ride on `Macroable`, the trait Eloquent already uses everywhere (`Builder`, `Collection`, `Str`, `Request`, …) to add methods to a class *from the outside*, without editing it. That's a textbook **open/closed**, and the natural tool for cross-module extension: `hasModelBuilderExtensions()` registers a builder **mixin**(`Builder::mixin(...)`), `hasModelExtensions()` adds relations via `resolveRelationUsing()`.

Macros are normally invisible to static analysis — but the companion [PHPStan extension](#enforcing-boundaries-static-analysis) (with Larastan) types the relations and mixins this package registers, so you extend modules without patching them **and** keep a green analysis. See [docs/model-extensions.md](docs/model-extensions.md).

Install
-------

[](#install)

```
composer require happenv-com/laravel-true-modular
```

The one non-obvious step: the package ships a custom `Application` that performs the topological sort and the extra lifecycle phase, so `bootstrap/app.php` must boot through it. The `php artisan true-modular:setup` command rewrites `bootstrap/app.php` for you - or wire it by hand as shown in [Getting started](docs/getting-started.md).

Requires PHP 8.3+ and Laravel 12/13.

Documentation
-------------

[](#documentation)

Full documentation lives in [`docs/`](docs/README.md):

[Getting started](docs/getting-started.md)Install and create your first module.[CLI commands](docs/cli-commands.md)Graph / impact / why / list, and the `--format` options.[Agentic coding](docs/agentic-coding.md)Working on the codebase with AI agents; the workflow.[Architecture &amp; runtime](docs/architecture-runtime.md)The lifecycle and the analysis layer.[Module dependencies](docs/module-dependencies.md)Discovery, ordering, cycles.[Model extensions](docs/model-extensions.md)Add attributes/relations to another module's model.[Module builders](docs/builders.md)The fluent `Module` API and every feature.[Lifecycle hooks &amp; schemas](docs/schema-hooks.md)Overridable provider hooks; report JSON schema.[Config merging](docs/config-merging.md)The four config strategies and merge semantics.[Best practices](docs/best-practices.md) · [Anti-patterns](docs/anti-patterns.md)Do's and don'ts.[Extending the package](docs/extending-the-package.md)Add features, renderers, sources.[Testing](docs/testing.md)Fixtures, helpers, patterns.[Laravel Boost](docs/laravel-boost.md)AI guidelines &amp; skills for coding agents.Development
-----------

[](#development)

```
composer install
vendor/bin/pest             # tests (Pest 4)
vendor/bin/pint             # format
vendor/bin/phpstan analyse  # static analysis (level 6 + larastan)
vendor/bin/rector process   # apply refactorings (--dry-run to preview)
```

Alternatives
------------

[](#alternatives)

This isn't the only way to build a modular Laravel app. If this package doesn't fit your needs, take a look at:

- [nWidart/laravel-modules](https://github.com/nWidart/laravel-modules) — organizes a large Laravel app into self-contained modules, each with its own views, controllers, and models, managed through a dedicated directory structure and generator commands.
- [InterNACHI/modular](https://github.com/InterNACHI/modular) — splits an app into separate modules using Composer path repositories and Laravel's native package discovery, instead of a custom directory structure.

License
-------

[](#license)

[MIT](LICENSE.md)

###  Health Score

52

—

FairBetter than 96% of packages

Maintenance95

Actively maintained with recent releases

Popularity30

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity56

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 97.5% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~4 days

Total

14

Last Release

24d ago

Major Versions

v0.3.5 → v1.0.02026-06-27

0.x-dev → v1.1.02026-06-27

PHP version history (2 changes)0.1PHP ^8.3

v0.3.2PHP ^8.4

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/855788?v=4)[Bartłomiej Gajda](/maintainers/webard)[@webard](https://github.com/webard)

---

Top Contributors

[![webard](https://avatars.githubusercontent.com/u/855788?v=4)](https://github.com/webard "webard (39 commits)")[![gorny-dev](https://avatars.githubusercontent.com/u/54044073?v=4)](https://github.com/gorny-dev "gorny-dev (1 commits)")

---

Tags

architecturelaravelmodularmodular-architecturemodular-monolithmodularity

###  Code Quality

TestsPest

Static AnalysisPHPStan, Rector

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/happenv-com-laravel-true-modular/health.svg)

```
[![Health](https://phpackages.com/badges/happenv-com-laravel-true-modular/health.svg)](https://phpackages.com/packages/happenv-com-laravel-true-modular)
```

###  Alternatives

[laravel/octane

Supercharge your Laravel application's performance.

4.0k26.6M231](/packages/laravel-octane)[unopim/unopim

UnoPim Laravel PIM

10.5k2.4k](/packages/unopim-unopim)[ecotone/laravel

Ecotone for Laravel — CQRS, Event Sourcing, Sagas, Durable Workflows, and Outbox on top of Laravel Queue, via PHP attributes.

21318.6k3](/packages/ecotone-laravel)[codewithdennis/larament

Larament is a time-saving starter kit to quickly launch Laravel 13.x projects. It includes FilamentPHP 5.x pre-installed and configured, along with additional tools and features to streamline your development workflow.

3991.8k](/packages/codewithdennis-larament)[duncanmcclean/statamic-cargo

Comprehensive e-commerce addon for Statamic. Build bespoke e-commerce sites without the complexity.

3518.3k](/packages/duncanmcclean-statamic-cargo)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
