- How do I install spatie/mjml-php with Composer?
- Run composer require spatie/mjml-php, then install the mjml JavaScript package with npm install mjml or yarn add mjml. Node 16 or higher must be available on the machine or container that renders email. The Composer package is only the PHP wrapper; the compiler itself comes from npm.
- Does spatie/mjml-php require Node.js on my server?
- Yes. The package is a thin PHP facade over the Node mjml CLI and does not reimplement rendering in PHP, so Node is a hard runtime dependency. If you use a minimal php-fpm image, you must add Node and the mjml npm package to it. The spatie/mjml-sidecar variant moves rendering to Lambda if you cannot ship Node.
- Is spatie/mjml-php Laravel-only or can I use it in plain PHP?
- It is a plain PHP package that converts MJML to HTML and works inside Laravel without a service provider or facade registration. You call Mjml::new()->toHtml() or convert() directly from your application code. In Laravel the main design decision is where to call it, not how to wire it up.
- How do I convert MJML to HTML in PHP with spatie/mjml-php?
- Use Mjml::new()->toHtml($mjml) for the simplest path, or convert($mjml) to get an MjmlResult you can inspect. The result exposes html(), array(), hasErrors(), and errors(). The returned HTML is the compiled MJML output and is ready for email clients.
- How do I minify or beautify MJML output with spatie/mjml-php?
- Chain minify() or beautify() on the Mjml instance before calling toHtml() or convert(). You can also chain hideComments() and validationLevel(), or pass a raw options array through to the Node mjml compiler. Options are forwarded to the CLI rather than interpreted in PHP.
- How do I validate MJML and show errors before saving a template?
- Use canConvertWithoutErrors() as a save-time gate, then call errors() to map MjmlError accessors line(), tagName(), and message() into inline validation messages. canConvert() only tells you whether conversion is possible, so the stricter check is usually what an email builder needs. This keeps invalid templates from reaching the send path.
- Why does spatie/mjml-php produce different HTML in dev and production?
- Rendered HTML depends on the Node mjml version, not the Composer version, so dev, CI, and production can drift silently if they resolve mjml differently. Pin mjml in a package.json or in your container image and treat MJML upgrades as a deliberate change. Re-baseline snapshot tests when you bump the compiler.
- Can I call Mjml::new()->toHtml() inside a Laravel Mailable send() method?
- You can, but each conversion spawns a Node child process and pays roughly 100 to 300 ms of startup, which is a poor fit for the request or queue send path. Render once when a template is published or saved, persist the HTML with a hash of the MJML source and resolved mjml version, and have Mailables reference stored HTML. That also makes caching and rate limiting much easier.
- How do I fix node not found errors from spatie/mjml-php under PHP-FPM?
- Set MJML_NODE_PATH to the absolute path of the node binary, or make sure the PATH seen by PHP-FPM workers includes it. PATH often differs between your shell, CI, and FPM, which is the classic first incident with this package. Verify discovery from the same user and environment that runs the render.
- What is the difference between spatie/mjml-php and spatie/mjml-sidecar?
- spatie/mjml-php runs the mjml CLI locally, so the PHP host needs Node at runtime. spatie/mjml-sidecar moves rendering to a Lambda invocation through MjmlFunction, which removes Node from the request cycle and suits a production send path. The sidecar model is AWS-shaped and adds a second deploy pipeline to own.