A comprehensive reference for how Project Planner stores, organizes, and manages your project data. Understanding the data structure helps with troubleshooting, backups, advanced customization, and integration with other tools.
Storage Locations
Project Planner stores data across three distinct locations depending on the type of information.
Primary Data File
Plugin settings are stored in:
.obsidian/plugins/obsidian-project-planner/data.jsonAs of v0.8.3 this file contains settings only. It has one top-level key:
- settings — all plugin configuration values
Task data is no longer stored here.
Per-Project Task Files (new in v0.8.3)
Each project's tasks are stored in a dedicated JSON file inside the vault:
{projectsBasePath}/{Project Name}/.planner-tasks.jsonThe default projectsBasePath is Project Planner, so a project named "My Project" stores its tasks at:
Project Planner/My Project/.planner-tasks.jsonBecause these files live inside your vault (not in .obsidian/), they are Git-trackable and synced by Obsidian Sync. Each file contains a single JSON object:
{
"version": 1,
"projectId": "a1b2c3d4-...",
"tasks": [ ... ]
}Markdown Task Files
When Bidirectional Markdown Sync is enabled, each task is also stored as an individual Markdown file:
{projectsBasePath}/{Project Name}/Tasks/{TaskTitle}.mdThese files mirror the task data and are kept in sync automatically.
View Preferences
Per-view display settings (column widths, sort order, visible columns, etc.) are stored inside data.json as part of settings. They sync across devices with Obsidian Sync.
Data Schema
Project Object
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "My Project",
"storageKey": "My Project",
"createdDate": "2026-01-15T10:00:00.000Z",
"lastUpdatedDate": "2026-08-01T14:22:00.000Z",
"lastSyncTimestamp": 1700000000000,
"buckets": [
{ "id": "bucket-uuid-1", "name": "To Do", "color": "#0078d4" },
{ "id": "bucket-uuid-2", "name": "In Progress" },
{ "id": "bucket-uuid-3", "name": "Done" }
],
"unassignedBucketName": "Unassigned",
"budgetTotal": 10000,
"defaultHourlyRate": 75,
"currencySymbol": "$"
}- id (required) — UUID v4 unique identifier
- name (required) — display name shown in the UI
- storageKey (required, v0.8.3+) — the folder name used on disk; set at creation and never changes, so renaming a project does not orphan its files
- createdDate — ISO 8601 timestamp of project creation
- lastUpdatedDate — ISO 8601 timestamp of last task change
- lastSyncTimestamp (optional) — Unix timestamp (ms) of the last Markdown sync
- buckets — array of Board view bucket objects; each has
id,name, and optionalcolor - unassignedBucketName — custom label for the Unassigned bucket
- budgetTotal — total project budget (cost tracking)
- defaultHourlyRate — default hourly rate applied to hourly-cost tasks
- currencySymbol — display symbol for currency (e.g.
$,€,£)
Task Object
{
"id": "f8e7d6c5-b4a3-2190-fedc-ba0987654321",
"title": "Design landing page",
"status": "In Progress",
"completed": false,
"priority": "High",
"parentId": null,
"collapsed": false,
"bucketId": "bucket-uuid-2",
"startDate": "2026-02-01",
"dueDate": "2026-02-14",
"createdDate": "2026-01-20",
"lastModifiedDate": "2026-02-03",
"tags": ["tag-uuid-1"],
"description": "Create wireframes and high-fidelity mockups.",
"subtasks": [
{ "id": "sub-uuid-1", "title": "Wireframe", "completed": true },
{ "id": "sub-uuid-2", "title": "Hi-fi mockup", "completed": false }
],
"links": [
{ "id": "link-uuid-1", "title": "Figma file", "url": "https://figma.com/...", "type": "external" }
],
"dependencies": [
{ "predecessorId": "other-task-uuid", "type": "FS" }
],
"effortCompleted": 4,
"effortRemaining": 6,
"percentComplete": 40,
"costEstimate": 750,
"costActual": 300,
"costType": "hourly",
"hourlyRate": 75,
"cardPreview": "none"
}Required Fields
- id — UUID v4 unique identifier
- title — task name
- status — current status label (must match a configured status name)
- completed — boolean
Optional Fields
- priority —
"Low","Medium","High", or"Critical" - parentId — UUID of the parent task;
nullor omitted for root-level tasks - collapsed — whether children are hidden in Grid view
- bucketId — UUID of the Board view bucket
- startDate / dueDate / createdDate / lastModifiedDate — dates in
YYYY-MM-DDformat - tags — array of tag ID strings
- description — Markdown-formatted body text
- subtasks — array of checklist items (
id,title,completed) - links — array of link objects (
id,title,url,type);typeis"obsidian"or"external" - dependencies — array of objects with
predecessorId(UUID) andtype:"FS"(Finish-to-Start),"SS"(Start-to-Start),"FF"(Finish-to-Finish), or"SF"(Start-to-Finish) - effortCompleted / effortRemaining — hours of work done and remaining
- percentComplete — 0–100; auto-calculated from effort values
- costEstimate / costActual — numeric cost values
- costType —
"fixed"or"hourly" - hourlyRate — per-task rate override; uses project
defaultHourlyRatewhen omitted - cardPreview — what to show on Board cards:
"none","checklist", or"description"
Tag Object
{
"id": "tag-uuid-1",
"name": "design",
"color": "#4a90d9"
}- id — UUID v4 unique identifier
- name — tag display name
- color — hex color string used in the UI
Data Organization
Per-Project Task Files
As of v0.8.3, tasks are no longer stored inside data.json. Each project maintains its own task file at {projectsBasePath}/{storageKey}/.planner-tasks.json:
{
"version": 1,
"projectId": "project-uuid-1",
"tasks": [
{ "id": "task-uuid-1", "title": "Task A", "status": "Not Started", "completed": false },
{ "id": "task-uuid-2", "title": "Task B", "status": "In Progress", "completed": false }
]
}Tasks are ordered by their position in the tasks array, which reflects manual drag-and-drop ordering.
Hierarchical Relationships
Parent-child task relationships are established through the parentId field. A task with parentId: null is a root-level task; otherwise it is nested under the referenced parent.
// Root task
{ "id": "parent-uuid", "title": "Epic: Redesign", "parentId": null }
// Child task
{ "id": "child-uuid", "title": "Update header", "parentId": "parent-uuid" }
// Grandchild task
{ "id": "grandchild-uuid", "title": "New logo", "parentId": "child-uuid" }Markdown File Format
When Markdown Sync is enabled, each task is written as a .md file with YAML frontmatter followed by body content:
---
id: f8e7d6c5-b4a3-2190-fedc-ba0987654321
title: Design landing page
status: In Progress
completed: false
priority: High
bucketId: bucket-uuid-2
startDate: 2026-02-01
dueDate: 2026-02-14
tags:
- tag-uuid-1
dependencies:
- FS:other-task-uuid
effortCompleted: 4
effortRemaining: 6
percentComplete: 40
---
Create the initial wireframes and high-fidelity mockups.
## Subtasks
- [x] Wireframe
- [ ] Hi-fi mockup
## Links
- [Figma file](https://figma.com/...)Date Format
- Current format:
YYYY-MM-DD(e.g.,2026-02-14) - Legacy format: Full ISO 8601 strings (e.g.,
2025-02-14T00:00:00.000Z)
Project Planner is backward-compatible and accepts both formats when reading data. New dates are always written in the short YYYY-MM-DD format.
Settings Schema
{
"settings": {
"enableMarkdownSync": true,
"autoCreateTaskNotes": true,
"syncOnStartup": false,
"enableDailyNoteSync": false,
"dailyNoteTagPattern": "#planner",
"dailyNoteScanFolders": [],
"dailyNoteDefaultProject": "",
"projectsBasePath": "Project Planner",
"defaultView": "grid",
"showCompleted": true,
"openViewsInNewTab": false,
"enableDependencyScheduling": true,
"enableParentRollUp": true,
"dateFormat": "iso",
"ganttLeftColumnWidth": 300,
"myDayDefaultView": "today"
}
}Data Backup
Best Practices
- Version control: Keep your vault in a Git repository. Task data lives in
{projectsBasePath}/{Project}/.planner-tasks.jsoninside the vault and is fully Git-trackable.data.jsonholds settings only. - Regular copies: Back up your vault folder periodically.
- Before upgrades: Note your current version before updating the plugin.
- Enable Markdown Sync: With sync enabled, tasks also exist as individual
.mdfiles — a built-in secondary copy. - Cloud storage: Store your vault on a cloud-synced folder (iCloud, Dropbox, OneDrive) for automatic off-site backup.
Recovery Options
- Restore
.planner-tasks.jsonfrom a Git commit or backup copy. - Re-import tasks from existing Markdown files using Markdown Sync.
- Manually reconstruct the JSON from exported or printed task lists.
Performance Considerations
As of v0.8.3, each project stores its tasks in a separate vault file rather than a single shared data.json. This significantly reduces the read/write surface for large vaults — only the active project's file is loaded during task operations. The limits below apply per project.
Tip
For best performance, keep individual projects under 500 tasks and the total across all projects under 2,000 tasks.
Optimization Tips
- Archive completed projects by exporting and removing them from the active data file.
- Minimize the number of subtasks and links per task to reduce file size.
- Use tags and buckets instead of deeply nested hierarchies.
- Periodically review and clean up orphaned tasks (tasks whose
parentIdpoints to a deleted parent).
Recommended Limits
- Tasks per project: ≤ 500
- Total tasks: ≤ 2,000
- Subtasks per task: ≤ 50
- Nesting depth: ≤ 5 levels
Data Migration
Version Upgrades
When the plugin loads after an upgrade, it checks for legacy task data in data.json. If found, tasks are silently migrated to the new per-project vault files and removed from data.json. No manual steps are required. Back up your vault with Git or Obsidian Sync before upgrading if you want a manual snapshot.
Exporting Data
- JSON: Copy
.planner-tasks.jsondirectly — it is valid, portable JSON. - Markdown: Enable Markdown Sync to generate individual
.mdfiles that can be used in any Markdown-compatible tool.
Technical Notes
UUID Generation
All IDs are RFC 4122 v4 UUIDs generated client-side using crypto.randomUUID() (or a polyfill on older platforms). This guarantees uniqueness without a central server.
Sync Conflict Resolution
When Markdown Sync detects a conflict between the JSON data and a Markdown file, the last write wins. A syncInProgress guard prevents recursive writes during a sync cycle. See Bidirectional Markdown Sync for details.
Data Integrity
- Plugin validates required fields on every save.
- Orphaned child tasks (invalid
parentId) are promoted to root level automatically. - Duplicate IDs are detected and regenerated on load.