Building a Static Site with Pandoc | Joel Dare

3 min read Original article ↗

By Joel Dare - Written July 14, 2026

Recently I was ranting that GitHub Builds are Unreliable.

Today I decided to do something about it.

On my newest project I used pandoc to convert my markdown files to html. In it’s simplest form that is simply a command like this:

pandoc -s index.md -o index.html

That works great, all by itself, but I want to use a bit of custom CSS. I use Neat CSS for most of my pages. That means I need to include two CSS files (neat.css and custom.css). Here’s the command to include those:

pandoc -s index.md -o index.html --css=neat.css --css=custom.css

But that still leaves the default pandoc CSS embeded in the html file and I wanted to remove that.

So, you export the template from pandoc:

pandoc -D html > template.html

With the template exported, you can now modify that template directly. I removed the entire <style> section.

Now that I have my own template, we need one more command-line option to use that template. Here’s our updated command.

pandoc -s index.md -o index.html --template=template.html --css=neat.css --css=custom.css

That command is starting to get a bit unweildy. It’s also unique for every file. I wanted to run a single build command to build the whole thing. I could have created a little bash script to do the build, but I reached for make.

I don’t know make very well, so at this point I ran Claude Code and had it help me finish this up.

Here’s the makefile I ended up with. It finds every .md file in the current directory or below and builds each one into an html file.

PANDOC := pandoc
TEMPLATE := template/template.html
NEAT := css/neat.css
CUSTOM := css/custom.css

MD_FILES := $(shell find . -type f -name '*.md')
HTML_FILES := $(MD_FILES:.md=.html)

all: $(HTML_FILES)

%.html: %.md $(TEMPLATE) $(NEAT) $(CUSTOM)
	$(PANDOC) \
		-s $< \
		-o $@ \
		--template=$(TEMPLATE) \
		--css=$(NEAT) \
		--css=$(CUSTOM)

clean:
	find . -type f -name '*.html' -delete

.PHONY: all clean

I noticed that my page was still being processed through GitHub Actions and Jekyll so I added one more file to this mix. This is an empty file that tells GitHub not to use Jekyll to build this GitHub Pages site.

That’s it. I can now build my site locally using one command.

This does not COMPLETELY stop GitHub from building the project if you’re using GitHub pages. It still runs the default actions. These still take ~30 seconds to run and will still fail if there are outages with GitHub Actions. But it does allow you to iterate more quickly because you can view the pages locally instead of waiting for them to build.


JoelDare.com © Dare Companies Dotcom LLC

Terms - Privacy