Skip to content

Commit 6b142e0

Browse files
authored
Merge pull request #5 from Hashnode/actions-flow
Switch template to the GitHub Actions publish flow
2 parents 3ab7256 + 0397cda commit 6b142e0

4 files changed

Lines changed: 106 additions & 188 deletions

File tree

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: Publish to Hashnode
2+
3+
on:
4+
push:
5+
branches: [main]
6+
workflow_dispatch:
7+
8+
jobs:
9+
publish:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
with:
14+
fetch-depth: 2
15+
- uses: Hashnode/publish-github-action@v1
16+
with:
17+
access-token: ${{ secrets.HASHNODE_PAT }}
18+
# Replace with your publication host, or use publication-id instead.
19+
publication-host: YOUR_BLOG.hashnode.dev
20+
posts-directory: posts

README.md

Lines changed: 63 additions & 173 deletions
Original file line numberDiff line numberDiff line change
@@ -1,183 +1,73 @@
1-
# Hashnode-source-from-github-template
2-
A template with boilerplate structure for Hashnode's Github as source feature
1+
# Publish to Hashnode from GitHub
32

4-
Please note: A **README.md** at the root is always ignored.
3+
Write blog posts as markdown files in this repository. Push to main, and they publish to your Hashnode publication through the [Publish to Hashnode GitHub Action](https://github.com/Hashnode/publish-github-action).
54

6-
If you don't find a log in your publication dashboard on Hashnode, but have made a commit to your connected repo, then make sure
5+
Publishing via the API requires a publication on [Hashnode Pro](https://hashnode.com/pro).
76

8-
* the file ends with .md extension, we support markdown files only.
9-
* you have connected the same repo as you made a commit to.
10-
* you added the correct blog domain in your markdown file.
11-
* Frontmatter: Make sure each article has these details at the top of the file.
12-
* A **README.md** at the root is always ignored.
7+
## Setup
138

14-
## Supported front matter fields and their description
9+
1. Click **Use this template** to create your own copy of this repository.
10+
2. Generate a Personal Access Token in [Settings → Developer](https://hashnode.com/settings/developer) on Hashnode.
11+
3. In your new repository, add the token as a secret named `HASHNODE_PAT` (Settings → Secrets and variables → Actions).
12+
4. Open `.github/workflows/publish-to-hashnode.yml` and replace `YOUR_BLOG.hashnode.dev` with your publication host.
13+
5. Edit `posts/example-post.md` or add a new `.md` file under `posts/`, commit, and push.
1514

16-
```
15+
That's it. Each push publishes new files and updates changed ones. The workflow's run summary shows what happened to every file.
16+
17+
## Writing posts
18+
19+
Every post is a markdown file with YAML frontmatter. Only `title` is required. Set a stable `slug`: it is how a file stays linked to its published post across pushes.
20+
21+
A post using every supported field:
22+
23+
```yaml
1724
---
18-
# Post Title
19-
# String | *REQUIRED*
20-
# Ex: Top 4 React UI Libraries for 2023
21-
title: Example title here
22-
23-
# Post Slug
24-
# What is slug? https://www.semrush.com/blog/what-is-a-url-slug
25-
# String | *REQUIRED*
26-
# Ex: top-4-react-ui-libraries-for-2023
27-
# - This is the URL of the post. It should be unique and should not be used by any other post.
28-
# - If you use the same slug of an existing post, the existing post will be updated.
29-
# - In order to let users update the post SLUG, we depend on the post slug as well
30-
# as it's path in the repo.
31-
# - If you change both path and slug of the post, the post will be treated as a new post and
32-
# will be published with a new slug.
33-
# - If you change only the slug of the post, the post will be updated with the new slug.
34-
# - If you change only the path of the post, the post will be will be updated with new path
35-
# and any other changes along with it if any.
36-
slug: example-slug
37-
38-
# Tags
39-
# String (comma-separated tag slugs) | *REQUIRED*
40-
# Ex: reactjs, css, python, nodejs
41-
# Upto 5 tag slugs
42-
# - You can find tags information from here https://github.com/Hashnode/support/blob/main/misc/tags.json
43-
# You can also update a post to edit this later.
44-
tags: reactjs, css, python, nodejs
45-
46-
# Publication Domain (hashnode.dev subdomain or your custom domain)
47-
# String | *REQUIRED*
48-
# Ex: townhall.hashnode.com
49-
# - This can also be a hashnode.dev subdomain as well.
50-
# - The publication domain name that you want to publish the post to.
51-
# This should be a valid domain name only.
52-
# - You should be an ADMIN of the publication to publish.
53-
domain: example.hashnode.dev
54-
55-
# Subtitle of the post
56-
# String | Optional
57-
# Ex: A curated list of the best React UI libraries for 2023
58-
subtitle:
59-
60-
# Cover Image URL of the post
61-
# String | Optional
62-
# Note: You must upload the image to Hashnode's CDN, before you can use it here.
63-
# Ex: https://cdn.hashnode.com/res/hashnode/image/upload/v1681132538878/itnaYF1h-.png
64-
# - To upload, Login to Hashnode and go to https://hashnode.com/uploader
65-
# Use the URL that is generated after the upload.
66-
cover:
67-
68-
# Should the post be ignored? When true it will not be picked up by Hashnode.
69-
# Boolean | Optional
70-
# Default value: false
71-
# Ex: true
72-
# - It's useful when you want to keep the post in your repo but don't
73-
# want it to be picked up by Hashnode.
74-
ignorePost:
75-
76-
# Publish on behalf of a team publication member
77-
# Username of the publication member
78-
# String | Optional | *WORKS WITH TEAM PUBLICATION ONLY*
79-
# Ex: sandeep
80-
# - This resembles the Change of author from draft settings of a
81-
# team publication in Hashnode editor.
82-
# - Fails if the user is not a member of the team publication or
83-
# if the publication is not a team publication
84-
publishAs:
85-
86-
# Canonical URL of the post
87-
# String | Optional
88-
# What is a canonical URL? https://moz.com/learn/seo/canonicalization
89-
# Ex: https://www.hashnode.com/post/top-4-react-ui-libraries-for-2023
90-
# - This is equivalent to original URL option present in draft settings
91-
# of a post in Hashnode editor.
92-
# - This is useful when you want to publish a post that is already
93-
# published on another platform.
94-
canonical:
95-
96-
97-
# Hide from Hashnode Community
98-
# Boolean | Optional
99-
# Default value: false // by default the post will be visible in the Hashnode's public feed.
100-
# Ex: true
101-
# - This is equivalent to "HIDE ARTICLE FROM HASHNODE FEED" option
102-
# present in draft settings of a post in Hashnode editor.
103-
# - This is useful when you want to publish a post to your publication
104-
# only but hide it from the Hashnode's public feed.
105-
# - You can also update a post to enable/disable this later.
106-
hideFromHashnodeCommunity:
107-
108-
# SEO Title
109-
# String | Optional
110-
# Ex: Top 4 React UI Libraries for 2023
111-
# - This is equivalent to SEO TITLE option present in draft settings
112-
# of a post in Hashnode editor.
113-
# - You can also update a post to update this later.
114-
seoTitle:
115-
116-
# SEO Description
117-
# String | Optional
118-
# Ex: A curated list of the best React UI libraries for 2023
119-
# - This is equivalent to SEO DESCRIPTION option present in
120-
# draft settings of a post in Hashnode editor.
121-
# - You can also update a post to update this later.
122-
seoDescription:
123-
124-
# Disable comments for a post
125-
# Boolean | Optional
126-
# Default value: false // by default the comments will be enabled for the post.
127-
# Ex: true
128-
# - This is equivalent to "DISABLE COMMENTS" option present in
129-
# draft settings of a post in Hashnode editor.
130-
# - You can also update a post to enable/disable this later.
131-
disableComments:
132-
133-
# Slug of the series that you want your post to be a part of
134-
# String | Optional
135-
# Ex: react-series
136-
# - This is equivalent to "ADD TO A SERIES" option present in
137-
# draft settings of a post in Hashnode editor.
138-
# - If invalid series is given, the post will not be added to any series.
139-
# - You can update the post again to correct it later.
140-
# - You can find series information from the series section in your publication dashboard.
141-
# You can also edit the series information from there.
142-
seriesSlug: // slug of the series
143-
144-
# Table of contents
145-
# Boolean | Optional
146-
# Default value: false // by default the table of contents will not be added to the post.
147-
# Ex: true
148-
# - This is equivalent to "GENERATE TABLE OF CONTENTS" option
149-
# present in draft settings of a post in Hashnode editor.
150-
# - If true, the table of contents will be added to the post.
151-
# - You can also update a post to enable/disable this later.
152-
enableToc:
153-
154-
# Save post as draft
155-
# Boolean | Optional
156-
# Default value: false // by default the post will be published.
157-
# Ex: true
158-
# - If true, the post will be saved as a draft.
159-
# - You can also update a draft with all the above attributes.
160-
# - This draft will be available under Drafts section of the
161-
# left sidebar in your publication dashboard.
162-
# - Note: Once you remove this attribute, the post will be
163-
# published and removed from drafts automatically.
164-
# - This follows the same rules as a post create and update
165-
# flow as well as the slug rules mentioned since
166-
# beginning of this manual.
167-
saveAsDraft:
168-
169-
170-
# Note:
171-
# This is in beta currently
172-
# Newsletter and Post scheduling is NOT supported as of now.
173-
25+
title: How I built my blog
26+
slug: how-i-built-my-blog
27+
subtitle: A tour of the stack
28+
tags: javascript, nextjs, web-dev
29+
cover: ./images/cover.png
30+
seriesSlug: building-in-public
31+
canonical: https://example.com/original
32+
seoTitle: How I built my blog with Next.js
33+
seoDescription: A walkthrough of the stack behind my blog.
34+
ogImage: https://example.com/og.png
35+
enableToc: true
36+
disableComments: false
37+
publishedAt: 2026-07-01T09:00:00Z
38+
saveAsDraft: false
39+
ignorePost: false
40+
hideFromCommunity: false
41+
publishAs: someusername
42+
coAuthors: user1, user2
43+
domain: other-blog.hashnode.dev
17444
---
175-
```
176-
* List of tags can be found here https://github.com/Hashnode/support/blob/main/misc/tags.json
177-
* Make sure you haven't included **ignorePost** in the frontmatter by mistake.
178-
* Uninstalling app via Github will remove it from all the publications that the repo was connected to. If you want to specifically remove the installation from a particular publication, do it from it's Dashboard (GitHub section).
179-
* You cannot create a new draft or a post with already published slugs
180-
* Do note that maximum of 10 file changes are respected in one particular commit.
45+
```
18146

47+
| Field | Notes |
48+
| --------------------------------------- | ----------------------------------------------------------------------------------- |
49+
| `title` | Required |
50+
| `slug` | Defaults to a slug of the title. Keep it stable. It is the update key |
51+
| `subtitle` | Shown under the title |
52+
| `tags` | Comma-separated or YAML list of tag slugs, max 15. Unknown tags are created |
53+
| `cover` | Cover image URL, or a repo path that gets uploaded to the CDN (alias: `coverImage`) |
54+
| `seriesSlug` | Slug of an existing series in your publication |
55+
| `canonical` | Canonical URL if the article was first published elsewhere (alias: `canonicalUrl`) |
56+
| `seoTitle`, `seoDescription`, `ogImage` | SEO and Open Graph overrides |
57+
| `enableToc` | Show a table of contents |
58+
| `disableComments` | Disable comments on the post |
59+
| `publishedAt` | ISO 8601 date, backdates the post |
60+
| `saveAsDraft` | Create a draft instead of publishing (new posts only) |
61+
| `ignorePost` | Skip this file entirely |
62+
| `hideFromCommunity` | Delist the post from feeds (alias: `hideFromHashnodeCommunity`) |
63+
| `publishAs` | Username of a publication member to publish as (team publications) |
64+
| `coAuthors` | Usernames of publication members, max 4 |
65+
| `domain` | Optional per-file publication override |
18266

67+
## Good to know
18368

69+
- **Create vs update.** The action looks up your `slug` in the publication. Found, the post is updated in place; not found, a new post is published. If your slug is already taken by another post, the API assigns a suffixed slug and the run summary warns you.
70+
- **Images.** Relative image paths (body and `cover`) upload to the Hashnode CDN automatically and resolve relative to the markdown file; a leading `/` resolves from the repository root. Supported: jpg, png, gif, webp, avif, up to 8 MB each. SVG is not supported. Absolute URLs pass through untouched.
71+
- **Drafts.** `saveAsDraft: true` creates a draft for new posts. Re-pushing the same file while it is still a draft creates another draft, so publish or remove the flag once done.
72+
- **Deletes.** Deleting a markdown file never deletes the post. Manage published posts from your dashboard.
73+
- Up to 10 changed files are processed per push by default (the `max-files` input raises it).

example-post.md

Lines changed: 0 additions & 15 deletions
This file was deleted.

posts/example-post.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
title: My first post published from GitHub
3+
subtitle: An example subtitle
4+
slug: my-first-post-published-from-github
5+
tags: general-programming, developer-blogging
6+
saveAsDraft: true
7+
---
8+
9+
This post lives as a markdown file in a GitHub repository. Pushing it to the main branch published it to Hashnode.
10+
11+
Edit this file and push again, and the post updates in place. The `slug` in the frontmatter is how the two stay linked, so pick one and keep it.
12+
13+
The `saveAsDraft: true` line above means this example lands as a draft, not a public post. Remove it when you write something real.
14+
15+
## Images
16+
17+
Reference images with a relative path and they get uploaded to the Hashnode CDN automatically:
18+
19+
```markdown
20+
![A diagram](./images/diagram.png)
21+
```
22+
23+
Absolute URLs work too and pass through untouched.

0 commit comments

Comments
 (0)