NIXX/DEVv1.14.0
ArticlesFavorites
Sign In
Sign In
Articles

Welcome to our blog

A curated collection of insightful articles, practical guides, and expert tips designed to simplify your workflow

Cover image for: Automating Blog Post Scheduling with GitHub Actions
July 29, 20255 MIN READ min readBy ℵi✗✗

Automating Blog Post Scheduling with GitHub Actions

A step-by-step look at how we auto-publish scheduled posts using Markdown, GitHub Actions, and Next.js.

webdevproductivityautomationgithub actions
ℵi✗✗

ℵi✗✗

Full-Stack Developer

Passionate about building tools and sharing knowledge with the developer community.

Was this helpful?

Popular Posts

  • NixOS vs. Arch Linux: Which One Belongs in Your Dev Setup?

    NixOS vs. Arch Linux: Which One Belongs in Your Dev Setup?

    5 MIN READ min read

  • How to Enable HTTPS on Localhost in Under 2 Minutes

    How to Enable HTTPS on Localhost in Under 2 Minutes

    3 MIN READ min read

  • Migrating from Create React App (CRA) to Vite: A Step-by-Step Guide

    Migrating from Create React App (CRA) to Vite: A Step-by-Step Guide

    4 MIN READ min read

  • Array Destructuring in PHP: A Practical Guide for Modern Developers

    Array Destructuring in PHP: A Practical Guide for Modern Developers

    5 MIN READ min read

Recommended Products

  • Dell 24 Monitor — SE2425HM Full HD

    Dell 24 Monitor — SE2425HM Full HD

    4.7
  • Hybrid ANC Bluetooth Headphones — 60H Playtime

    Hybrid ANC Bluetooth Headphones — 60H Playtime

    5.0
  • Apple MacBook Air M2

    Apple MacBook Air M2

    4.4
  • Samsung Galaxy S23

    Samsung Galaxy S23

    4.2

May contain affiliate links

Topics

webdev33productivity16cybersecurity12javascript11automation9guide8react7typescript7php6tutorial6freelancing5github actions5privacy5how to4Node.js4
+111 more topics →
🇺🇸USD ACCOUNTOpen a free US-based USD accountReceive & save in USD — powered by ClevaSponsoredInterserver Hosting#1 VALUEAffordable, reliable hosting from $2.50/mo99.9% uptimeSponsored

Publishing consistently is easier said than done when the alternative is remembering to push a button at the right time. For nixx.dev, the solution was to remove the manual step entirely: posts are written, scheduled via front matter, and published automatically when the scheduled time arrives.

The system uses three components: Markdown files with a status field in the front matter, a GitHub Actions cron workflow that runs daily, and a Next.js Route Handler webhook that checks for due posts and updates their status to published. There is no CMS dependency and no third-party publishing tool. Everything lives in the repository.

This post walks through how each component works and how they fit together.

What this covers:

  • Storing post metadata and schedule in Markdown front matter

  • A lightweight admin interface for managing drafts (optional)

  • The GitHub Actions cron workflow

  • The Next.js Route Handler webhook logic

  • Rebuild and deployment on publish


Step 1: Store Post Metadata in Markdown Front Matter

All blog content on nixx.dev is stored in Markdown files in /content/blog. Each file includes a front matter block with the publish date and a status field:

---
title: "How to Build a Website in 2025"
date: "2025-04-10T08:00:00Z"
status: draft
---

The status field accepts three values: draft, scheduled, and published. When a post is ready to go live at a future date, the status is set to scheduled and the date field is set to the target publish time in ISO 8601 format.

This structure keeps content management entirely within the repository. Posts can be written, reviewed, and committed to GitHub before they are live, and the visibility state is version-controlled alongside the content itself.


Step 2: Manage Posts with a Lightweight Admin Interface (Optional)

For teams or content-heavy projects, editing front matter directly in code is workable but friction-prone. We built a small login-protected dashboard that allows drafts to be edited visually, unpublished posts to be previewed, and scheduling to be set through a date picker that writes back to the front matter.

This step is optional. A solo developer comfortable with editing Markdown files directly can skip it entirely. The automation in Steps 3 and 4 works the same regardless of whether the status field was set through an interface or a text editor.


Step 3: Trigger a Daily Check with GitHub Actions

The automation runs via a GitHub Actions scheduled workflow that fires every day at 07:00 UTC. The workflow's only job is to call the webhook endpoint, which handles the actual publishing logic.

Create .github/workflows/publish-scheduled.yml:

name: Publish Scheduled Posts

on:
  schedule:
    - cron: '0 7 * * *'  # Every day at 7:00 AM UTC

jobs:
  publish:
    runs-on: ubuntu-latest

    steps:
      - name: Trigger Webhook
        uses: distributhor/workflow-webhook@v1
        with:
          url: https://nixx.dev/api/webhooks/check-scheduled-posts
          method: POST

The workflow is intentionally minimal. Keeping the scheduling logic in the application rather than in the GitHub Actions workflow means it is easier to test locally, easier to debug when something goes wrong, and not coupled to GitHub's infrastructure beyond the trigger.

Note: GitHub does not guarantee exact cron timing. Scheduled workflows may be delayed by a few minutes under high load. For a publishing system, this is acceptable. For anything requiring second-level precision, a different approach would be needed.


Step 4: Write the Webhook Logic with a Next.js Route Handler

With Next.js v15 and the App Router, the webhook is implemented as a Route Handler at app/api/webhooks/check-scheduled-posts/route.ts.

