Skip to main content
As of Obsidian v1.7.2, tabs in the background are deferred by default to improve performance. This guide explains what deferred views are and how to work with them in your plugins.

What Are Deferred Views?

Deferred views are a performance optimization introduced in Obsidian v1.7.2. When a tab is in the background (not currently visible), Obsidian doesn’t fully load the view’s content. Instead, it shows a placeholder until the user switches to that tab.
This optimization significantly reduces memory usage and improves app responsiveness when many tabs are open.

How It Works

When a view is deferred:
  1. Instead of your custom view class (like MarkdownView), the leaf contains a DeferredView
  2. The view’s content is not loaded or rendered
  3. When the user switches to the tab, Obsidian loads the actual view
  4. Your view’s normal lifecycle methods are then called

Checking for Deferred Views

Using WorkspaceLeaf.isDeferred

Check if a leaf is currently deferred:
import { WorkspaceLeaf } from 'obsidian';

const leaf = this.app.workspace.activeLeaf;
if (leaf && leaf.isDeferred) {
  console.log('This leaf is deferred');
} else {
  console.log('This leaf is fully loaded');
}

Checking View Type

You can also check the view type:
const leaf = this.app.workspace.activeLeaf;
if (leaf) {
  const viewType = leaf.view.getViewType();
  
  if (viewType === 'deferred') {
    console.log('View is deferred');
  } else {
    console.log('View type:', viewType);
  }
}

Loading Deferred Views

Using loadIfDeferred

Force a deferred view to load:
const leaf = this.app.workspace.activeLeaf;

if (leaf && leaf.isDeferred) {
  // Load the view if it's deferred
  await leaf.loadIfDeferred();
  
  // Now the view is fully loaded
  console.log('View loaded:', leaf.view.getViewType());
}
loadIfDeferred() is safe to call even if the view is not deferred - it will simply return immediately.

Using revealLeaf

The recommended way to ensure a view is loaded is to use Workspace.revealLeaf():
const leaf = this.app.workspace.getLeavesOfType('markdown')[0];

if (leaf) {
  // Reveal the leaf (brings it to foreground and loads if deferred)
  await this.app.workspace.revealLeaf(leaf);
  
  // Now the leaf is active and fully loaded
  console.log('Leaf revealed and loaded');
}
revealLeaf() handles everything: it brings the leaf to the foreground, loads it if deferred, and ensures it’s ready to use.

Handling Deferred Views in Plugins

Finding Your Custom View

When searching for your custom view type:
import { WorkspaceLeaf } from 'obsidian';

const MY_VIEW_TYPE = 'my-custom-view';

// Find leaves of your view type
const leaves = this.app.workspace.getLeavesOfType(MY_VIEW_TYPE);

if (leaves.length > 0) {
  const leaf = leaves[0];
  
  // Ensure the view is loaded before using it
  await this.app.workspace.revealLeaf(leaf);
  
  // Now safe to interact with the view
  const view = leaf.view;
  // Use view...
}

Activating Your View

When activating a view from a command:
async activateView() {
  const { workspace } = this.app;

  // Try to find existing view
  let leaf = workspace.getLeavesOfType(MY_VIEW_TYPE)[0];
  
  if (!leaf) {
    // Create new leaf if doesn't exist
    const rightLeaf = workspace.getRightLeaf(false);
    if (rightLeaf) {
      leaf = rightLeaf;
      await leaf.setViewState({
        type: MY_VIEW_TYPE,
        active: true,
      });
    }
  }

  if (leaf) {
    // Reveal leaf (loads if deferred and brings to front)
    await workspace.revealLeaf(leaf);
  }
}

Working with File Views

For views that display files:
async openFile(file: TFile) {
  const leaf = this.app.workspace.getLeaf('tab');
  
  // Open the file
  await leaf.openFile(file);
  
  // Ensure the view is loaded
  await this.app.workspace.revealLeaf(leaf);
  
  // Now the view is ready
}

Best Practices

1
Always Use revealLeaf
2
When you need to interact with a leaf, always use revealLeaf():
3
// Good
await this.app.workspace.revealLeaf(leaf);
const view = leaf.view;
view.doSomething();

// Avoid
const view = leaf.view; // Might be DeferredView!
view.doSomething(); // May fail
4
Check View Type Before Casting
5
Always verify the view type before casting:
6
import { MarkdownView } from 'obsidian';

const leaf = this.app.workspace.activeLeaf;
if (leaf && !leaf.isDeferred) {
  const view = leaf.view;
  if (view instanceof MarkdownView) {
    // Safe to use as MarkdownView
    const editor = view.editor;
  }
}
7
Handle Both States
8
Design your plugin to handle both deferred and loaded views:
9
function processLeaf(leaf: WorkspaceLeaf) {
  if (leaf.isDeferred) {
    console.log('Leaf is deferred, will process when loaded');
    return;
  }
  
  // Process the loaded view
  const view = leaf.view;
  // ...
}
10
Use Workspace Events
11
Listen for layout changes to know when views are loaded:
12
this.registerEvent(
  this.app.workspace.on('layout-change', () => {
    // Views may have been loaded or deferred
    this.updateViewList();
  })
);

Migration Guide

If your plugin was written before v1.7.2, here’s how to update it:

Before (Old Code)

// This may fail with deferred views
const leaves = this.app.workspace.getLeavesOfType('markdown');
if (leaves.length > 0) {
  const view = leaves[0].view as MarkdownView;
  const editor = view.editor; // May fail!
}

After (Updated Code)

// Proper handling of deferred views
const leaves = this.app.workspace.getLeavesOfType('markdown');
if (leaves.length > 0) {
  const leaf = leaves[0];
  
  // Ensure view is loaded
  await this.app.workspace.revealLeaf(leaf);
  
  // Now safe to cast and use
  const view = leaf.view as MarkdownView;
  const editor = view.editor; // Safe!
}

Testing with Deferred Views

To test your plugin with deferred views:
  1. Open multiple tabs in Obsidian
  2. Switch between tabs to trigger deferring
  3. Use your plugin’s commands on background tabs
  4. Verify your plugin handles deferred views correctly
Plugins that don’t handle deferred views may throw errors or behave unexpectedly when tabs are in the background.

Official Guide

For more details, see the official Obsidian developer documentation: 🔗 Understanding Deferred Views

Common Issues

Issue: Type Error on View

Problem: Getting type errors when accessing view properties Solution: Check if the view is deferred and load it first:
if (!leaf.isDeferred) {
  const view = leaf.view;
  // Safe to use view
}

Issue: View Methods Don’t Work

Problem: Calling methods on a deferred view fails Solution: Use revealLeaf() before interacting:
await this.app.workspace.revealLeaf(leaf);
// Now methods will work

Issue: Cannot Find Custom View

Problem: getLeavesOfType() returns leaves but view is wrong type Solution: The leaf exists but is deferred. Load it:
const leaves = this.app.workspace.getLeavesOfType(MY_VIEW_TYPE);
if (leaves.length > 0) {
  await this.app.workspace.revealLeaf(leaves[0]);
  // Now leaf.view is your custom view
}

Creating Views

Learn how to create custom views

Official Guide

Read the official Obsidian guide

Build docs developers (and LLMs) love