Navigate back to the homepage

Building and deploying a static site using GatsbyJS and Bitbucket Pipelines

Andrew L
September 26th, 2020 · 4 min read


This post documents my journey with learning to build and deploy a website/blog in GatsbyJS, and making use of Bitbucket Pipelines to eventually automate the build and deploy process.

In the past I’ve looked into building my own CMS, used off the shelf PHP based CMS’s, but wanted to try out something different with a markdown/git based workflow.

Overall requirements:

  • Basic git knowledge
  • Apache-based web-hosting with FTP Access.
  • Bitbucket Account and project/repo where you can save your code.

Setting up GatsbyJS

Install latest Git


Install Node.JS

Setup Gatsby

Setting up a GatsbyJS starter site

Hello World Demo

1npm install -g gatsby-cli
3gatsby new gatsby-site
5cd gatsby-site
7gatsby develop

Navigate to http://localhost:8000

Hello World

Novela Starter


With Gatsby CLI

1gatsby new gatsby-site
3cd gatsby-site
5gatsby develop

or via Git Bash

1git clone novela-site
3cd novela-site
5npm install
7gatsby develop

Navigate to http://localhost:8000

Novela Light
Novela Dark

Ctrl-C to exit the development mode.

Preparing the files for deployment

From what I’ve learnt about GatsbyJS so far:

  • the public/ folder is the output folder for the static content files, which can be deployed to a web host.
  • The particular theme I’m using - ended up building around 35mb of files - which was quite a large for a simple site. I eventually traced these down to some .map files in the public folder
  • Some of these .map files were from a netlify plugin - which I don’t have a need for at the moment.

Fix #1 in gatsby-config.js

Comment out the gatsby-plugin-netlify-cms plugin


