Tools
Tools: Introducing Ⓜ️ Meddler! A Medium Export Converter
2026-02-13
0 views
admin
What is Ⓜ️ Meddler? How does it work? ## Supplementary Data ## The Command-Line Tool ## What does the output look like? ## Under the Hood ## Why I Built This ## I Still Love Medium! ## Try Meddler Out! Two of the best features of Medium are the fact you can export your email subscribers list and export your entire account, including your writing. Why are these two of the best features? Because this means that, at anytime, you can take both your work and audience to another platform. What happens when platforms don't offer this? When Vine shut down in 2017, creators lost years of work overnight. When Yahoo acquired and then killed Geocities, an estimated 38 million user-built pages vanished. More recently, platforms like Cohost and Revue closed with limited or no export options. Even Substack's export gives you a basic CSV, which is not a simple plug-and-play for your new blog. Medium, to its credit, lets you take your data with you. The problem is, though, the export of your work? For anybody that's used the export feature, they know it has a few issues. Medium provides a GDPR-compliant data export in the form of a .zip archive containing HTML files. While this preserves content, the format is: And, most importantly for me, the files are not SSG-ready. No YAML, TOML, or JSON front matter, and no clean Markdown body. I'm somebody who's been an advocate of the IndieWeb for quite awhile now. And so I decided to use my skills as a developer to solve this issue myself. So, I created Ⓜ️ Meddler, a command-line tool and website that will take the .ZIP of your export that Medium gives you and turn it into clean, portable Markdown formats for Jekyll, Hugo, Eleventy, or Astro.js. What does this mean? That you can migrate your body of work to your own independent JAMstack blog anytime. You have your blog as a repository on GitHub, GitLab, or CodeBerg and host it on a platform like Netlify or Vercel and wire to a domain from Porkbun or other provider. This means you're completely platform-independent. You own and control every aspect of your digital online presence. Now, this blog post isn't a tutorial for getting your own static-site generator up online. There are plenty of other helpful resources for that. This is about how to use the tool I made to easily migrate and transfer your work from Medium to your new independent blog. I decided to create two different converters for this project: a command-line tool for power users, and a simple drag-and-drop website for everyone else. The site, https://meddler.fyi, runs entirely in the browser. No server, no uploads to third parties, which makes it private and fast. I used my own Medium export (of over 300 stories, ranging from drafts to responses to full articles) to make sure it correctly handled and exported the wide variety of data that Medium gives you. When you successfully upload your export .ZIP, you'll see all the data it contains. Next, the configuration screen gives granular control over how your export is converted. Here's a breakdown of what each section does: Format & Target lets you choose your static site generator (Hugo, Eleventy, Jekyll, Astro, or Generic) and front matter format (YAML, TOML, or JSON). Selecting a target automatically applies sensible defaults. For example, choosing Hugo switches front matter to TOML and enables shortcodes for embeds. You can also choose output format: Markdown (the default), cleaned HTML, or structured JSON. Content Options controls what gets included. You can toggle draft posts, responses (your short replies written to other people's articles), and whether drafts go into a separate folder. There's also an option to extract the featured image into front matter. Image Handling is one of my favourite features. You can either keep the original Medium CDN URLs (faster, but they may break over time as Medium changes infrastructure) or download all images locally so they're bundled with your export. The web version fetches images directly from Medium's CDN in your browser. You can also organize images per-post into subdirectories like images/my-post-slug/01.jpeg instead of having everything messy in a flat folder. Embed Handling determines how YouTube videos, GitHub Gists, Tweets, and other embedded content are converted. "Raw HTML" preserves the original iframes. "SSG shortcodes" auto-detects the embed type and converts them to native shortcodes (e.g., Hugo's {{</* youtube */>}}. "Placeholder links" gives you the most portable option, plain Markdown links. Medium's export includes far more than just your posts. Meddler can extract and convert all of it: Advanced options include date format (ISO 8601 or date-only), section break style (horizontal rules, extra spacing, or none), and the ability to add arbitrary custom front matter fields, handy if your blog template expects fields like layout, locale, or canonical_url. As you change settings, you can click "Show live preview" to see exactly what your converted Markdown will look like, front matter and all, updating in real time. You'll get a helpful log explaining what's going on as the converter runs. It shows you each phase: converting posts, downloading images (with a progress bar), processing supplementary data, and finally zipping everything up. At the end, you get a summary report telling you exactly how many posts were converted, how many drafts and responses were included, how many images were downloaded (and if any failed), and how many supplementary data files were generated. Once it's done, you download a single .zip file containing your entire converted blog, ready to drop into your static site generator's content directory. If you're comfortable with a terminal, the CLI version gives you even more power and reliability. Install it with a single command: Then convert your export: That's it. One command and your entire Medium archive is converted. But the CLI also supports fine-grained control: You can target any supported SSG (hugo, eleventy, jekyll, astro, or generic), choose your front matter format, control image downloading, and toggle which content to include. There's also a --dry-run flag that shows you what would be converted without writing any files—useful for previewing large exports. For repeatable workflows, you can create a .meddlerrc.json configuration file: Notice the template variables, {{author.name}}, {{url}}, {{date}}, etc. These let you inject dynamic metadata into custom front matter fields, which is incredibly useful for themes that expect specific fields. The CLI also has better image downloading than the web version. Because it runs on your machine with Node.js, it doesn't have the browser's CORS restrictions, so it can reliably fetch every image from Medium's CDN. For large exports with hundreds of images, this makes a real difference. Here's an example of what a converted post looks like with YAML front matter: The metadata that Medium embeds in the HTML such as title, subtitle, publish date, canonical URL, author, and tags all get extracted and structured into proper front matter. The body is clean Markdown with ATX-style headings, fenced code blocks, and proper link formatting. Meddler is a TypeScript monorepo with three packages. The core library (@berryhouse/core) handles all the parsing and conversion logic. It uses cheerio to parse Medium's HTML and Turndown to convert it to Markdown, with custom rules for Medium-specific elements like drop caps, section dividers, mixtape embeds (those linked article cards), and embedded content like YouTube videos and GitHub Gists. The CLI (@berryhouse/meddler) wraps the core library with Commander.js for argument parsing, chalk for coloured terminal output, and ora for progress spinners. The web app is built with React, Vite, and Tailwind CSS, and uses JSZip for ZIP file handling, all running entirely client-side. You can view the NPM package here: https://www.npmjs.com/package/meddler-cli Over the years, I've accumulated over 300 stories of articles, drafts, and responses on Medium. When I've tried to move my writing to my own blog, I hit the same wall. Medium's export is HTML soup. When I attempted to convert years ago, I remember having to initialize a WordPress account to use the Medium-to-Wordpress plug-in, followed by a CLI tool that would convert Wordpress posts to Jekyll markdown. The process was clunky and error-prone. No tools handle the full picture and none of them offered a web interface for people who don't want to touch a terminal. So I built the tool I wished existed. I tested it against my own massive export, fixed edge cases, and made sure it handled everything from a brand-new account with zero posts to a veteran writer with hundreds of articles and years of bookmarks, claps, and highlights. I've been a writer on Medium for over ten years now, my first article published at the end of 2015, titled "The Best Time to Start a New Year's Resolution is Right Now". Since then, I've seen many platforms rise and fall. I've stayed on Medium because I sincerely think it's a wonderful place to write, relative to many others. I earn a living with the Medium partner program. I think Medium is one of the few platforms that has ignored enshittification and promotes thoughtful, longform writing which the web desperately needs. I mentioned many of these points in "Move to a Better Internet in 2026". So, please don't get me wrong. I'm not making this tool because I want to leave Medium, or I think you ought to leave. Rather, I'm making it so you have the ability to have your own your work. Publish on your own site, syndicate elsewhere. I also now post my articles to my own site, 🔆 Brennan.Day (with the added benefit of not being paywalled), an independent publication built with 11ty, and I really think everyone should have their own website that they make from scratch. The IndieWeb is becoming more accessible than ever, and gives you freedom and flexibility (and fun!) that no social media platform can. If you miss what the Internet used to be, this is how we reclaim it. The more of us that migrate away from corporate, privacy-hostile platforms and services, the less of a chokehold they'll have on the Internet as a whole. You can read "The Absolute Beginner's Guide to the IndieWeb for Writers and Non-Coders" to see more about that. If you're thinking about migrating from Medium (or just want a backup of your content in a portable format) give Meddler a try: Your words are yours. They should live wherever you want them to. Meddler is not affiliated with Medium. It's an independent, open-source tool built for the IndieWeb community. Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse COMMAND_BLOCK:
npm install -g meddler-cli Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
npm install -g meddler-cli COMMAND_BLOCK:
npm install -g meddler-cli CODE_BLOCK:
meddler convert medium-export.zip --preset hugo Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
meddler convert medium-export.zip --preset hugo CODE_BLOCK:
meddler convert medium-export.zip --preset hugo CODE_BLOCK:
meddler convert medium-export.zip \ --target jekyll \ --front-matter yaml \ --images download \ --include-drafts \ --include-responses Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
meddler convert medium-export.zip \ --target jekyll \ --front-matter yaml \ --images download \ --include-drafts \ --include-responses CODE_BLOCK:
meddler convert medium-export.zip \ --target jekyll \ --front-matter yaml \ --images download \ --include-drafts \ --include-responses CODE_BLOCK:
{ "frontMatter": "yaml", "target": "hugo", "includeDrafts": true, "imageMode": "download", "supplementary": ["profile", "earnings", "bookmarks"], "extraFields": { "author": "{{author.name}}", "canonical_url": "{{url}}" }
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
{ "frontMatter": "yaml", "target": "hugo", "includeDrafts": true, "imageMode": "download", "supplementary": ["profile", "earnings", "bookmarks"], "extraFields": { "author": "{{author.name}}", "canonical_url": "{{url}}" }
} CODE_BLOCK:
{ "frontMatter": "yaml", "target": "hugo", "includeDrafts": true, "imageMode": "download", "supplementary": ["profile", "earnings", "bookmarks"], "extraFields": { "author": "{{author.name}}", "canonical_url": "{{url}}" }
} COMMAND_BLOCK:
---
title: "My Article Title"
subtitle: "A deeper look at the topic"
date: "2023-06-15T14:30:00.000Z"
slug: "my-article-title"
canonical_url: "https://medium.com/@username/my-article-title-abc123"
author: "Your Name"
medium_id: "abc123def456"
draft: false
tags: - programming - web-development
image: "images/my-article-title/featured.jpeg"
---
## Heading Your clean Markdown content here, with all of Medium's
presentation cruft stripped away... Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK:
---
title: "My Article Title"
subtitle: "A deeper look at the topic"
date: "2023-06-15T14:30:00.000Z"
slug: "my-article-title"
canonical_url: "https://medium.com/@username/my-article-title-abc123"
author: "Your Name"
medium_id: "abc123def456"
draft: false
tags: - programming - web-development
image: "images/my-article-title/featured.jpeg"
---
## Heading Your clean Markdown content here, with all of Medium's
presentation cruft stripped away... COMMAND_BLOCK:
---
title: "My Article Title"
subtitle: "A deeper look at the topic"
date: "2023-06-15T14:30:00.000Z"
slug: "my-article-title"
canonical_url: "https://medium.com/@username/my-article-title-abc123"
author: "Your Name"
medium_id: "abc123def456"
draft: false
tags: - programming - web-development
image: "images/my-article-title/featured.jpeg"
---
## Heading Your clean Markdown content here, with all of Medium's
presentation cruft stripped away... - Not portable: files are single-page HTML documents with inline CSS and Medium-specific class names.
- Noisy: includes Medium's presentation layer (graf--, section--, markup-- CSS classes), making content reuse difficult.
- Scattered: metadata like publish date, canonical URL, subtitle, and author are embedded in the HTML footer and header, not structured as data. - Bookmarks—your reading list, exported as structured data
- Claps—every post you've clapped for, with clap counts
- Highlights—quotes you've highlighted on other people's articles
- Interests—the tags, topics, publications, and writers you follow
- Lists—your curated reading collections
- Earnings—Partner Program revenue data per article
- Social graph—who you follow (users, publications, topics)
- Profile—your display name, bio, avatar URL, connected accounts - Web: meddler.fyi—drag, drop, download. No installation required.
- CLI: npm install -g meddler-cli for power users and automation.
- Source: github.com/brennanbrown/meddler The entire project is open source under the AGPL-3.0 license and contributions are welcome!
how-totutorialguidedev.toaimlserverswitchnodegitgithub