fourlabs/robots-bundle
A lightweight PHP bundle for defining and serving robots.txt directives from configuration, making it easy to control crawler access to your application. Simple to integrate, but minimally adopted and sparsely documented, so evaluate fit carefully.
Architecture fit — the package does not fit the stated stack. fourlabs/robots-bundle is a Symfony bundle, not a Laravel package. It depends on machinery Laravel does not provide: a bundle class plus DI extension to register services and config, a kernel.response event subscriber that inspects the controller for a @Robots annotation, and an annotation reader (doctrine/annotations or Symfony's) to parse it. None of that boots inside a Laravel service provider — there is no bundle registry, no kernel.response, no compiler passes, and no annotation-driven routing. The realistic integration is not "install and configure" but "reimplement roughly 60–100 lines of logic with the same semantics."
Integration feasibility — low as a dependency, moderate as a reference design. The portable contract is small and clear: a per-route declaration of one or more X-Robots-Tag directives (noindex, nofollow, noarchive, nosnippet, max-snippet:N, unavailable_after:...) projected onto the response header. In Laravel that is a middleware plus a PHP 8 attribute (or a route default) resolved by reflection on the controller action. Estimated 1–2 days for a spike, ~1 day to productionize with tests. The non-obvious work is not the header formatting; it is precedence rules, error-response coverage, and proving that production revenue routes never inherit noindex.
Technical risk — high, and it is package-specific rather than problem-specific. The repository shows 1 star, 0 dependents, and a 0.005 package score against a 5.5 opportunity score. That gap is the headline: the capability is worth ~1,000× the artifact. Concrete risks:
doctrine/annotations is in maintenance mode; adopting it now bakes in a migration to attributes.__invoke controllers) are unproven.X-Robots-Tag is crawler-facing. A silently dropped header is an SEO regression; a leaked noindex on a revenue landing page is a measurable business loss, not a bug ticket.Key questions for the owning engineer (or the vendor, if we ever consider Symfony):
TPM recommendation: do not adopt as a dependency. Leverage it as a reference implementation and fund a first-party Laravel middleware with PHP 8 attributes — owned by us, tested by us, upgradeable by us.
Stack fit. A global or route-group middleware registered in bootstrap/app.php (Laravel 11+) or Kernel.php. Metadata source, in order of preference:
#[Robots('noindex, nofollow')]. Reflection-cached, zero dependencies, forward-compatible.->defaults('robots', 'noindex'). Cheapest, no reflection, but less discoverable at the call site.doctrine/annotations unless we already depend on it.Only if the target application is genuinely Symfony does the calculus flip: composer require fourlabs/robots-bundle, register in bundles.php, annotate controllers — and even then, only after the version questions above are answered, with a pinned fork if upstream is stale.
Migration path — preserve semantics, not code. (a) Publish the supported directive vocabulary and precedence order: route-level > route-group > global default. (b) Port the header-formatting logic if it is correct, then rewrite the plumbing around it. (c) Inventory every place a controller currently sets robots headers by hand — that inventory, not the bundle, is the real scope.
Compatibility. Validate against our actual PHP and Laravel versions, not the package's declared constraints. Watch for header-name casing (X-Robots-Tag), comma-joined directives versus repeated header lines, interaction with Cache-Control/ETag, and 304 Not Modified short-circuits — a 304 must not silently drop an intended noindex.
Sequencing (with gates):
noindex.Maintenance. This is the primary reason to avoid the dependency: with 1 star and 0 dependents there is no upstream maintainer to inherit risk from — we become the maintainer of a fork we did not write, in a framework (Symfony) we do not run. A first-party ~100-line middleware costs hours per year and adds no version-conflict surface. If leadership insists on the dependency, pin an exact version and vendor the source into the repo.
Support. No vendor, no community, no issue-tracker signal, no SLA. Escalation is internal only. Name a single owning engineer and document the fallback ("delete the middleware; headers revert to framework defaults") in the runbook before launch.
Scaling. Negligible runtime cost — one reflection lookup per request (cached) and one header write. The scaling concern is organizational: as route count grows, per-route declarations drift. Mitigate with a CI check that every public route explicitly declares an indexability stance, plus a global noindex default outside production.
Failure modes to plan for:
noindex leaking onto a revenue or brand page via overly broad route-group defaults — the negative test is the control.X-Robots-Tag on non-HTML resources, but not across redirects) — treat this as an SEO policy input, not an app assumption.Ramp-up. Low. One engineer can learn and own the middleware in under a day; the SEO stakeholder needs a short briefing on the directive vocabulary and on the tradeoff that indexability changes ship with deploys rather than through a CMS. Budget ~1 hour of SEO review per feature that touches public routes.
TPM scorecard: build, don't buy — ~2.5 engineer-days, zero new dependencies, one named owner, two regression tests (positive and negative), and a dark-launch observation window. Decision to revisit: only if we migrate to Symfony and the bundle shows commit activity and a CI matrix.
How can I help you explore Laravel packages today?