Date Note Hierarchy#
Trilium's journal feature organizes notes into a nested date hierarchy, auto-creating parent containers on demand. The canonical nesting is:
Calendar (calendarRoot)
└── Year (yearNote)
└── [Quarter (quarterNote)] ← optional
└── Month (monthNote)
└── [Week (weekNote)] ← optional
└── Day (dateNote)
All hierarchy logic lives in date_notes.ts. Each level is identified by a label attribute whose value is the date string for that level (e.g., #yearNote="2025", #monthNote="2025-03", #dateNote="2025-03-15").
Calendar Root#
The root is found via the #calendarRoot label. If a hoisted workspace note has #workspaceCalendarRoot, that takes precedence. If no root exists at all, a new "Calendar" note is created under the tree root and tagged #calendarRoot and #sorted.
Each hierarchy level function accepts an optional _rootNote parameter; if omitted, getRootCalendarNote() resolves the default root. Passing a specific root enables multiple independent calendars in a single vault.
Hierarchy Levels#
| Level | Label | Key/Value Format | Notes |
|---|---|---|---|
| Year | #yearNote | YYYY | Always present |
| Quarter | #quarterNote | YYYY-Q# | Only if root has #enableQuarterNote |
| Month | #monthNote | YYYY-MM | Parent is quarter or year depending on flag |
| Week | #weekNote | YYYY-W## | Only if root has #enableWeekNote |
| Day | #dateNote | YYYY-MM-DD | Parent is week or month depending on flag |
Optional Quarter Notes#
Quarter notes are inserted between year and month when the calendar root has the #enableQuarterNote label. The quarter label value uses the format YYYY-Q# (e.g., 2025-Q1).
Optional Week Notes and Cross-Month Cloning#
Week notes are inserted between month and day when the calendar root has the #enableWeekNote label. When getWeekNote() creates a new week note, it determines the week's start and end dates. If the week spans two calendar months, the week note is also cloned into the second month via cloningService.cloneNoteToParentNote(), so the same week note appears under both month containers without duplication of content.
Week numbering respects three user-configurable options (synced across instances) :
firstDayOfWeek— default1(Monday)firstWeekOfYear— default0minDaysInFirstWeek— default4
Note Creation and Templates#
Each level creates notes via createNote() (a thin wrapper around noteService.createNewNote). Notes inherit the isProtected flag from their parent if a protected session is active.
Each level also supports a template relation on the calendar root:
| Level | Template Relation |
|---|---|
| Year | #yearTemplate |
| Quarter | #quarterTemplate |
| Month | #monthTemplate |
| Week | #weekTemplate |
| Day | #dateTemplate |
Title Patterns#
Note titles are generated by getJournalNoteTitle() using pattern labels on the calendar root:
| Level | Label | Default |
|---|---|---|
| Year | #yearPattern | {year} |
| Quarter | #quarterPattern | Quarter number (localized) |
| Month | #monthPattern | {monthNumberPadded} - {month} |
| Week | #weekPattern | Week number (localized) |
| Day | #datePattern | {dateNumberPadded} - {weekDay} |
Available placeholders span all parent levels (e.g., {year}, {isoMonth}, {weekDay}, {ordinal}, etc.). Cross-year week notes use the week's own year rather than the calendar year for the {year} placeholder.
REST API#
The server exposes date note accessors under /api/special-notes/* :
GET /api/special-notes/days/:date— returns/creates day note (?calendarRootId=supported)GET /api/special-notes/weeks/:weekGET /api/special-notes/months/:monthGET /api/special-notes/quarters/:quarterGET /api/special-notes/years/:yearGET /api/special-notes/days-notes-for-month/:month— returns a{ date → noteId }map for calendar widgets
The client-side scripting API (api.getDayNote(), api.getWeekNote(), etc.) wraps these endpoints, waits for WebSocket sync, then resolves the note from the in-memory cache.