orchestra/installer
A reusable installer foundation for Orchestra Platform extensions, handling install, uninstall, and update routines so packages can wire up migrations, configuration, and resources consistently within Laravel applications.
Install it as a global Composer binary, not a project dependency. orchestra/installer never belongs in a composer.json — it is a one-shot scaffolding tool.
composer global require orchestra/installer:^5.2
# add the global bin dir to PATH:
# ~/.composer/vendor/bin (or ~/.config/composer/vendor/bin on newer Composer)
orchestra --version
If orchestra isn't found after install, it's almost always the PATH problem above, not a broken install. Verify with composer global config bin-dir --absolute.
First use case is the only use case: stand up a fresh Orchestra Platform app.
orchestra install my-app
cd my-app
git init && git add -A && git commit -m "scaffold: orchestra/installer v5.2.x"
php artisan serve # admin UI at /admin
Know what you actually got: orchestra install is not a thin composer create-project wrapper. It fetches the skeleton and runs provisioning — environment/dependency checks, database configuration, migrations, admin user creation, core extension registration and asset publishing, and (as of v5.2.0) authorization/ACL setup via AuthorizationCreated and schema creation via SchemaCreated. That provisioning is the package's entire value proposition, and it's the work you'd otherwise reproduce by hand.
Where to look first, in order:
README.md — command signature, options (--force, target path), prompt behavior.src/Console/ in the installer source — the actual subcommand bodies. This is ground truth; there is no standalone docs site for the installer.src/Installation/ — the provisioning steps and event dispatch sites, which is where the interesting logic lives.Practical first move: run it once into a throwaway directory inside a container or VM and read the console transcript line by line. That transcript is the best documentation available of what the installer did to your machine — which files it wrote, which migrations it ran, which extensions it registered.
Set expectations for "day-to-day." The installer itself runs maybe once per project. Your day-to-day is the scaffolded app: php artisan, composer require, migrations, the admin UI. The installer earns its keep by removing a few days of bootstrap work, not by being a thing you invoke repeatedly.
Scaffold once, commit the result, never run it again on that repo. Treat it as a bootstrapper, not a build step. Immediately after orchestra install, git init and commit the unmodified scaffold as your baseline. That commit is your diff anchor for every customization that follows, and it's your escape hatch if the installer later rots. Regenerating the scaffold in CI is an anti-pattern — it couples your build to a zero-adoption global binary and to upstream skeleton drift.
Pin and document a four-way version matrix. composer global require grabs latest by default; don't let it.
composer global require orchestra/installer:^5.2
Record, in the generated project's README: exact installer version, PHP version, Laravel version, and Orchestra Platform version. The installer picks the skeleton version for you, so a stale installer silently gives you a stale skeleton — and a stale skeleton against your local PHP/Laravel produces cryptic Composer resolution errors that look like installer bugs but are constraint failures. This matrix is cheap to write and saves hours.
Hook provisioning through the two v5.2.0 events. AuthorizationCreated and SchemaCreated are the supported extension points for post-install customization — org default roles, extra permissions, additional migrations, reference data:
Event::listen(
\Orchestra\Installation\Events\AuthorizationCreated::class,
fn ($event) => /* attach default roles / seed ACL entries */
);
Event::listen(
\Orchestra\Installation\Events\SchemaCreated::class,
fn ($event) => /* post-schema migrations or seeders */
);
Register these in something loaded during install — an internal starter template or a provider the installer boots — not in code you expect to execute at runtime repeatedly. This is scaffold customization, not application behavior.
Script the whole flow for repeatable demos and workshops. Any laptop should produce the same app:
#!/usr/bin/env bash
set -euo pipefail
composer global require orchestra/installer:^5.2
rm -rf /tmp/demo-app
orchestra install /tmp/demo-app --force
cp .env.demo /tmp/demo-app/.env
cd /tmp/demo-app && php artisan migrate --seed && php artisan serve
Adapt .env.demo values to whatever the prompts would have asked for, so the interactive step is either satisfied by defaults or skippable.
Post-scaffold, it's plain Laravel — use your normal tooling. The generated project is a standard Laravel app: Artisan, Composer, Sail, Pest/PHPUnit, your usual CI templates all work unchanged. Drop in your .env, composer require your own packages, run php artisan migrate --seed, register your own service providers. The installer gives you a different skeleton; it doesn't lock you into a different workflow. This is where most of your day-to-day leverage actually comes from — the scaffold is a starting point, not a framework you write against.
Prefer pre-seeded .env over fighting prompts for non-interactive runs. The installer prompts for database credentials and admin user details, and no --no-interaction mode is documented. To run headless, prepopulate the target .env before invoking so prompts take defaults — and verify against the command signature in src/Console/ before betting a pipeline on it. The safer pattern by far: run once locally, commit the scaffold, never run the installer in CI.
Audit the generated composer.json after scaffolding. If orchestra/installer appears in require or even require-dev, something went wrong. It's a one-time developer tool, never a runtime dependency. Make this a checklist item in your scaffold commit.
Extend through the platform, not the installer. Custom admin resources, extensions, asset publishing, and CRUD surfaces are Orchestra Platform concerns — handled in the generated app via standard Laravel/Orchestra extension registration. Reach for the installer only when you need something to happen during provisioning; reach for the platform for everything after.
The biggest trap: composer create-project is not equivalent. Coming from vanilla Laravel habits you'll assume you can skip the installer and just composer create-project orchestra/platform. You can't — not without reproducing the provisioning yourself. The AuthorizationCreated and SchemaCreated steps simply don't happen, so you get an app missing its ACL and schema setup, and the failure surfaces later as confusing runtime permission errors rather than an obvious install failure. Either use the installer, or replicate those steps from source.
Zero dependents means zero safety net. No Stack Overflow corpus, no blog posts on the v5.2.0 events, no third-party fixes. When it breaks, your options are: read src/Installation/, read the event handlers, or file an issue and wait. Budget debugging time accordingly, and don't put it on a critical path.
The database must be reachable before you start. The installer prompts for credentials and immediately runs migrations and seeding. Have the DB up, a clean schema, and migration permissions ready. Half-completed installs leave orphaned databases and stray .env files to clean up by hand.
--force overwrites without mercy, and there's no dry run. The installer wants an empty target directory. Never point it at anything you care about — not a repo with uncommitted work, not a directory holding sample data you wanted to keep.
Failure recovery is entirely manual. If it dies mid-way — composer step, migration step, admin user creation — there is no documented resume and no persisted internal state between steps. Recovery is: delete the partial directory, check for stray .env files and leftover databases, start over. Don't try to pick up where it stopped.
Debugging order: read the console, then read the platform. The installer prints each provisioning step, so the failing step is usually obvious from the transcript. But the fix almost always lives in the platform docs or source, not the installer's — the installer is orchestration; the interesting logic is downstream. Don't spend an afternoon in the wrong repo.
The extension surface is exactly two events. Beyond AuthorizationCreated and SchemaCreated there is no plugin system, no config file, no pluggable providers. If you need different behavior, fork the installer or post-process the generated app. Don't go hunting for extension points that aren't there.
Install it in a container or dedicated VM, not your workstation. It runs with your user's privileges, hits the network, and writes to your database including ACL provisioning. That's a supply-chain surface you don't want on a machine holding production credentials. Prefer composer global require over any curl | bash convenience script on principle.
Don't confuse installer friction with platform friction. PHP/Laravel version constraints, prompt ergonomics, lacking CI mode — these are installer problems, and they're cheap to work around (pin, containerize, commit the scaffold). Whether the platform fits is a separate question you should evaluate after you have it running, not before.
Document your fallback path — the highest-value artifact from any spike. Write the runbook for scaffolding a new project after the installer goes stale: the manual composer create-project steps plus a reproduction of the authorization and schema provisioning. A zero-adoption tool with no community behind it will eventually rot against a newer PHP or Laravel; that runbook is what keeps onboarding working when it does.
How can I help you explore Laravel packages today?