obsidian-bases

Create database-like views of Obsidian notes using .base files with filters, formulas, and multiple display modes. Supports four view types: table, cards, list, and map, each configurable with custom property ordering and grouping Define computed properties using formulas with conditional logic, date arithmetic, string formatting, and 15+ built-in functions Apply global or view-specific filters using tag, folder, property, date, and link conditions with AND/OR/NOT logic Includes summaries for numeric, date, and boolean properties (Average, Sum, Min, Max, Median, Earliest, Latest, Checked, Unique, etc.) Embed bases in markdown files and validate YAML syntax; common issues include unquoted special characters, mismatched quotes in formulas, and missing null checks for optional properties

INSTALLATION
npx skills add https://github.com/kepano/obsidian-skills --skill obsidian-bases
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

$2a

# Global filters apply to ALL views in the base

filters:

  # Can be a single filter string

  # OR a recursive filter object with and/or/not

  and: []

  or: []

  not: []

# Define formula properties that can be used across all views

formulas:

  formula_name: 'expression'

# Configure display names and settings for properties

properties:

  property_name:

    displayName: "Display Name"

  formula.formula_name:

    displayName: "Formula Display Name"

  file.ext:

    displayName: "Extension"

# Define custom summary formulas

summaries:

  custom_summary_name: 'values.mean().round(3)'

# Define one or more views

views:

  - type: table | cards | list | map

    name: "View Name"

    limit: 10                    # Optional: limit results

    groupBy:                     # Optional: group results

      property: property_name

      direction: ASC | DESC

    filters:                     # View-specific filters

      and: []

    order:                       # Properties to display in order

      - file.name

      - property_name

      - formula.formula_name

    summaries:                   # Map properties to summary formulas

      property_name: Average

Filter Syntax

Filters narrow down results. They can be applied globally or per-view.

Filter Structure

# Single filter

filters: 'status == "done"'

# AND - all conditions must be true

filters:

  and:

    - 'status == "done"'

    - 'priority > 3'

# OR - any condition can be true

filters:

  or:

    - 'file.hasTag("book")'

    - 'file.hasTag("article")'

# NOT - exclude matching items

filters:

  not:

    - 'file.hasTag("archived")'

# Nested filters

filters:

  or:

    - file.hasTag("tag")

    - and:

        - file.hasTag("book")

        - file.hasLink("Textbook")

    - not:

        - file.hasTag("book")

        - file.inFolder("Required Reading")

Filter Operators

Operator

Description

==

equals

!=

not equal

>

greater than

<

less than

>=

greater than or equal

<=

less than or equal

&#x26;&#x26;

logical and

||

logical or

!

logical not

Properties

Three Types of Properties

  • Note properties - From frontmatter: note.author or just author
  • File properties - File metadata: file.name, file.mtime, etc.
  • Formula properties - Computed values: formula.my_formula

File Properties Reference

Property

Type

Description

file.name

String

File name

file.basename

String

File name without extension

file.path

String

Full path to file

file.folder

String

Parent folder path

file.ext

String

File extension

file.size

Number

File size in bytes

file.ctime

Date

Created time

file.mtime

Date

Modified time

file.tags

List

All tags in file

file.links

List

Internal links in file

file.backlinks

List

Files linking to this file

file.embeds

List

Embeds in the note

file.properties

Object

All frontmatter properties

The this Keyword

  • In main content area: refers to the base file itself
  • When embedded: refers to the embedding file
  • In sidebar: refers to the active file in main content

Formula Syntax

Formulas compute values from properties. Defined in the formulas section.

formulas:

  # Simple arithmetic

  total: "price * quantity"

  # Conditional logic

  status_icon: 'if(done, "✅", "⏳")'

  # String formatting

  formatted_price: 'if(price, price.toFixed(2) + " dollars")'

  # Date formatting

  created: 'file.ctime.format("YYYY-MM-DD")'

  # Calculate days since created (use .days for Duration)

  days_old: '(now() - file.ctime).days'

  # Calculate days until due date

  days_until_due: 'if(due_date, (date(due_date) - today()).days, "")'

Key Functions

Most commonly used functions. For the complete reference of all types (Date, String, Number, List, File, Link, Object, RegExp), see FUNCTIONS_REFERENCE.md.

Function

Signature

Description

date()

date(string): date

Parse string to date (YYYY-MM-DD HH:mm:ss)

now()

now(): date

Current date and time

today()

today(): date

Current date (time = 00:00:00)

if()

if(condition, trueResult, falseResult?)

Conditional

duration()

duration(string): duration

Parse duration string

file()

file(path): file

Get file object

link()

link(path, display?): Link

Create a link

Duration Type

When subtracting two dates, the result is a Duration type (not a number).

Duration Fields: duration.days, duration.hours, duration.minutes, duration.seconds, duration.milliseconds

IMPORTANT: Duration does NOT support .round(), .floor(), .ceil() directly. Access a numeric field first (like .days), then apply number functions.

# CORRECT: Calculate days between dates

"(date(due_date) - today()).days"                    # Returns number of days

"(now() - file.ctime).days"                          # Days since created

"(date(due_date) - today()).days.round(0)"           # Rounded days

# WRONG - will cause error:

# "((date(due) - today()) / 86400000).round(0)"      # Duration doesn't support division then round

Date Arithmetic

# Duration units: y/year/years, M/month/months, d/day/days,

#                 w/week/weeks, h/hour/hours, m/minute/minutes, s/second/seconds

"now() + \"1 day\""       # Tomorrow

"today() + \"7d\""        # A week from today

"now() - file.ctime"      # Returns Duration

"(now() - file.ctime).days"  # Get days as number

View Types

Table View

views:

  - type: table

    name: "My Table"

    order:

      - file.name

      - status

      - due_date

    summaries:

      price: Sum

      count: Average

Cards View

views:

  - type: cards

    name: "Gallery"

    order:

      - file.name

      - cover_image

      - description

List View

views:

  - type: list

    name: "Simple List"

    order:

      - file.name

      - status

Map View

Requires latitude/longitude properties and the Maps community plugin.

views:

  - type: map

    name: "Locations"

    # Map-specific settings for lat/lng properties

Default Summary Formulas

Name

Input Type

Description

Average

Number

Mathematical mean

Min

Number

Smallest number

Max

Number

Largest number

Sum

Number

Sum of all numbers

Range

Number

Max - Min

Median

Number

Mathematical median

Stddev

Number

Standard deviation

Earliest

Date

Earliest date

Latest

Date

Latest date

Range

Date

Latest - Earliest

Checked

Boolean

Count of true values

Unchecked

Boolean

Count of false values

Empty

Any

Count of empty values

Filled

Any

Count of non-empty values

Unique

Any

Count of unique values

Complete Examples

Task Tracker Base

filters:

  and:

    - file.hasTag("task")

    - 'file.ext == "md"'

formulas:

  days_until_due: 'if(due, (date(due) - today()).days, "")'

  is_overdue: 'if(due, date(due) < today() &#x26;&#x26; status != "done", false)'

  priority_label: 'if(priority == 1, "🔴 High", if(priority == 2, "🟡 Medium", "🟢 Low"))'

properties:

  status:

    displayName: Status

  formula.days_until_due:

    displayName: "Days Until Due"

  formula.priority_label:

    displayName: Priority

views:

  - type: table

    name: "Active Tasks"

    filters:

      and:

        - 'status != "done"'

    order:

      - file.name

      - status

      - formula.priority_label

      - due

      - formula.days_until_due

    groupBy:

      property: status

      direction: ASC

    summaries:

      formula.days_until_due: Average

  - type: table

    name: "Completed"

    filters:

      and:

        - 'status == "done"'

    order:

      - file.name

      - completed_date

Reading List Base

filters:

  or:

    - file.hasTag("book")

    - file.hasTag("article")

formulas:

  reading_time: 'if(pages, (pages * 2).toString() + " min", "")'

  status_icon: 'if(status == "reading", "📖", if(status == "done", "✅", "📚"))'

  year_read: 'if(finished_date, date(finished_date).year, "")'

properties:

  author:

    displayName: Author

  formula.status_icon:

    displayName: ""

  formula.reading_time:

    displayName: "Est. Time"

views:

  - type: cards

    name: "Library"

    order:

      - cover

      - file.name

      - author

      - formula.status_icon

    filters:

      not:

        - 'status == "dropped"'

  - type: table

    name: "Reading List"

    filters:

      and:

        - 'status == "to-read"'

    order:

      - file.name

      - author

      - pages

      - formula.reading_time

Daily Notes Index

filters:

  and:

    - file.inFolder("Daily Notes")

    - '/^\d{4}-\d{2}-\d{2}$/.matches(file.basename)'

formulas:

  word_estimate: '(file.size / 5).round(0)'

  day_of_week: 'date(file.basename).format("dddd")'

properties:

  formula.day_of_week:

    displayName: "Day"

  formula.word_estimate:

    displayName: "~Words"

views:

  - type: table

    name: "Recent Notes"

    limit: 30

    order:

      - file.name

      - formula.day_of_week

      - formula.word_estimate

      - file.mtime

Embedding Bases

Embed in Markdown files:

![[MyBase.base]]

<!-- Specific view -->

![[MyBase.base#View Name]]

YAML Quoting Rules

  • Use single quotes for formulas containing double quotes: 'if(done, "Yes", "No")'
  • Use double quotes for simple strings: "My View Name"
  • Escape nested quotes properly in complex expressions

Troubleshooting

YAML Syntax Errors

Unquoted special characters: Strings containing :, {, }, [, ], ,, &#x26;, *, #, ?, |, -, <, >, =, !, %, @, must be quoted.

# WRONG - colon in unquoted string

displayName: Status: Active

# CORRECT

displayName: "Status: Active"

Mismatched quotes in formulas: When a formula contains double quotes, wrap the entire formula in single quotes.

# WRONG - double quotes inside double quotes

formulas:

  label: "if(done, "Yes", "No")"

# CORRECT - single quotes wrapping double quotes

formulas:

  label: 'if(done, "Yes", "No")'

Common Formula Errors

Duration math without field access: Subtracting dates returns a Duration, not a number. Always access .days, .hours, etc.

# WRONG - Duration is not a number

"(now() - file.ctime).round(0)"

# CORRECT - access .days first, then round

"(now() - file.ctime).days.round(0)"

Missing null checks: Properties may not exist on all notes. Use if() to guard.

# WRONG - crashes if due_date is empty

"(date(due_date) - today()).days"

# CORRECT - guard with if()

'if(due_date, (date(due_date) - today()).days, "")'

Referencing undefined formulas: Ensure every formula.X in order or properties has a matching entry in formulas.

# This will fail silently if 'total' is not defined in formulas

order:

  - formula.total

# Fix: define it

formulas:

  total: "price * quantity"

References

BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card