A native local development environment in Rust.
Grove serves *.test domains with automatic routing, local HTTPS, multi-version
PHP and zero external dependencies — from a single Rust core.
Local PHP/Laravel development today means choosing between friction points:
- Laravel Valet is elegant and light, but macOS-only and leans on Homebrew + Composer + dnsmasq.
- Herd ships static binaries but is closed, won't let you load custom PHP extensions, and gates databases, mail testing and dumps behind a Pro license.
- Docker / Sail is flexible but heavy and slow for simple local work.
Grove takes a different path: one Rust codebase, three platforms, and nothing to install around it.
| Valet | Herd | Docker/Sail | Grove | |
|---|---|---|---|---|
| Cross-platform | macOS only | macOS + Win | ✅ | ✅ |
| No Homebrew/Composer/dnsmasq | ❌ | ✅ | ➖ | ✅ |
| Custom / bring-your-own PHP | ✅ | ❌ | ✅ | ✅ |
| Full extension set (intl, mysqli, pdo_sqlite…) | ➖ | ➖ | ✅ | ✅ |
| Bundled static PHP | ❌ | ✅ | ➖ | ✅ |
| Idle footprint | tiny | small | heavy | tiny |
| Open / no license wall | ✅ | ❌ | ✅ | ✅ |
- 🌐 Automatic
*.testrouting via an embedded DNS resolver — no manual hosts editing. - 🔒 Local HTTPS with a private root CA and on-demand per-site leaf certificates.
- 🐘 Bundled PHP, with the extensions you actually need — install multiple self-contained versions (
grove php install 8.5|8.4|8.3), with per-siteisolateand lazy FPM pools. The prebuilt static-PHP sets each have a hole — one lackspdo_sqlite/pdo_pgsql, the other lacksintl/mysqli— so Grove builds the union itself: both PDO drivers andintl,mysqli,sodium,readline,apcu,xsl.grove php extaudits any build and tells you what each gap would cost you. - 🐞 Step-debugging —
grove debug onloads Xdebug into the FPM pools (trigger mode, zero idle overhead) so a DAP-capable editor can set breakpoints;grove debug envwires up CLI debugging (artisan, tests). - ⬢ Bundled Node.js — download node · npm · npx, with per-site Node versions; no nvm or Homebrew.
- 🗄️ Bundled services — Grove downloads and supervises PostgreSQL, MySQL, ElyraSQL and Redis itself, so there is no database/cache or Homebrew to install separately. ElyraSQL is a single-binary, single-file MySQL-compatible server: your Laravel
.envsaysDB_CONNECTION=mysqland nothing else changes. - 📧 Built-in mail-catcher — an SMTP server that captures outgoing mail, with a Mailpit-style viewer.
- 🌍 Public tunnels —
grove shareexposes a local site to the internet (demos, webhooks) via a self-hostable, native Expose/ngrok alternative. - 📦 Reproducible environments — commit a
grove.toml(PHP/Node versions, services, HTTPS, dev), and a teammate goes fromgit cloneto a running, identical setup with onegrove up. Or package the whole thing — config,.env, and database — into one shareable file withgrove bundle export(no Docker). - ⇄ Request timeline, replay & test-gen — Grove is the proxy, so it records a live, framework-agnostic log of every request. Expand any request to see headers + body — credentials redacted, since the same data goes to your AI assistant over MCP — replay it (
grove replay <id>, which uses the unredacted capture so it still works), or copy it as a curl/.http/Pest test — turn a failing request into a regression test in one click. - 🔗 Causal chain — turn on
grove sql-captureand each request shows the SQL it issued and the mail it sent within its time window, plus derived metrics — "this 500 also ran 20 queries and sent an email" — with zero app instrumentation. Surfaced over MCP (grove_request_chain). - ✨ Explain this error —
grove explain <id>(and thegrove_explainMCP tool, plus an Explain button in the app) curate one bundle — the request, its causal chain, and the matching stacktrace from the Laravel log — ready to hand to your AI assistant. - 🪝 Local webhook hub — capture incoming webhooks at
/__grove/hooks/<bucket>(a local webhook.site), expose them withgrove share, inspect each payload, and re-deliver them to your app while you fix the handler. Herd catches mail; Grove catches webhooks too. - 🌿 Another branch beside yours —
grove try <branch>checks the branch out in a worktree, serves it at<site>--<branch>.testwith its own copy of your database, and migrates that copy. Your checkout and your database stay as they were.grove try --donetakes it all away. - 🔍 Which commit broke this request? —
grove bisect --good <ref> --request <id>replays a recorded request against each commit, each checked out beside yours with a fresh, migrated database, and letsgit bisectname the first bad one. - 🔁 Replay against the same data —
grove replay <id> --same-datasnapshots the site's database on the first run and restores it before every later one, so a request that writes can be retried from the same starting point. - 🐢 Which route got slower —
grove routeskeeps each route's typical time and flags the ones that got at least twice as slow, with a request id to look at. - 🤖 AI tools (MCP) —
grove mcpexposes your sites, requests, webhooks, logs, route timings and database schema to Claude/Cursor over the Model Context Protocol. Local-only and read-only by default. Ask your assistant "what did the last 500 look like?" or "show me theordersschema." With--allow-write, an agent can also open a sandbox: its own branch, site and database copy to work in, with nothing touching yours. - 🛠 Tools — migrate MySQL from Herd, and convert whole databases between MySQL, ElyraSQL, PostgreSQL and SQLite.
- ⏱️ Database snapshots —
grove db snapshottakes a point-in-time snapshot of the bundled MySQL/PostgreSQL (a SQL dump) or ElyraSQL (a hot copy of its one database file) andgrove db restorerolls it back, so risky migrations are fearless. - 🌳 A database per git branch —
grove db branches ongives each branch its own database and swaps it in when you check the branch out. - 💤 Databases that run only when used —
grove service on-demand mysql onholds the port and starts the server on the first connection. It starts as soon as a site that uses it is looked up, and stops again after it has sat idle. - 🔀 Toolchain on your PATH —
grove path installputs the bundledphp,composer,cpx,node,npmandlaravelon your PATH, auto-switching to each project's pinned version — so you can drop Herd/Valet entirely. - 📦
cpxbuilt in — npx for Composer packages:cpx laravel/pint,cpx phpstan analyse,cpx friendsofphp/php-cs-fixer fixrun a package's CLI without installing it in your project or globally.cpx exec -r '…'andcpx tinkerrun ad-hoc PHP with your app booted. Shipped as a shim over Grove's own PHP — nothing tocomposer global require. - 🐳 Docker / OrbStack aware — auto-discovers containers and serves them as
<name>.testwith trusted local HTTPS, next to native sites. - ⚡ Runs your dev processes —
grove devreads the processes your app declares via Laravel'sDevCommands(artisan dev:list) and supervises them per site — Vite HMR, queue worker, and your own additions like Reverb orstripe listen. It skipsserve(Grove is the server) andpail(the Logs panel), needs no open terminal, and falls back to Vite + a queue worker on older Laravel or non-Laravel sites. Use it instead ofphp artisan dev, not alongside it. - 🧩 Driver system — Laravel, WordPress, generic PHP, static sites, and reverse proxy (Vite/Node).
- 🌊 Streaming both ways — responses are forwarded as PHP flushes them, so Server-Sent Events and long-lived streams work, and a large download costs no memory. Uploads stream too: a 400 MB upload moves through Grove in a few MB of RSS rather than a gigabyte.
- 🚀 Nothing done twice — proxied requests reuse pooled connections instead of handshaking per asset, static files revalidate with an
ETag(a reload of unchanged assets costs a304, not a re-transfer), and DNS answers are cacheable so the system resolver stops asking on every connection. - 🛡 Built to stay up — a panic in one request stays in that request, the accept loop backs off instead of spinning a core when file descriptors run out, and silent connections are timed out rather than held forever.
- 🌱 Create / import sites — scaffold a new Laravel or static project, or link existing ones.
- 🖥️ GUI + CLI in parity — both are thin clients over the same daemon, plus a macOS menu-bar icon.
- 🔌 Zero external dependencies — DNS, proxy, FastCGI and TLS are all built in.
Grove has no runtime dependency on Homebrew, Composer, dnsmasq, OpenSSL or
Laravel Valet. DNS, the reverse proxy, FastCGI and TLS are all built into the
Rust core. Even PHP can be downloaded as a self-contained static binary via
grove php install — it links only against the operating system's own
libraries. grove import reads an existing Valet config if one is present,
but it never requires Valet to be installed.
📘 New here? Read the full installation guide — a step-by-step manual with example terminal output, a first site, HTTPS, services and troubleshooting.
# 1. First-run setup: config, root CA, a static PHP build, resolver + trust
sudo grove init
# 2. Install the background service (launchd/systemd binds 80/443/53 and hands
# them to a daemon that runs as you; starts at boot)
sudo grove install
# 3. Point Grove at your projects
grove park ~/Code # every subdirectory becomes <name>.test
# or, inside one project:
grove link
# 4. Open https://myproject.test 🎉
grove secure myproject # enable HTTPS
grove isolate myproject 8.3 # pin a PHP version for this siteThe daemon binds privileged ports (53/80/443) and runs PHP as your user, so it is installed as a root service.
sudo grove startworks too for a foreground/one-off run.
From a clean machine to a running *.test Laravel app in under five minutes —
no Homebrew, no Composer, no Valet.
| Category | Commands |
|---|---|
| Setup | init, ca trust / ca uninstall, install / uninstall (service) |
| Lifecycle | daemon, start, stop, restart |
| Sites | new, up (from grove.toml), park / unpark, link / unlink, list, secure / unsecure, isolate / unisolate, proxy |
| PHP | php install, php register, php discover, php list, use |
| Node | node list, node install <version>, node use <site> <version>, node unuse <site> |
| Services | service list, service install, service start, service stop, service restart |
| Databases | db snapshot, db list, db restore <id>, db rm <id> |
| Observability | requests [site] (live request timeline), sql-capture on|off|status (SQL causal chain) |
| Toolchain | path install, path show, path uninstall |
| Dev | dev start [site], dev stop [site], dev list |
| Tunnels | share <site> (public URL via grove-tunnel server) |
mail, mail show <id>, mail clear |
|
| Logs | logs (list sources), logs <site> (view entries) |
| Operations | status, doctor, env [site], import (Valet) |
Every command supports --json for scripting and Elyra Conductor integration.
The GUI is a thin client that proxies everything to the daemon over the same
grove-ipc JSON-RPC the CLI uses — they are always in parity. The frontend is
Svelte 5 + Vite and shares the Elyra Conductor look & feel (Tokyo Night palette,
JetBrains Mono). The dashboard surfaces every site with its driver, PHP version,
a one-click HTTPS toggle, isolate, and shortcuts to open in the browser or
Finder, alongside service, mail, tunnels, tools, logs and doctor panels. The
Requests panel is a live, framework-agnostic timeline of every request Grove
proxies (status colour-coding, slow-request highlighting, per-site filter). The
Logs panel parses per-site Laravel logs and Grove's own service logs into a
level/date/message view with a stacktrace detail pane. A Settings panel (⌘,)
manages parked paths, the TLD, default PHP, the mail-catcher port,
launch-at-login and the theme (auto/light/dark).
# Build the frontend (the GUI binary embeds it at compile time)
cd crates/grove-gui/ui && pnpm install && pnpm build && cd -
# Build and launch
cargo build --release -p grove-cli -p grove-gui
grove gui # starts the daemon if needed, then opens the appAfter changing the UI, rebuild the frontend and grove-gui so the new bundle
is re-embedded. Closing the window keeps Grove running in the menu bar; quit via
the menu-bar icon.
Grove's source of truth is a single declarative TOML file
($GROVE_HOME/config.toml). Runtime state that can be re-derived is kept out of
it, so the file stays human-readable and diff-friendly.
[general]
tld = "test"
default_php = "8.5"
auto_start = true
[[parked]]
path = "~/Code"
[services]
mail_enabled = true
mail_port = 1025
[[sites]]
name = "inside-next"
path = "~/Code/inside-next"
php = "8.5" # per-site PHP
node = "22" # per-site Node
secure = true
driver = "laravel"
[[sites]]
name = "frontend"
path = "~/Code/frontend"
driver = "proxy"
proxy_to = "http://127.0.0.1:5173"A single long-running daemon binds the privileged ports (DNS 53, HTTP 80, HTTPS 443) and supervises the FPM pools. The CLI and GUI are thin clients that talk to the daemon over local IPC.
grove-core site registry, driver detection, config, paths (pure, no OS I/O)
grove-ipc JSON-RPC protocol + transport (CLI/GUI ↔ daemon)
grove-tls root CA + leaf issuance (rcgen/rustls)
grove-dns embedded resolver for *.<tld> (hickory)
grove-proxy HTTP/HTTPS proxy + minimal FastCGI client (hyper)
grove-runtime PHP version + FPM pool supervisor
grove-os platform integration (resolver, trust store, elevation)
grove-daemon long-running process: binds ports, serves IPC
grove-cli clap frontend (binary: `grove`)
grove-gui Tauri 2 + Svelte 5 desktop GUI (thin client over grove-ipc)
# Requirements: Rust 1.94+, and (for the GUI) Node 20+ with pnpm.
cargo build --release # build the CLI + daemon
cargo test # run the test suiteFor local testing without binding privileged ports, set an isolated home and high ports:
export GROVE_HOME=/tmp/grove-home
mkdir -p "$GROVE_HOME"
cat > "$GROVE_HOME/config.toml" <<'EOF'
[general]
tld = "test"
default_php = "8.5"
http_port = 8080
https_port = 8443
dns_port = 5354
[[parked]]
path = "~/Code"
EOF
grove daemonFrom 0.1.2 the macOS app is code-signed with a Developer ID and notarized
by Apple, so it opens normally — download the .dmg, drag Grove to
/Applications, and launch it. No Gatekeeper warning, no workarounds.
To actually serve *.test (which needs ports 53/80/443), install the background
service once: sudo grove install. The GUI is a dashboard over that daemon.
Apple Silicon only. Prebuilt macOS releases target
aarch64— notarizing the Intel build on GitHub'smacos-13runner routinely hangs, so it isn't shipped. On an Intel Mac, build from source:cargo build --release.
Everything above is free and open source, forever — the core is never gated. Grove Pro ($99/seat/year) unlocks power features on top:
- Database client — a built-in Database panel that auto-connects from each
site's
.env. Browsing +SELECTis free; Pro adds inline row editing, a schema inspector, and a production-safety guard. - End-to-end encrypted team secret sync (
grove secret) — a project's.envshared securely, never pasted into a chat window. Encrypted on your machine (age/X25519); the backend only ever stores ciphertext.
Licenses are verified offline. See Pro & Teams.
- Installation guide · Pro & Teams · Docker · Tunnels · Debugging · Architecture · Configuration · Commands · Testing · Security
- Changelog
Contributions are welcome! See CONTRIBUTING.md to get started, and please follow our Code of Conduct. For security issues, see SECURITY.md.

