Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Installer Laravel Package

getecz/laravel-installer

A Laravel installer package that streamlines scaffolding new applications, with an interactive CLI to set up projects quickly and consistently. A handy starting point for developers who want a fast, repeatable Laravel setup.

View on GitHub
Deep Wiki
Context7

Getting Started

The installer is a "post-deploy setup wizard": it gives a self-hosted install the same first-run experience as WordPress/Nextcloud — requirement checks → database config → migrations → admin account → finish — instead of asking users to edit .env by hand.

Minimal path to a running wizard:

composer require getecz/laravel-installer
php artisan vendor:publish --provider="Getecz\LaravelInstaller\InstallerServiceProvider"
php artisan migrate          # if the package ships its own state table

Then look here first, in this order:

  1. config/installer.php (published) — routes prefix, middleware, whether the wizard is gated, and the requirements list.
  2. routes/ inside the package (or php artisan route::list | grep install) — the actual step URLs, so you know what the wizard is really doing before you customize it.
  3. The published views (resources/views/vendor/installer/) — this is where 90% of your day-to-day customization happens.

First use case to wire up: guard the app until installation is complete. Typically you add the package's middleware to your web group (or a custom group) so unauthenticated/uninstalled requests are redirected to /install:

// bootstrap/app.php (Laravel 11/12)
->withMiddleware(function (Middleware $middleware) {
    $middleware->web(append: [
        \Getecz\LaravelInstaller\Http\Middleware\EnsureInstalled::class,
    ]);
})

Then visit /install on a fresh clone and walk the wizard end-to-end once on a throwaway database. That single pass tells you more than the README — you'll see exactly which files it writes and which artisan commands it shells out to.

Implementation Patterns

The "installed" flag is the contract. Most installers of this shape write a lock file (e.g. storage/installed or a settings row) plus a cached config value. Treat that flag as the single source of truth and read it in exactly one middleware — don't scatter if (installed()) checks through controllers.

Environment-aware gating. You almost never want the wizard live in local dev. Common pattern:

// config/installer.php
'enabled' => env('INSTALLER_ENABLED', !app()->environment('local')),

and short-circuit the middleware in local so php artisan serve never kicks you into a wizard you've already completed.

Docker / CI provisioning. For self-hosted apps shipped as images, split "wizard install" from "automated install":

  • Interactive: let users hit /install.
  • Automated: run the same steps as artisan commands in your entrypoint (php artisan migrate --force, seed admin from env, touch the lock file). Keep the wizard's underlying actions in services so your entrypoint and the wizard share code — otherwise you maintain two installers.

Customizing steps instead of forking. The maintainable pattern is: (a) publish views, (b) add your own extra step routes that live around the package rather than modifying it. E.g. add a "license key" or "SMTP test" step as a Laravel route that renders your own view and redirects back into the wizard's final step. Forking a 38-star package means you own every future Laravel 13 compatibility fix.

Post-install handoff. After the final step the wizard should: write/refresh .env → php artisan config:clear → php artisan key:generate --force (if not done) → migrate --force → seed admin → set the lock. Capture each as a discrete step with success/failure UI so a failed migration doesn't leave a half-installed app with a "done" flag.

Testing your install flow. In CI, add a job that boots a fresh container, POSTs through each wizard step, asserts you land on the dashboard, and asserts /install now 404s/redirects. This is the only reliable way to catch regressions when the package updates — you have zero dependents and 38 stars, so you are effectively the QA team.

Gotchas and Tips

  • .env writes fail silently. The wizard rewrites .env via file_put_contents; on read-only container filesystems or with wrong ownership it can appear to succeed while nothing changes. Check is_writable(base_path('.env')) in your requirements step and surface it explicitly.
  • env() returns stale values after the wizard writes .env. Once config is cached, env() returns null outside config files, and a fresh .env isn't re-read in the same request. Do config:clear / config:cache (via Artisan::call) after saving, and re-resolve the DB connection rather than trusting the booted config.
  • Database connection during the DB step. You can't just set DB_* env vars and continue — the connection was already resolved at boot. Pattern: accept the form, write .env, call config:clear, then DB::purge() and reconfigure at runtime to test the credentials before advancing.
  • Re-running the wizard is destructive. Without a hard lock, a second visit re-runs migrations/seeds and can reset the admin password or duplicate seed data. Guard with both a middleware check and a route-level abort_unless(!installed(), 404) — belt and suspenders, because middleware groups get edited.
  • APP_KEY rotation. If the wizard runs key:generate after you've already encrypted data (or sessions), you'll invalidate everything. Generate the key in the first step, before any DB writes, or require it to be pre-set in the deployment environment.
  • Storage symlink & permissions. php artisan storage:link and chmod -R on storage//bootstrap/cache are the two requirements that fail most often on shared hosting. Make them part of the requirements checklist rather than a migration step.
  • Behind a proxy / subdirectory. Route generation and asset URLs break if the app lives at /app behind nginx. Set ASSET_URL and TrustProxies before testing the wizard, or the "next" buttons will point at the wrong host.
  • Don't trust the requirements list. It reflects the author's PHP config. Add your own checks (extensions you actually use: pdo_mysql, gd, intl, redis) via the package's callback/hook if it exposes one — otherwise prepend a check in your own view.
  • No dependents means no ecosystem. Pin the version in composer.json ("getecz/laravel-installer": "^1.0") and read the diff on every bump; a small package like this can change route names or the lock-file location between minor releases, and your middleware will silently stop gating.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource