
While I’m still dialing a few things in, particularly trying to reduce the friction even more on my iPad, I’m quite comfortable with the writing workflow I have for this site at this point. This post will be the first in a series of posts I’m working on to share how I make it work.
A high-level overview
I had a few major friction points the last time I used Hugo. The first was trying to manage content. I had all the posts in a single directory and it just wasn’t usable. Second was properly handling drafts. I accidentally published a draft on more than one occasion and I don’t want to do that again. Finally was handling post dates, particularly with dra…

While I’m still dialing a few things in, particularly trying to reduce the friction even more on my iPad, I’m quite comfortable with the writing workflow I have for this site at this point. This post will be the first in a series of posts I’m working on to share how I make it work.
A high-level overview
I had a few major friction points the last time I used Hugo. The first was trying to manage content. I had all the posts in a single directory and it just wasn’t usable. Second was properly handling drafts. I accidentally published a draft on more than one occasion and I don’t want to do that again. Finally was handling post dates, particularly with drafts.
Today I solve the first issue by using a different post structure. Instead of storing all 800 plus files in a single folder, I put all my posts in /content/posts/<year>/ folders. Adding the year folders makes it so much easier for me to sort through the old post list and find what I’m looking for when I’m trying to link back to it.
I’ve also improved how I name the draft files themselves. In the year folder files are named in the following format: MM-DD-<post title>.md. The date is based on the publish date they appear on the site and makes it even easier for me to find the content I was looking for. Previously I would sometimes use a date, but it was usually when I started a post draft. This could get very confusing when I was trying to find an old post.
Of course, a good naming convention actually has to be followed. To do this today I use two scripts that can be run in any number of ways: “Create Draft” and “Promote Draft.”
Working with drafts
A screenshot of the Task Selection in VS Code.
Create Draft does what it says. It creates a new post draft under /content/drafts/ and labels the file with a timestamp. This lets me work on the draft for as long as I want without risking publishing it. The file name doesn’t matter either, I can change it to anything I want to help make sorting multiple drafts easier.
As for the draft itself, it uses most of the normal front matter but with a few twists. First, it adds the base of an image for the featured image. Next it also adds empty taxonomy terms for both category and tags. Finally, it doesn’t add a date at all as I don’t necessarily know when I’ll publish the post.
To launch the Create Draft script I can either run it from a VS Code task or run it as a GitHub Action. The former works great when I’m on my laptop. The latter I use when I’m working from my iPad.
A screenshot of a post draft in VS Code.
Publishing new content
When a draft is ready I run the “Promote Draft” script either from VS Code’s task runner or GitHub Actions. It asks me for a few fields: “now” or “later”, the post file name and a date.
If I only have one post the post file name field doesn’t matter as it will select the only post. If there are multiple posts and I forget to specify the filename it will fail with a robust error messages that even lists all the drafts in the folder. I rarely have more than a couple of drafts I’m working on at a given time so this make publishing a given post very easy.
If I want the post to appear on my site immediately, I select “now” and run the script. It will move the post to the appropriate post folder, rename it to conform to my post naming structure, add a timestamp to the date front matter and set the draft flag to false. If I run it through GitHub Actions it will even handle the post commit and if I run it via VS Code I just commit the changes when the script is done.
If I don’t want to publish the post right that moment I can specify “Later” when running the script and enter the date I want it to publish on in YYYY-MM-DD format. It will do all the same as above only it will set the date and time in the file name and in the date front matter to 8:00 am in my home timezone on the date I specified.
When “now” is selected via GitHub Action it will automatically trigger my deployment action to send it to CloudFlare. If I’ve elected to publish it later the 8:00 am is key as I’ve set my deployment script to also run on a daily schedule at 9:00 am in my home timezone. This will catch the future post date appropriately and publish it to my site, all while accounting for the fact that scheduled GitHub actions aren’t perfectly timed.
As a bonus, when new content is published an additional GitHub Action is kicked off to notify various services of the new content, kinda like Ping-o-matic does in WordPress.
Issues I still need to work on
For the most part, this works great. I can write from IA Writer, my app of choice on my iPad, or VS Code on my Mac and no my post will be available on my site when I want it to be. This is already a lot better than my workflow the last time I tried to use Hugo.
Where I still have some friction is with the iPad. I cannot preview a post so if I get anything wrong, like an image path, I’ll be in trouble. Second, I have to manually kick off the actions on GitHub’s website, update the repo in Working Copy and then remember to sync it all later. It’s not bad but I think I can do better and I’m still experimenting with ways to make that happen.
Finally, editing pages still isn’t great with this workflow (nor was it good with WordPress either). I’m also working on a way to draft edits to pages and have them automatically publish themselves when I want them to.
In the end, though, this is a sustainable workflow I can live with. Content is easier to find and organize, drafting posts is less error-prone and posts are published when I want them to be without me having to worry about publishing anything by accident or missing a post entirely. That’s a huge win and I’m excited for what it will enable for me going forward.
So how do these scripts work?
I’ll follow-up in the coming weeks with posts on each of the scripts, create draft and publish, as well as the VS Code tasks, GitHub Actions and other automation I’m using to make this all work.