How to Customize Ghost Theme CSS with Yarn: Local Dev Setup and Live Reload

Ghost CMS theme CSS customization with Yarn and Gulp development workflow

You've cloned the Source or Casper theme, opened up assets/screen.css, made your changes — and nothing shows up in the browser. You restart Ghost. You clear the cache. Still nothing. This is probably the most common Ghost theme development frustration, and it happens because Ghost's default themes don't serve raw CSS files. They compile them.

The forum thread that inspired this post captured it perfectly: someone had set up a full local Ghost environment with Yarn and Gulp, saved edits to assets/screen.css, watched Yarn rebuild the file — but still had to restart Ghost every single time just to see a color change. The fix turned out to be a browser caching issue, not a Ghost issue at all. But getting to that answer required understanding how the whole build pipeline works.

This guide walks through the complete Ghost theme CSS workflow — from setting up your local dev environment to watching changes live without restarts.

Quick answer: Ghost's default themes (Source, Casper, Dawn) compile CSS through Yarn and Gulp into a minified file in the /built directory. To see CSS changes live, run yarn dev inside your theme folder and disable browser caching in DevTools (Network tab → "Disable cache"). You don't need to restart Ghost between changes.

Ghost CMS theme CSS customization with Yarn and Gulp development workflow

Why does Ghost use Yarn and Gulp to compile CSS?

Ghost's built-in themes don't use a single flat CSS file. Instead, they split styles across multiple partial files, then use Gulp (a Node.js task runner) to merge and minify everything into one output file in the assets/built/ directory. Yarn manages the dependencies needed to run that Gulp pipeline.

This approach is standard in modern web development — it keeps the source CSS organized and produces a smaller, faster file for production. The trade-off: editing raw CSS files won't do anything until they're compiled. That's what trips up most new Ghost theme developers.

