How WordPress compares to the JAMStack

Last modified April 15, 2020
.* :☆゚

For the past three+ years, I’ve been a predominantly WordPress-based developer.

I build custom websites based on a boilerplate theme and workflow, and try not to rely on too many plugins for all my builds. Page builders aren’t even something I know too much about because I rarely if ever use them.

I know WordPress hasn’t had a very good reputation recently, and many think is is bloated, outdated, or hard to maintain. One or all of these things could be true, depending on the developer.

I’m always keen to optimise performance and builds where I can, so I spent over a year experimenting with static sites and the jamstack to see how viable it is to use an SSG for an actual production site.

For this post, I wanted to delve into the roadblocks I encountered, and shed light on how the workflows differ for a WordPress and jamstack build.

What does JAMStack mean?

JAMStack architecture is based on three principles: JavaScript, APIs, and Markdown. It’s premise is that it leverages JavaScript’s ecosystem to generate entirely static sites without needing to request data dynamically from a server. Many SSGs are also git based, meaning they can be used to build and deploy from an online repository.

Compare this to a traditional website such as WordPress, which separates the server from the front-end through it’s LAMP stack: Linux, Apache, MySQL, and PHP. Data is served from a database at the time a user visits a site, meaning there will always be a delay to load the entire page while dynamic data is being fetched.

Around a year ago I started tinkering with other content management systems and JAMStack-based static site generators to explore alternatives to WordPress. The main reason being, if there’s an opportunity where I can optimise my work I’m always keen to do better.

I wanted to see if there really was anything better than WordPress because static sites do have merit. At the end of the day no matter what you do to optimise a WordPress build, it still pulls in data from a server, which is inherently slower than a statically generated site serving static content.

Static sites are also considered more secure since there is technically no ‘server’ to carry out malicious attacks (however there can still be vulnerabilities introduced in code but that’s a whole other topic).

Learning the ins and outs of the JAMStack was fun and interesting, and I learnt a lot. But the more I tinker with SSGs, the more I also realise WordPress is actually still a solid choice for commercially made websites. Based on its capabilities and versitility alone, WordPress has a big advantage when it comes to actually managing content on a day to day basis with a visual admin interface.

There are always pros and cons to every use-case, and of course the decision to use a SSG or WordPress depends on your project requirements. From the outset, it might seem like an easy choice to pick an SSG for performance alone, but realistically that’s only if the client and content manager is myself because of the sheer amount of time required to complete and maintain a static site.

I love WordPress, but I also like to think I have given the JAMStack a fair chance over the past year. I’m definitely not writing serverless sites off anytime soon either (this site is statically generated using Hugo), I think it just might take a few years for the technology to advance to a stage where its viable for both developers and clients.

Image processing

One of the biggest roadblocks I encountered was how to optimise images responsively. If you’re familiar with WordPress you’ll probably know that it has fantastic image management already built in. It dynamically creates different sized images when an image is uploaded, and has various image based functions to serve them up appropriately.

You can use a single function to output a complex srcset, or build your own markup like below:

$id = get_post_thumbnail_id(get_the_ID());
$size = 'medium';
$img_src = wp_get_attachment_image_url( $id, $size );
$img_srcset = wp_get_attachment_image_srcset( $id, $size );
$title = get_post($id)->post_title;
$alt = isset(get_post_meta($id, '_wp_attachment_image_alt')[0]) ? get_post_meta($id, '_wp_attachment_image_alt')[0] : $title;
<img src="<?php echo esc_url( $img_src ); ?>"
srcset="<?php echo esc_attr( $img_srcset ); ?>"
sizes="(min-width: 768px) 150px, 80vw"
alt="<?php echo $alt; ?>"

When you’re using a static site generator though, you often have to rely on third party APIs to dynamically serve the content you need. The site may be statically generated, but you still need to host the images somewhere.

It makes a lot of sense to separate images from content, because image size can add up fast and can not only affect the bandwidth of your hosting but also take up valuable space and make your site less transportable. Many image hosting services are popping up now, and it seems like Cloudinary is a popular choice, which is also the service I tried.

