tightenco/mise
Mise, from Tighten, is a Laravel package that helps you get your application's environment in place, offering simple Artisan commands and sensible defaults for preparing and managing project setup so new and existing apps stay consistent and ready to develop.
Mise is a global CLI, not an application dependency — you don't composer require it into a project. Install it once per machine and it becomes a "recipe runner" you point at any Laravel app.
composer global require tightenco/mise
# ensure the global bin dir is on your PATH, e.g. ~/.composer/vendor/bin or ~/.config/composer/vendor/bin
cd ~/code/my-laravel-app
mise
The first-run flow: Mise detects you're inside a Laravel project, lists the available recipes, prompts you to pick one, asks any recipe-specific questions, then writes files / patches strings / runs shell commands. There is no service provider, no config file in your app, and nothing to uninstall afterwards.
Where to look first
mise --help and mise --version — confirm the binary resolves and see the actual subcommands your pinned version exposes.recipes/ directory (or the recipes repo referenced in the README) — read the JSON of the recipe you intend to run before running it. That file is the entire contract: it tells you exactly which files get overwritten and which shell commands execute.git status immediately after a run — Mise's output is a diff, and reviewing it is the whole safety model.First useful use case: pick a single, low-risk recipe on a throwaway branch of a real project — something that installs a dev tool (Pest, Pint, a CI workflow file) rather than one that restructures app/. That gives you a feel for the prompt ergonomics and the diff shape without betting a production codebase on an early-stage tool.
1. Treat recipes as reviewed, versioned setup scripts. The value proposition is that "how we set up a Laravel app" stops being tribal knowledge in a wiki and becomes an executable artifact. Author recipes in a repo your team controls (a fork of the upstream recipes, or a local directory if your Mise version supports pointing at one), and put them through PR review like any other code that touches every project.
2. A recipe per concern, not per project. Good granularity:
pest — require the package, publish tests/Pest.php, delete the PHPUnit example tests.pint — require, publish pint.json with your house style.github-actions — drop in .github/workflows/tests.yml, patched with the right PHP matrix.docker / sail — add compose files and a Makefile.Composability matters more than one mega-recipe, because projects diverge and a failed half-run of a 40-step recipe is miserable to unwind.
3. Recipe shape you'll be writing. Expect a JSON file with four kinds of operations — questions (rendered with Laravel Prompts), files (copy/download into the project), string replacements (patch composer.json, .env.example, service providers), and commands (shell). Sketch:
{
"name": "Install Pest",
"description": "Pest 3 with our base TestCase and arch tests",
"questions": [
{ "name": "arch", "type": "confirm", "message": "Add architecture tests?", "default": true }
],
"files": {
"tests/Pest.php": "stubs/Pest.php",
"tests/ArchTest.php": "stubs/ArchTest.php"
},
"commands": [
"composer require pestphp/pest pestphp/pest-plugin-laravel --dev --with-all-dependencies",
"php artisan pest:install --no-interaction"
]
}
Check the exact schema against the version you install — this is a young package and key names have moved.
4. Wrap it for onboarding and CI parity. Because the CLI is interactive, don't script it into CI directly. Instead, use Mise as the authoring tool: run the recipe by hand, review the diff, commit the result, and let CI use plain composer install. If you need non-interactive runs, push for flags or feed answers via the recipe's defaults rather than piping input into prompts.
5. Pair it with Laravel's native install:* commands. Anything the framework already ships (php artisan install:api, install:broadcasting, starter-kit conventions) should stay native; reserve recipes for the team-specific delta on top. Otherwise you're maintaining a fork of Laravel's own installers.
6. Pin it in your toolchain docs. Record tightenco/mise at an explicit version in your onboarding README or a mise-installing snippet in your dotfiles, so two developers don't run two different recipe interpreters against the same recipe file.
Nothing is transactional. A recipe is a sequence of file writes and shell commands with no rollback. If composer require fails on step 4, steps 1–3 have already mutated your project. Always run Mise on a clean working tree so git diff and git checkout -- . are your undo button. Make this a reflex, not a note in a doc.
Recipes are generally not idempotent. Re-running one typically re-executes composer require, re-downloads files (clobbering local edits), and re-appends strings. Don't run a recipe twice "to be sure." If you're authoring, guard appends where you can and assume overwrite semantics for files.
It executes arbitrary shell. A recipe sourced from the internet is a script from the internet with a friendly prompt in front of it. Read the JSON first, and be deliberate about which recipe sources you allow — this is a supply-chain surface, especially for a package with a small/no visible dependent base. Treat unknown recipes the way you'd treat curl | bash.
Interactive prompts block automation. Confirm/select questions require a TTY. Expect trouble in Docker builds, CI, and any scripted bootstrap. Bake answers into the recipe's defaults, or shell out to the underlying commands yourself.
Global install drift. composer global update will silently move you to a new Mise that may not understand your recipes. Pin the constraint ("tightenco/mise": "1.x-dev" or a caret on a known-good minor) and treat upgrades as a small migration.
Partial-state debugging. When something goes wrong, the useful artifacts are: the recipe JSON, the last command Mise printed, and git diff. Mise is thin — there's no log file to mine, so capture stdout. If a command inside the recipe fails, run that exact command manually to see the real error; Mise may only surface a truncated message.
Cross-platform shell assumptions. Recipe commands are run through the system shell. &&-chained commands, rm, and cp -r behave differently under Windows cmd. If your team is mixed-OS, prefer PHP/Artisan-based commands over POSIX shell in your own recipes.
Path assumptions. File destinations are relative to the project root, and many recipes assume a conventional Laravel skeleton. Non-standard layouts (domain folders, monorepos with the app in apps/web) will land files in odd places — inspect the diff, don't trust the summary.
Where to extend. The leverage point is the recipe catalog, not the tool: fork the recipes, add your house recipes, and keep Mise itself as an unmodified dependency. That keeps upgrades cheap and your opinions portable — and if Mise stalls, your recipes are still readable documentation of "how we set up a project," which is a much better exit ramp than a pile of bespoke shell scripts.
Overall posture: a genuinely nice idea — declarative, prompt-driven scaffolding — but with a thin adoption signal and no dependents, budget for the schema and CLI moving under you. Evaluate it on one internal starter project before making it the official onboarding path.
How can I help you explore Laravel packages today?