I have been using Gatsby consistently since late 2020 while it was V2. I first learnt about it when looking for a React way to fetch Airtable data easily for my first side project, Prepr.tv using the Gatsby Source Airtable plugin. Since then, I’ve been using Gatsby consistently for multiple personal projects and even for my previous company, where we’ve used it to rebuild the company website and CloudTheatre landing page, easily achieving almost-perfect Lighthouse score.
Gatsby’s wide plugin ecosystem makes it very easy to integrate with major data sources. Eventhough not everyone likes Gatsby’s opinionated way of sourcing data, I find it very easy to populate data everywhere on the website using graphql and fragments. As a designer who was just starting out with limited web development experience, building website with Gatsby feels like a no-brainer.
As of writing, I’m riding on Gatsby 5 to manage multiple content-focused static websites that sources data locally (through MDX and JSON), like USMART, OwConstruction and my side project PaletteUI. As the projects to manage grow, I realised that Gatsby’s way to building website affects my development speed and experience.
My issues with Gatsby
1. Inflexible Image Component
The Gatsby ecosystem offers 2 kinds of image components, namely
GatsbyImage to produce optimised pictures with multiple srcset and format. For those who’re still foreign to Gatsby’s image plugin, the difference between those two components can be simplified as below:
<StaticImage/>is your regular drop-in component that only accepts relative or absolute path through the
<GatsbyImage/>is for graphql transformed images. In most cases such as a blog page with cover photo, you have to query and fetch the blog data through graphql, locate the image node, then pass the
gatsbyImageDatadata into the component as props.
The problem comes when I’m developing a website with JSX. Imagine the following scenario:
- You’re using
<GatsbyImage/>inside a slider component called
- You’re using
Slider.json your index page. Now want to feed some images in it.
<GatsbyImage/>only accepts graphql transformed images, not variables, you’ll be forced to query images through graphql
allImageSharpto obtain the right images.
This workflow doesn’t make a good developer experience because what actually happens look something like this:
- You put your image into the image folder.
- Visit the localhost graphql url and display the transformed images through
allImageSharpquery. The code looks something like line 332, but without line 333.
- Search for the correct file name, copy and paste back into your React code (in above’s case, starting from line 334).
- The array of transformed image data returned by
allImageSharpquery can now be used anywhere on the page. But you have to follow the order of images because the return data is an array, so you actually feed images into components like this:
imageProp: data.allImageSharp.edges.node(see line 309).
The workflow is not straightforward, and the code becomes extremely hard to maintain. I feel that Gatsby’s image plugin is built for the MDX or CMS workflow in mind (which is how enterprise companies use Gatsby for their website), not for hardcoded JSX.
The closest example that I can find is NextJS’s Image component, but that doesn’t generate blur placeholders. As of writing, I couldn’t fine any helper image functions to generate byte-sized low-resolution placeholder.
2. Slow build time
This is a universal issue for most Gatsby developer who cannot afford GatsbyCloud (discontinued October 2023). If your website is hosted on platforms like Netlify or Cloudfare Pages, the average build time for a minimal site will be around 1.5 - 2 minutes, regardless if you use pure JSX or programmatically generate pages through MDX / CMS.
Now imagine if the website is connected with CMS, for everytime your client publish a page, they’ll have to wait that duration to check the final build. This hurts the user experience because client cannot quickly re-iterate content in near real-time.
There are few techniques to reduce Gatsby’s build time, such as using SliceAPI or use different rendering methods like Deferred Static Generation. But if a minimal 13 pages website still need code optimisation to achieve slightly faster build time, I do not feel it’s worth the effort.
3. Lots of dependencies
Plugin is an amazing concept, but managing lots of them is not. I feel it’s time for Gatsby to absorb some of the essential plugins, to name a few:
I think most of the listed plugins are important enough to produce a decent website. From what I see, more plugins = more things to worry when things break.
What do I look for in a new framework
- Simpler and more straightforward Image component: I do not mind building my own if the framework provides utility functions, but it needs to support file path and variables.
- Faster pre-rendering builds: Ideally around 20 seconds. My current Astro site takes around 30 seconds to build on Netlify, but still better than Gatsby which triples the duration.
- Easy way to manage content: As someone who is spoilt by Gatsby’s graphql workflow that standardises and centralises content, I’m looking for an equally good or better DX when sourcing data locally.
- Easier way to create dynamic pages: To programmatically generate pages on buildtime, Gatsby’s requires you to make changes on
gatsby-node.jsand a template JSX file, where dynamic data are populated. I hate to admit, after years of developing with Gatsby, I still have to refer to the docs.
- Supports good unstyled components library like headlessUI: So I can continue creating websites that are accessibility-friendly with my own CSS.
- Familiar syntax: Ideally, still uses JSX.
Astro checks all the boxes with few caveats
Astro achieves all of the above, plus you can use MDX without any additional configuration!
However, migrating from Gatsby to Astro new framework do come with some trade-offs, which I expected. Few of my early considerations and worries include:
1. Replicating Gatsby’s image functionality
<Picture/> component to generate images in different formats and densities.
But if you’re looking for an exact replacement, you’ll need to use Astro’s
getImage() helper function to generate low-res placeholders, feed it into the first
<img/> that has lower z-index. Then, have another
<img/> that will show the actual image when lazy-loaded.
The outcome can should look something like this:
<div> <div> <img src="placeholder.jpg"/> </div> <picture> <source type="image/webp" srcset=".../images.webp, 1000w" /> <img decoding="async" loading="lazy" alt="an image" src=".../images.jpg" srcscet=".../images.jpg, 1000w" /> </picture> </div>
2. No more instant navigation
Astro is a MPA framework. This means that Astro sites only load resources page by page, making the initial load time quicker. However, NextJS / Gatsby can produce sites that feels instant when navigating between pages after hydration.
Ngl, I missed that snappy navigation behaviour, and I haven’t found a way to reproduce that experience. It takes more than just optimising assets and preloading other page resource with
rel=preload (refer MDN web docs).
However, you can “overcome” this by using Astro’s ViewTransition API to crossfade or slide between pages, pretty neat!
3. More things to beware
- No deferred or incremental builds technology yet. If you plan to build lots of dynamic pages (like blog posts) without using SSR, you’ll have to rely on special config to achieve fast build speed. However, I would imagine if you have 10,000 pages to build, you should have enough budget to pay the server-side computing cost too.
- You rely on UI libraries. Astro doesn’t have the biggest selection of UI library compare to React. However, you can opt into React or any other web framework to continue using your favourite UI library.
- You’re on your own when it comes to less-known web best practices. For example, look out for Flash of Unstyled Content .
- You have to write duplicated code to enable CMS Preview in order to build pages on hosting platform, while allowing your client to preview drafts from CMS using SSR. Currently, Astro does not have Preview Draft feature like NextJS. However, keep an eye on this ongoing disucssion on Astro.
- Need to manually generate multiple favicon for PWA. Gatsby can achieve this easily via gatsby-plugin-manifest. There are some guide on google though, such as this tutorial by Kremalicious.
- No out-of-the-box solution client-side state management across pages. You can read Astro’s recommendation here.
scripttag below your page or component.
Will I still use Gatsby in future
Yes, but only for a specfic cases. I think Gatsby’s plugin ecosystem really simplifies the way static site can fetch and query data, especially if they’re from complex and relational database like Airtable.
I’ll still keep an eye on what’s new with The Gatsbyverse. However at this moment, Astro allows me to develop faster and fits my use cases perfectly for the foreseeable future.