The main downside I came across though was that it was a very time consuming process to set up, just for one site. This balloons if you plan on using a CMS. It also means one extra service to pay for- as well as one more account you and the client has to be aware of.

Image management overall has to be scrutinised more carefully when using content managers for static sites. If you don’t use a service like Cloudinary, you may just end up storing all your images in a folder within your static site. This might not be a problem if you only use ~5-20 images total across your site. However, because most SSGs are git based, including images in your repository can mean a longer build time, and as I said earlier, makes your site less transportable because of the weight of images. Over time, this images folder can be come huge and unwieldy. If you wanted to sort images by date and in folders, you would have to write a custom function to process that. And I haven’t even gotten to how to serve responsive images, which is a mission in itself.

Responsive images on static sites is a manual process, unless you use an API like Cloudinary. Even then, it’s time consuming to set up for each different site, because you need to get several different pieces talking to each other and programatically copying and resizing uploaded images. Implementing responsive images on static sites is not an easy thing to do, and does not come automatically for most SSGs.

Content editing and management

I tried Netlify CMS along with Netlify to host my builds, and while the services are fantastic, the overall capabilities weren’t enough for me. It wasn’t a fault with the architecture, but moreso a problem with the limited nature of markdown.

Markdown is a language that is supposed to make writing text faster and easier. It was never meant to be used as a content markup language (as far as I know). Despite this, many SSGs use markdown to process content, with page metadata listed at the top in YAML or other. In fact the M in jamstack stands for ‘markdown’, which is why it features so prominently in static sites.

In my opinion, markdown is too basic of a ‘language’ to be using to process content. Blog articles might mostly contain text, but they may also contain images, links, and pullquotes. None of these basic things are possible in markdown without writing all the manual html yourself. This means that when you write a blog post, even if you use a CMS like Netlify CMS, you may still have to manually type out href tags, srcset tags, blockquotes, and pullquotes manually.

