Uploading a ZIP file is the default way to update a Ghost theme.

But this gets annoying quickly, especially if you are only making a small change to your site.

Did you know you can also upload theme ZIPs using the Ghost API?

This post shows how you can integrate an upload command into your Ghost project to make it a lot easier to update a live theme.

Requirements

You need Node running on your machine. I've chosen Node to power this because if you're developing Ghost themes on your computer, you will already have Node on your machine ✨

For this tutorial, you'll also need the Ghost Admin API package. You can install this inside your local Ghost project with npm or yarn:

npm install @tryghost/admin-api --save

yarn add @tryghost/admin-api

The JavaScript file

To accomplish uploading a theme from the command line, we will create a small JavaScript file and use Node to run it when we want to upload.

We will use the Ghost Admin API package to interface with your site's Admin API, which makes it easy to upload the file with a simple upload() call (instead of writing out a full API call).

Feel free to copy the code and save it—for example, as publish.cjs—in the same directory where you save your theme ZIPs.

You need to create a Custom integration in Ghost (Settings > Integrations) and then paste your API key and API URL into the file.

Make sure the ZIP_FILE_PATH is also correct (this should be a relative path from this script to your ZIP file).

/**
 * This script uploads a ZIP file to a Ghost site.
 *
 * Create a Custom integration in Ghost settings, then paste the "API URL" and "Admin API key" below.
 */

const GhostAdminAPI = require("@tryghost/admin-api");

const ZIP_FILE_PATH = "theme_zip_file.zip";

const API_URL = "https://yoursite.com";
const API_KEY = "api_key_from_ghost_settings";

(async function main() {
  const api = new GhostAdminAPI({
    url: API_URL,
    key: API_KEY,
    version: "v5.0",
  });

  await api.themes.upload({ file: ZIP_FILE_PATH });

  // Uncomment this to activate the theme in Ghost
  // await api.themes.activate(THEME_NAME);
})();
💡
If you upload a new theme, it won't be activated by default. You can uncomment the last line of code to force-activate themes after every upload, but this typically isn't needed. You can manually activate new themes in Ghost from Settings > Design > Change theme.

How to upload

Now, whenever you have a ZIP file of the latest version of your theme, you can run node publish.cjs, and your theme will be updated on your live site.

It only takes a second or two and you don't need to be uploading any ZIP files ever again. Pretty neat.

If you work on multiple Ghost sites, you can drop this file into each theme folder and add each site's API URL and API key.

Expanding with npm commands

To take this tutorial a step further, lets's create some npm commands to handle ZIPing and uploading.

This means you only need to run one command when you want to publish theme changes.

In your theme folder, there will be a package.json file (which is required in every Ghost theme).

Under scripts , add the following:

{
  "name": "your-theme-name",
  ...
  "scripts": {
    "zip": "bestzip $npm_package_name.zip assets/* locales/* partials/* src/* *.hbs *.js *.md *.yaml .github/* LICENSE package.json",
    "publish": "npm run zip && node publish.cjs"
  },
  ...
}

You need to run npm install --save-dev bestzip to install the bestzip package.

The zip script creates a ZIP file for your theme, including some important files and folders.

The publish command will create a ZIP and then publish the file to your live site.

So in the future, after editing your theme files on your computer, you can simply run npm run publish in Terminal or similar command line tool, and your theme will be ZIPed and uploaded.

Thanks for reading!

Dan Rowden   Dan Rowden

I am the founder of Codelet. I have five years experience publishing and developing for Ghost, on over 100 sites. Codelet publishes Ghost themes, blog posts and offers expert Ghost support.