Skip to content

Instantly share code, notes, and snippets.

@futzlarson
Last active April 21, 2026 19:41
Show Gist options
  • Select an option

  • Save futzlarson/39337421cdba693225d213da9efd0648 to your computer and use it in GitHub Desktop.

Select an option

Save futzlarson/39337421cdba693225d213da9efd0648 to your computer and use it in GitHub Desktop.
Vapor build: php artisan optimize caching wrong paths on all environments

Vapor php artisan optimize: original analysis was wrong

TL;DR

The previous version of this gist claimed php artisan optimize should be moved from build to deploy because cached views/routes contain wrong file paths. That's incorrect. Cached Blade views only contain path references in PHP comments (/**PATH ... ENDPATH**/), not in executable code. Laravel resolves paths dynamically at runtime.

Moving optimize to deploy actually breaks the deploy because Lambda's /var/task is read-only and event:cache/view:cache can't write there.

The standard Vapor template (optimize in build) is correct. Don't change it.

What php artisan optimize actually does

Runs four sub-commands:

  • config:cache → writes bootstrap/cache/config.php
  • route:cache → writes bootstrap/cache/routes-v7.php
  • event:cache → writes bootstrap/cache/events.php
  • view:cache → compiles Blade templates to storage/framework/views/

What Vapor does at runtime

Vapor's runtime stubs (vendor/laravel/vapor-core/stubs/{cli,fpm,octane}Runtime.php) re-run config:cache on every cold start:

$app->make(ConsoleKernelContract::class)->call('config:cache');

This overwrites whatever was cached at build time with correct runtime paths. Vapor also explicitly flushes config.php and routes-v7.php from bootstrap/cache during build (vendor/laravel/vapor-cli/src/BuildProcess/CopyApplicationToBuildPath.php:111), confirming this is intentional.

The same runtime stubs also remap Laravel's storage path to /tmp/storage on every cold start (cliRuntime.php:54-56):

StorageDirectories::create();
$app->useStoragePath(StorageDirectories::PATH);  // '/tmp/storage'

Vapor does NOT auto-handle: event cache or route cache. View cache is handled implicitly (see below).

Why these caches still work fine on Lambda

Cache Path-sensitive? Why it works
config.php Yes Re-cached at runtime by Vapor stub
routes-v7.php No References class names, not file paths
events.php No Class-to-listener mappings, no paths
Compiled Blade views N/A on Lambda CopyApplicationToBuildPath::flushStorageDirectories() deletes storage/framework/views/ from the build artifact (vendor/laravel/vapor-cli/src/BuildProcess/CopyApplicationToBuildPath.php:132). Views recompile on-demand at runtime into /tmp/storage/framework/views/ (Vapor remaps storage via $app->useStoragePath('/tmp/storage') in cliRuntime.php:54-56). Running view:cache in build is effectively a no-op — harmless, just slightly wasteful.

So runtime view caching on Vapor is per-container and lazy: first render of a template pays the compile cost once, then every subsequent request on that same container reuses the compiled file (Blade mtime-checks against the immutable source in /var/task). When the container is evicted, the next cold start starts empty again.

Why the deploy-step approach breaks

If you move php artisan optimize to deploy: in vapor.yml:

file_put_contents(/var/task/bootstrap/cache/events.php):
Failed to open stream: Read-only file system

Lambda mounts /var/task read-only. event:cache and view:cache can't write there. The deploy hook fails. Even if you wanted to override the cache paths via env vars (APP_EVENTS_CACHE, etc.) to point to /tmp, you'd lose the cache between invocations because /tmp isn't shared across containers.

FAQ: php artisan about shows "Views NOT CACHED" on production

Expected behavior, not a problem. When you run:

vapor command production --command="php artisan about"
  • Vapor spins up a fresh CLI Lambda container.
  • Runtime stub remaps storage to /tmp/storage/, which is empty on cold start.
  • Blade's view-cache inspector reads from storage_path('framework/views')/tmp/storage/framework/views/ — empty.
  • Result: "NOT CACHED".

You will essentially never see "CACHED" from this command on Vapor, regardless of how well caching is working in your FPM containers serving real traffic. The CLI container doesn't share /tmp with them.

Don't try to add view:cache to a deploy hook in response — /var/task is read-only, and the compiled views wouldn't survive the cold-start storage remap anyway. The status is cosmetic.

What about the original Sentry error?

The original gist cited this:

File does not exist at path /opt/homebrew/var/www/Care-Management/.vapor/build/app/
vendor/laravel/framework/src/Illuminate/Foundation/Configuration/../resources/health-up.blade.php

That's a separate issue — likely a missing view file or a Filament health-check resolution problem. It's not caused by view:cache.

Conclusion

Leave vapor.yml as-is:

build:
    - 'composer install --no-dev --optimize-autoloader'
    - 'php artisan optimize'         # ✅ Correct here
    - 'php artisan event:cache'
    - 'php artisan icons:cache'
    - 'php artisan filament:cache-components'
    - 'php artisan filament:assets'
    - 'npm ci && npm run build && rm -rf node_modules'
deploy:
    - 'php artisan migrate --force'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment