Obsidian Bases Plugin API: Accessing View Results Without a Full BasesView
What plugin developers actually want from Bases
Obsidian Bases arrived as a first-party, GUI-driven way to define cohorts of notes — filter by frontmatter properties, build table views, no query language required. For users that’s the whole point. For plugin developers it raises an immediate question: can I get those filter results programmatically, without re-implementing the query engine from scratch?
Short answer: only if you build a full view component. There is no app.bases.getViewFiles() today.
What the current Bases API exposes
Obsidian v1.10.0 shipped the Bases system alongside an API for registering custom view types inside .base files. Plugins call registerBasesView() to add a new view type, and Obsidian calls onDataUpdated on your view whenever the underlying query re-runs.
Inside your BasesView subclass, this.data.data is an array of every file matching the current view’s filters. this.data.allProperties includes computed properties — things like file.links that go beyond raw file metadata. The official developer documentation at docs.obsidian.md/plugins/guides/bases-view covers the full registration setup, and the TypeScript API reference documents BasesView, BasesViewConfig, and BasesViewRegistration.
A minimal registration looks like this:
this.registerBasesView({
type: 'my-custom-view',
name: 'My View',
icon: 'list',
factory: (config) => new MyBasesView(config),
});
What this requires from your plugin
Quite a bit. Your plugin has to implement a render function and appear as a selectable view type in the .base file’s view switcher. That’s reasonable if the goal is to present Bases data in a novel way — a Kanban board, a timeline, a custom list. It’s overkill if all you need is a TFile[] to feed into processing logic that already exists elsewhere in your plugin.
The gap: no headless query path
The feature request thread on the Obsidian forum puts it plainly. Many plugins — Dataview, Tasks, spaced repetition tools, project managers — already compile lists of notes through their own filter systems. Users end up maintaining the same filter in two places: once in Bases, once in the plugin. A headless API would collapse that duplication.
The proposed signature:
await app.bases.getViewFiles(baseFile: TFile, viewName: string): Promise<TFile[]>
Simple, typed, async. Nothing about rendering. Just the files that would appear in that view. That API does not exist in Obsidian today.
Two imperfect workarounds
Implement a BasesView
Register a BasesView, use onDataUpdated to store the file list somewhere your plugin can read, and access it from the rest of your code. This works. The problem is it’s coupled to UI state — the user has to open your view inside the .base file before data flows at all. A plugin that needs file lists as a background operation shouldn’t require a visible, open pane to function.
Open a leaf and read internal state
The approach described in the original feature request: open the .base file in a new leaf programmatically, wait for the query controller to settle, then read controller.results. It works well enough to ship — the Pairwise Elo Ranking plugin uses it today. The fragility is real. controller.results is not a documented API surface and can change in any Obsidian release without warning. The approach also creates visible UI side effects unless you’re careful about hiding and cleaning up the leaf after use.
Why the plugin ecosystem cares
A clean headless API would change the calculus for several popular plugins. Dataview could add Bases as a FROM source — something like LIST FROM "Books.base#To Read" — so users stop maintaining parallel filter definitions in two places. Tasks could scope task queries to a Base view instead of a folder or tag. Spaced repetition plugins build decks from file lists; a Bases view is a natural, user-friendly way to define one without touching a config file.
None of these require anything exotic. They already have the logic to do something useful with a TFile[]. They just need a reliable, documented way to get one from a Base.
What would make the API more complete
The basic getViewFiles() call covers most cases. Two additions would round it out. First, a reactive subscription — a callback fired when the Base filter or underlying files change — so plugins can stay in sync without polling. Second, access to computed property values alongside the TFile references, for plugins that need frontmatter data like status or priority already resolved.
Neither is strictly necessary for a first version. The one-shot call alone would unblock most of the use cases the community is asking for.
