Project Structure

Explainer v2 is organized as a pnpm workspace managed by Turborepo. Here is the top-level layout:

explainer-v2/
├── apps/
│   ├── docs/          # Documentation site (Astro)
│   ├── blog/          # Blog (Astro)
│   └── website/       # Landing page (Astro)
├── packages/
│   ├── ui/            # Shared React UI components
│   ├── mdx/           # MDX components & remark plugins
│   └── thumbnail/     # OG thumbnail generation
├── .github/workflows/ # CI/CD deploy workflows
├── Dockerfile         # Multi-stage Docker build
├── nginx.conf         # Nginx configuration
├── turbo.json         # Turborepo pipeline config
├── pnpm-workspace.yaml
└── .env               # Environment variables

Apps

AppPortPackage NamePurpose
apps/docs4321@explainer/docsMain documentation site with multi-project, versioning, and i18n support
apps/blog4322@explainer/blogBlog with posts, tags, RSS feed, and reading time
apps/website4323@explainer/websiteMarketing landing page

Each app is an independent Astro project that can be built and deployed separately.

Packages

PackageNamePurposeUsed by
packages/ui@explainer/uiButton, Card, Navbar, ThemeToggle, Dropdown, MobileMenu, LocaleSwitcherAll apps
packages/mdx@explainer/mdxMDX component overrides, Callout, Steps, Tabs, CodeGroup, Preview, remark plugins, Shiki configDocs, Blog
packages/thumbnail@explainer/thumbnailOG image generation using Satori + ResvgDocs, Blog, Website

Workspaces

The monorepo is defined in pnpm-workspace.yaml:

pnpm-workspace.yaml
packages:
  - 'apps/*'
  - 'packages/*'

Turborepo handles task orchestration. The turbo.json configuration ensures packages are built before the apps that depend on them:

turbo.json
{
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    },
    "lint": {}
  }
}

Environment variables

The .env file at the root configures cross-app navigation URLs:

VariableDefaultDescription
PUBLIC_WEBSITE_URLhttp://localhost:4323Website app URL
PUBLIC_DOCS_URLhttp://localhost:4321Docs app URL
PUBLIC_BLOG_URLhttp://localhost:4322Blog app URL

These variables are used by the shared navbar to link between apps. In production, set them to your deployed domains (e.g., https://explainer.dev, https://docs.explainer.dev).