Upgrade Guide
These are the changes users need to actively consider when upgrading to the MJML 5 beta from MJML 4.x (and early MJML 5 alphas):
Highlights
- Replaced legacy
html-minifierandjs-beautifywithhtmlnano+cssnano. [breaking change] - Added templating syntax sanitization (runs before PostCSS and is restored afterwards)
- Safer, stricter handling of
mj-includeandignoreIncludes[breaking change] - Restructured outer HTML: the
<body>tag is now driven bymj-body, not the global skeleton. [breaking change] mjml-browserbuild/minification pipeline updated- Better attribute consistency across components (including more flexible
border-radius). [breaking change] - Migration helper removed [breaking change]
- Updated toolchain: Node 20/22/24 in CI. Removed Node 16/18 [breaking change]
HTML/CSS minification & formatting
What changed
- HTML minification now uses
htmlnanoinstead ofhtml-minifier. - CSS minification now uses
cssnanopresets wired viamjml-core. - Minification options can be added via
.mjmlconfig.js
Impact [potential breaking changes]
- Generated HTML is more aggressively minified. If you rely on exact formatting (e.g. diffing raw HTML, parsing by regex, or checking snapshots), you may see changes.
- Some obscure
html-minifierspecific options used in custom tooling will no longer apply; options are now expressed ashtmlnano/cssnanoconfigs. - Template tags may error in PostCSS (see Template syntax handling and sanitization below)
- Fixes this issue: #2589
What to do
- Review any automation that assumes pretty‑printed HTML (tests, diffs, CI snapshot comparisons).
- If you previously passed
minify/beautifyflags or custom minifier options, re‑map them to the newhtmlnano/cssnanoconfig.
Notes
cssnanouseslitepreset by default. Due to this issue: #2919.defaultpreset can be used if your fonts don’t contain numerals
More detail: (#2858 (comment))
Template syntax handling and sanitization (PostCSS)
What changed
- Template syntax (e.g.
{{ }}) is now sanitized before PostCSS and with syntax restored post-processing.
Impact
- A
CssSyntaxErrorerror will occur when applying CSS minification to files with some template syntax - Fixes this issue: #2858 (comment)
What to do
- If you use a templating engine on top of MJML (Handlebars, Liquid, Twig, etc.), run your existing templates and visually verify output.
- Pay special attention to templates that put templating markers in CSS or style attributes.
More detail: (#2858 (comment))
Includes are more locked down
What changed
ignoreIncludes/allowIncludes(CLI) defaults and behavior have changed to be more secure. Includes are ignored by default- A new
includePathoption is introduced to explicitly control where includes can be loaded from outside of a templates filePath - Support MJML, HTML and CSS includes only
Impact [potential breaking changes]
- Includes are ignored by default, you will need to explicitly allow them
- Projects that relied on implicit include behavior (e.g. loading templates from arbitrary paths without explicit configuration) may now fail, warn, or simply skip includes.
- In locked‑down environments (containers, CI, hosting), path resolution for includes may change and require configuration.
- Fixes this issue: #2589
What to do
- Audit usage of mj-include and any config that touches
ignoreIncludes/allowIncludes. - Explicitly configure
includePath(and related options) in your.mjmlconfigor CLI usage to match your desired include directories (see docs) - Expect safer, stricter defaults; don’t rely on includes working without explicit configuration.
More detail: (#2858 (comment))
mj-body and skeleton structure
What changed
- The
<body>HTML tag is now generated under mj-body instead of a global skeleton file. - Added
idattribute tomj-body mj-bodyattributes have been refactored:classattribute is applied to thebodytag rather than the childdivbackground-colorremoved frombody, applies to childdivonly
Impact [potential breaking changes]
- If you rely on the exact skeleton (where
<body>lived, what attributes were on it), this structure is now different. - External CSS that relies on the specific placement of the
classmay no longer apply - Fixes this issue: #2396
What to do
- Re‑check any tooling that injects or manipulates the outer HTML skeleton around MJML output.
- Re‑verify any CSS relating to
classorbackground-colorattributes that were applied tomj-body
Notes
Browser bundle / build scripts
What changed
mjml-browserbuild/minification pipeline has been updated to use new minifiers
Why
- New minifiers were not compatible
Impact
- If you import
mjml-browserdirectly or depended on its legacy build scripts, behavior and bundle size/shape might change. - Bundle size down from 1.22M to 1.04M
What to do
- Re‑build any tools using
mjml-browserand verify they still load, minify, and run as expected.
Attributes & layout consistency
What changed
- All
border-radiusattributes now accept a string, previously this was inconsistent across components. Allows more flexible input - Updated the
inner-paddingattributes ofmj-heroand fixed an Outlook issue withwidth/padding
Impact [potential breaking changes]
- For some components,
border-radiusvalues are less strict inner-paddingformj-herois now applied to all clients, not just Outlook
What to do
- Visual regression‑test focusing on all instances
border-radiusandmj-hero'sinner-padding
Migration helper removal
What changed
- The standalone
mjml-migratetool and associatednoMigrateWarnoption are removed.
Impact [potential breaking changes]
- You can no longer rely on MJML 5 to automatically migrate very old MJML syntax (3.x/early 4.x) on the fly.
What to do
- If you still have legacy MJML, migrate those templates with MJML 4 tooling before moving the project to MJML 5, or update them manually.
Node.js version support
What changed
- CI now runs against Node LTS 20, 22 and 24; older Node versions are effectively deprecated/unsupported.
Impact [potential breaking changes]
- MJML 5 may not work (or will be untested) on Node 16/18 in the long term.
What to do
- Plan to run MJML 5 on Node 20, 22 or 24 in CI and production.
Full Changelog: v5.0.0-alpha.11...v5.0.0-beta.1