The Problem

Ghost is a headless Node.js CMS for professional publishing, handling memberships, subscriptions, and newsletters. The core problem it solves is giving publishers a modern, self-hostable platform that separates content management from presentation, with built-in monetization through memberships and subscriptions rather than relying on third-party services.

What This Does

This repository is a monorepo collection of five self-contained projects, not a single codebase. The ghost/ directory (4,531 files) contains the core CMS and admin application, while apps/ (2,016 files) holds separate frontend applications: portal for member signup/login, comments-ui for comment threads, announcement-bar for site notifications, and admin-x-* for the modern admin interface. The e2e/ directory (283 files) contains Playwright end-to-end tests.

The stack is predominantly JavaScript (3,106 files) with TypeScript (790 files) and TSX (853 files). The admin app runs on Ember.js within ghost/admin, while the apps use React and Vite. Package management is pnpm, with Docker and GitHub Actions for CI/CD.

How It Is Wired

Execution starts at several independent entry points. The portal app's componentDidMount in apps/portal/src/app.js reaches 194 functions—the widest reach in the repo—and handles member-facing flows. The announcement bar's init in apps/announcement-bar/src/index.js reaches 111 functions. These are separate applications that talk to the Ghost API rather than sharing code.

The code's internal call graph shows 1,811 resolved call edges. The most-called function is t (called from 118 places), a translation helper in apps/portal/src/utils/errors.js—changing it breaks nearly everything in the portal. makeRequest (called from 29 places) handles API calls, while query (26 places) in ghost/admin/app/adapters/base.js is the admin's data-fetching backbone. The ghost/admin/app/controllers/lexical-editor.js is the largest hub with 66 functions, and it reads/writes files, suggesting it handles editor state persistence.

Only 43 functions touch the filesystem, 2 make outbound network calls, and 1 runs an external command—this is primarily an API-driven system where most I/O happens through the Ghost content/admin APIs.

How To Use It

# Clone and install
git clone https://github.com/moses-y/Ghost
cd Ghost
pnpm install

# Development
pnpm dev

# Production build
docker build -f Dockerfile.production -t ghost .

Configuration lives in .env.example at the root. The Dockerfile uses node:$NODE_VERSION-bookworm-slim as a base. The README documents the production path: npm install ghost-cli -g then ghost install for server deployment, or ghost install local for local development.

Real-World Use

A publisher deploys Ghost via Docker, uses the admin interface at ghost/admin to write posts, and the portal app handles member signups and subscriptions. The comments-ui app renders comment threads on the public site. Each app is independently deployable and talks to the core Ghost API.

Code Health & Issues

Static analysis found 9 issues (1 critical, 2 high, 5 medium, 1 low):

  • Critical - Secrets in workflows a fork can trigger - .github/workflows/deploy-to-staging.yml holds CANARY_DOCKER_BUILD with publish/cloud scope; a PR becomes credential exfiltration. Fix: use workflow_run jobs that never check out PR code.
  • High - Committed .env files - apps/comments-ui/.env, apps/portal/.env, apps/signup-form/.env.development are tracked despite .gitignore rules. These are likely live credentials. Fix: git rm --cached and rotate.
  • Medium - Unpinned Docker base image in Dockerfile.production; no dependency vulnerability scan in CI; no pre-commit secret gate; persist-credentials: false missing in CI checkout; preinstall lifecycle script in package.json runs on every install.
  • Low - No timeout-minutes on CI jobs, risking overlapping runs.

The repo has tests (1,764 files), CI via GitHub Actions, a license, and a lockfile. The committed secrets are the most urgent issue—they should be rotated and removed before any public use.

The Bottom Line

Ghost is a mature, well-architected publishing platform with a clean separation between core CMS and frontend apps. The committed .env files and workflow secrets are serious security liabilities that need immediate remediation. For a production deployment, use the official Ghost CLI or Docker image rather than building from this fork until those are resolved.