Supercharge Your Ghost Theme

Ghost 4.20.0 introduced custom settings, which gives developers the power to offer a lot more customization in their themes. In this tutorial, I show you what custom settings are and how to use them.

by Ryan Feigenbaum

Supercharge Your Ghost Theme

Share this post

Supercharge Your Ghost Theme

Supercharge Your Ghost Theme

For theme developers, custom settings are cool as shit. Before, if you wanted to give users customization options, it usually required them to edit Handlebars files, inject JS or CSS, or some unholy mixture of the two. Now, you can empower a user to customize their theme easily without having them touch a line of code.

Release 4.20.0 · TryGhost/Ghost
✨ Added ability for themes to define custom settings (#13661) - Kevin Ansfield✨ Added Offers feature to Ghost - Fabien O’Carroll⚡ Improved Ghost boot time and memory usage by lazy loading routes ...
That's one small commit for Ghost, one giant leap for Ghost theme developers. 😂
How to use custom settings in Ghost themes - Developer docs
Find out how to empower users to modify their theme with custom settings that are built directly into your Ghost theme!

What type of customization are we talking about?

The only limit is your imagination, really, but you can solve some common pain points for users right out of the gate.

OK, now I want to do it. Tell me how

Implementing custom settings requires two things:

  1. An entry in the theme's package.json file
  2. Reference to the setting in the theme file

Once these are in place, the user can make their customizations via the Design menu in the Ghost Admin.

Example of custom settings on the Ghost Admin page
Example of custom settings on the Ghost Admin page

To begin, add a custom key to the config object in your package.json file.

 "config": {
    "posts_per_page": 10,
    "image_sizes": {
    "custom": {
Custom settings in package.json

Within the custom object, you can then define the name of your custom setting. Names must be in snake_case with lowercase letters. Underscores (_) are replaced by spaces in the UI.

For each setting, you can specify one of five types and where appropriate a default value.

  1. select: choose from a list of predefined items
  2. boolean: true or false
  3. color: choose a color via a color picker
  4. image: upload an image
  5. text: enter an arbitrary bit of text

In addition to custom setting types, you can also specify a group. By default, custom settings will appear in the site-wide group. If the setting affects the entire site, like defining a color scheme, then this default works. However, you can also assign custom settings to only appear in the post or homepage toggle menus. A post setting might be the ability to switch on syntax highlighting, whereas a homepage setting might be the ability to specify the hero image's size.

When you put this all together, your entry in your package.json looks like this:

    "config": {
        "custom": {
            "color_scheme": {
                "type": "select",
                "options": ["Smart", "Material", "Gruvbox", "Dracula", "Nord"],
                "default": "Smart"
            "cta": {
                "type": "text",
                "group": "homepage"
            "syntax_highlighting": {
                "type": "boolean",
                "default": "false",
                "group": "post"
Custom settings example in package.json

Custom settings are great and all, but before you come up with a list of 1,001 options that will take your user a year to read, please note that custom settings are limited to 15.

Give me the custom settings data, please

So far, we've defined our custom settings, which will show them as options on the Design page. But how do we access this data in the theme?

Values are accessible via your theme's Handlebars markup. For example, let's say you had a text custom setting called cta that allows a user to write a custom call to action. In your theme file, you would access it with {{@custom.cta}}.

This @custom object is new to Ghost. You can access a specific custom setting key in your template to render the value or use the object with other Ghost Handlebars helpers for more complex logic.

Let's take a look at how you'd implement the three custom settings above in Handlebars.

Color Scheme

First, create a Handlebars partial that contains each of the color palettes you want to use. Here, I'm using a style tag in conjunction with CSS custom properties. It's custom custom, baby.

{{#match @custom.color_scheme "smart"}}
    :root {
      --primary: #0d48a0;
      --surface: #e0e5eb;
      --text: #040506;

{{#match @custom.color_scheme "material"}}
    :root {
      --primary: #0277bd;
      --surface: #eee;
      --text: #111;
Partial file: color_scheme.hbs

You'll also notice the new #match helper. The default behavior, as used here, is to match the custom setting value to the specified string. So, if the user chooses the material theme, then the #match helper will show those CSS values only.

The final piece of the puzzle here is to load the color_scheme.hbs partial in the <head> tag of your default.hbs file.

Now the user can drastically change the look of their site with the flip of a switch, and you only have to build a single theme. Pretty cool.


The CTA custom setting will render the user-specified text wherever you invoke the value. Here, I'll use it on a custom homepage.

<section class="homepage-cta">
  {{#if @custom.cta}}

The #if block checks whether the user entered custom text. If not, then the <p> isn't rendered at all.

Otherwise, the user can wordsmith till the cow's come home and their copy will be dutifully updated on the homepage with every save.

Syntax Highlighting

When including code in a post, it's nice if that code has syntax highlighting (where words are given different colors depending on their meaning). To implement this, you need to use a third-party library like Prism or highlight.js.

However, not all users need syntax highlighting, so it would be best to only load those libraries for users who opt in.

{{#contentFor "head"}}
  {{if @custom.syntax_highlighting}}
    <link rel="stylesheet" href="syntax-highlight.css"> 
    <script src="syntax-highlight.js" defer></script>

The code here uses the contentFor helper in conjunction with the syntax highlighting custom setting to only load the syntax highlighting JS and CSS based on the user's needs. For those who don't need it, you save them from loading unnecessary libraries. 💪

Smart 2: Custom settings preview

I'll soon launch version 2 of my open-source Smart theme, filled to the brim with custom settings. (My partner, Maddie, is currently rocking version 1.)

Some of the things I'm bringing to the theme:

Custom Setting Purpose
Search key Enter your API key to enable search
Comments Enable Disqus comments
Hero size Control the size of the hero image
Members Add in extra member functionality or disable it entirely
Color schemes Choose from several color schemes 💅
Post width Define your default post width
Social media icons Add additional social media icons to the navbar
Custom CTA text Add custom text to the homepage

Custom settings open up the possibilities for Ghost theme development exponentially, improving the user and developer experience alike.

For inspiration on what you can do with custom settings, I recommend checking out the official Ghost repo to see some of the creative mischief they have already gotten up to (for example, with Wave, Alto, and the OG Casper).

OK, byeee 👋