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.ymlholdsCANARY_DOCKER_BUILDwith publish/cloud scope; a PR becomes credential exfiltration. Fix: useworkflow_runjobs that never check out PR code. - High - Committed
.envfiles -apps/comments-ui/.env,apps/portal/.env,apps/signup-form/.env.developmentare tracked despite.gitignorerules. These are likely live credentials. Fix:git rm --cachedand rotate. - Medium - Unpinned Docker base image in
Dockerfile.production; no dependency vulnerability scan in CI; no pre-commit secret gate;persist-credentials: falsemissing in CI checkout;preinstalllifecycle script inpackage.jsonruns on every install. - Low - No
timeout-minuteson 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.