Home

Published

- 2 min read

Hashnode Sync - A CLI for syncing with Hashnode

img of Hashnode Sync - A CLI for syncing with Hashnode

My Role: Sole Developer
Timeline: 1 day
Tech Stack: Node.js JavaScript GraphQL npm CLI

The Problem

This was my Hashnode GraphQL hackathon submission. I wanted a tool that I could use to sync my markdown blogs with Hashnode without many extra steps. It will track the blogs, see whether they changed and sync with my online blog.

The Solution

I built hashnode-sync, an npm command-line tool that automatically synchronizes local markdown files with a Hashnode blog. It detects changes, additions, or deletions and uses the Hashnode GraphQL API to keep the blog content in sync, enabling a seamless “content as code” workflow.

Impact & Results

  • Automated the publishing workflow, reducing the time to post or update an article from several minutes to a single command.
  • Enables a “content-as-code” approach, allowing writers to use tools like Git for versioning and collaboration on blog posts.
  • Published on npm for anyone to use.

Key Takeaways

  • Gained practical experience designing a CLI tool and integrating with a third-party GraphQL API.
  • Learned the process of publishing and versioning a public package on npm.
  • Discovered that advanced language features like Proxies can offer elegant solutions to common problems like state persistence.

My Contributions

  • Designed the core change-detection logic using SHA-256 content hashing to minimize API calls.
  • Built the end-to-end CLI experience, from an interactive setup prompt to full integration with Hashnode’s GraphQL API for CRUD operations on posts.
  • Engineered an elegant configuration persistence layer using JavaScript Proxies for simplified state management.

Technical Challenges & Decisions

Challenge: Persisting the sync state (which files were synced, their IDs, and last-known state) across separate CLI runs. Solution: Instead of manual read/write operations, I used a JavaScript Proxy to wrap the configuration object. This automatically intercepted any modification and seamlessly persisted the state to the hashnode-syncrc.json file. This choice greatly simplified the codebase.

// sync-json.js
function getSyncedJson(path) {
	const data = fs.readFileSync(path)
	const obj = JSON.parse(data)
	return new Proxy(obj, {
		set(target, property, value) {
			Reflect.set(target, property, value) // Update in-memory object
			saveJsonFile(path, target) // Persist change to disk
			return true
		}
	})
}

Challenge: Avoiding redundant API calls for files that hadn’t been modified. Solution: I stored a SHA-256 hash of each file’s content and metadata. On subsequent runs, the CLI only triggers an API update if a file’s calculated hash differs from the stored one, ensuring API calls are made only when necessary.

GitHub: https://github.com/Aryan3212/hashnode-sync