keepsuit/liquid
PHP implementation of the Liquid template engine with Shopify-compatible syntax, tags, and filters. Build safe, flexible, user-editable templates in Laravel or any PHP app with customizable tags and drops.
Architecture fit. keepsuit/liquid is a standalone PHP port of Shopify's Liquid markup language, not a Laravel-first package. That is the right shape for the only use case that justifies it: rendering user-authored or tenant-authored templates (email/notification bodies, invoice and document layouts, CMS blocks, white-label portal content) where the template author is not a developer and must not be able to execute arbitrary PHP. It is explicitly the wrong tool as a replacement for Blade on application views — you would trade compile-time safety and IDE/tooling support for a dynamic language with no benefit. Architecturally it slots in as a leaf dependency: a stateless parse-and-render engine that our own TemplateRenderer contract wraps, so domain code never sees Liquid types.
Integration feasibility. Composer install, MIT license, no framework coupling, no database or queue requirements — the integration cost is genuinely low. The real work is not composer require; it is (a) sandboxing untrusted input, (b) caching parsed templates so we don't re-parse on every render, and (c) mapping our domain objects into the Liquid context array/drops in a way that doesn't leak internals. A keepsuit/laravel-liquid wrapper exists in the same vendor namespace that would supply a service provider and Blade-adjacent ergonomics; treat it as a separate dependency with its own maintenance risk and evaluate it independently rather than assuming it inherits the core library's characteristics.
Technical risk. Three concerns dominate:
nil/falsy semantics, for loop variables). Divergence will show up as templates that render correctly on Shopify or in a customer's existing system but differently on ours — a class of bug that is expensive to diagnose and erodes customer trust. We need a conformance fixture suite, not vibes.Also flag the metadata: the recorded latest release date (2026-10-19) is future-dated, which means either a data artifact or a mis-tagged release — confirm the actual tag history and commit cadence on the repo before treating "actively maintained" as established.
Key questions for the maintainer / diligence spike.
for ranges, deep include/render recursion, and unbounded output?Stack fit. Pin to PHP 8.1+ and the Laravel version currently standard in our estate. The package sits alongside Blade, not in place of it: Blade renders the application shell, Liquid renders the tenant-supplied fragment that gets injected into that shell. Keep Liquid out of the request hot path for anonymous traffic; scope it to authenticated, template-owning tenants.
Isolation and boundaries. Define a TemplateRenderer interface in our domain with render(string $template, array $context): string (and a separate validate() for authoring-time feedback). Register the Liquid implementation behind it in a service provider. All Liquid types stay inside that adapter. This is what makes the vendor-risk answer "replaceable in a sprint" rather than "rewrite the feature."
Migration path. Assume one of two starting states. (a) From hardcoded/Blade templates: migrate a single low-risk template family first — transactional email is ideal because volume is bounded, failures are observable, and rollback is trivial. (b) From a SaaS templating vendor or an existing homegrown str_replace system: build a translation layer and run both engines in shadow mode on real tenant templates, diffing output before cutover. Do not attempt a big-bang migration of a customer's template library; version the template syntax per tenant so old and new coexist.
Compatibility and caching. Wrap the parse step in a cache keyed by template hash + package version, stored in the existing cache backend. This neutralizes most of the performance objection and gives us a clean invalidation story on package upgrades. Pin the dependency to an exact minor version and treat upgrades as events that require re-running the conformance suite and invalidating the parse cache.
Sequencing.
TemplateRenderer contract, service provider binding, parse cache, authoring-time validation endpoint.Decision gate. If step 1 fails on sandboxing or spec fidelity, the fallback is Twig with a restricted tag/filter set — more mature, better supported, but a different authoring dialect and a harder sell to customers who already know Liquid.
Maintenance. Budget explicitly for the possibility that we become the maintainer. Concretely: fork to our own namespace on day one of production use (or at minimum vendor the source with a documented patch process), keep our patches as a small, reviewable diff, and assign one named engineer as owner. Upstream releases should be treated as proposals, not upgrades. The parse cache must be version-keyed so an upgrade can't silently serve stale ASTs.
Support. No commercial support channel, no SLA, no vendor to escalate to. Internal support load falls into two buckets: template-authoring questions ("why did my variable render blank?") which is a product/docs problem, and rendering defects which are ours to fix. Plan for a public template-authoring guide and an in-product validator that surfaces errors at save time rather than at send time — this is the single highest-leverage operational investment.
Scaling. Rendering is CPU-bound and interpreted. At our volumes this is fine for email/document generation; it becomes a concern if Liquid ever lands in a high-QPS page render path. Mitigations: parse caching (required, not optional), a render timeout, offloading document generation to the queue, and per-tenant rate limiting on template saves so a pathological template can't be saved in the first place. Watch memory on large for loops over large collections — pass paginated/bounded data into the context rather than whole result sets.
Failure modes to instrument.
Ramp-up. Liquid is small and well-documented via Shopify's public reference, so engineer ramp-up is measured in days, not weeks. The genuine learning curve is on the product side: whoever owns template authoring needs to understand Liquid's falsy semantics and filter behavior to write good docs and validation messages. Allocate design and docs time alongside the engineering ticket — for a user-authored templating feature, the authoring experience is the product, and this package gives you an engine, not an experience.
How can I help you explore Laravel packages today?