Obsidian Plugin Development Cheat Sheet

Obsidian Plugin Development Cheat Sheet #

A comprehensive guide to developing plugins for Obsidian, from setup to release.

πŸš€ Getting Started #

Prerequisites #

Development Vault #

  • ALWAYS use a separate, dedicated vault for plugin development to avoid data loss in your main vault.
  • Create a new, empty vault for development purposes.

Sample Plugin Setup #

  1. Clone the sample plugin into your development vault’s .obsidian/plugins directory:

    cd /path/to/your/dev-vault/.obsidian/plugins
    git clone https://github.com/obsidianmd/obsidian-sample-plugin.git your-plugin-name
    
  2. Install dependencies:

    cd your-plugin-name
    npm install
    
  3. Start the development server:

    npm run dev
    

    This command watches for changes in your .ts files and automatically compiles them into main.js.

  4. Enable the plugin in Obsidian:

    • Go to Settings > Community plugins.
    • Turn on community plugins.
    • Enable your new plugin under Installed plugins.

πŸ—οΈ Core Concepts #

manifest.json #

This file contains metadata about your plugin. Restart Obsidian after making changes to this file.

  • id: A unique identifier for your plugin (e.g., hello-world).
  • name: The human-friendly name of your plugin.
  • author: Your name.
  • version: The current version of your plugin.
  • minAppVersion: The minimum version of Obsidian required.
  • description: A short description of your plugin.
  • isDesktopOnly: Set to true if your plugin uses Node.js or Electron APIs.

main.ts - The Plugin Class #

This is the main entry point for your plugin. It must export a default class that extends Plugin.

import { Plugin } from 'obsidian';

export default class MyPlugin extends Plugin {
  async onload() {
    // Plugin startup logic here
  }

  onunload() {
    // Plugin cleanup logic here
  }
}

Plugin Lifecycle #

  • onload(): This method is called when your plugin is enabled. Use it to set up UI elements, register event listeners, and add commands.
  • onunload(): This method is called when your plugin is disabled. Use it to clean up any resources created in onload() to prevent memory leaks.

🧩 API Fundamentals #

Access the Obsidian API via this.app from within your plugin class.

  • this.app.vault: Interact with files and folders in the vault.
    • getFiles(): Get all files in the vault.
    • getAbstractFileByPath(path): Get a file or folder by its path.
    • create(path, content): Create a new file.
    • modify(file, content): Modify an existing file.
    • process(file, (data) => newData): Atomically modify a file.
  • this.app.workspace: Manage the visual layout of Obsidian.
    • getActiveViewOfType(viewType): Get the active view of a specific type (e.g., MarkdownView).
    • getLeaf(): Get a new workspace leaf.
    • updateOptions(): Force a refresh of editor options.
  • this.app.metadataCache: Access cached metadata for Markdown files.
    • getFileCache(file): Get cached information like headings, links, and tags.

🎨 UI Development #

Ribbon Icons #

Add an icon to the left-hand ribbon.

this.addRibbonIcon('dice', 'My Plugin Action', (evt: MouseEvent) => {
  new Notice('Hello, world!');
});

Status Bar Items #

Add an element to the status bar at the bottom.

const statusBarItemEl = this.addStatusBarItem();
statusBarItemEl.setText('Status Bar Text');

Commands #

Add a command to the command palette.

this.addCommand({
  id: 'my-command',
  name: 'My Command',
  callback: () => {
    // Command logic here
  },
  // Use checkCallback for conditional commands
  checkCallback: (checking: boolean) => {
    const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView);
    if (markdownView) {
      if (!checking) {
        // Execute the command
      }
      return true;
    }
    return false;
  }
});

Settings Tab #

Create a settings tab for your plugin.

import { App, PluginSettingTab, Setting } from 'obsidian';

interface MyPluginSettings {
  mySetting: string;
}

const DEFAULT_SETTINGS: MyPluginSettings = {
  mySetting: 'default'
}

class MySettingTab extends PluginSettingTab {
  // ... (implementation in main.ts)
}

πŸ’Ύ Data Persistence #

Save and load plugin data using loadData() and saveData().

interface MyPluginSettings {
  mySetting: string;
}

const DEFAULT_SETTINGS: Partial<MyPluginSettings> = {
  mySetting: 'default'
};

export default class MyPlugin extends Plugin {
  settings: MyPluginSettings;

  async onload() {
    await this.loadSettings();
  }

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

  async saveSettings() {
    await this.saveData(this.settings);
  }
}

βœ… Best Practices #

  • Resource Management: Use this.register... methods (registerEvent, registerDomEvent, registerInterval) to automatically clean up resources when the plugin is unloaded.
  • Security: Avoid using innerHTML or outerHTML. Use createEl, createDiv, etc., to build DOM elements programmatically.
  • Styling: Use CSS classes instead of inline styles. Use Obsidian’s CSS variables for consistency.
  • File Operations: Prefer the Vault API (app.vault) over the Adapter API (app.vault.adapter). Use Vault.process() for background file modifications.
  • Async/Await: Prefer async/await over Promises for cleaner asynchronous code.

πŸ“¦ Releasing Your Plugin #

  1. Update manifest.json: Increment the version number.
  2. Update versions.json: Add the new version and the minimum required Obsidian version.
  3. Create a GitHub Release: Tag the release with the exact version number (e.g., 1.0.1).
  4. Upload Assets: Attach main.js, styles.css (if any), and manifest.json to the release.
  5. Submit to Community List: Create a pull request to the obsidian-releases repository.