| raw | true |
|---|---|
| title | Migration Guide: v1 to v2 |
| description | Migrate from Foundation for Emails (Inky v1) to Inky v2. Covers syntax changes, removed features, and upgrade steps. |
| nav_group | Guides |
| nav_order | 3 |
Inky v2 is a ground-up rewrite in Rust with significant improvements:
- 10-100x faster -- Rust core compiles to native binary, WASM, or shared library
- Cleaner syntax -- attributes over classes, singular
<column>,sm/lgshorthand - New components -- video, hero, social, card, alert, badge, accordion, blockquote, preview
- CLI toolchain --
inky build,inky watch,inky validate,inky init - CSS inlining -- built-in, enabled by default
- Framework CSS -- SCSS framework with variable overrides, injected automatically
- Layouts and includes --
<layout>,<include>, template variables - Validation -- catches missing alt text, Gmail clipping, Outlook issues
- Template-friendly -- auto-detects Handlebars, ERB, Jinja2, Mailchimp, etc.
- Cross-platform -- one engine powers CLI, Node.js, PHP, Python, and Ruby
inky migrate email.inkyinky migrate src/ -o migrated/inky migrate src/ --in-placeconst inky = require("inky");
const result = inky.migrateWithDetails(v1Html);
console.log(result.html); // migrated HTML
console.log(result.changes); // ["<columns> -> <column>", ...]| v1 Syntax | v2 Syntax | Notes |
|---|---|---|
<columns> |
<column> |
Plural to singular |
</columns> |
</column> |
Closing tag too |
<h-line> |
<divider> |
Renamed |
large="6" on <column> |
lg="6" |
Shorthand |
small="12" on <column> |
sm="12" |
Shorthand |
<spacer size="16"> |
<spacer height="16"> |
Clearer attribute name |
<spacer size-sm="10"> |
<spacer sm="10"> |
Shorthand |
<spacer size-lg="20"> |
<spacer lg="20"> |
Shorthand |
<button class="small"> |
<button size="small"> |
Class to attribute |
<button class="alert"> |
<button color="alert"> |
Class to attribute |
<button class="expand"> |
<button expand> |
Class to bare attribute |
<button class="radius"> |
<button radius> |
Class to bare attribute |
<button class="rounded"> |
<button rounded> |
Class to bare attribute |
<button class="hollow"> |
<button hollow> |
Class to bare attribute |
<callout class="primary"> |
<callout color="primary"> |
Class to attribute |
<menu class="vertical"> |
<menu direction="vertical"> |
Class to attribute |
<center><menu>...</menu></center> |
<menu align="center">...</menu> |
Wrapping to attribute |
tiny, small, large
primary, secondary, success, alert, warning
expand, expanded, radius, rounded, hollow
v1:
<container>
<row>
<columns large="6" small="12">Left</columns>
<columns large="6" small="12">Right</columns>
</row>
</container>v2:
<container>
<row>
<column lg="6" sm="12">Left</column>
<column lg="6" sm="12">Right</column>
</row>
</container>v1:
<button class="small alert expand" href="#">Click Me</button>v2:
<button size="small" color="alert" expand href="#">Click Me</button>v1:
<button class="small alert custom-btn" href="#">Click</button>v2:
<button class="custom-btn" size="small" color="alert" href="#">Click</button>Custom CSS classes that aren't migration targets are preserved in the class attribute.
v1:
<container>
<row>
<columns large="6" small="12">
<button class="small alert" href="#">Click</button>
<spacer size="16"></spacer>
<h-line></h-line>
<callout class="primary">Important</callout>
</columns>
<columns large="6" small="12">
<center>
<menu class="vertical">
<item href="#">Link</item>
</menu>
</center>
</columns>
</row>
</container>v2:
<container>
<row>
<column lg="6" sm="12">
<button size="small" color="alert" href="#">Click</button>
<spacer height="16"></spacer>
<divider></divider>
<callout color="primary">Important</callout>
</column>
<column lg="6" sm="12">
<menu align="center" direction="vertical">
<item href="#">Link</item>
</menu>
</column>
</row>
</container>-
v1 syntax isn't fully supported, but it doesn't hard-fail the build either. A handful of common v1 patterns (
<columns>,<h-line>,large="..."/small="..."on<column>,<spacer size="...">) are still accepted as compatibility aliases and just produce av1-syntaxwarning frominky build/inky validate. Other v1 patterns — class-based styling like<button class="small alert expand">,<center><menu>wrapping — aren't recognized at all and are silently treated as plain CSS classes, with none of the v1 behavior and no warning. Runinky migratefirst rather than relying on the aliases or the warning to catch everything. -
.inkyfile extension -- Source templates should use.inky. The CLI auto-generates.htmloutput files. Both.inkyand.htmlare accepted as input. -
CSS inlining is on by default -- v1 had no built-in inlining. If you handle inlining separately, pass
--no-inline-css. -
Framework CSS is injected by default -- The built-in SCSS framework is compiled and injected into each email. Disable with
--no-framework-cssif you use your own CSS. -
role="presentation"on all layout tables -- v2 adds accessibility attributes to all generated tables. This is a non-breaking output change but may affect CSS selectors or snapshot tests.
inky migrate is a tag scanner, not a regex rewrite -- it parses each tag properly rather than pattern-matching across the raw string. That means:
- Attributes are never dropped, reordered, or corrupted. Attributes after
class="..."on<callout>/<menu>, attribute values containing/or>, and attribute names/values that merely look like a migration target (e.g. adata-largeattribute, or a value oflarge=) are all left alone -- only the documented class-to-attribute conversions happen. - Tag matching is case-insensitive.
<COLUMNS>,<Columns>, and<columns>all migrate the same way. - Formatting outside migrated tags is preserved byte-for-byte. Only the tags actually being migrated are rewritten; everything else in the file -- whitespace, line breaks, quoting style -- is untouched.
- v1 syntax inside HTML comments,
<raw>blocks,<script>/<style>/<textarea>/<title>content, and ERB<% %>tags is left alone. The scanner doesn't migrate text that isn't actually markup in that context.
- Run
inky validateafter migration to catch any remaining issues. - The migrator is safe to run multiple times -- already-migrated syntax is left unchanged.
- Use
inky migrate --in-placewith version control so you can review the diff. - The
migrateWithDetails()API returns a list of changes made, useful for logging or reports.