I've been using Obsidian's Task plugin for several years already. I came to really enjoy it, but there were a couple of things that I wished were different.
The main thing, especially in my work context, was that Tasks were "only" a checkbox line with a lot of metadata crammed into them. If you like using tags or other structured info, it gets cluttered quickly. I wanted a way to organize and filter my tasks more flexibly.
When Obsidian released the new Bases feature, I realized I could use it for my tasks too. For the past couple of months, I’ve been gradually replacing the Tasks plugin with a Base-powered system and I’m really happy with the result.
Why Bases?
Now, every task can be a self contained note, not just a single line. Inside it, I can add as much information I want: subtasks, comments, instructions, links to related notes, etc. But more importantly, I can define custom properties and structure the data however I need.
Bases bring a database-like layer to Obsidian. That means I can create a task structure tailored to my workflow.
For example, I use properties to link my notes to projects, systems, dependecies, etc. This lets me filter tasks based on what project or system they relate to, or see what’s blocked, overdue, or due soon.
My Task Template
Here's the frontmatter I currently use for Task template:
---
priority:
effort:
due_date: ""
scheduled_date: ""
category: "[[Task.base]]"
status: ToDo
depends_on: []
related_project:
related_system:
done_date:
---
I can add any fields I want in the future, but this has been good enough for now.
Task Views in My Base
I currently have 1 Task Base with 8 different views, used in different places.
For example, in my Daily template, I want to see all tasks that are either: - due today - scheduled for today - or overdue
Here's a sample of the views I use: - All - Tasks for Daily - Overdue - Behind Schedule - Due in 7 Days - Scheduled for 7 Days - Due Today - Scheduled for Today
For example, the “Tasks for Daily” view filters out completed or cancelled tasks and shows everything scheduled/due today or earlier.
And in my Daily note, I just reference that view:
# Tasks
![[Task.base#Tasks for Daily Template]]
It automatically renders a table with the relevant tasks.
Calculating Task Urgency
One thing I really liked in the Tasks plugin was the Urgency score. Which is a dynamic number based on due dates, priority, etc. You can recreate that with a Formula field in Bases, and even go beyond what Tasks offered and define the properties and weights you want.
Here’s the formula I’m using to assign an urgency score. Overdue tasks are weighted more heavily:
(IF(priority.isEmpty(),0,priority*2)
+
3 * IF(
due_date.isEmpty(),
0,
IF(
today() == due_date,
1,
IF(
(today() - due_date).days > 0,
2 + 0.2 * MIN((today() - due_date).days, 60),
1 / ((due_date - today()).days + 1)
)
)
)
+
IF(
scheduled_date.isEmpty(),
0,
IF(
today() == scheduled_date,
2,
IF(
(today() - scheduled_date).days > 0,
1 + 0.2 * MIN((today() - scheduled_date).days, 60),
1 / ((scheduled_date - today()).days + 1)
)
)
)
).round(1)
You can tweak the weights depending on how aggressive you want it to be with deadlines.
Auto-Populating the Done Date
One feature I missed from the Tasks plugin was the auto-filled done_date
when checking off a task.
I created a small custom plugin for this. It's very simple: when the frontmatter status
becomes Done
, it sets the done_date
to today’s date. If you uncheck it, the done_date
gets cleared.
Here's the plugin:
manifest.json
{
"id": "date-when-status-done",
"name": "Date When Status Done",
"version": "1.0.1",
"minAppVersion": "1.9.10",
"description": "When frontmatter `status` becomes `Done`, set `done_date` to today's date.",
"author": "you",
"isDesktopOnly": false
}
main.js
const obsidian = require('obsidian');
class DateWhenStatusDone extends obsidian.Plugin {
constructor(app, manifest) {
super(app, manifest);
this.statusProp = 'status'; // watch this frontmatter key
this.doneValue = 'Done'; // trigger value
this.stampProp = 'done_date'; // field to write/clear
this.dateFormat = 'YYYY-MM-DD'; // date format
this.lastSeen = new Map();
}
async onload() {
this.app.workspace.onLayoutReady(() => this._scanAll());
this.registerEvent(this.app.metadataCache.on('changed', (file) => this._handleFile(file)));
this.registerEvent(this.app.vault.on('modify', (file) => this._handleFile(file)));
}
_scanAll() {
const files = this.app.vault.getMarkdownFiles();
for (const f of files) this._remember(f);
}
_remember(file) {
const fm = this._fm(file);
const cur = this._readStatus(fm);
this.lastSeen.set(file.path, cur);
}
_fm(file) {
const cache = this.app.metadataCache.getFileCache(file);
return (cache && cache.frontmatter) ? cache.frontmatter : {};
}
_readStatus(fm) {
const v = fm ? fm[this.statusProp] : undefined;
if (Array.isArray(v)) return v.join(', ');
return v;
}
async _handleFile(file) {
if (!(file instanceof obsidian.TFile) || file.extension !== 'md') return;
const fm = this._fm(file);
const path = file.path;
const prev = this.lastSeen.get(path);
const cur = this._readStatus(fm);
if (prev === cur) return;
this.lastSeen.set(path, cur);
const isDone = typeof cur === 'string' && cur.trim().toLowerCase() === this.doneValue.toLowerCase();
if (isDone) {
// Status just became Done → set today's date
await this.app.fileManager.processFrontMatter(file, (frontmatter) => {
const m = (typeof window !== 'undefined' && window.moment) ? window.moment() : null;
const today = m && m.format ? m.format(this.dateFormat) : new Date().toISOString().slice(0, 10);
frontmatter[this.stampProp] = today;
});
} else {
// Status is something else → clear the done_date
await this.app.fileManager.processFrontMatter(file, (frontmatter) => {
if (frontmatter.hasOwnProperty(this.stampProp)) {
delete frontmatter[this.stampProp];
}
});
}
}
}
module.exports = DateWhenStatusDone;
To use it:
- Drop this into your Vault's
.obsidian/plugins/
folder - Enable it in the Community Plugins section
Now, whenever I mark a task as Done, the date is recorded automatically. And if I change it back to something else, it clears the date.
Final Thoughts
Switching from the Tasks plugin to Bases didn't take the amount of energy and time I thought it would. The flexibility I gained is more than worth it. Tasks as notes (with filters, formulas, properties, and views) have made my system feel way more organized and adaptable.
It’s not for everyone, but if you’re someone who likes to tinker and tailor your workflow, Bases open up a lot of possibilities.
Let me know if you’re trying something similar or thinking of switching!