tfd/statamic-cloudinary
Connects Statamic to Cloudinary so images and assets are stored, managed, and delivered through Cloudinary's CDN. Configure the asset driver and serve optimized, responsive media from your Statamic site with minimal setup.
Architecture fit. The addon occupies the correct seam in a Statamic application: it decorates the asset-rendering layer rather than replacing it. It registers through the standard Statamic addon contract (src/ServiceProvider.php), merges and publishes config to config/statamic/cloudinary.php, registers a view namespace (cloudinary), a Blade component (<x-cloudinary-image />), an Antlers tag (src/Tags/Cloudinary.php), and a wildcard {{ cloudinary:field }} surface. All transformation logic is centralized in TFD\Cloudinary\Converter\CloudinaryConverter, which is the right shape — a single translation point for Glide-style parameters into Cloudinary transformation syntax. The tag retains a Glide fallback, which means adoption is additive and reversible; the existing Statamic asset pipeline remains intact as a safety net. This is a delivery-offload addon, not a storage migration, which is architecturally the lower-risk posture. Note, however, that the architecture's safety net is only as good as its implementation: v1.5.1 reveals the fallback was structurally present but functionally broken on the wildcard surface, so "the fallback exists" must be read as a per-surface property, not a global one.
Integration feasibility. Mechanically low effort: composer require tfd/statamic-cloudinary, publish config, supply Cloudinary credentials via environment, then swap {{ glide:* }} / {{ asset }} call sites for the cloudinary tag or Blade component. No frontend build pipeline exists or is needed. The real feasibility question is not install cost but the mapping model: the docs confirm support for Statamic asset IDs, asset URLs, and mapped external URLs, but do not state clearly whether assets must already exist in Cloudinary or whether the addon relies on Cloudinary's remote-fetch delivery type to pull from the existing origin. That single decision determines whether this is a one-hour config change or a full asset-synchronization project.
Technical risk. The risks are predominantly supply-chain and verification, not design. v1.5.1 materially sharpens — but does not change the direction of — this picture:
Tags\Cloudinary::wildcard() raised ArgumentCountError at both fallback sites rather than degrading. Two consequences: an install with missing/invalid Cloudinary credentials 500s on every {{ cloudinary:field }} tag, and a correctly configured install 500s as soon as a referenced asset is missing or is renamed. This is a hard availability bug on a runtime path, not a cosmetic one — missing assets are the normal steady state on content-managed sites. Pin >=1.5.1; treat 1.5.0 as unusable. Existing projects on 1.5.0 should be audited for wildcard tag usage and for assets deleted or renamed since adoption.ItemNotFoundException, log at error level, and fall back to Glide. That pattern is sound for uptime and bad for observability — but on the wildcard path it wasn't even delivering uptime. Do not generalize the fallback guarantee across tag surfaces without testing each one.require-dev pinned orchestra/testbench ^9 (Laravel 11), and those releases were blocked by security advisories — meaning no test runner was installable at all. Every release through 1.5.0 shipped with no executable test suite. v1.5.1 adds the first tests for Tags\Cloudinary and repairs the harness, which is a genuine improvement, but the harness now runs Testbench 10 / Laravel 12 while the package declares Statamic ^5.73.11 || ^6.4. Statamic 5 on Laravel 10/11 remains claimed but unproven, and AGENTS.md still notes no CI matrix. The absence of CI is the mechanism by which a broken fallback reached a tagged release; until a matrix exists, assume this class of defect can recur.21stdigital but the package and PSR-4 namespace are TFD\Cloudinary. That pattern suggests a fork, transfer, or vendored addon. Ownership and upstream-tracking cadence must be confirmed before committing.Key questions.
fetch-type URLs against the Statamic origin? What is the public_id derivation rule, and is it stable across renames? (The 1.5.0 bug makes rename-safety a first-class question, not a footnote.)^5 claim backed by any test run, or is it aspirational? What is the plan for a CI matrix, and is there a commitment (or fork posture) if it does not arrive?Stack fit. Designed for Laravel + Statamic 5/6 and PHP 8.x. It follows framework conventions (config merge/publish, view namespaces, Blade component aliasing) and introduces no queue workers, no migrations, no schema, and no service dependencies beyond the Cloudinary PHP SDK. That makes it a clean fit for conventional Statamic sites, including Blade/Livewire front-ends; it is a poor fit for headless setups where Statamic is not rendering the image markup, since the value is concentrated in the tag and component.
Migration path. Adopt in four reversible steps, with a hard version floor:
>=1.5.1 in composer.json. Do not allow the constraint to resolve to 1.5.0. If already on 1.5.0, upgrade before anything else and re-test deletion/rename behaviour.{{ cloudinary }} / {{ cloudinary:field }} / <x-cloudinary-image />. Keep the Glide fallback enabled. Explicitly include the wildcard tag in the pilot, since that is the surface with the newest and least-proven test coverage. Diff the emitted URLs and measure bytes and TTFB against the Glide baseline.Compatibility. Pin to the addon's declared Statamic range and to >=1.5.1, and validate against the Laravel version actually deployed — do not inherit the addon's test-harness result, since after 1.5.1 it only exercises Laravel 12. If the project runs Statamic 5 on Laravel 10/11, budget an explicit smoke-test pass on the real runtime; that combination has now been proven to have had no runnable test suite for the package's entire release history. The MIT license is a genuine asset here: if upstream lags a Statamic release, forking and maintaining an internal copy is legally and technically uncomplicated.
Sequencing. Version gate first (1.5.1 floor). Secrets management and Cloudinary account provisioning next. Negative-path testing of the fallback must precede any template change — the fallback is the entire risk-mitigation story, and it was broken as recently as one patch release ago. Parameter parity audit must precede broad rollout. Cost modeling (transformations, bandwidth, storage) must precede the storage-migration decision. Template migration should never precede the audit — otherwise unmapped parameters surface as visual regressions in production rather than in a diff.
Maintenance. Small surface area (service provider, converter, one tag, one component, one view) and conservative conventions keep code maintenance cheap. Two counterweights. First, the dev toolchain itself was broken until this release — an uninstallable test harness means dependency bumps to require-dev can silently disable verification, so CI must assert that the suite actually runs, not merely that it exists. Second, upstream tracking: Statamic 5→6 already crossed a major boundary, the Cloudinary SDK moves independently, and 1.5.0→1.5.1 demonstrates that patch releases can carry availability-relevant fixes. Assign an internal owner, treat the addon as a fork-in-waiting, and adopt a standing rule: bump to patch releases deliberately, read the changelog, and re-run negative-path tests. Because composer lint runs php-cs-fixer fix (mutating, not dry-run), CI should use the dry-run variant explicitly.
Support. Community-only, effectively single-maintainer, negligible installed base, no commercial SLA and no meaningful issue-tracker signal at 7 stars. The 1.5.1 fix shows the maintainer is responsive and does repair regressions — a positive signal — but also that a defect of this severity can ship and persist for a full version cycle. Acceptable for a delivery-layer utility provided the fallback is verified and alarmed; unacceptable for anything in the critical path of a revenue-bearing page without an internal fallback plan. Contractually: assume you own the code the day you adopt it.
Scaling. This is the addon's strongest argument. Image transformation is CPU- and IO-heavy on the origin; pushing it to Cloudinary removes that from your web tier and gives you a global CDN and modern format negotiation (AVIF/WebP) without running Glide at scale. Two new ceilings replace the old one: Cloudinary plan quotas (transformations/month, bandwidth, storage) and API rate limits on any upload/sync path. Both are manageable but must be metered from day one — transformation overage is a classic silent-budget incident. Also confirm cache-key stability, since unstable URLs defeat CDN efficiency and quietly inflate cost. Worth modeling explicitly: until 1.5.1, a missing asset produced a 500 on the wildcard path, and 500s are not cacheable and not cheap — a content hygiene problem could have become an origin-capacity problem.
Failure modes. Enumerate and instrument these before go-live:
>=1.5.1, alert on the fallback log line and on Cloudinary error rate; otherwise misconfiguration is invisible indefinitely.public_id derivation changes, images 404. Pin the derivation rule and test it.Ramp-up. Developer ramp-up remains small — an afternoon to read the config, converter, tag, and the new Tags\Cloudinary tests, and to render the component in a scratch template. Operational ramp-up is the real cost and has grown slightly: Cloudinary account and billing ownership, a documented kill-switch procedure for the addon (revert to Glide), a runbook for credential rotation, dashboards covering transformation count, bandwidth, error rate, and fallback frequency, plus a negative-path smoke test (no credentials, missing asset, wildcard tag) added to the deploy checklist. Budget roughly one engineer-week end-to-end for a mid-size site — mostly parity auditing, observability, and now fallback verification, not integration.
How can I help you explore Laravel packages today?