NgMd
On this page ▾
One command for a fresh project. A six-step path if you're integrating NgMd into an existing AnalogJS app.

Installation

The published create-ngmd package copies a ready AnalogJS project with the NgMd site frame, authoring components and build pipeline. It does not install dependencies or run git init; the next step does the install.

pnpm create ngmd@latest my-docs
npm create ngmd@latest my-docs
yarn create ngmd my-docs
bun create ngmd my-docs
cd my-docs
pnpm install
pnpm run dev

Open http://localhost:5173. Done.

Run the same command inside an Nx workspace and the site becomes an Nx app in apps/my-docs. See Nx Monorepos. The scaffolder copies a slim template that owns its dependencies. You don't depend on create-ngmd after install. It never appears in your package.json.

After install: first steps

Open src/ngmd.config.ts. Change brand name, description, public URL, GitHub URL, sidebar nav, and the keywords auto-link map. The page title, description and social tags in index.html read from site, and public/og.png is the social card image. Drop a .md file under src/content/. The path becomes the URL. No wrapper needed. All colours, radii, and fonts live as CSS variables in src/styles.css. Swap one token, the whole site follows. See every authoring component rendered inline from markdown.

Path B · Manual integration

For when you already have an AnalogJS app and want to pull NgMd in piece by piece. The scaffolder is what gets tested on every release; the manual path is documented for completeness but goes stale faster.

Prerequisites

Required floor for Angular 22 (or Node ≥ 24.15.0). pnpm, npm, yarn, or bun. Any of the four. pnpm create analog@latest if you don't have one yet.

1. Install content dependencies

The runtime libraries NgMd composes:

pnpm add @analogjs/content marked-shiki shiki@^1.29.2 @angular/elements @lucide/angular @orama/orama ts-morph
pnpm add -D @tailwindcss/typography

2. Enable content in vite.config.ts

Wire Shiki into the AnalogJS content pipeline:

import analog from '@analogjs/platform';

export default defineConfig({
  plugins: [
    analog({
      content: {
        highlighter: 'shiki',
        shikiOptions: {
          highlight: { themes: { light: 'github-light-default', dark: 'github-dark-default' }, defaultColor: false },
        },
      },
    }),
  ],
});

3. Provide content renderer in src/app/app.config.ts

Standalone renderer plus Shiki highlighter:

import { provideContent, withMarkdownRenderer } from '@analogjs/content';
import { withShikiHighlighter } from '@analogjs/content/shiki-highlighter';

export const appConfig: ApplicationConfig = {
  providers: [
    provideFileRouter(),
    provideContent(withMarkdownRenderer(), withShikiHighlighter()),
  ],
};

4. Copy the NgMd source

From a scaffolded NgMd project, copy these into yours, along with src/app/services/, src/app/utils/, src/types/, src/base.ts and src/app/register-elements.ts:

Sidebar, command palette, breadcrumb, TOC, page footer, site footer, source actions, LLM actions, version switcher, content banners, toaster, sponsor list, and the code-copy, code-group, external-links, heading-anchors and media-enhancer DOM helpers. All 17 authoring components: callout, alert, card, card-grid, tabs, pill-row, workflow, hero, code-block, accordion, badge, video, image (plus pill, step, tab, accordion-item). Video, image, keywords (runtime). Code-import, code-group, code-highlight (build-time). Tailwind tokens, fuchsia accent, Shiki dual-theme CSS, Custom Element hide-before-defined rule. Nav, brand, keyword auto-link map. page-meta, link-guard, md-links, site-html, sitemap, search-index, raw-md, vars, api-gen, and their shared plugin-utils.ts. Plus the externalLinkGuard inline in vite.config.ts.

5. Wire the plugins in vite.config.ts

Import and register the NgMd plugins next to the analog plugin: siteHtmlPlugin, varsPlugin, externalLinkGuard, internalLinkGuard, mdLinksPlugin, pageMetaPlugin, sitemapPlugin, rawMdPlugin, searchIndexPlugin, apiGenPlugin. Pass prerender: {routes: async () => prerenderRoutes(import.meta.dirname)} to analog() so the build writes an HTML file for every page and a 404.html. Copy index.html too: its %SITE_NAME%, %SITE_DESCRIPTION% and %SITE_URL% tokens are filled from ngmd.config.ts by siteHtmlPlugin.

6. Deploy

Drop a netlify.toml at the repo root with publish = "dist/analog/public" and a /* to /404.html rule with status 404, so unknown paths show the not-found page. Connect the repo to Netlify, Vercel, or any Node-friendly host. Done.

Path B goes stale faster than Path A. If a step looks wrong, the scaffolded template at github.com/erkamyaman/ngmd is the source of truth.

Hosting under a sub-path

A GitHub Pages project site lives at https://user.github.io/repo/, not at the root of its host. Set the path in ngmd.config.ts:

site: {
  url: 'https://user.github.io',
  base: '/repo/',
  // ...
},

site.url stays the origin. The NGMD_BASE environment variable overrides site.base, so CI can set it without touching the config:

NGMD_BASE=/repo/ pnpm run build

The value can be written repo, /repo or /repo/; all become /repo/. A full URL or a relative path (./) is rejected. With a base set, the build:

  • passes it to Vite as base, so scripts, styles and public/ files load from /repo/
  • sets <base href> in index.html, which the Angular router reads, so route links, the sidebar and search results stay under /repo/
  • prefixes root-absolute links and images in your markdown ([Theming](/concepts/theming), ![](/images/a.png)) and relative .md links with /repo/
  • puts the base in the sitemap, robots.txt, og:url and og:image, and in the "Copy Markdown Link" permalink
  • prerenders every page as before, so /repo/concepts/theming opens directly

Link to pages and images with root-absolute paths (/images/a.png), as in the rest of these docs. Hand-written <a> and <img> tags in markdown are covered too, but a src or href set from code, such as [src]="logo" in a component, needs the base added or a path relative to the page base (logos/vite.svg, no leading slash). For a host that serves a 404.html from the sub-path (GitHub Pages does), no extra rule is needed.

To update an existing site, copy src/base.ts, src/marked-extensions/ngmd-base.ts and the new site-html.plugin.ts, sitemap.plugin.ts and md-links.plugin.ts. Replace <base href="/" /> in index.html with <base href="%SITE_BASE%" />, and in vite.config.ts add base to the config and pass it to siteHtmlPlugin, sitemapPlugin, mdLinksPlugin and getBuildExtensions, as in the starter.

Where to next