Fetch Substack posts, convert to Markdown with front matter, replace content, and export as ZIP — lightweight, dependency-free, and easy to use.
- 📬 Fetch posts from any Substack user.
- 🏷️ Generate Markdown with front matter for Hashnode, Hugo, Jekyll, Astro, or custom format.
- 🔄 Replace multiple strings in Markdown content (
replaceslike Golangstrings.NewReplacer). - ⚡ Supports sequential or concurrent fetching with optional limit.
- 💨 Chainable API: offset, limit, numbering, progress callback, completed callback.
- 📦 Export multiple posts as a ZIP file automatically.
npm install @kitmodule/kitsubstack<script src="https://unpkg.com/@kitmodule/kitsubstack/dist/kitsubstack.min.js"></script>or
<script src="https://cdn.jsdelivr.net/npm/kitsubstack-js/dist/kitsubstack.min.js"></script><script src="https://unpkg.com/@kitmodule/kitsubstack/dist/kitsubstack.min.js"></script>
<script>
const kit = new KitSubStack("example.substack.com");
kit.offset(0)
.limit(5)
.numbering(true)
.frontMatter("hashnode")
.replaces("Substack", "Hashnode")
.progress(fetch => {
if (fetch.success) console.log("✅ Fetched:", fetch.post.slug);
else console.error("❌ Error:", fetch.slug ?? "unknown");
})
.completed(filename => console.log("✅ ZIP ready:", filename))
.zip();
</script>const { KitSubStack, zipSubstackToHashnode } = require("@kitmodule/kitsubstack");
// Basic usage
const kit = new KitSubStack("example.substack.com");
await kit.offset(0)
.limit(10)
.frontMatter("hashnode")
.zip();
// Shortcut helper
await zipSubstackToHashnode("example.substack.com", 0, 5, true);| Parameter | Type | Description |
|---|---|---|
| input | string | object |
| Method | Description | |
|---|---|---|
.offset(n) |
Set the starting post index | |
.limit(n) |
Set number of posts to fetch | |
| `.numbering(true | false)` | Prepend numbering to file names |
.progress(callback) |
Callback for each fetched post | |
.completed(callback) |
Callback when ZIP is ready | |
.concurrent(n) |
Run n fetches concurrently |
|
.replaces(...args) |
Replace multiple strings in content, e.g. .replaces("0","1","2","3") |
|
| `.frontMatter(type | callback)` | Set front matter preset or custom function |
.zip() |
Fetch posts, generate Markdown + front matter, and export ZIP |
| Preset | Fields |
|---|---|
| hashnode | title, slug, tags, date, image |
| hugo | title, slug, date, draft, tags, description, cover |
| jekyll | layout, title, slug, date, categories, description, image |
| astro | title, pubDate, description, tags, heroImage |
| default | title, slug, date, description, image |
Supports async custom functions:
kit.frontMatter(async post => ({
title: post.title.toUpperCase(),
date: post.post_date,
tags: post.postTags?.map(t => t.name) ?? [],
}));kit.replaces(
"Substack", "Hashnode",
"2025", "2026"
);- Works like Golang
strings.NewReplacer. - Replaces all occurrences in each post body.
KitSubStack is dependency-free and already integrates the following Kit modules:
| Package | Purpose | Integrated in KitSubStack? |
|---|---|---|
| KitZip JS | Create ZIP files from Markdown or other files; lightweight and chainable. | ✅ Yes |
| KitYAML JS | Convert JavaScript objects to YAML front matter for Markdown files. | ✅ Yes |
| KitMarkdown JS | Convert HTML to Markdown in a lightweight, dependency-free way. | ✅ Yes |
⚡ Note: You don’t need to install anything extra to use KitSubStack. These packages are included and work out of the box. However, you can still use each module individually in other projects or integrate them into a custom workflow, for example: fetch posts → convert HTML to Markdown → generate YAML front matter → export ZIP.
If you find this library useful, you can support me:
Released under the MIT License © 2025 Huỳnh Nhân Quốc · Open Source @Kit Module