You could link to a site easily in Markdown using [this syntax]( but you cannot add important additional attributes such as rel="noopener" or target="_blank" without writing the entire href tag out manually. This is a major oversight of many editors in my opinion, and an SSG’s biggest achilles heel.

It’s one big reason why I can’t see myself using a SSG for a client any time soon- simply because you can’t expect clients to know or want to use HTML to write what should be a simple blog post.

WordPress’ TinyMCE based editor is old but extremely powerful, because it allows you to use a visual editor as well as write plain html markup. Honestly after trying many content management systems, visual editors in my opinion should be purely markup based without markdown mixed in. Markdown simply introduces too much overhead and abstraction which doesn’t suit the dynamic nature of the web.


Maintaining a static site can be a pain if you use a lot of third party plugins, APIs, and scripts. The more dependencies you have, the more likely it is you’ll have to update it in the future.

This happened to me on more than one occasion on this site where I am using Hugo and Gulp. I love Gulp but most problems stemmed from many of its dependencies coupled with Hugo’s updates which caused things to fail over time. This resulted in many hours of debugging to sort out the site compilation. It got so bad I contemplated moving this entire site to WordPress. It’s hard to let go of something though when you’ve spent so much time on it already!

I also tried some other boilerplates using webpack and PostCSS, as well as some eleventy starters and gatsby starters. They all had different configuration needs and over time, contained many vulnerabilities flagged by npm. I actually crafted a static site boilerplate using eleventy and Netlify CMS I was going to try to use for client projects last year, however I don’t think it will even build now without some major debugging, which I’m not really keen on getting into.

Debugging templates and data

Debugging is a huge pain point for me when using SSGs, and is actually where I appreciate PHP even more for how easy it is to dump data and trace errors (that is, once you get xdebug working which is a whole other story…). If you’re using WordPress, it’s considerably easier to debug because it is extremelly well documented and you are most likely only dealing with a single language at a time.

One big problem with static sites is how so many different languages and concepts can be interspersed within each other. You have MDX, handlebars, html in markdown, css in js, yaml in json, the list goes on! It would be great if it all worked seamlessly, but inevitably you will get errors when building a site. It can be hard to trace these errors back to the source when it’s hard to tell what language or concept is throwing it in the first place.

The tradeoff that goes hand in hand with this is the fact that syntax highlighting in code editors can be iffy, and may not even exist at all for your use-case. For example, if you use PostCSS to process your css, syntax highlighting is NOT easy to set up since it uses the same .css file extension. If you wanted to create a custom endpoint or RSS feed, you may need to put handlebars concepts or YAML within a JSON or XML file.

In fact, here is an example of the xml file I am using right now for this very site, to create a custom rss feed:

<rss version="2.0" xmlns:atom="" xmlns:content="">
    <title>{{ if eq  .Title  .Site.Title }}{{ .Site.Title }}{{ else }}{{ with .Title }}{{.}} on {{ end }}{{ .Site.Title }}{{ end }}</title>
    <link>{{ .Permalink }}</link>
    <description>Recent content {{ if ne  .Title  .Site.Title }}{{ with .Title }}in {{.}} {{ end }}{{ end }}on {{ .Site.Title }}</description>
    <generator>Hugo --</generator>{{ with .Site.LanguageCode }}
    <language>{{.}}</language>{{end}}{{ with }}
    <managingEditor>{{.}}{{ with $ }} ({{.}}){{end}}</managingEditor>{{end}}{{ with }}
    <webMaster>{{.}}{{ with $ }} ({{.}}){{end}}</webMaster>{{end}}{{ with .Site.Copyright }}
    <copyright>{{.}} {{printf "2019-"}}</copyright>{{end}}{{ if not .Date.IsZero }}
    <lastBuildDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</lastBuildDate>{{ end }}
    {{ with .OutputFormats.Get "RSS" }}
        {{ printf "<atom:link href=%q rel=\"self\" type=%q />" .Permalink .MediaType | safeHTML }}
    {{ end }}
    {{ range .Pages }}
        <title>{{ .Title }}</title>
        <link>{{ .Permalink }}</link>
        <pubDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</pubDate>
        {{ with }}<author>{{.}}{{ with $ }} ({{.}}){{end}}</author>{{end}}
        <guid>{{ .Permalink }}</guid>
        <description>{{ .Summary | html }}</description>
        <content:encoded>{{ printf "<![CDATA[" | safeHTML }}{{ .Content | html }}{{ printf "]]>" | safeHTML }}</content:encoded>
    {{ end }}

Readable much? To be fair, this does make use of the go language, of which I have to say, I’m not a very big fan of. But this is just one example of how hard it is to debug files such as these - if any of the go code fails, you really do have to read and test each and every single bracket and character and white space to figure out what is going wrong. Absolute insanity.

The fun doesn’t stop there though. Mixing languages is a huge risk when it comes to debugging, and this was also made apparent when I tried using PostCSS in another SSG build with eleventy. All I got to say is, when you mix JS with CSS, and use custom JS functions to process CSS, when things go wrong (I guarantee something will at some point), the debugging will be absolutely painful.

I know it seems like I have a lot to complain about in this incredibly long winded post of all the things I dislike about SSGs, but honestly, I do love the concept and I hope it will be easier to set up and become more user-intuitive for everyday people to use in the future. Whether that takes a year or a few years, its pretty clear to me that static sites are gaining in popularity mainly due to speed and performance. Static sites have such a great performance and security advantage that WordPress can’t provide, and if you can trade-off the developer time or cost of third party services, then it can be a good investment.

WordPress is going in the way of a cross between markup and markdown editor with Gutenberg, and I have my own reservations on the vision of how content in WordPress will be managed in the future. The development of Gutenberg just proves how hard it is to create a visual interface to manage and edit content for the web though- particularly when markdown and markup is mixed together. For now though, I will continue using WordPress and TinyMCE and continue experimenting with static sites, and look forward to a time when we can easily build a static site without the overhead that goes with it.