Laravel + Vue Starter Kit: Docker-verified fork
We took the official laravel/vue-starter-kit (Inertia + Vue 3 + shadcn-vue + Fortify), ran it inside Docker, and published a production-hardened fork with the complete diff on GitHub. The finding set matches the React Starter Kit's, by des…
Verification environment
- PHP 8.5.5
- Laravel 13.5.0
- Composer 2.9.7
- Node 22.22.2
- npm 10.9.7
- Frontend Vue 3 (Composition API) + Inertia
- Database SQLite (tests)
- OS Docker Desktop (php:8.5-cli-bookworm)
Laravel + Vue Starter Kit: Docker-verified fork
We took the official laravel/vue-starter-kit (Inertia + Vue 3 + shadcn-vue + Fortify), ran it inside Docker, and published a production-hardened fork with the complete diff on GitHub. The finding set matches the React Starter Kit's, by design — the Laravel backend is shared between the official starter kits — giving 8 commits on top of upstream and lifting the test suite from 40 passed to 44 passed / 151 assertions. This article is a standalone log of the Vue fork so Vue-focused readers don't have to cross-reference the React article.
Sister articles:
- Laravel + React Starter Kit: Docker-verified fork — same backend, same findings
- Laravel + Livewire Starter Kit: Docker-verified fork — different frontend, some findings diverge
Target
| Field | Value |
|---|---|
| Name | Laravel + Vue Starter Kit |
| Official URL | https://github.com/laravel/vue-starter-kit |
| Stack | Laravel 13 + Inertia + Vue 3 (Composition API) + shadcn-vue + Fortify |
| Upstream license | MIT |
| Improvement license | MIT |
Verification date
2026-04-19
Environment
All steps ran inside a Docker Desktop container (CodeLift spec §5-6).
| Item | Value |
|---|---|
| Base image | php:8.5-cli-bookworm + Node 22 |
| PHP | 8.5.5 |
| Laravel Framework | 13.5.0 |
| Composer | 2.9.7 |
| Node / npm | 22.22.2 / 10.9.7 |
| Frontend | Vue 3 (Composition API) + Inertia |
| Test DB | SQLite |
| Upstream commit | laravel/vue-starter-kit@1233a92 |
Baseline
docker compose run --rm app on upstream main: 40 passed (136 assertions), 22.99s. Vite build clean. Solid template, same quality as the React variant.
Given the Laravel backend is shared across the starter kits, every finding below lands in essentially the same file for both repos. Honest framing: these are the same issues, ported to this fork — because the Vue team needs the diff on its own upstream to be able to take it.
Improvements
Long-form rationale lives in the React sister article. This article lists the Vue-side changes directly.
A. npm run build fails opaquely when run before composer install
@laravel/vite-plugin-wayfinder shells out to php artisan wayfinder:generate. Without Composer deps, artisan can't boot. Error doesn't name composer install. Same as React.
Fix: Setup section in README.
B. .env.example ships dev defaults with no production hints
APP_DEBUG=true, LOG_LEVEL=debug, SESSION_ENCRYPT=false, no SESSION_SECURE_COOKIE.
Fix: inline comments showing the production-recommended values.
C. config/app.php hardcodes the timezone
config/app.php:68 is 'timezone' => 'UTC'. APP_TIMEZONE has no effect.
Fix:
- 'timezone' => 'UTC',
+ 'timezone' => env('APP_TIMEZONE', 'UTC'),
D. No security response headers in the middleware stack
bootstrap/app.php appends only HandleAppearance, HandleInertiaRequests, AddLinkHeadersForPreloadedAssets. No CSP / HSTS / X-Content-Type-Options / X-Frame-Options / Referrer-Policy / Permissions-Policy.
Fix: new SetSecurityHeaders middleware appended to the web stack.
- Always on:
X-Content-Type-Options: nosniff,X-Frame-Options: SAMEORIGIN,Referrer-Policy: strict-origin-when-cross-origin,Permissions-Policy: camera=(), microphone=(), geolocation=() - Production only:
Strict-Transport-Security: max-age=31536000; includeSubDomainsplus a CSP tuned for Inertia + Vite-built assets.
CSP keeps 'unsafe-inline' in script-src — this is the same in Vue and React because Inertia inlines initial props into a <script> tag regardless of the frontend framework. Moving to a nonce-based CSP means changes in HandleInertiaRequests; out of scope here.
New test: tests/Feature/SecurityHeadersTest.php — 2 assertions.
E. No HTTPS scheme enforcement helper
Repo-wide grep for forceScheme, forceHttps, TrustProxies returns zero matches. Proxies that terminate TLS and forward plain http:// make Laravel generate http:// URLs.
Fix: three lines in AppServiceProvider::configureDefaults, guarded by isProduction().
if (app()->isProduction()) {
URL::forceScheme('https');
}
F. Password rules — already handled upstream
Same as the React variant: AppServiceProvider::configureDefaults installs strong Password::defaults in production (min 12, mixed case, numbers, symbols, uncompromised()). No change. Documenting it so readers don't re-flag it.
G. Login rate limiter keys on email + IP only
Single-layer limit — IP rotation bypasses.
Fix: two-layer limit.
return [
Limit::perMinute(5)->by($email.'|'.$ip), // burst guard
Limit::perHour(20)->by('login-account|'.$email), // account cumulative
];
H. Two-factor auth is available but not policy-enforced
Fortify feature enabled with full UI and tests. No admin-forced 2FA, no reminder banner. Design decision, not a defect. No code change.
I. All logs interleave into a single channel
config/logging.php ships the default stack → single layout. Auth events interleave with queries and app logs.
Fix — two files:
config/logging.php: addauthchannel (daily, 90-day retention, env-tunable).app/Listeners/AuthActivitySubscriber.php: new subscriber, registered viaEvent::subscribeinAppServiceProvider::boot. Subscribes toIlluminate\Auth\Events\Registered|Login|Logout|Failed|PasswordReset+ Fortify 2FA enable/disable. Structuredinforecords withuser_id,email,ip,user_agent.
New test: tests/Feature/Auth/AuthLoggingTest.php — 2 assertions.
J. Only the password endpoint carries an explicit settings throttle
routes/settings.php throttles only settings/password. profile.update and profile.destroy fall back to framework defaults.
Fix: throttle:10,1 on profile update, throttle:3,1 on profile destroy (account deletion is terminal).
Before / after
| Dimension | Official | Improved |
|---|---|---|
php artisan test |
40 passed / 136 assertions | 44 passed / 151 assertions |
| Setup-order documentation | None | README Setup section |
Production hints in .env.example |
None | Inline comments |
APP_TIMEZONE takes effect |
No (hardcoded) | Yes |
| Baseline security headers | None | 4 always-on + HSTS / CSP in production |
| HTTPS scheme forcing | None | Production-only URL::forceScheme('https') |
| Login rate limit | Email + IP | Email + IP and email-only |
| Auth event logging | Mixed in default log | Dedicated auth daily channel |
| Settings endpoint rate limit | Password only | + profile update / destroy |
When this improvement fits
- You're starting a new production product on top of
laravel/vue-starter-kitand want the security + observability floor set before shipping features. - You already scaffolded and want a cherry-pickable production-hardening checklist.
- You're deciding between Vue and React starter kits: the backend hardening cost is the same for both. Pick by frontend preference, not by what's missing here.
Choosing between Vue and React variants
The Laravel-side production work is identical. Pick the starter based on team familiarity, component library taste, and hiring signal. (A follow-up comparison article will put React / Vue / Livewire starters side-by-side on production readiness.)
Reproducing and adopting
Improvement branch: codelift-dev/vue-starter-kit#improvements.
git clone https://github.com/codelift-dev/vue-starter-kit.git
cd vue-starter-kit
git checkout improvements
docker compose -f codelift/docker-compose.yml build
docker compose -f codelift/docker-compose.yml run --rm app
Application-level diff only (excluding the CodeLift codelift/ directory):
git diff main improvements -- . ':!codelift'
Each finding is a standalone commit, cherry-pickable.
License
- Upstream: MIT (Laravel LLC and contributors)
- Improvement: MIT (CodeLift / JIT Inc.)
Findings reflect the state on the verification date; upstream may change.
Featured in comparisons
Related articles
- Laravel + React Starter Kit: Docker-verified fork We took the official laravel/react-starter-kit (Inertia + React 19 + shadcn/ui + Fortify), ran it inside Docker Desktop to observe its actual behavior, and published a production-hardened fork with the complete commit-by-commit diff on Git…
- Laravel + Livewire Starter Kit: Docker-verified fork We took the official laravel/livewire-starter-kit (Livewire v4 + Flux + Alpine), ran it inside Docker, and published a production-hardened fork with the complete diff on GitHub. Upstream starts at 33 passed; the improved branch reaches 37 …