Grove · · 4 min read

Grove 0.6 — delete Herd, and stop fearing migrations

Grove 0.6 puts its bundled toolchain on your PATH with directory-aware version shims — so Herd and Valet can finally go — and adds instant database snapshots so you can run scary migrations without the knot in your stomach.

Grove 0.6 — delete Herd, and stop fearing migrations

There's a moment in every local setup's life where it graduates from "serves my sites" to "runs my whole day." Grove 0.6 is that graduation. Two features, both born from the same nagging feeling: why am I still doing this by hand?

The first lets you finally uninstall Herd and Valet for good. The second lets you run a scary migration without that little knot in your stomach. Let's take them in turn.

grove path — your toolchain, on your PATH, automatically

Grove has always bundled everything: PHP, Node, Composer, databases. But there was a gap. Grove used those bundled binaries to serve your sites — yet when you dropped into a terminal and typed php artisan, composer install, or npm run build, you were still leaning on whatever php some other tool had put on your PATH. Usually Herd's.

So Herd stayed installed. Not because you used its UI — just because it owned php and composer in your shell.

Grove 0.6 closes that gap:

$ grove path install
✓ Installed shims for php, composer, node, npm, npx, laravel.

Provisioning the bundled toolchain (php, composer, node)… ✓ provisioned toolchain: PHP 8.4 CLI, Composer, Node 22

Add Grove's toolchain to your PATH, then restart your shell:

echo 'export PATH="$HOME/Library/Application Support/Grove/shims:$PATH"' >> ~/.zshrc

Add that line, restart your shell, and now php, composer, node, npm, npx and laravel all come from Grove.

The clever bit: per-directory version switching

Here's what makes it more than a symlink. The shims are directory-aware. When you run php inside a project, Grove resolves the exact version that project pins — the one you set with grove isolate or grove node use — and falls back to your default everywhere else:

$ cd ~/Code/legacy-app        # pinned to PHP 8.1
$ php -v
PHP 8.1.29 (cli) ...

$ cd ~/Code/elyra-web # pinned to PHP 8.4 $ php -v PHP 8.4.10 (cli) ...

No .tool-versions, no mise activate, no shell hooks. Grove already knows which version each site runs, so the terminal just matches. It's the asdf experience with zero configuration, because the answer was already in Grove's registry.

How it stays safe

One architectural note, because it's the interesting part. Grove's daemon runs as root (it binds ports 80/443/53). So the runtimes it downloads live in a root-owned directory. The shims, though, run as you.

Rather than have your shell try to write into root-owned dirs (and fail), provisioning goes through the daemon — root downloads PHP, Composer and Node into the shared runtimes dir — and the shims are strictly read-only resolvers. They find what's there and exec it, replacing themselves so there's zero overhead and signals/exit codes pass through cleanly. Clean separation, no sudo in your daily loop.

And with that, Herd and Valet can go:

$ grove path install
$ # ...uninstall Herd / valet uninstall...
$ sudo grove install     # re-assert Grove's resolver + CA, just in case

grove db — snapshots, or: migrations without the knot

You know the feeling. You've written a migration that drops a column, or backfills a table, or renames something load-bearing. You run it on your local database — the one with three weeks of hand-crafted test data you'll never reproduce — and you hope.

Grove owns your database service. So it can do something no standalone CLI can do well: snapshot it, instantly, and roll back.

$ grove db snapshot --db myapp --note "before the big migration"
✓ snapshot 20260707-164708 created (mysql, myapp, 2173 bytes)

Now run the scary thing. If it goes sideways:

$ grove db restore 20260707-164708
✓ restored snapshot 20260707-164708 into mysql (myapp)

And your three weeks of data are back, exactly as they were. Here's the full loop, start to finish:

$ grove db snapshot --db myapp --note "pre-migrate"
✓ snapshot 20260707-164708 created (mysql, myapp, 2173 bytes)

$ php artisan migrate # ...and it eats your data...

$ grove db list 20260707-164708 mysql myapp 2 KB 2026-07-07 16:47:08 UTC — pre-migrate

$ grove db restore 20260707-164708 ✓ restored snapshot 20260707-164708 into mysql (myapp)

It works for PostgreSQL too (--engine postgres --db myapp), and for MySQL you can omit --db to snapshot everything at once. Snapshots are plain SQL dumps under $GROVE_HOME/snapshots/ with a small JSON index — nothing proprietary, nothing you can't read or grep. When you're done, grove db rm <id> cleans up.

Because Grove is the database supervisor, none of this needs connection strings or credentials. It knows where MySQL lives and which port it's on. You just say "snapshot," and it does.

The theme, again

If Grove 0.5 was about getting out of your way while you build (serving Vite over HTTPS, running your dev processes), 0.6 is about the two moments around building: setting up your terminal, and taking risks with your data.

Both used to involve another tool, a bit of ceremony, or a small prayer. Now they're one command each.

$ grove path install     # your toolchain, everywhere, auto-versioned
$ grove db snapshot      # a save point, whenever you want one

Grove auto-updates — after it relaunches, hit Tools → Restart daemon and both are live. Go delete Herd. Go run that migration. 🌱🌳

Next on the workbench: a zero-config request timeline (every request Grove proxies, with timings), and grove.toml + grove up for reproducible, one-command team environments.