1plugins: [
2 ...
3 /* {
4 resolve: `gatsby-plugin-netlify-cms`,
5 options: {
6 },
7 },*/
8 ...

Fix #2 in gatsby-config.js

Add a plugin ‘gatsby-plugin-no-sourcemaps’


1plugins: [
2 ...
3 {
4 resolve: "gatsby-plugin-no-sourcemaps",
5 },
6 ...

Fix #3 - Remove some large images

Removed some of the sample author avatars in the starter theme. These were located under /content/authors/authors/avatars

Perform a clean and build

1gatsby clean
2gatsby build

After doing this, the file size of the public folder was down to around 8mb.

Automating a deployment to Apache-based Web Hosting using Bitbucket pipelines

Plan environments

For this site, I wanted to have at least one test environment, and one production environment.

For simplicity these would be on different sub-domains so that the website would always be served from / path.

Set up FTP accounts on Web Hosting provider

For my particular web hosting provider, I setup a sub-domain and an FTP account for each environment.

Prepare Bitbucket git repo

At the moment I’m performing the builds locally, and commiting the contents of public/ into git. This is NOT the most efficient way to do this, as it will significantly increase the size of the repository, but for an MVP, this is what I had working with the git-ftp plugin later on.

For now I had to update the .gitignore file with the starter theme to comment out the public folder, so that it does not get ignored in git commits. I will have to revisit this later once I have a different method working with bitbucket pipelines.


1# gatsby files
3# public

I’m using Bitbucket for their pipelines feature.

Prepare bitbucket-pipelines.yml with git-ftp

I had a working pipeline from another POC I had run around using git-ftp to push files to a server.

This plugin works by detecting which git commit your code is up to, and syncing the differences to the latest onto your FTP server. Behind the scenes it creates and updates a file called .git-ftp.log on your target folder, and uses this to keep track of the latest commit deployed.

Due to the way the plugin behaves, it needs a ‘git ftp init’ stage to be run the very first time you use it. This creates the .git-ftp.log file, and then afterwards you just run ‘git ftp push’ which will incrementally copy the files over.

The below bitbucket-pipelines.yml file should live in the root folder of your git project, alongside .gitignore and gatsby-config.js etc.


1image: samueldebruyn/debian-git
4 custom:
5 git-ftp-init-develop:
6 - step:
7 name: Initialize develop
8 deployment: Test
9 script:
10 - apt-get update
11 - apt-get -qq install git-ftp
12 - git config git-ftp.syncroot $FTP_LOCAL_PATH
13 - git config git-ftp.url ftp://$FTP_HOST:$FTP_PORT/$FTP_REMOTE_PATH
14 - git config git-ftp.user $FTP_USER
15 - git config git-ftp.password $FTP_PASS
16 - git config --list
17 - git ftp init
18 - echo $?
19 git-ftp-incremental-develop:
20 - step:
21 name: Deploy to develop
22 deployment: Test
23 script:
24 - echo " > 0. Everything is awesome!"
26 # Initialize
27 - echo " > 1. Install git-ftp"
28 - apt-get update
29 - apt-get -qq install git-ftp
31 # Show status
32 - git status -uno --porcelain
34 # Set git-ftp config
35 - echo " > 2. Setting git-ftp config"
36 - git config git-ftp.syncroot $FTP_LOCAL_PATH
37 - git config git-ftp.url ftp://$FTP_HOST:$FTP_PORT/$FTP_REMOTE_PATH
38 - git config git-ftp.user $FTP_USER
39 - git config git-ftp.password $FTP_PASS
40 - git config --list
42 - echo " > 3. Initiating Push of $FTP_LOCAL_PATH"
43 # Push updates. Init is used for the first time only, after that push is used
44 # git ftp init
45 - git ftp push
47 # Exit Code
48 - echo $?

This setup uses build variables that can be defined next in your environment specific settings. This keeps a consistent configuration between environments, and also avoides any hardcoded values in this file, especially passwords!

Your folder is not ready to be commited and pushed to the git repository on Bitbucket. This also enables the deployments screen for the next step.

Prepare bitbucket deployment environments

On your bitbucket repository, under ‘Repository settings’ on the left menu, you should find that the Pipelines > Deployments screen is now populated with ‘Test/Staging/Production’ environments.

Bitbucket Deployments screen

Under each of these, you can define environment specific variables, that can be read by your pipeline code in the previous step. This also allows secure storage of some values, such as passwords.

Bitbucket Deployments screen


This allows you to have the same set of pipeline steps for different environments, and just the values are different, for each environment.

Ensuring you mark passwords as ‘secured’ is also important - this prevents them from being printed in logs during the build process!

Deploying using git-ftp plugin

Now you should be ready to run the pipeline on your repo. You’ll need to first run custom: git-ftp-init-develop. This can take some time to first copy all the files across to your web hosting.

Bitbucket Run git-ftp init custom pipeline

If this has run successfully then you should be able to access your website now.

For ongoing edits and changes, my current workflow is:

  1. Work on new posts locally in VSCode. Use gatsby develop for previewing posts
  2. gatsby clean and gatsby build when the post is ready
  3. Commit and push changes to git repo
  4. Run pipeline custom: git-ftp-incremental-develop (note: this can be easily automated upon commits)


There are a number of potential issues that could be a problem later on, that I will need to tackle in the future:

  • The free plan in Bitbucket comes with 50 build minutes per month. At the moment each deployment I run takes around 5-6 minutes, so this will quickly eat up the available build minutes. Need to look into why the FTP stage is taking so long to run, especially when uploading files from my PC to my web hosting does not take nearly as long.
  • This method is currently dependent on building the files locally, whereas I’d want to eventually only need to write markdown from any device, and have the build process perform the gatsby clean and gatsby build stages. However, this would likely not work with git-ftp, so I’d need to go back to investigating why atlassian/ftp-deploy takes even longer to copy the files to the server.
  • I don’t think I have SSH/SFTP a vailable on my web hosting, otherwise atlassian/rsync-deploy might be a more efficient option.
© 2020
Link to $