Script: export post as Markdown via Ghost Admin API
Once upon a time I deleted the production database
Long, long ago, when I was a young and inexperienced sysadmin, I ran some Heroku commands, and discovered that I had deleted my production Heroku PostgreSQL database for this Ghost blog. There was no option to rollback, and my backups didn’t include my draft posts. On that day, I decided to store the primary versions of all my posts locally, as versioned markdown files, that I paste into Ghost when I’m ready to publish.
This has worked fine, but the Ghost editor has gotten so nice, I often want to use it for drafting posts. And at the same time, Markdown, though still supported via the Markdown card, no longer has first-class support, and there’s no way to copy-and-paste formatting created with the new Ghost editor into a Markdown file.
I looked around and couldn’t find any existing scripts to export posts as markdown. So I wrote a little script, based on the Ghost Admin API demos repo, that fetches the content of a post by ID, and converts it to Markdown with the wonderful tool Pandoc (which I’ve written about before).
I thought I’d share it in case it’s useful for other people.
You will need to have the following installed:
- NodeJS
- NPM
- Pandoc
The only other dependency is the Ghost Admin API SDK, which can be installed with:
npm install @tryghost/admin-api
Here is the script itself:
// © 2025 Curiositry.
//
// First:
// npm install @tryghost/admin-api
// Run with:
// node get-post-as-markdown.js "POSTID" https://blah.ghost.io "ADMIN_API_KEY" | pandoc -f html+smart -t markdown-smart --wrap="preserve"
if (process.argv.length < 4) {
console.error('Missing an argument');
process.exit(1);
}
const postId = process.argv[2];
const url = process.argv[3];
const key = process.argv[4];
const GhostAdminAPI = require('@tryghost/admin-api');
const api = new GhostAdminAPI({
url: url,
key: key,
version: 'v6.8'
});
api.posts.read({id: postId}, {formats: ['html']})
.then((post) => {
console.log("<h1>"+post.title+"</h1>")
console.log("<h2>"+post.excerpt+"</h2>")
console.log(""+post.slug+"")
console.log(post.html);
})
.catch((err) => {
console.error(err);
});
So, how do we use it?
To output the text to your console for testing, run it with:
node get-post-as-markdown.js "POSTID" https://blah.ghost.io "ADMIN_API_KEY" | pandoc -f html+smart -t markdown-smart --wrap="preserve"
or, to write to a file (more useful!), use:
node get-post-as-markdown.js "POSTID" https://blah.ghost.io "ADMIN_API_KEY" | pandoc -f html+smart -t markdown-smart --wrap="preserve" -o "$(date -I) My Output Filename 1.md"
Obviously, replace POSTID with your post id, which you can see when you’re editing a post, because it’s the last part of the url (https://YOURSITE.com/ghost/#/editor/post/POSTID). And replace the url with your Ghost url, and the API key with one that you set-up by going to https://www.YOURSITE.com/ghost/#/settings/integrations/new, and following the steps, and then copying the ADMIN_API_KEY value.
Caveats:
- Sometimes it hard wraps lines. If you don’t like that, try switching
--wrap=preservefor--wrap=none. - For some reason, even though it’s set to output HTML, Ghost editor cards such as snippets don’t always render as HTML.
- It smartens straight typewriter-style quotes and apostrophes into proper curly quotation marks and apostrophes, because I like that. If you don’t, switch this part
-f html+smart -t markdown-smartto-f html -t markdown. - Square brackets and other special characters may have unecessary backslash escapes, which you’ll probably want to remove manually.