The Ghost Themes Developer Hub

Welcome to the Ghost Themes developer hub. You'll find comprehensive guides and documentation to help you start working with Ghost Themes as quickly as possible, as well as support if you get stuck. Let's jump right in!

Get Started    


Keep up to date with the latest changes

The following document acts as a reference for developers who want to keep their theme up-to-date with the latest changes in the Ghost theme API. Since the original public release of 0.3.2 there have been a number of changes to the Ghost theme API and the way Ghost themes work, resulting in some new requirements and some deprecated features.

Got ideas?!

If you have bright ideas for improvements we could make to our theme API, or use cases that aren't quite working, please tell us about it! We have a special themes category in our forum.

Keeping up to date

The best way to keep up-to-date with the changes is to subscribe to the developer blog. All theme related blog posts are tagged with 'themes', so you can subscribe to an RSS feed of only theme related posts if you prefer.


Ghost 1.0.0 will validate your theme, you can run the same tests online at GScan. You can upload your theme here and get a summary of any errors, warnings or recommendations. This will allow you to validate the theme and make it work with Ghost 1.0.0.


GScan is also the underlying validation method when you upload your theme or activate it in Ghost Admin. If your theme uses some of the deprecated features, which are classified as a fatal error, because the theme won't be working with Ghost 1.0.0, you won't be able to upload or activate it. See the warning box below to have an overview which features will prevent your theme from being uploaded.

Ghost 1.25.0

(24th July 2018)


The HTML output of posts created/edited using the Koenig beta editor has changed. We do not expect any further changes to Koenig output before Ghost 2.0.

⚠️ All posts in Ghost 2.0 will have the same HTML as current Koenig beta posts so now is a great time to make sure your theme will be compatible :wink+: Check out the Ghost 2.0 Theme Compatibility forum post for full details of changes.

Content wrapper

  • The .kg-post wrapper element has been removed. If you are currently relying on the .kg-post element (or the .kg-card-markdown element if getting your theme ready for 2.0) it is recommended to add your own wrapper element around the {{content}} helper in your post templates.

Image classes

  • .kg-image-wide and .kg-image-full classes have been renamed to .kg-width-wide and .kg-width-full
  • The above width classes will now be applied to the <figure> element rather than the <img> element


{{content}} output of Koenig posts before 1.25.0 (Ghost 1.23.0-1.24.9):

<div class="kg-post">
    <figure class="kg-image-card">
        <img class="kg-image kg-image-wide" src="...">
        <figcaption>example wide image</figcaption>

{{content}} output of Koenig posts after 1.25.0:

<figure class="kg-image-card kg-width-wide">
    <img class="kg-image" src="...">
    <figcaption>example wide image</figcaption>

The default markdown editor still exists in Ghost 1.x so themes will need to stay compatible with the old HTML output. For a post created with the default editor the {{content}} output may look something like this:

<div class="kg-card-markdown">
    <p><img src="..."></p>

It's worth re-stating that in Ghost 2.0 the .kg-card-markdown wrapper will disappear so make sure your have your own wrapper around {{content}} if needed. Eg, Casper's post.hbs has had the .post-content wrapper added:

<section class="post-full-content">
    <div class="post-content">

Ghost 1.23.0

(22nd May 2018)


  • Our new Koenig editor has been released in beta and requires CSS changes to add support.

Theme's CSS should be prepared for content that has been edited with Koenig, for a complete example check the Casper Koenig implementation.

Content wrapper

  • All existing posts created with the Ghost 1.0 markdown editor are rendered in a wrapper element with .kg-card-markdown CSS class (no change here but this class will be deprecated in the future).
  • All posts edited or saved with the Koenig editor enabled are wrapped in an element with .kg-post class instead of .kg-card-markdown.

Image classes

  • Koenig allows images to be rendered as "wide" or "full-width" as well as adding captions to images but your theme needs to support this for the styles to work in your published posts
  • Add support for the <figure> and <figcaption> elements (see below)
  • Add support for .kg-image-wide and .kg-image-full classes

