On this page
CLI reference
Gacela ships a small CLI that assists you while building, inspecting and tuning modules in your application.
All commands below are invoked through vendor/bin/gacela. Run it without arguments to list the installed commands, or
vendor/bin/gacela help <command> for one command's complete options.
The binary walks up from the current directory to the nearest vendor/autoload.php and bootstraps with that project
root, so it works from anywhere in the tree the way other Composer tooling does. gacela.php, setAppModulePaths() and
the cache directory always resolve against the project root, never against the directory you happened to run from.
Before 2.1 the command looked only in the working directory and failed after a single cd src.
Project setup
init
Create the gacela.php bootstrap file required by every other command:
vendor/bin/gacela init [--force|-f]--force overwrites an existing file.
Module discovery
list:modules
Render every module discovered under your project namespaces.
vendor/bin/gacela list:modules [--detailed|-d] [<filter>]filter: substring to narrow the output-d,--detailed: render each module's contents in detail
Scope which directories this (and debug:modules, cache:warm, doctor) scans with
setAppModulePaths().
A module is recognized by any class that descends from AbstractFacade, not only a direct child of it. A project
with its own base Facade in between (ShopFacade extends AppBaseFacade extends AbstractFacade) used to disappear from
list:modules, doctor, debug:graph and cache:warm, with nothing reporting the omission.
With no appModulePaths configured the scan starts at the project root. It prunes vendor, node_modules and any
hidden directory before descending, rather than walking them and discarding the results afterwards. The rule is
deliberately narrow: everything else is descended into, because assuming a project's build/ or data/ holds no
modules is how discovery starts silently missing them. An appModulePaths entry pointing inside a pruned directory
still works, since the configured root itself is never filtered.
debug:modules
Walk every discovered module and inspect the constructor of each pillar (Facade, Factory, Config, Provider). Complements
list:modules (structural view) and debug:dependencies (single-class deep-dive).
vendor/bin/gacela debug:modules [--detail|-d] [<filter>]- Default output groups by module with per-pillar resolvable/unresolvable counts.
--detailincludes every parameter, not just unresolvable ones.filteraccepts a namespace substring (e.g.App\\Shop) or a directory (e.g.src/).
debug:dependencies
Inspect a single class's constructor and report each parameter's resolvability through the container.
vendor/bin/gacela debug:dependencies <class|file> [--tree]- Accepts a fully qualified class name or a path to a PHP file declaring the class.
- Each parameter is tagged (
bound → target,autowirable,has default, orunresolvablewith a reason). - Parameters annotated with
#[Inject]show up taggedinject, with the override concrete rendered inline when present. --treeappends the transitive dependency graph after applying bindings and contextual bindings. Nodes are markedbinding,instance,autowired, orunresolvable; cycles are shown and cut.
debug:module
Inspect a single module: its resolved Facade, Factory, Config and Provider, the container bindings it registers, and its
dependency tree. Complements debug:modules (all modules, structural) and debug:dependencies (single class).
vendor/bin/gacela debug:module <module> [-j|--json] [-t|--tree]module: module name, or a part of it (required)-j,--json: output machine-readable JSON-t,--tree: only print the dependency tree
debug:graph
Render the whole-app module dependency graph — which module imports which (edges via cross-module Facade usage).
vendor/bin/gacela debug:graph [<filter>] [-f|--format=text|mermaid|graphviz|json] [--check]filter: only include modules matching this substring-f,--format:text(default),mermaid,graphviz, orjson--check: exit non-zero when an unreviewed dependency cycle exists--allowed-cycles <file>: JSON allowlist of reviewed cycles and their reasons--compare-to <graph.json>: diff the current graph against saved JSON output
The mermaid / graphviz formats are handy for architecture diagrams. Use --check in CI.
See Failing on dependency cycles for the allowlist format and the
CI comparison workflow.
Imports are read with PHP's tokenizer rather than matched line by line, so grouped (use App\Shop\{A, B};), multiline
and aliased imports all produce edges, as do use function and use const. A leading \ on an import and an uppercase
USE no longer hide a dependency. Modules are resolved through a name index instead of comparing every import against
every module, which is what makes the scan cheap on large graphs.
debug:container
Inspect the container's user bindings and plugins only (framework-internal services are excluded).
vendor/bin/gacela debug:container [<class>] [-s|--stats] [-t|--tree]- No arguments (or
-s,--stats): print container statistics — registered services, frozen services, factory services, bindings, cached dependencies, and process memory usage. <class>(or-t,--treewith a class): render the dependency tree for that fully qualified class name. Passing a class implies--tree;--treewithout a class errors.-s,--statsalways takes precedence:debug:container SomeClass --statsprints statistics, not the dependency tree, even though a class was given.
Caching & production
cache:warm
Pre-resolve all module classes, write the persistent caches and (optionally) the merged configuration cache. Run this once per deploy in production.
vendor/bin/gacela cache:warm [-c|--clear] [-a|--attributes]-c,--clear: clear existing cache before warming (same as runningcache:clearfirst)-a,--attributes: pre-scan and cache#[ServiceMap]attributes
Under the hood cache:warm batches file writes via AbstractPhpFileCache::beginBatch() / commitBatch() and flushes
with atomic rename(), so a single write replaces the previous N modules × 4 resolvers full-file rewrites.
Exit code. As of 2.1 the command exits non-zero when module discovery fails or any module fails to warm, so a broken
deploy step is not reported green. It previously always exited 0 and printed the failures as warnings. The merged
configuration cache is only written when the file cache is enabled.
cache:clear
Remove every Gacela cache file.
vendor/bin/gacela cache:clearClears the project-scoped class-name, custom-service, and merged-config cache files, cacheable-method entries, and the container's in-process reflection memos.
Configuration health
doctor
Aggregate environmental and wiring health checks with per-check remediation hints. Bundled checks include cache
staleness, suffix mismatches, and filename/class mismatches, plus any ModuleHealthCheckInterface registered through
GacelaConfig::addHealthCheck().
vendor/bin/gacela doctor [<filter>] [--strict]filter: restrict module-scoped checks to a namespace substring.- By default warnings still exit
0;--strictmakes warnings fail too and is the recommended CI mode.
The staleness check covers the merged configuration cache too, compared against every file ConfigLoader would
read: base patterns, environment patterns and local overrides. That cache keeps serving values after a config/*.php
file changes while every class-name entry stays fresh, which is how doctor used to report "all cache entries are
fresh" on a stale configuration.
validate:config
Validate the current Gacela configuration for errors and best practices.
vendor/bin/gacela validate:config- Reports missing
gacela.php(warning). - Walks every registered binding and emits type-mismatch warnings with the expected interface/class, the actual type chain, and a fix hint.
- Interface-keyed bindings are checked as well (previously skipped).
- Non-class binding keys (plain string ids such as
'db.dsn') are accepted rather than reported as non-existent.
debug:config
Print the effective merged configuration as a table, after every config/*.php file and environment override is
resolved.
vendor/bin/gacela debug:config [<filter>]filter: only show keys containing this substring.- Backed by
Config::getAllValues(), so it reflects exactly what your modules see at runtime.
Profiling
profile:report
Generate a performance report from the in-memory Profiler. Enable the profiler (Profiler::getInstance()->enable())
early in your bootstrap, run your code, then dump the report.
vendor/bin/gacela profile:report [--format=table|json|summary] [--sort=duration|memory|operation]--format:table(default),json, orsummary.--sort:duration(default),memory, oroperation.
The profiler keeps a stack of start times per operation, so nested and recursive spans each record their own duration.
Starting an operation that was already in flight used to overwrite the outer timestamp and collapse both into one entry.
Calling disable() drops whatever is still in flight, since a span left open while profiling is off can never be closed
and would otherwise pair a later stop() with a stale start.
Code generation
make:file
Generate a Facade, Factory, Config, Provider, or any combination of them.
vendor/bin/gacela make:file [-s|--short-name] <path> <filenames>...path: file path, e.g.App/TestModule/TestSubModulefilenames: any combination offacade,factory,config,provider-s,--short-name: drop the module prefix from the generated class name
vendor/bin/gacela make:file App/TestModule facade factory providerBoth generators resolve the target directory by stripping only the matched psr-4 prefix from the path. Replacing the
namespace text everywhere it occurred rewrote it inside the module name too, so App/Application against App\ => src/
produced src/srclication. A psr-4 entry mapped to a list of directories is accepted; the first is used, because that
is where Composer itself looks first.
make:module
Generate a full module: Facade, Factory, Config, and Provider.
vendor/bin/gacela make:module [-s|--short-name] [-t|--template=basic|service|minimal] [--minimal] [--with-tests] <path>-s,--short-name: drop the module prefix from the generated class name-t,--template:basic(four pillars),service(four pillars plus a wired Domain service), orminimal(Facade and Factory only).--minimal: shorthand for--template=minimal.--with-tests: also scaffold aGacelaTestCase-based facade test (only valid with--template=service).
vendor/bin/gacela make:module -s App/TestModulevendor/bin/gacela make:module --template=service --with-tests App/Checkout