This guide is for installing a local development copy of Ghost from source, primarily for the purpose of modifying Ghost core

Prerequisites

Before getting started, you'll need these global packages to be installed:

Then install these global packages

yarn global add knex-migrator grunt-cli ember-cli bower

Create Github forks

First you'll need to make forks of both the Ghost and Ghost-Admin respositories. Click on the fork button right at the top, wait for a copy to be created over on your personal Github account, and you should be all set!

Fork


Configure repositories

The next step is to configure the Git repositories for local development

Ghost Core

The main Ghost repository contains the full Ghost package, including the Admin client and default theme which will also be automatically set up

# First clone Ghost and make it your working dir
git clone git@github.com:TryGhost/Ghost.git && cd Ghost

Properly rename your references

# Rename origin to upstream
git remote rename origin upstream

# Ensure it has the correct path
git remote set-url upstream git@github.com:TryGhost/Ghost.git

# Add your fork as an origin, editing in <YourUsername>!
git remote add origin git@github.com:<YourUsername>/Ghost.git

Ghost Admin

Because Ghost-Admin is a submodule repository of the main Ghost repository, the same steps need to be repeated to configure Git here, too.

# Switch to Ghost-Admin dir
cd core/client

Properly rename your references again

# Rename origin to upstream
git remote rename origin upstream

# Ensure admin also has the correct path
git remote set-url upstream git@github.com:TryGhost/Ghost-Admin.git

# Add your fork as an origin, editing in <YourUsername>!
git remote add origin git@github.com:<YourUsername>/Ghost-Admin.git

Bring Ghost-Admin up to date

# Quick check that everything is on latest
git checkout master && git pull upstream master

# Then return to Ghost root directory
cd ../../

Run setup & installation

# Only ever run this once
yarn setup

The setup task will install dependencies, initialise the database, set up git hooks & initialise submodules and run a first build of the admin. The very first build generally takes a while, so now's a good time to re-open that Reddit tab.


Start Ghost

# Run Ghost in development mode
grunt dev

Ghost is now running at http://localhost:2368/


Stay up to date

When your working copies become out of date due to upstream changes, this is the command always brings you back up to latest master

# Update EVERYTHING
grunt master

That's it, you're done with the install! The rest of this guide is about working with your new development copy of Ghost.


Dev Commands

When running locally there are a number development utility commands which come in handy for running tests, building packages, and other helpful tasks.

Running Ghost

The most commonly used commands for running the core codebase locally

grunt dev
# Default way of running Ghost in development mode
# Builds admin files on start & then watches for changes

grunt dev --server
# Ignores admin changes

grunt dev --no-server-watch
# Ignores server changes

grunt build
# Build admin client manually

grunt prod
# Build full Ghost package for production

Database tools

Ghost uses it's own tool called knex-migrator to manage database migrations

knex-migrator reset
# Wipe the database

knex-migrator init
# Populate a fresh database

Server Tests

Tests run with SQlite. To use MySQL, prepend commands with NODE_ENV=testing-mysql

grunt test-all
# Run all tests

grunt test-unit
# Run unit tests

grunt test-integration
# Run integration tests

grunt test-functional
# Run functional tests

grunt test:path/to/test.js
# Run a single test

grunt lint
# Make sure your code doesn't suck

Client Tests

Client tests should always be run inside the core/client directory. Any time you have grunt dev running the client tests will be available at http://localhost:4200/tests

ember test
# Run all tests in Chrome + Firefox

ember test --server
# Run all tests, leave results open, and watch for changes

ember test -f 'gh-my-component'
# Run tests where `describe()` or `it()` matches supplied argument
# Note: Case sensitive

ember test --launch=chrome
# Run all tests in Chrome only

ember test -s -f 'Acceptance: Settings - General' --launch=chrome
# Most useful test comment for continuous local development
# Targets specific test of area being worked on
# Only using Chrome to keep resource usage minimal

Troubleshooting

Some common Ghost development problems and their solutions

ERROR: (EADDRINUSE) Cannot start Ghost
This error means that Ghost is already running, and you need to stop it

ERROR: ENOENT
This error means that the mentioned file doesn't exist

ERROR Error: Cannot find module
Install did not complete. Remove your node_modules and re-run yarn

Error: Cannot find module './build/default/DTraceProviderBindings'
You switched node versions. Remove your node_modules and re-run yarn

ENOENT: no such file or directory, stat 'path/to/favicon.ico' at Error (native)
Your admin client has not been built. Run grunt prod for production or grunt dev

TypeError: Cannot read property 'tagName' of undefined
You can't run ember test at the same time as grunt dev. Wait for tests to finish before continuing and wait for the "Build successful" message before loading admin.

yarn.lock conflicts
When rebasing a feature branch it's possible you'll get conflicts on yarn.lock because there were dependency changes in both master and <feature-branch>.

  1. Note what dependencies have changed in package.json
    (Eg. dev-1 was added and dev dep dev-2 was removed)
  2. git reset HEAD package.json yarn.lock - unstages the files
  3. git checkout -- package.json yarn.lock - removes local changes
  4. yarn add dev-1 -D - re-adds the dependency and updates yarn.lock
  5. yarn remove dev-2 - removes the dependency and updates yarn.lock
  6. git add package.json yarn.lock - re-stage the changes
  7. git rebase --continue - continue with the rebase

It's always more reliable to let yarn auto-generate the lockfile rather than trying to manually merge potentially incompatible changes.