import { promises as fs } from 'fs';
import path from 'path';
import matter from 'gray-matter';

export async function POST() {
  const POSTS_DIR = path.join(process.cwd(), 'content/blog');
  const files = await fs.readdir(POSTS_DIR);

  for (const file of files) {
    const filePath = path.join(POSTS_DIR, file);
    const content = await fs.readFile(filePath, 'utf-8');
    const { data } = matter(content);

    const now = new Date();
    const publishDate = new Date(data.date);

    if (data.status === 'scheduled' && publishDate <= now) {
      const updated = matter.stringify(content, { ...data, status: 'published' });
      await fs.writeFile(filePath, updated);
      console.log(`Published: ${data.title}`);
    }
  }

  return new Response(
    JSON.stringify({ message: 'Checked and published scheduled posts.' }),
    {
      status: 200,
      headers: { 'Content-Type': 'application/json' },
    }
  );
}

The logic is straightforward:

  1. Read all files in the /content/blog directory

  2. Parse each file's front matter using gray-matter

  3. For any file with status: scheduled and a date that is now in the past, rewrite the file with status: published

  4. Return a 200 response confirming the check completed

The gray-matter package handles both reading and writing front matter without disturbing the rest of the Markdown content. Install it with npm install gray-matter.

One consideration for production: this webhook writes directly to the filesystem, which works on a self-hosted or VPS deployment where the repository is checked out on the server. On Vercel or other serverless platforms, the filesystem is read-only at runtime. In that case, the webhook would need to commit the status change back to the repository via the GitHub API rather than writing the file directly, and the subsequent commit would trigger a new deployment.


Step 5: Rebuild and Deploy After Publishing

Writing the updated status: published to the Markdown file is the trigger, but the site needs to rebuild before the post is visible to visitors.

For staging on Vercel, deployment is automatic on every push to the connected branch. If the webhook commits the status change back to the repository, Vercel detects the commit and triggers a rebuild.

For production on a custom VPS, the deploy script runs after the webhook completes:

cd /var/www/nixx.dev
git pull origin production
npm run build
pm2 restart next

This can be integrated into the webhook handler itself, triggered as a separate step in the GitHub Actions workflow after the webhook call, or run via a deployment hook in the hosting platform's settings.


Complete System Overview

Component

Role

Markdown front matter

Stores post content, publish date, and status

status field

Controls visibility: draft, scheduled, or published

GitHub Actions cron

Triggers daily at 07:00 UTC

Next.js Route Handler

Checks post dates and updates status to published

VPS deploy script

Rebuilds and restarts the site after publishing


Key Takeaways

  • Storing status and date in Markdown front matter keeps scheduling version-controlled alongside content and removes any dependency on a CMS or external publishing tool.

  • A GitHub Actions cron workflow is the lightest way to trigger a daily check. The scheduling logic itself belongs in the application, not the workflow.

  • The Next.js Route Handler uses gray-matter to read and write front matter without affecting the Markdown body content.

  • On serverless platforms where the filesystem is read-only at runtime, the webhook needs to commit status changes back to the repository via the GitHub API instead of writing files directly.

  • Rebuilding and redeploying after the status change is the final step. On Vercel this is automatic if the change is committed. On a VPS it requires a deploy script triggered after the webhook.


Conclusion

The complete system is modest in complexity but effective in practice. Posts are written and committed ahead of time, and the publishing step happens without requiring anyone to be present. The entire workflow is version-controlled, CMS-free, and runs on infrastructure already in use for deployment.

For any Next.js project that manages content in Markdown and wants scheduled publishing without adding a CMS dependency, this approach is worth considering. The webhook logic is under fifty lines, the GitHub Actions workflow is a dozen, and the only external dependency beyond Next.js itself is gray-matter.


Managing content on a Next.js site with a different approach? Share how your setup works in the comments.

Topics
webdevproductivityautomationgithub actions
Interserver Hosting#1 VALUEAffordable, reliable hosting from $2.50/mo99.9% uptimeSponsored

Discussion

Join the discussion

Sign in to share your thoughts and engage with the community.

Sign In
Loading comments…

Continue Reading

More Articles

View all
Cover image for: What Is Identity Theft (and How to Protect Yourself Online)
Nov 17, 20256 MIN READ min read

What Is Identity Theft (and How to Protect Yourself Online)

Identity theft can happen to anyone — often without you even realizing it. Learn what it means, how it happens, and the smart steps you can take today to keep your personal information safe online.

Cover image for: Build a Fun Alphabet Reader with TypeScript, Vite & Speech Synthesis API
Jun 27, 20254 MIN READ min read

Build a Fun Alphabet Reader with TypeScript, Vite & Speech Synthesis API

An interactive, educational project for beginners to learn modern frontend development.

Cover image for: AI for DevOps: Tools That Are Already Changing the Game
Jun 17, 20256 MIN READ min read

AI for DevOps: Tools That Are Already Changing the Game

How artificial intelligence is transforming CI/CD pipelines, monitoring, and incident response—today.

Cover image for: Array Destructuring in PHP: A Practical Guide for Modern Developers
Mar 12, 20255 MIN READ min read

Array Destructuring in PHP: A Practical Guide for Modern Developers

From PHP 7.1 to 8.1—learn how array destructuring simplifies variable assignment, reduces boilerplate, and improves readability in modern PHP development.

|Made with · © 2026|TermsPrivacy
AboutBlogContact

Free, open-source tools for developers and creators · Community driven