The full HTML structure for rendered image cards is as follows:

<figure class="kg-image-card">
   <img src="..." class="kg-image (kg-image-wide|kg-image-full)">

Ghost 1.22.4

(24th April 2018)


  • The translatable options for seconds in the {{reading_time}} helper got removed. See the reading time helper and i18n docs for full details.

Ghost 1.22.0

(27th March 2018)

In Ghost 1.22.0 we've shipped multiple authors. Single author functionality is deprecated. Therefore we've added or extended functionality for multiple authors.


  • We've added a new shiny {{authors}} helper (same behaviour as our tags helper). The helper is a new formatting helper, which helps outputting multiple authors.
  • We've added an additional {{primary_author}} data helper.



Ghost 1.21.2

(14th Feb 2018)


  • {{#get}} helper filters can now use dates

Ghost 1.17.0

(7th Nov 2017)


  • {{reading_time}} helper that calculates and renders the estimated reading time for a post. See the reading time helper docs for full details.

Ghost 1.15.0

(19th Oct 2017)


  • {{#next_post}}{{/next_post}} & {{#prev_post}}{{/prev_post}} now support in="author"

Ghost 1.14.0

(13th Oct 2017)


  • {{#next_post}}{{/next_post}} & {{#prev_post}}{{/prev_post}} now support in="primary_tag"

Ghost 1.13.0

(10th Oct 2017)


  • Custom post templates can now be added by naming post templates custom-{{template-name}}.hbs, any such templates are selectable on a per-post basis by post authors in the admin area's post settings menu. See the custom template docs for full details.
  • Filter posts by primary_tag

Ghost 1.7.0

(22nd Aug 2017)


  • The {{#has}} helper has been extended with another two comparison attributes:
    • any and all attributes to match against multiple properties
      See the has helper docs for full details.

Ghost 1.6.0

(15th Aug 2017)


  • The {{#has}} helper is now able to do more comparisons:
    • number and index matching inside of foreach loops, including "nth" support
    • slug and id matching inside of posts, authors, tags, etc
      See the has helper docs for full details. More changes coming soon!

Ghost 1.5.0

No theme-related changes.

Ghost 1.4.0

(2nd Aug 2017)


  • We have added a new feature to be able to set custom code injections per post.
  • So {{ghost_head}} and {{ghost_foot}} helpers output both the global and the per post code injection if available.

Ghost 1.3.0

(1st Aug 2017)


  • The {{excerpt}} helper will now default to outputting the posts new custom_excerpt property if there is one. If custom_excerpt is not set the behaviour is the same as before.
  • Posts now have a {{custom_excerpt}} property which contains the user-provided custom excerpt.

Ghost 1.2.0

(31st July 2017)


  • Posts now have a {{primary_tag}} dynamic property that can be used to access the first tag associated with any post.

Ghost 1.0.2

(27th July 2017)


  • Posts now have a {{comment_id}} dynamic property that must be used when creating a unique post identifier for Disqus.

Ghost 1.0.0

(23rd July 2017)

Strong requirements around package.json

  • name is required
  • version is required
  • is required, author.url and are optional
  • 'Posts per page' will no longer be a setting in Ghost Admin, but a recommended property for the package.json file of the theme: posts_per_page [is highly recommended]
  • Further optional properties will be possible to use, see here

Theme config

  • {{@blog.posts_per_page}} as global data attribute will be replaced with {{@config.posts_per_page}}, which is now set in the theme's package.json, instead of in settings. See config.

Image properties & helper renamed

  • The {{image}} helper has been removed. Use {{img_url}} instead. See here
  • {{author.image}} -> replace with {{author.profile_image}}. See here
  • {{author.cover}} -> replace with {{author.cover_image}}. See here
    • {{post.image}} -> replace with {{post.feature_image}}. See here
    • {{@blog.cover}} -> replace with {{@blog.cover_image}}. See here
    • {{tag.image}} -> replace with {{tag.feature_image}}. See here

Deprecated features removed

  • The usage of {{meta_description}} in <head> will be deprecated. It's going to be included in the {{ghost_head}} helper.
  • Removal of deprecated {{pageUrl}} helper. Use {{page_url}} instead.
  • Removal of deprecated {{body_class}} classes. Use only classes listed in the Context Overview. Classes that are deprecated include:
    • .archive-template appearing on paginated pages, use .paged
    • .post-template and .page appearing on static pages, use .page-template
    • .page-template-{{slug}} appearing on static pages, use .page-{{slug}}
    • Also note, .page-{{slug}} used to only appear on pages with custom templates, in 1.0.0 they will be ever present, the same as .tag-{{slug}} or .author-{{slug}}.


  • All themes are validated by GScan, and can only be activated if they are valid.
  • Favicon is now an upload in settings, rather than a theme feature. Favicons included in themes will no longer work.
  • The {{get}} helper's {{else}} condition is now only triggered for errors, not empty results, instead please use {{else}} on the block helper you use inside the {{#get}} helper.

Theme upload and activation restrictions

The usage of the following deprecated helpers and object attributes will cause that the theme can't be uploaded or activated:

  • {{pageUrl}}
  • {{image}}
  • {{author.image}}
  • {{author.cover}}
  • {{post.image}}
  • {{}}
  • {{}}
  • {{post.tags.[#].image}}
  • {{@blog.cover}}
  • {{tag.image}}

Theme activation and upload is also not possible if the following cases apply:

  • Usage of invalid Handlebars
  • Missing index.hbs template
  • Missing post.hbs template
  • Usage of Symlinks

Ghost 0.11.0 - Ghost 0.11.10

No theme-related changes

Ghost 0.11.0

(15th September 2016)

No changes

Ghost 0.10.0

(29th August 2016)


  • helpers {{amp_ghost_head}}, {{amp_content}} and {{amp_components} for AMP support
  • template amp.hbs

Ghost 0.9.0

(27th July 2016)


  • timezone property available via @blog
  • {{#foreach}} and {{tags}} respect the visibility property, meaning internal tags are not shown
  • if your theme contains a manifest.json in the root it is now served as a static file

Ghost 0.8.0

(18th May 2016)


  • @labs global property, currently has publicAPI and subscribers properties
  • twitter and facebook properties available via @blog
  • twitter and facebook properties available for authors / users
  • {{twitter_url}} and {{facebook_url}} helpers for outputting urls based on usernames
  • (labs only) subscribe context, with subscribe.hbs template & {{subscribe_form}} helper

Ghost 0.7.9

(7th April 2016)


  • page_url helper now supports "next" and "prev" as strings, rather than variables

Ghost 0.7.8

(18th February 2016)

No changes

Ghost 0.7.7

(18th February 2016)

No changes

Ghost 0.7.6

(3rd February 2016)


  • current class in navigation now gets applied even if you missed a trailing slash from the URL.

Ghost 0.7.5

(12th Jan 2016)


  • from and to attribute for both {{foreach}} and {{tags}}

Ghost 0.7.4

(22nd Dec 2015)


  • {{meta_title}}, {{meta_description}}, {{body_class}} & {{post_class}} no longer throw aSyNcId errors when used inside the {{#get}} helper, or the prev & next post helpers.
  • The @last variable will now be correct when using the limit attribute with {{#foreach}}
  • ghost.url.api JavaScript utility works correctly with multiple requests

Ghost 0.7.3

(16th Dec 2015)


  • permalinks and posts_per_page properties available via @blog
  • limit attribute for both {{foreach}} and {{tags}}
  • Custom post templates i.e. post-{{slug}}.hbs


  • {{ghost_head}} overwriting author.image with author.cover
  • {{pagination}} now works inside the {{#get}} helper


  • ghost.url.api JavaScript utility can now be included on external sites

Note: in 0.7.3 the way Ghost handles pages of the RSS feed that don't exist has changed (they now correctly return 404). This has impacted on some themes which were parsing the RSS feed to provide features.

Ghost 0.7.2

(27th Nov 2015)


  • {{#get}} helper (Beta access only)
  • ghost.url.api JavaScript function (Beta access only)

Ghost 0.7.1

(27th Sep 2015)


  • bug with {{#if current}} in {{navigation}} helper

Ghost 0.7.0

(3rd Sep 2015)


  • {{foreach}} now supports block params e.g. {{foreach posts as |mypost|}}
  • {{foreach}} has an a @number property that outputs the index, starting with 1 instead of 0.


  • {{tags}} and {{author}} not working inside {{prev_post}} and {{next_post}}


  • {{tags}} now respects the order that tags are added to posts

Ghost 0.6.4

(21 May 2015)


  • {{meta_description}} not working correctly on pages

Ghost 0.6.3

(14 May 2015)


  • New private context, with private.hbs template & .private-template body class
  • Custom author templates i.e. author-{{slug}}.hbs


  • {{meta_title}} not working correctly on pages

Ghost 0.6.2

(22 Apr 2015)


  • {{#prev_post}} & {{#next_post}} helpers not rendering

Ghost 0.6.1

(22 Apr 2015)


  • {{ghost_head}} throwing errors on custom error.hbs pages
  • {{}} being incorrectly available sometimes

Ghost 0.6.0

(13 Apr 2015)


  • {{#prev_post}} & {{#next_post}} helper


  • @blog globals now work in navigation.hbs and pagination.hbs
  • {{meta_title}} and {{meta_description}} now work inside of the post scope

Ghost 0.5.10

(9 Mar 2015)

No changes

Ghost 0.5.9

(28 Feb 2015)


  • {{navigation}} helper
  • {{@blog.navigation}} data

Ghost 0.5.8

(12 Jan 2015)


  • {{#has}} helper no longer matches partial tags
  • {{excerpt}} helper handles footnotes correctly


  • {{image}}, {{meta_title}} and {{meta_description}} updated for tags
  • {{url}} and {{image}} are now synchronous

Ghost 0.5.7

(15 Dec 2014)

No changes

Ghost 0.5.6

(4 Dec 2014)


  • {{image}} helper works correctly with subdirectories

Ghost 0.5.5

(19 Nov 2014)

No changes

Ghost 0.5.4

(18 Nov 2014)

No changes

Ghost 0.5.3

(21 Oct 2014)


  • {{ghost_head}} output


  • Themes now work correctly when symlinked

Ghost 0.5.2

(25 Sep 2014)


  • {{#is}} helper
  • {{image}} for posts
  • Custom tag templates i.e. tag-{{slug}}.hbs


  • {{body_class}} output
  • {{meta_title}} output
  • {{meta_description}} output
  • {{ghost_head}} output


  • .archive-template and .page classes from {{body_class}}.
  • .post-template will soon only appear on posts, not pages.

Ghost 0.5.0

(11th Aug 2014)


  • Author pages i.e. author.hbs
  • home.hbs template
  • {{plural}} helper


  • {{has}} helper updates for authors
  • {{author}} changed to output HTML


  • {{}} now outputs an empty string

Please see the multi-user blog post for more information.

Ghost 0.4.2

(26th Mar 2014)


  • package.json support (will be required)
  • {{log}} helper
  • {{#has}} helper
  • Tag pages tag.hbs
  • Custom page templates i.e. page-{{slug}}.hbs


  • {{pageUrl}} -> {{page_url}}
  • {{tags}} changed to output HTML


  • {{pageUrl}} will be removed

Please see the 0.4.2 blog post for more information.

Ghost 0.4.0

(13th Jan 2014)


  • Featured posts
  • Static pages with page.hbs
  • Custom error pages error.hbs
  • Customisable favicon
  • {{asset}} helper
  • {{encode}} helper


  • {{tags}} got prefix and suffix options
  • {{excerpt}} got unicode character support


  • Using {{@blog.url}} or relative urls for assets - please use the {{asset}} helper

Please see the 0.4.0 blog post for more information.


Keep up to date with the latest changes