Skip to main content
The Plugin class provides a structured lifecycle for managing your plugin’s initialization, operation, and cleanup. Understanding these lifecycle methods is essential for building reliable Obsidian plugins.

The Plugin Class

All Obsidian plugins extend the Plugin class, which itself extends Component. This inheritance provides automatic lifecycle management and resource cleanup.
export abstract class Plugin extends Component {
  app: App;
  manifest: PluginManifest;
  
  onload(): Promise<void> | void;
  onunload(): void;
  onUserEnable(): void;
  onExternalSettingsChange?(): any;
}

Core Lifecycle Methods

onload()

The onload() method is called when your plugin is loaded. This is where you should perform all initialization:
async onload() {
  // Load plugin settings
  await this.loadData();
  
  // Register commands
  this.addCommand({
    id: 'example-command',
    name: 'Example Command',
    callback: () => {
      console.log('Command executed');
    }
  });
  
  // Register views
  this.registerView(
    'example-view',
    (leaf) => new ExampleView(leaf)
  );
  
  // Register events
  this.registerEvent(
    this.app.workspace.on('file-open', (file) => {
      console.log('File opened:', file);
    })
  );
}
The onload() method can be synchronous or asynchronous. Use async if you need to load settings or perform other asynchronous operations during initialization.

onunload()

The onunload() method is called when your plugin is disabled or Obsidian is shut down. The Component system automatically cleans up registered resources, but you can override this method for custom cleanup:
onunload() {
  // Custom cleanup logic
  console.log('Plugin unloaded');
}
You typically don’t need to manually unregister events, DOM listeners, or intervals registered through registerEvent(), registerDomEvent(), or registerInterval(). These are automatically cleaned up when the plugin unloads.

onUserEnable()

Called when the user explicitly enables the plugin through the settings. This is useful for opening custom views or performing one-time setup:
onUserEnable() {
  // Open a welcome view when user first enables the plugin
  this.app.workspace.getRightLeaf(false).setViewState({
    type: 'example-view',
    active: true
  });
}

onExternalSettingsChange()

Called when the plugin’s data.json file is modified externally (e.g., by a sync service):
async onExternalSettingsChange() {
  // Reload settings from disk
  await this.loadData();
  // Update UI or plugin state
  this.refreshUI();
}

Registration Methods

During onload(), use these methods to register plugin features:

Registering Commands

this.addCommand({
  id: 'open-sample-modal',
  name: 'Open Sample Modal',
  callback: () => {
    new SampleModal(this.app).open();
  }
});

Registering Views

this.registerView(
  'custom-view',
  (leaf: WorkspaceLeaf) => new CustomView(leaf)
);

Registering Events

this.registerEvent(
  this.app.vault.on('modify', (file) => {
    console.log('File modified:', file.path);
  })
);

Registering DOM Events

this.registerDomEvent(document, 'click', (evt: MouseEvent) => {
  console.log('Click detected');
});

Registering Intervals

this.registerInterval(
  window.setInterval(() => {
    console.log('Periodic check');
  }, 5000)
);
Always use window.setInterval() instead of setInterval() to avoid TypeScript confusion between Node.js and browser APIs.

Registering Settings Tabs

this.addSettingTab(new SampleSettingTab(this.app, this));

Registering Ribbon Icons

this.addRibbonIcon('dice', 'Sample Plugin', (evt: MouseEvent) => {
  console.log('Ribbon icon clicked');
});

Registering Status Bar Items

const statusBarItem = this.addStatusBarItem();
statusBarItem.setText('Status: Active');
Status bar items are not available on mobile.

Best Practices

Initialize in onload()

Perform all plugin initialization in onload(). Never initialize in the constructor.

Use Register Methods

Always use registerEvent(), registerDomEvent(), and registerInterval() for automatic cleanup.

Async Operations

Make onload() async if you need to load settings or perform other asynchronous initialization.

Minimal onunload()

Let the Component system handle cleanup automatically. Only override onunload() for custom cleanup logic.

Complete Example

import { Plugin, TFile } from 'obsidian';

export default class ExamplePlugin extends Plugin {
  settings: MyPluginSettings;

  async onload() {
    // Load settings
    await this.loadSettings();

    // Add ribbon icon
    this.addRibbonIcon('dice', 'Example Plugin', () => {
      console.log('Ribbon icon clicked');
    });

    // Add status bar
    const statusBarItem = this.addStatusBarItem();
    statusBarItem.setText('Status Bar Text');

    // Register command
    this.addCommand({
      id: 'open-sample-modal',
      name: 'Open sample modal',
      callback: () => {
        new SampleModal(this.app).open();
      }
    });

    // Register settings tab
    this.addSettingTab(new SampleSettingTab(this.app, this));

    // Register event handlers
    this.registerEvent(
      this.app.workspace.on('file-open', (file: TFile) => {
        console.log('File opened:', file.path);
      })
    );

    // Register DOM event
    this.registerDomEvent(document, 'click', (evt: MouseEvent) => {
      console.log('Document clicked');
    });

    // Register interval
    this.registerInterval(
      window.setInterval(() => this.checkStatus(), 5 * 60 * 1000)
    );
  }

  onunload() {
    console.log('Plugin unloaded');
  }

  async loadSettings() {
    this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
  }

  async saveSettings() {
    await this.saveData(this.settings);
  }
  
  checkStatus() {
    // Periodic status check logic
  }
}

App Architecture

Learn about the App object and its major modules

Events

Deep dive into the event system and event registration

Build docs developers (and LLMs) love