Obsidian Plugin Development
Build production-ready Obsidian plugins using the obsidian-sample-plugin-plus template.
Quick Start: New Plugin
1. Create from Template
# Clone the template (or use GitHub's "Use this template" button) gh repo create my-plugin --template davidvkimball/obsidian-sample-plugin-plus --public --clone cd my-plugin # Or clone directly git clone https://github.com/davidvkimball/obsidian-sample-plugin-plus.git my-plugin cd my-plugin rm -rf .git && git init
2. Configure Plugin Identity
Update these files with your plugin's info:
manifest.json:
{
"id": "my-plugin",
"name": "My Plugin",
"version": "0.0.1",
"minAppVersion": "1.5.0",
"description": "What your plugin does",
"author": "Your Name",
"authorUrl": "https://yoursite.com",
"isDesktopOnly": false
}
package.json: Update name, description, author, license.
README.md: Replace template content with your plugin's documentation.
3. Initialize Development Environment
pnpm install pnpm obsidian-dev-skills # Initialize AI skills ./scripts/setup-ref-links.sh # Unix # or: scripts\setup-ref-links.bat # Windows
4. Clean Boilerplate
In src/main.ts:
- •Remove sample ribbon icon, status bar, commands, modal, and DOM event
- •Keep the settings tab if needed, or remove it
- •Rename
MyPluginclass to your plugin name
Delete styles.css if your plugin doesn't need custom styles.
Development Workflow
Build & Test
pnpm dev # Watch mode — rebuilds on changes pnpm build # Production build pnpm lint # Check for issues pnpm lint:fix # Auto-fix issues pnpm test # Run unit tests
Install in Obsidian
Copy build output to your vault:
# Unix cp main.js manifest.json styles.css ~/.obsidian/plugins/my-plugin/ # Or create a symlink for development ln -s $(pwd) ~/.obsidian/plugins/my-plugin
Enable the plugin in Obsidian Settings → Community Plugins.
Use Hot Reload plugin for automatic reloading during development.
Plugin Architecture
Entry Point (src/main.ts)
import { Plugin } from 'obsidian';
export default class MyPlugin extends Plugin {
settings: MyPluginSettings;
async onload() {
await this.loadSettings();
// Register commands, ribbons, events, views
}
onunload() {
// Cleanup: remove event listeners, views, DOM elements
}
async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
}
async saveSettings() {
await this.saveData(this.settings);
}
}
Settings Pattern
See references/settings.md for the complete settings UI pattern.
Common Patterns
See references/patterns.md for:
- •Commands (simple, editor, check callbacks)
- •Ribbon icons
- •Modals
- •Events and lifecycle
- •File operations
- •Editor manipulation
Constraints
- •No auto-git: Never run
git commitorgit pushwithout explicit approval - •No eslint-disable: Fix lint issues properly, don't suppress them
- •No
anytypes: Use proper TypeScript types - •Sentence case: UI text uses sentence case (ESLint may false-positive on this — ignore if so)
Release Checklist
- •Update version in
manifest.jsonandpackage.json - •Update
versions.jsonwith"version": "minAppVersion" - •Run
pnpm build— zero errors - •Run
pnpm lint— zero issues - •Create GitHub release with tag matching version (no
vprefix) - •Upload:
main.js,manifest.json,styles.css(if used)
References
- •Settings UI — Complete settings tab implementation
- •Common Patterns — Commands, modals, events, file operations
- •Obsidian API Docs — Official documentation