A powerful GitHub Action that seamlessly publishes blog posts from your GitHub repository to Hashnode publications. This action handles markdown files with frontmatter, processes content, and manages posts through Hashnode's GraphQL API.
- Automated Publishing: Create and update posts on Hashnode directly from your GitHub repository
- Smart Updates: Only processes changed files, minimizing API calls
- Image Handling: Automatically processes both cover images and inline images
- Post Management: Handles creation, updates, and delisting of posts
- Frontmatter Support: Rich metadata support through YAML frontmatter
- Debug Output: Comprehensive debugging information for troubleshooting
- A Hashnode account and publication
- A GitHub repository containing your markdown posts
- A Hashnode Personal Access Token
- Go to your repository's Settings → Secrets and Variables → Actions
- Create a new secret
HASHNODE_ACCESS_TOKEN
with your Hashnode API tokenName: HASHNODE_ACCESS_TOKEN Value: your_hashnode_api_token
Create .github/workflows/publish.yml
:
name: Publish to Hashnode
on:
push:
branches:
- main
paths:
- 'content/posts/**'
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v44
- uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Publish to Hashnode
uses: actions/publish-github-to-hashnode@v1
with:
added-files: ${{ steps.changed-files.outputs.added_files }}
changed-files: ${{ steps.changed-files.outputs.all_changed_files }}
access-token: ${{ secrets.HASHNODE_ACCESS_TOKEN }}
publication-host: 'blog.mydomain.com'
posts-directory: 'content/posts'
your-repo/
├── content/
│ └── posts/
│ ├── my-first-post.md
│ └── images/
│ └── cover.jpg
└── .github/
└── workflows/
└── publish.yml
---
title: My Awesome Post
subtitle: A detailed guide to awesomeness
slug: my-awesome-post
tags: javascript,webdev,tutorial
enableTableOfContents: true
coverImage: images/cover.jpg
coverImageAttribution: Photo by Author
publishedAt: 2024-03-20T10:00:00Z
disableComments: false
---
Your post content here...
Field | Required | Type | Description |
---|---|---|---|
title | Yes | string | Post title |
slug | Yes | string | URL slug for the post |
subtitle | No | string | Post subtitle |
tags | No | string | Comma-separated list of tags |
enableTableOfContents | No | boolean | Enable/disable TOC |
coverImage | No | string | Path to cover image |
coverImageAttribution | No | string | Attribution for cover image |
publishedAt | No | string | ISO 8601 datetime |
disableComments | No | boolean | Disable comments |
- Create/edit markdown files in your repository
- Commit and push changes
- GitHub Action automatically:
- Detects changed files
- Processes markdown content
- Updates images to use absolute URLs
- Creates/updates posts on Hashnode
- Provides detailed output of operations
{
"added": [{
"id": "post123",
"title": "New Post",
"slug": "new-post"
}],
"modified": [{
"id": "post456",
"title": "Updated Post",
"slug": "updated-post"
}],
"deleted": [],
"errors": []
}
- name: Publish to Hashnode
id: publish
uses: actions/publish-github-to-hashnode@v1
# ... inputs ...
- name: Process Results
run: |
echo "Published posts: ${{ fromJSON(steps.publish.outputs.result_json).added }}"
echo "Summary: ${{ steps.publish.outputs.result_summary }}"
Enable debug logs by setting repository secret:
ACTIONS_STEP_DEBUG=true
View detailed logs in GitHub Actions run.
- Fork the repository
- Create a feature branch
- Submit a Pull Request
Please check existing issues and create a new one before submitting PRs.
MIT License - see LICENSE for details
- Create an issue for bugs/features