Werner Glinka

CODING

From Metalsmith to Eleventy - Porting an Actual Site

Feb 10, 2026

In theory, migrating a site from Metalsmith to Eleventy should be straightforward, copy the content, adjust some configuration, done.

Theory met practice when I ported my art website.

The site isn''t large: a homepage with an artwork carousel, sixteen individual artwork pages, a works gallery, five studio notes, a couple of press articles, and an about page. Twenty-seven pages total. All built with the same component architecture I''d developed over years of Metalsmith work. If any site should port cleanly, this one should.

It mostly did. The interesting parts are where it didn''t.

The Content Migration

The content files moved without modification. Both platforms use YAML frontmatter, and my pages define everything as structured sections rather than markdown body content. Copy the files, change the layout path in frontmatter frompages/sections.njktosections.njk, and the content is ready.

The data files—JSON defining the artwork carousel and gallery grid—moved just as easily. The asset files, several years of artwork photographs organized by year, copied over with their directory structure intact.

The first build completed successfully. Thirty files written. That''s when I started actually looking at what it produced.

Navigation Showing Everything

The main menu listed every page on the site. Home, Works, About, Studio Notes—but also every individual artwork page, every studio note post, every article. The navigation component was doing exactly what it was told: display all pages with anavLabelin their frontmatter.

In Metalsmith, I''d used a menu plugin which allowed me to be selective about which pages got included in the navigation. In the Eleventy port, I''d copied all the frontmatter without thinking about what the normalization plugin would do with it. The normalized collections plugin builds the main menu from every page that declares a navigation label. Every page had one.

The fix was simple: removenavLabelfrom pages that shouldn''t appear in the main menu. Only four pages needed it—Home, Works, About, and Studio Notes. The rest were accessible through their parent sections, not through top-level navigation.

Components Not Rendering

The homepage carousel didn''t appear. Neither did the works gallery grid. The sections were in the frontmatter, the components existed, but the sections rendered empty.

The problem was data access patterns. The artist-slider component expected artwork data atdata.artworks[section.artworks.source]. The image-grid component expecteddata[section.dataSource]. These paths assumed data would be accessible under adatanamespace in templates.

This is where the_data/data/directory convention matters. Eleventy''s data cascade makes any JSON file in_data/available as a global variable named after the file. A file at_data/site.jsonbecomessitein templates. But my components expected data under adataobject—data.artworks,data.works, not justartworksorworksat the root level.

The solution: nest adata/directory inside_data/. Files at_data/data/artworks/home-slider.jsonbecome accessible asdata.artworks[''home-slider'']. The directory structure creates the namespace the components expect. It''s ugly but a small price to pay for components compatibility.

This convention, paired with the normalization plugin handling collection data shapes, forms the bridge between platforms. Metalsmith builds pass data explicitly through the pipeline. Eleventy''s data cascade provides it automatically. The_data/data/pattern makes both approaches resolve to the same access paths in templates.

No component changes required. The components were already correct—they just needed the environment configured to deliver data where they expected to find it.

Image Paths

The works gallery rendered its grid layout, but the images showed only alt text. The thumbnails weren''t loading.

The image paths inworks.jsonwere relative:/2001/2001.01.004.jpg. The original Metalsmith build had resolved these against a base path. The Eleventy build didn''t know to do that.

I updated the paths to be fully qualified:/assets/images/artworks/thumbnails/2001/2001.01.004.jpg. Explicit paths that work regardless of how the build system handles path resolution.

Component Naming

The studio notes pages used a component calledblog-navigationfor previous/next links between posts. That component had been renamed tocollection-linksin the published component library—a more accurate name since it works for any collection, not just blogs.

The fix was updating the frontmatter in all five studio notes pages to referencecollection-linksinstead ofblog-navigation, and downloading the renamed component.

But then the collection links rendered empty. The component was hardcoded to look forcollections[''blog''], and my collection was namedstudio-notes.

I made the component configurable, adding support for acollectionNameproperty with a default fallback toblog. Then addedcollectionName: ''studio-notes''to each studio notes page. The component now works for any collection name, which is what it should have done from the start.

What the Fixes Reveal

Each problem pointed to an assumption that worked in one environment but not the other.

The navigation issue revealed that I''d been relying on selective frontmatter rather than explicit configuration. The data access issue revealed assumptions about directory structure baked into component expectations. The image path issue revealed reliance on implicit path resolution. The component naming issue revealed hardcoded values that should have been configurable.

None of these were Eleventy problems or Metalsmith problems. They were assumptions I''d made while building in one environment that didn''t survive the move to another. The migration exposed them. Fixing them made the components more robust and more portable.

The site works now. The carousel autoplays, the gallery grid displays justified layouts, the collection navigation links posts correctly. The build produces the same output it did on Metalsmith, but with less configuration and more of the pipeline handled by Eleventy''s defaults.

More importantly, I understand both platforms better than I did before. Metalsmith''s explicitness taught me how static site generators work. Eleventy''s conventions taught me where I''d been doing unnecessary work. The migration taught me which assumptions were load-bearing and which were incidental.

The next post covers extending the site with capabilities I hadn''t implemented in Metalsmith: a full bilingual version using Eleventy''s i18n support.