Skip to content
Switch branches/tags
Go to file

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time

Ghost Storage Cloudinary

npm version Build Status Maintainability Test Coverage Known Vulnerabilities

A fully featured and deeply tested Cloudinary Ghost storage adapter.


  • Compatible with all Ghost versions 🚀
  • Latest Cloudinary NodeJS SDK
  • Image upload, existence check & deletion (when Ghost will support it)
  • Ability to upload in dated sub-directories (alike first Ghost default Local storage adapter YYYY/MM)
  • Ability to upload images into a specific directory
  • Ability to tag images
  • Cool plugins!
  • Should be compatible with mmornati/ghost-cloudinary-store configuration


Install from Yarn

  • Go into Ghost root directory
  • Download the adapter:
$ yarn add ghost-storage-cloudinary@2
$ mv node_modules/ghost-storage-cloudinary core/server/adapters/storage
  • Done, go configure

Install on Docker

Here's an example of using this adapter with a containerized Ghost:

FROM ghost:3-alpine as cloudinary
RUN su-exec node yarn add ghost-storage-cloudinary@2

FROM ghost:3-alpine
COPY --chown=node:node --from=cloudinary $GHOST_INSTALL/current/node_modules $GHOST_INSTALL/current/node_modules
COPY --chown=node:node --from=cloudinary $GHOST_INSTALL/current/node_modules/ghost-storage-cloudinary $GHOST_INSTALL/current/core/server/adapters/storage/ghost-storage-cloudinary
RUN set -ex; \
    su-exec node ghost config ghost-storage-cloudinary; \
    su-exec node ghost config storage.ghost-storage-cloudinary.upload.use_filename true; \
    su-exec node ghost config storage.ghost-storage-cloudinary.upload.unique_filename false; \
    su-exec node ghost config storage.ghost-storage-cloudinary.upload.overwrite false; \
    su-exec node ghost config storage.ghost-storage-cloudinary.fetch.quality auto; \
    su-exec node ghost config storage.ghost-storage-cloudinary.fetch.cdn_subdomain true;

Here, we use the Ghost CLI to set some pre-defined values.

ℹ️ For Ghost version 1.x, use ghost-storage-cloudinary@1 package version.


Check out configuration.json.dist for a complete example.

  • Ensure to disable Ghost Image Optimisation
  • The optional useDatedFolder = false to upload images in dated sub-directories (alike default Ghost Local storage adapter)
  • The auth property is optional if you use the CLOUDINARY_URL environment variable authentification method
  • The optional upload property contains Cloudinary API upload options
  • The optional fetch property contains Cloudinary API image transformation options

Recommended configuration

  • upload.use_filename = true in order use the original image name
  • upload.unique_filename = false unlikely Ghost local storage adapter which auto-dedup an existing file name, Cloudinary will return the existing image URL instead of deduping the image
  • upload.overwrite = false goes along with previous option: returns existing image instead of overwriting it
  • upload.folder = "my-blog" allows to upload all your images into a specific directory instead of Cloudinary media library root
  • upload.tags = ["blog", "photography"] if you want to add some taxonomy to your uploaded images
  • fetch.quality = "auto" equals auto:good (see doc)
  • = false set to true if you want to serve images over SSL (not recommended for performances)
  • fetch.cdn_subdomain = true to really use the benefit of Cloudinary CDN

❤️ Don't forget to checkout the plugins!


Run yarn install without the --production flag.

Runs the tests and generate coverage:

$ npm t

Runs the linter:

$ npm run eslint

To enable debug logs, set the following environment variable:


Many thanks to @mmornati, @sethbrasile and all other contributors for their work. In the continuation of this project, don't hesitate to fork, contribute and add more features.