docs / Getting started
Getting started
Three commands from a normal Laravel app: install, compile, deploy. The compile step gives you a verdict before anything reaches Cloudflare.
Requirements
Laravel is the source of truth and stays untouched; PHP is needed only while the build runs. Nothing else has to be installed globally — wrangler is reached throughnpx (a local or global Wrangler wins instead).
| component | tested with | requirement |
|---|---|---|
| Laravel | 13.37.0, 11.34.2 | ≥ 10 |
| PHP (build time only) | 8.3.30 | ≥ 8.3; the parity oracle is 8.3.30 |
| Node | 22.18.0 | ≥ 22 |
| Bun | 1.4.0 | ≥ 1.0 (the suite passes under Bun) |
| Composer | — | not required: vendor-lite provisions the vendor tree from composer.lock |
| Wrangler | 4.151.1 | 4.x, run through npx; not bundled |
| PHP extensions | pdo_sqlite, sqlite3 | build only, for the schema compiler |
The first build
Run it from the app root (the directory with artisan). --strict is the honest mode: a route the compiler cannot serve fails the build instead of shipping a different answer than Laravel would.
# in a real Laravel app (vendor + public/build there)
npm i -D laravel-workers
npx laravel-workers build --strict # compile only → dist/
npx laravel-workers deploy # build, then D1 (+ deploy) on request
npx laravel-workers deploy --plan --mode 3 --d1-auto # preview; changes nothingThe build writes dist/: the Worker module, the router, the compiled config and views, the D1 schema, the cron list and the frontend build. A cache hit (unchanged inputs) skips every Laravel boot and restores dist/ in about a second; CI should pass--no-cache instead, because a cache hit prints no READINESS block.
$ npx laravel-workers build --strict … schema → snapshots → views → metadata → controllers READINESS: RUNS ON THE EDGE every route is served by a compiled handler, a snapshot or a port; no route is ignored, and no binding is missing.
What the build does for you
| normally | in this toolchain |
|---|---|
| composer install | vendor-lite reads composer.lock, fetches dist zips from packagist, writes its own autoloader and Laravel's vendor/composer/installed.json so package discovery still works. Content-addressed cache: paid once per lock. |
| migrate against a real database | tools/schema-compile.php boots the app, migrates an in-memory SQLite and dumps the DDL via pragma. Your database/ is never touched; the output is D1-ready. |
| key:generate | a base64: key is written into .env when missing, and stays stable across rebuilds — the worker encrypts cookies with it. |
| wrangler.jsonc | scaffolded when absent (worker name from the app-directory slug, a placeholder D1 id); init writes a fuller config when you want one. |
The first deploy
deploy asks only what it cannot decide — mode, worker name, database — and every prompt has a default you can accept with Enter. Preview it first: --plan uses the same resolver and the same safety decisions, but writes nothing and makes no Cloudflare call unless you add --check.
A failed build touches nothing on Cloudflare. After a successful run the URL, the worker name and the D1 id are recorded in lw-state.json inside the app, so the second deploy is short. The deploy guide covers the schema guard, the account guard and the flags.
Where to go next
- CLI reference — every command, flag and exit code.
- Routes & ports — what
--strictenforces and how a port replaces a route. - Limits — what does not run at the edge, and the escape hatch.
- Compatibility — all 105 Laravel documentation pages, with a verdict.
- The audit — the construct census behind the coverage claims.
Source: README.md §Quick start, §Requirements, §Zero-touch — repository ba1e9a5 (laravel-workers 0.4.10)