Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Static Laravel Package

backstage/laravel-static

Backstage Laravel Static helps you add static content and prebuilt HTML pages to Laravel apps, combining fast, cache-friendly delivery with familiar routing, views, and Artisan workflows.

View on GitHub
Deep Wiki
Context7

Getting Started

Install with composer require backstagephp/laravel-static, publish the package config, and attach the package middleware (or per-route opt-in — check the README for the exact class/tag names, as they change pre-1.0) to the routes you want cached. Cached files are written per-URI to the configured local disk.

Look first at three things:

  1. The published config — this is where the disk, compression, and cache-growth levers live, and it's exactly what static:status prints back to you, so the numbers and the knobs are on one screen.
  2. php artisan static:status — new in v0.11.0. Run it before and after warming the cache; it's the fastest way to see what is actually on disk.
  3. php artisan route:list — decide which routes are safe to cache (GET, no session/auth-dependent output) before turning the middleware loose.

First use case: cache one marketing or blog page, hit it, then run static:status. Now append ?utm_source=test to the URL, request it again, and re-run the command. You'll watch a new file appear as its own cached page. That single exercise explains the majority of "why is my static cache huge" incidents.

Implementation Patterns

Cache-then-measure loop. Treat warming and static:status as a pair. Warm the routes, read the status output, and only then decide whether to enable compression or prune. The command is cheap and read-only; there is no reason to guess.

Query-string discipline at the edge. Because a file is written per-URI including the query string, any page that accepts tracking parameters (utm_*, fbclid, gclid) will slowly multiply. Two patterns work well:

  • Strip or canonicalize tracking parameters at the web-server / middleware layer before the cache sees them, so variants never get written.
  • Accept the variants but schedule static:clear --only-with-query-strings (with --disk= and, if you want to be selective, --limit=) on a cron. The status output's "top URLs by cached variants" and "most common query parameters" tables tell you exactly which parameter to add to your strip list.

Compression is a size lever, not a page-count lever. Enabling gzip/brotli adds compressed siblings on disk (which count toward size) but not toward the page count. That distinction is deliberate in the status output — it means turning compression on will never read as cache growth, so you can enable it without invalidating your monitoring baselines.

Monitoring and alerting. Use static:status --json from a scheduled command or an external check, and alert on size on disk or on the query-string-variant ratio (the WARN line in human output). Pair the alert with the pruning command so a threshold breach has an automated response. The JSON output is stable enough for a disk-usage probe; the human output is for humans.

Multi-disk setups. static:status --disk= inspects a specific disk, while static:clear --only-with-query-strings scopes the prune. If you cache tenant sites or multiple content types on separate disks, run status per disk in your dashboard rather than aggregating — the per-host breakdown in the status output can conflate tenants that share a disk.

Extension point: scheduled maintenance. A sensible default is a nightly static:status --json (log the numbers) plus a weekly or size-triggered static:clear --only-with-query-strings. This keeps the cache from silently accumulating newsletter/bot variants without you needing to remember to check.

Gotchas and Tips

  • Nothing is evicted automatically. The cache only shrinks on static:clear. There is no LRU/TTL eviction built into what this release describes — file age distribution is reported, not enforced. If you need bounded growth, you have to schedule the prune yourself.
  • The variant multiplication is the whole story. In the example, 17 cached pages came from 11 distinct URLs — the gap is entirely query strings. Before you blame page content or image size, run status; if a parameter table leads with utm_source or fbclid, prune first, optimize later.
  • --only-with-query-strings is the safe prune. It reclaims the variant space while leaving your canonical, parameter-free pages intact — the pages you'd have to re-warm. Prefer it over a full static:clear whenever the cause is tracking parameters.
  • du-style output collapses pass-through levels. Large-directory totals are cumulative with single-entry intermediate directories folded away, so a directory with one huge subdirectory shows up at the top rather than its child — don't misread a collapsed level as a single directory of that size.
  • Compressed siblings are excluded from the page count. If you're reconciling "pages" against your route count and seeing a mismatch, this is usually why, not a caching bug.
  • Only local disks can be inspected. static:status (and presumably the --disk= option) refuses remote disks because walking one would be an API call per file. If your cache lives on S3, the command has nothing to say; you'll need a different observability path there.
  • Memory scales with distinct URL paths, not files. That's what makes the command usable on multi-million-file caches — but it also means the "top URLs by variants" ranking is over paths, not individual compressed variants. Fine for finding the offending URL, just don't read the counts as file counts.
  • Pre-1.0 stability. v0.11.0 is a pre-1.0 release; command options and config keys can change between minor versions. Pin the version in composer.json and re-check the changelog before upgrading — read each release note for renamed flags rather than assuming --only-with-query-strings will keep its spelling.
  • Debugging workflow. static:status --limit=N then --json is the right order: use the limited human view to find the anomaly, then pipe the JSON into jq for exact numbers before writing the alert rule.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource