Skip to main content

Command Palette

Search for a command to run...

Understanding Ghost's Code Structure with Node.js: A Developer's Guide

Detailed Exploration of Ghost's Code: Monorepo, Microservices, and Container-First Setup

Updated
6 min read
Understanding Ghost's Code Structure with Node.js: A Developer's Guide

The Story Behind This Solution

Installing Ghost seemed easy at first, as it was a new platform for publishing. However, when I cloned the repository and explored the code, I discovered it was much more complex than a typical WordPress clone.

Ghost is not just a blogging platform; it’s a powerful publishing ecosystem built with modern development practices that would impress any engineering team.

What began as a simple curiosity turned into an interesting look at monorepo architecture, microservices design, and best practices for containerization. I spent hours navigating through folders to understand the design choices and how everything fits together. The more I learned, the more I appreciated the careful engineering behind Ghost's architecture.

This experience taught me valuable lessons about building modern applications, especially those that need to grow from personal blogs to large publishing platforms.

If you want to learn how to set up a production-ready Node.js application or understand Ghost’s codebase for contributions or customisation, this guide can help you avoid the hours I spent figuring it out.

The Problem: Navigating Ghost's Complex Structure

What I Initially Tried

I first approached Ghost as I would any other Node.js project. I looked for the main entry point, found the routes, and tried to understand the data flow. I expected a straightforward src folder with organised models, views, and controllers. Instead, I found a repository filled with many folders, multiple package.json files, and what felt like different applications mixed.

I followed the common advice to "start with package.json and work my way up," but Ghost's monorepo structure made this difficult. Each subfolder had its own package.json file, dependencies, and purpose, making it hard to grasp the overall architecture from any single entry point.

Reading the official Ghost documentation partly helped, but it mainly focuses on how to use and deploy Ghost, not on its internal structure. I needed to learn the codebase better to make meaningful contributions and customisations.

The Real Impact

  • Time Cost: I spent nearly 8 hours over one weekend just mapping out the basic structure.

  • Project Impact: This delayed my Ghost customisation project by a full week.

  • Learning Cost: I had to unlearn my assumptions about typical Node.js project structures.

  • Professional Stakes: Understanding this architecture would influence how I build my own large-scale applications.

Why This Problem Matters

Ghost shows how content management systems have changed from large, complex systems to more modern and flexible designs. Learning about Ghost helps us understand how today’s applications deal with complexity, scalability, and user experience.

For developers working with big Node.js applications, Ghost's structure offers a guide for organising code, managing dependencies, and using microservices within a single repository.

The Solution: The Ghost Architecture Deep Dive Method

The Breakthrough Moment

I realised I needed to look at Ghost not just as one application, but as a network of connected services. Ghost is more than just a blogging platform; it is a publishing platform with different areas like content creation, user management, analytics, and commenting systems. Each part is built to grow independently while sharing common resources.

High-Level Overview

Ghost uses a single repository, called a monorepo, to improve development and maintenance. Each part functions as a separate service that can be deployed and scaled independently. This combines the benefits of a monorepo with the advantages of microservices.

Technical Implementation

Step 1: Understanding the Monorepo Structure

Ghost organises its codebase in one repository that contains multiple applications, shared libraries, development tools, and deployment configurations. At the root level, you’ll find configuration files that impact the entire system. Specialised folders store code specific to certain areas.

This setup allows developers to make changes to several components in one pull request. It also makes it easy to share code between services and keeps tools and standards consistent across the platform.

Be cautious: not all folders follow a traditional MVC structure. Many represent separate microservices or development tools.

Step 2: Decoding the Development Environment

Ghost depends on containerization to create consistent development environments. Docker configurations, VS Code settings, and AI assistant settings work together, making the development experience uniform, no matter the developer's local machine setup.

While the containerised approach may take longer to set up initially, it solves “works on my machine” problems and ensures consistent performance across teams. This method makes it easy for new developers to contribute and keeps the development environment similar to production.

The Complete Framework: The Ghost Repository Navigation System

Phase 1: Repository Overview Analysis

Objective: Understand the overall organisation and find key components.

Steps:

  1. Check root-level files: Start with package.json, docker-compose.yml, and .dockerignore to grasp the project structure and dependencies.

  2. Identify configuration folders: Review .cursor, .github, .vscode, and .adr to understand development and automation setups.

  3. Locate main application folders: Find ghost, apps, and E2E folders to see where core functionality resides.

Tools: Use a code editor with a folder tree view, and have basic knowledge of Docker and Node.js project structures.
Time: Expect to spend 30–45 minutes on initial mapping.

Phase 2: Deep Dive Implementation

Objective: Understand how each component contributes to the whole system.

Steps:

  1. Analyse the core Ghost application: The ghost folder holds the main Node.js application with the admin interface, API endpoints, and core features.

  2. Explore micro-frontend architecture: The apps folder contains 12 separate frontend applications (like comments UI, admin interface, activity pub, signup forms, statistics) that utilise micro-frontend patterns.

  3. Review the development infrastructure: Look at Docker configurations, analytics setup with Grafana, and testing frameworks in the E2E folder.

Validation: Start the development environment using docker-compose up and check that all services launch correctly.
Troubleshooting: If services won’t start, check the environment variables in .env.example and ensure all Docker dependencies are configured properly.

Key Takeaways

  • Using Monorepo with Microservices: Ghost shows how to enjoy the advantages of a single code repository (monorepo) while still benefiting from the flexibility of microservices.

  • Container-First Development: The entire development setup is run in containers. This keeps everything consistent and makes it easier to set up.

  • Separation of Concerns: The system divides analytics, monitoring, core application, and frontend elements. They stay connected in use but are handled separately in the architecture.

Professional Lessons

  1. Documenting Architecture is Important: The .adr folder shows how crucial it is to keep a record of architectural choices for future developers.

  2. Focus on Developer Experience: Ghost invests a lot in developer productivity through extensive settings for VS Code, AI tools, and automated workflows.

  3. Designed for Growth from the Start: Ghost's architecture is built for enterprise-level needs right from the beginning, rather than being added later.

What's Next?

Get the Code

Do you have questions about the way Ghost is built? Did you find this guide helpful?

This detailed look at Ghost's structure shows how modern publishing platforms manage complexity and growth. Learning these patterns will help you design your own large-scale Node.js applications better.