Building a Write-Once Publishing Pipeline

The problem

Writing content is the easy part.

Publishing it consistently across platforms — with the right metadata, images, tags, canonical URLs, and updates — is where things usually fall apart.

Most workflows still look like this:

  • Write content in one tool
  • Copy/paste it into WordPress
  • Reformat it for another platform
  • Forget what was published where
  • Lose track of updates and fixes

I wanted something different:

Write once. Publish many. Update safely. Automate everything.

That goal led to building a fully automated, Git-driven publishing pipeline.


The core idea

At the heart of this system is a simple principle:

Markdown in Git is the single source of truth.

Everything else — publishing, updating, tracking, media handling — is derived from that.

The pipeline is designed to be:

  • Idempotent (safe to run repeatedly)
  • Stateless at the CI level
  • State-aware via a database
  • Extensible to new platforms
  • Ready for containerization and Kubernetes

Current feature set

As of today, the pipeline supports:

Content & metadata

  • Markdown with YAML frontmatter
  • Title, slug, tags, featured image
  • Per-platform publish switches
  • Optional force_update flag

Publishing

  • WordPress publishing via REST API
  • Automatic post creation and updates
  • Draft or published status
  • Automatic canonical URL generation

Featured images

  • Uploads media via WordPress REST API
  • Reuses existing media (idempotent)
  • Declares images directly in Markdown

State tracking

  • PostgreSQL-backed state
  • Tracks:
    • Which platform a post was published to
    • Platform-specific post IDs
    • Content hashes
    • Publication timestamps
  • Automatic detection of content changes

Safe updates

  • Content hash comparison
  • Automatic post updates when Markdown changes
  • No duplicate publishing
  • No manual DB editing required

The workflow

The publishing flow looks like this:

  1. Write or edit a Markdown file
  2. Commit and push to Git
  3. Jenkins pipeline runs
  4. The publisher:
    • Parses frontmatter
    • Computes content hash
    • Checks platform state in PostgreSQL
    • Uploads featured image if needed
    • Creates or updates the WordPress post
    • Updates state in the database
  5. Pipeline finishes — safely and repeatably

Flow diagram

Here is the high-level flow of the system:

publishing-flow.png

Why this architecture works

A few design decisions make this pipeline robust:

Git is truth

All content and intent live in Git. No hidden state, no UI-only changes.

Database is state

The database tracks what happened, not what should happen. This makes updates and corrections safe.

CI is stateless

Jenkins doesn’t store anything between runs. That makes the system portable and container-friendly.

Platform abstraction

WordPress is just one publisher. Dev.to, Substack, Patreon, or others can be added without changing the core model.


Where this is heading

This pipeline already behaves like a backend service.

The natural next steps are:

  • Add more publishing targets (Dev.to, Substack, etc.)
  • Introduce analytics and engagement tracking
  • Package the publisher as a container
  • Run it inside Kubernetes
  • Add a simple UI on top
  • Offer it as Publishing as a Service

One repo, one workflow, one source of truth — for years of content.


Final thoughts

This started as “I just want to publish more easily”.

It ended up becoming a fully automated publishing platform with:

  • Git-based content management
  • CI-driven execution
  • Database-backed state
  • Idempotent, update-safe publishing

And the best part?

Writing content is now the only manual step left. Everything else is automation. Cool and nifty.

Did you find this post helpful? You can support me.

Author Profile

12ww1160DevOps engineer & architect

Leave a Reply

Your email address will not be published. Required fields are marked *

4 × 1 =