The Source theme (Ghost's current default) uses Tailwind CSS compiled through this same pipeline. The older Casper theme uses plain CSS partials. Both follow the same compile-before-serve pattern.

How do I set up a Ghost theme development environment from scratch?

You need Node.js, Ghost running locally, and Yarn. Here's the exact setup:

Step 1: Install Node.js with nvm

Ghost themes require a specific Node version. Don't use the default system Node — version mismatches cause Yarn and Gulp errors. Use nvm:

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
nvm install 18
nvm use 18
node --version  # Should show v18.x.x

Node 18 is the most compatible version for Ghost's current toolchain. Node 20+ can work, but Node 18 avoids the most common Yarn/GScan conflicts.

Step 2: Install Ghost CLI and run Ghost locally

npm install ghost-cli@latest -g
mkdir ghost-local && cd ghost-local
ghost install local

This spins up a local Ghost instance at http://localhost:2368. No Docker required — though if you're already using Ghost in Docker, you can still work on themes by mounting the theme directory.

Step 3: Clone or copy the theme

# Navigate to Ghost's themes directory
cd ghost-local/content/themes/

# Clone Source theme (Ghost's default)
git clone https://github.com/TryGhost/Source.git my-custom-theme

cd my-custom-theme

Step 4: Install dependencies

npm install -g gscan  # Ghost theme validator
yarn install          # Install all theme dependencies

If yarn install fails with a GScan/Node compatibility error, drop to Node 16:

nvm install 16
nvm use 16
yarn install

How do I run Yarn to watch CSS changes live?

Once dependencies are installed, start the development watcher from inside your theme folder:

yarn dev

This command does three things simultaneously:

  • Watches your source CSS files for changes
  • Compiles and minifies them into assets/built/ on every save
  • Runs a BrowserSync-style watcher in some themes

You'll see output like this in the terminal:

yarn run v1.22.10
$ gulp
[10:24:01] Using gulpfile /path/to/theme/gulpfile.js
[10:24:01] Starting 'default'...
[10:24:01] Starting 'css'...
[10:24:03] Finished 'css' after 1.87 s
[10:24:03] Starting 'watch'...

That last line — Starting 'watch'... — means Gulp is now watching. Save any CSS file and it recompiles automatically, usually in under 2 seconds.

Why are my CSS changes not showing even with yarn dev running?

This is the most common confusion, and it has nothing to do with Ghost or Yarn. It's browser caching.

Your browser stores static files like CSS aggressively. Even when Yarn rebuilds the CSS file on disk, the browser serves its cached copy. The fix:

  1. Open DevTools (F12 or Cmd+Option+I)
  2. Go to the Network tab
  3. Check "Disable cache" (only active while DevTools is open)
  4. Reload the page

After this, every save + reload cycle will show your CSS changes immediately. No Ghost restarts needed.

Alternatively, do a hard reload with Ctrl+Shift+R (Windows/Linux) or Cmd+Shift+R (Mac) to bypass the cache for a single reload.

If you're seeing stale styles on a Cloudflare-cached site, you'll also need to purge the Cloudflare cache after uploading your updated theme.

When do I need to restart Ghost during theme development?

There are a few cases where a restart is actually required:

Action Restart needed?
Editing CSS files No — just reload browser (with cache disabled)
Adding new template files (.hbs) Yes
Adding new static assets (images, fonts) Yes
Editing existing .hbs templates No — Ghost reloads templates automatically in local mode
Changing package.json settings Yes
Updating gulpfile.js Yes (restart yarn dev too)

Ghost's local development mode (ghost start --development) handles template reloading better than production mode. Always develop locally first, then package and upload your finished theme via the admin dashboard.

How do I package and upload my theme to Ghost?

When you're done making changes, build the production version and zip it up:

# Build production CSS (minified, no source maps)
yarn build

# Validate with GScan before uploading
gscan /path/to/your-theme

# Package the theme (run from inside the theme directory)
zip -r ../my-theme.zip . --exclude "node_modules/*" --exclude ".git/*"

Then upload via Ghost Admin → Design → Change theme → Upload theme. Ghost runs GScan automatically on upload — any fatal errors will block the theme from activating.

To automate this, some developers use yarn zip if the theme's package.json includes a zip script. Check your theme's package.json for available scripts:

cat package.json | python3 -c "import sys,json; d=json.load(sys.stdin); print(json.dumps(d.get('scripts',{}), indent=2))"

How do I customize the Source theme's CSS specifically?

Source uses Tailwind CSS, so it's slightly different from older Ghost themes:

# Source theme file structure
assets/
  css/
    screen.css       # Main CSS entry point (imports Tailwind utilities)
  built/
    screen.css       # Compiled output — don't edit this directly!

For Source, you have two paths:

Option 1: Add custom CSS below the Tailwind imports — Edit assets/css/screen.css and add your rules after the existing import lines. Yarn will compile them in.

Option 2: Extend Tailwind config — Edit tailwind.config.js to add custom colors, fonts, or spacing. This is the recommended path for larger style changes.

For Casper (the older default theme), CSS files live in assets/css/ as plain PostCSS partials. Edit those files and Gulp merges them.

You can also use the new ghst CLI to manage some theme operations directly from the command line without leaving your terminal.

What are common Yarn errors when building Ghost themes?

Error Cause Fix
error gscan@4.x requires node@^16 Node version mismatch nvm use 16 or nvm use 18
yarn: command not found Yarn not installed globally npm install -g yarn
Cannot find module 'gulp' Gulp not installed in project yarn add gulp
EACCES: permission denied Running Yarn as root Use --unsafe-perm flag or fix ownership
CSS builds but browser shows old styles Browser cache Disable cache in DevTools Network tab

If you're running into zsh command not found errors on macOS, the fix is usually adding nvm to your shell profile or sourcing it manually.

Can I edit theme CSS without setting up a local dev environment?

Yes — with some limitations. Ghost Admin's Code Injection feature (Settings → Code Injection → Site Header) lets you add raw CSS wrapped in a <style> tag. This overrides theme styles without touching theme files.

This works well for small tweaks: font size changes, color overrides, layout adjustments. For larger changes, you're better off with the full Yarn workflow to keep your styles maintainable.

Another option: upload a modified theme via Settings → Design → Change theme. You can make CSS edits directly in the source files, run yarn build, zip, and upload — no need to keep a local dev server running if you're only making occasional changes.

For sites where performance is a priority, avoid stacking Code Injection CSS on top of an already-compiled theme — it adds render-blocking style recalculation. Bake your styles into the theme build instead.

Frequently Asked Questions

Do I need to restart Ghost every time I change CSS in a Ghost theme?

No. If you're running yarn dev in your theme folder, Gulp watches for file changes and recompiles automatically. You only need to reload your browser — with cache disabled in DevTools. Ghost restarts are only needed when adding new template files or static assets.

What's the difference between yarn dev and yarn build?

yarn dev starts a file watcher that recompiles CSS whenever you save changes — it's for development. yarn build runs a one-time production build with minification and no source maps — use this before packaging and uploading your theme to a live Ghost site.

Which files should I edit when customizing CSS in a Ghost theme?

Edit files in assets/css/ (for Casper) or add custom CSS to assets/css/screen.css (for Source). Never edit files in assets/built/ — those are generated by the build process and your changes will be overwritten on the next compile.

Why does yarn install fail for Ghost themes?

The most common cause is a Node.js version mismatch. Ghost's theme toolchain (GScan, Gulp) has specific Node compatibility requirements. Switch to Node 16 or 18 using nvm: nvm install 18 && nvm use 18, then retry yarn install.

How do I find out which Gulp tasks are available in a Ghost theme?

Run yarn run (no arguments) inside the theme directory. This lists all available scripts defined in package.json. Common ones include dev, build, zip, and test.

Can I use npm instead of Yarn for Ghost theme development?

Technically yes, but Ghost's official themes ship with a yarn.lock file. Using npm can create dependency conflicts. Stick with Yarn unless you specifically need npm for your project's other dependencies.

How do I upload a compiled Ghost theme to a live site?

Run yarn build, then zip the theme folder excluding node_modules and .git: zip -r ../theme.zip . --exclude "node_modules/*" --exclude ".git/*". Upload via Ghost Admin → Design → Change theme → Upload theme. Ghost validates it with GScan on upload.

What's the fastest way to test CSS changes without a local dev setup?

Use Ghost Admin's Code Injection (Settings → Code Injection → Site Header) to add <style> tags with your overrides. It's not ideal for production use, but it's the quickest way to prototype visual changes without a build pipeline.

The Ghost theme development workflow clicks once you understand the compilation step. Set up nvm, run yarn install with Node 18, start yarn dev, and disable browser cache. From there, the feedback loop is fast — save a CSS file, reload, see the change. Use yarn build when you're ready to ship, validate with GScan, and upload via the dashboard.

Subscribe to Ghost SEO

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe