Medium to git-based blog migration: keep your rankings
A Medium to git-based blog migration playbook: export your posts, handle redirects since medium.com isn't your domain, and protect your rankings.
A Medium to git-based blog migration playbook: export your posts, handle redirects since medium.com isn't your domain, and protect your rankings.

Every other migration in this series starts the same way: export your content, map your URLs, write a 301 for each one. Medium breaks that playbook at step one. You don't own medium.com, so unless you were on Medium's free custom domain feature, you can't write a server-side redirect at all. The honest starting question for a Medium migration isn't "how do I redirect," it's "do I even get to."
That's a genuinely different problem than the one we cover for Ghost, Webflow, or HubSpot, all platforms where you at least control the domain the posts live on. It's also a different decision than cross-posting to Medium with a canonical tag while keeping your original live elsewhere. This post is for teams leaving Medium entirely, not syndicating to it. This post covers why Medium caps a company blog's long-term value even when it's performing well, what its export actually gives you, and the two-track redirect reality depending on whether you used a custom domain.
A post that ranks well on Medium is still ranking on Medium's authority, not yours, and every outbound link from it passes nothing back to you. Here's what that costs a growing SaaS blog.
Medium.com carries a Domain Rating of 94 and is linked to by roughly 814,300 referring websites as of mid-2026, pulling in about 30.1 million organic search visits that same month (Ahrefs). That's an enormous amount of crawl priority and ranking power sitting on a domain you'll never own a fraction of. Your post ranks because it's hosted on Medium's authority, borrowed for as long as you keep publishing there. The day you leave, that borrowed authority stays exactly where it was: with Medium.
Compare that to a post on your own domain. Every backlink it earns, every bit of topical trust it builds, compounds toward a domain you control indefinitely. On Medium, the same effort compounds toward Medium's number, not yours.
Medium sets rel=nofollow on every outbound link by default (Talotics), so even a link from a well-ranked Medium post to your product or your own domain passes zero link equity. That's a separate problem from ranking: it means Medium can't even function as a source of real backlink authority for you while you're publishing there.
The metered paywall adds a second, quieter cost. Googlebot generally sees a metered paywall as a fresh, cookie-less visit each time it crawls, so it indexes the full article even after a human reader has hit their free-article limit for the month (RankStudio). That's good news for indexing and bad news for conversion: your post can rank on page one and still lose a meaningful share of clicks to a paywall prompt the search engine itself never saw.
The clearest documented case is Baremetrics. Its top-performing Medium posts topped out at 8,000 to 10,000 views, with one outlier hitting roughly 40,000, while equivalent posts on its own domain consistently pulled in multiples of that once the company moved back (Baremetrics). Founder Josh Pigford put the deeper issue in one line: "I realized Medium is really great about surfacing content, but it removes the face of it." Distribution without attribution is the trade you're making every time you publish there instead of on your own domain.
Medium's export gives you the raw material, but it's HTML, not Markdown, and it's missing the images entirely. Budget time for the conversion, not just the download.
From Settings, then Security and apps, then Download your information, Medium generates a .zip of HTML files, one per story, carrying Medium's own presentation-layer CSS classes inline (Medium Help Center). That's not Markdown and it's not structured JSON the way Ghost's export is; it's raw HTML built for Medium's own reader, not for a static site generator. Every post needs an HTML-to-Markdown conversion pass before it's usable in a git-based blog, and a hand review after, the same discipline every platform in this series needs at the content-conversion step.
You don't have to write that conversion yourself. mediumexporter is a CLI tool that takes a single Medium post URL and exports it straight to Markdown, downloading the post's images alongside it into an output folder. medium-2-md does the same job with YAML front matter added, useful if your new git-based blog expects frontmatter fields on every file the way this one does. Both exist specifically because Medium's own export leaves you with HTML, not a format any static site generator reads natively.
The HTML files in Medium's export only link to images hosted on Medium's CDN; the actual image files aren't included in the .zip at all (medium-export-image-fill). That's exactly the gap the medium-export-image-fill script was built to close: it downloads every referenced image into a local folder and rewrites the HTML to point at the local copies instead of Medium's servers. Run something like it, or download images by hand, before you do anything that could break that CDN link, including trimming a post's content or changing where readers land.
Medium's export includes each story's original publish date in the HTML, and both mediumexporter and medium-2-md carry that date through into the Markdown output rather than stamping the file with the export date. Set your new post's date field to the original Medium publish date, not the day you migrate it. A five-year-old post that suddenly shows today's date in your sitemap and RSS feed reads as freshness-gaming to anyone who checks, and it also throws off your own archive's chronology. The same goes for author credit: pull the byline from the export and set it in your new frontmatter's authorInfo, rather than defaulting every migrated post to whoever happens to run the import script.
This is the fork every other post in this series skips, because every other platform in this series puts you on infrastructure you control. Medium splits into two genuinely different cases depending on one setting you made (or didn't) when you started publishing.
Medium reintroduced free custom domains for members in September 2020, after pausing the feature in 2018 to rebuild its cross-domain SSL handling (Jarango). If you set one up, blog.yourcompany.com pointing at your Medium publication, that domain's DNS has always been yours, not Medium's. Point it at a new host instead and you get the same real, server-side 301 redirects every other migration in this cluster relies on.
Google's own site-move documentation treats a permanent, 301 or 308, redirect as a strong canonicalization signal: "the indexing pipeline uses the redirect as a signal that the redirect target should be canonical" (Google Search Central). A 302, 303, or 307 doesn't earn that same treatment, because those codes signal a move that might not be permanent. If you're in the custom-domain case, expect temporary ranking fluctuation while the move settles, on the order of a few weeks for a medium-sized site per Google's own estimate, and keep the redirects live for at least a year, the window Google itself recommends (Google Search Central).
If your posts live at medium.com/@username, or a Medium publication URL you never mapped a custom domain to, there's no redirect to write. Medium, not you, controls medium.com's infrastructure, and it gives you no mechanism to send a server-side 301 from a URL on its domain to one on yours (Content Powered). This is the case most solo writers and early-stage teams are actually in, since a custom domain was always an opt-in extra step, not the default.
The standard workaround has two parts. First, set Medium's own canonical link field on each post to point at the new URL (below). Second, edit each post down to roughly the first 25% of its original content, leaving the rest as a hook, with a link to the full version on your new domain (Inblog). Neither move is a redirect. Both reduce the odds that Medium's copy keeps outranking or cannibalizing the version you actually want people to find, the same duplicate-content dynamic we cover in keyword cannibalization, just running across two domains instead of inside one.
Open the story, click More settings, scroll to Advanced Settings, and select "This story was originally published elsewhere." Enter your new domain's URL and save (Medium Help Center). Only the story's author can set this field, and it's a per-post action; there's no bulk tool to run it across your whole archive at once. Budget the time accordingly if you're migrating a few dozen posts.
Be honest with yourself about the ceiling here. A canonical tag and a trimmed excerpt are real signals, not a guarantee, and they're weaker than a 301 by design, since Medium's own systems still control whether the trimmed post stays indexed at all. Expect a slower, less certain recovery than the custom-domain case, and expect some of your Medium posts to keep showing up in search results pointing at the old URL for longer than you'd like. That's the honest cost of never having owned the domain in the first place, not a sign you did the migration wrong.
Work through this before you touch a single post:
date to its original Medium publish date and its author credit to the original byline, not the migration date.Once your posts are Markdown files in a repo, the publishing question changes from "does Medium still have my post" to "what does our git workflow look like for content." A new post is a branch and a file. Review happens as PR comments instead of Medium's own story stats page, which nobody outside the writer checks. A merge to main triggers the same build and deploy pipeline the rest of your product already uses, no separate Medium login and no dependence on a domain you never controlled.
You also get to gate every merge on checks Medium has no equivalent for: broken links, valid canonicals, a working sitemap, before a bad page ever reaches production. Our GitHub Actions SEO checks post walks through four automated jobs that do exactly that, and if you're weighing a headless CMS layer over flat Markdown files for the new setup, our headless CMS vs git-based blog post covers that tradeoff directly.
That handoff is also where a repo-native writing tool fits, instead of a Medium export you paste into a script once and never touch again. A git-based AI blog writer reads your repo's conventions, drafts a post as a Markdown file on a branch, and opens a pull request the same way a human contributor would, so nothing auto-publishes and your existing review process still gates every post. If you're building keyword strategy fresh alongside the migration rather than just porting an old Medium archive, our guide to SEO for SaaS covers picking winnable keywords before you're locked into any platform's constraints, and Lyra's plans start at $39 a month if you want to see what running that workflow costs once you're there.
Once your Medium migration lands on git, Lyra can take over the writing from there, reading your repo's conventions and opening a pull request for every new post, the same review gate you already use for code.
FAQ
Only if you published through Medium's free custom domain feature, where you control the DNS. Point that domain at a new host and you can write real server-side 301 redirects. If your posts live at medium.com/@username or a default publication URL, Medium controls that infrastructure, not you, so a true 301 isn't available. The workaround is setting Medium's own canonical link field on each post and trimming the Medium copy to a partial excerpt that links to the full version on your new domain.
A .zip file of HTML files, one per story, using Medium's own presentation-layer CSS classes inline, not Markdown or structured JSON. The HTML only links to your images on Medium's CDN; the image files themselves aren't included, which is why third-party tools like medium-export-image-fill exist to download them into a local folder separately.
Some fluctuation is normal and expected during any URL change, per Google's own site-move guidance. The bigger risk with Medium specifically is that you never controlled the rankings in the first place: medium.com carries a Domain Rating of 94 and roughly 30.1 million organic search visits a month, and that authority stays with Medium, not with you, the moment you leave. Recovery depends on whether you can 301 (custom domain) or have to rely on canonical links and content trimming (no custom domain).
Open the story, click More settings, scroll to Advanced Settings, and select 'This story was originally published elsewhere.' Enter your new domain's URL and save. Only the story's author can set this field, and it has to be done post by post; there's no bulk canonical tool in Medium's editor.
No. Medium sets rel=nofollow on every outbound link by default, so even a link from a well-ranked Medium post passes no link equity to your new domain. That's separate from the canonical link field, which is about which URL Google treats as the source, not about link authority.
Built by the tool you're reading about
Lyra finds the topics worth ranking for, writes them in your repo's voice, fact-checks every claim, and opens a pull request scored and ready to merge. You review and hit merge. Want to see what she'd write for you? Start free with three posts, no card.
Keep reading

A Contentful to git-based blog migration playbook: convert Rich Text JSON and entry references to Markdown, protect your rankings, and cut the metered API bill.

A Substack to git-based blog migration playbook: keep your subscriber list, redirect the /p/ URLs, and protect the rankings you already earned.

Content pruning for AI-era SEO means deleting or merging thin posts, not refreshing them. A decision framework, an audit, and what Google's 2026 update changed.