Summary
When building a documentation/help center with hierarchical content (categories as subdirectories), the AnalogJS content system has several undocumented limitations that make nested content structures surprisingly difficult to implement.
What I tried to build
A docs section at /docs with articles organized in categories:
src/content/docs/
erste-schritte/
willkommen.md → /docs/erste-schritte/willkommen
erster-upload.md → /docs/erste-schritte/erster-upload
assets/
hochladen.md → /docs/assets/hochladen
Problems encountered
1. injectContentFiles does not include content body
The ContentFile interface defines content?: string | object, but injectContentFiles() only returns filename, attributes, and slug — never the actual markdown content. This is not documented.
If you use injectContentFiles to find articles and then try to render with <analog-markdown [content]="article.content">, it fails with TypeError: Cannot read properties of undefined (reading 'render') because content is undefined.
Suggestion: Document clearly that injectContentFiles = metadata only, injectContent = metadata + content body.
2. injectContent with subdirectory doesn't work with nested directories
Using injectContent({ param: 'slug', subdirectory: 'docs' }) works when all .md files are directly inside src/content/docs/. But if articles are in subdirectories like src/content/docs/erste-schritte/willkommen.md, the slug from a [...slug] catch-all route becomes erste-schritte/willkommen (contains /).
Looking at the source code (analogjs-content.mjs:119-122):
// If slug contains path separators, treat it as root-relative to /src/content
const newBase = slug.includes('/')
? `/src/content/${slug}`
: `${filePath}/${slug}`;
When the frontmatter slug contains /, the lookup becomes root-relative to /src/content/, completely ignoring the subdirectory prefix. This means:
subdirectory: 'docs' + slug erste-schritte/willkommen → should resolve to src/content/docs/erste-schritte/willkommen.md
- But actually resolves to
src/content/erste-schritte/willkommen.md (ignoring docs/)
There's no way to use both subdirectory and nested paths together.
3. contentDir in prerender config doesn't scan subdirectories
The contentDir option in vite.config.ts only scans .md files at the top level of the specified directory. Files in subdirectories are not discovered. This requires either:
- Listing each subdirectory separately as its own
contentDir entry
- Flattening the content structure
Suggestion: Support recursive scanning or document this limitation.
4. No documented pattern for hierarchical/nested content
The documentation shows flat content structures (e.g., src/content/blog/my-post.md). There's no guidance on:
- How to organize content in category subdirectories
- How to use
[...slug] catch-all routes with content
- The interaction between frontmatter
slug values containing / and the resolution logic
Workaround
I ended up flattening all docs articles into src/content/docs/ (no subdirectories) and using frontmatter metadata (category, categoryTitle) to maintain the logical hierarchy. This works but loses the benefit of filesystem organization.
Environment
@analogjs/platform: 2.3.1
@analogjs/content: installed with platform
- Angular: 21
- Node: 24
Suggestions
- Document
injectContentFiles vs injectContent — clarify that only injectContent loads the content body
- Fix or document subdirectory + nested slug interaction — either make
subdirectory work correctly with path-containing slugs, or document why it doesn't
- Support recursive
contentDir scanning — or document that only top-level files are discovered
- Add a "hierarchical content" recipe — showing how to build category-based documentation with AnalogJS
Summary
When building a documentation/help center with hierarchical content (categories as subdirectories), the AnalogJS content system has several undocumented limitations that make nested content structures surprisingly difficult to implement.
What I tried to build
A docs section at
/docswith articles organized in categories:Problems encountered
1.
injectContentFilesdoes not includecontentbodyThe
ContentFileinterface definescontent?: string | object, butinjectContentFiles()only returnsfilename,attributes, andslug— never the actual markdown content. This is not documented.If you use
injectContentFilesto find articles and then try to render with<analog-markdown [content]="article.content">, it fails withTypeError: Cannot read properties of undefined (reading 'render')becausecontentis undefined.Suggestion: Document clearly that
injectContentFiles= metadata only,injectContent= metadata + content body.2.
injectContentwithsubdirectorydoesn't work with nested directoriesUsing
injectContent({ param: 'slug', subdirectory: 'docs' })works when all.mdfiles are directly insidesrc/content/docs/. But if articles are in subdirectories likesrc/content/docs/erste-schritte/willkommen.md, the slug from a[...slug]catch-all route becomeserste-schritte/willkommen(contains/).Looking at the source code (analogjs-content.mjs:119-122):
When the frontmatter
slugcontains/, the lookup becomes root-relative to/src/content/, completely ignoring thesubdirectoryprefix. This means:subdirectory: 'docs'+ slugerste-schritte/willkommen→ should resolve tosrc/content/docs/erste-schritte/willkommen.mdsrc/content/erste-schritte/willkommen.md(ignoringdocs/)There's no way to use both
subdirectoryand nested paths together.3.
contentDirin prerender config doesn't scan subdirectoriesThe
contentDiroption invite.config.tsonly scans.mdfiles at the top level of the specified directory. Files in subdirectories are not discovered. This requires either:contentDirentrySuggestion: Support recursive scanning or document this limitation.
4. No documented pattern for hierarchical/nested content
The documentation shows flat content structures (e.g.,
src/content/blog/my-post.md). There's no guidance on:[...slug]catch-all routes with contentslugvalues containing/and the resolution logicWorkaround
I ended up flattening all docs articles into
src/content/docs/(no subdirectories) and using frontmatter metadata (category,categoryTitle) to maintain the logical hierarchy. This works but loses the benefit of filesystem organization.Environment
@analogjs/platform: 2.3.1@analogjs/content: installed with platformSuggestions
injectContentFilesvsinjectContent— clarify that onlyinjectContentloads the content bodysubdirectorywork correctly with path-containing slugs, or document why it doesn'tcontentDirscanning — or document that only top-level files are discovered