Develop a Local Obsidian Plugin
Creating a custom Obsidian plugin allows you to extend the functionality of your vault, interact with the file system, or integrate external tools.
While there are starter templates available, building a plugin from scratch helps you understand the lifecycle, the event system, and the build process required to make TypeScript run inside Obsidian.
This guide covers the manual creation of a plugin that:
- Adds an entry to the File Explorer context menu (Right-click on file).
- Adds an entry to the Editor menu (The “3 dots” top-right).
- Executes a custom command.
Obsidian plugins run simply as JavaScript files. Because Obsidian relies on the Electron framework, your plugin has full Node.js access. Be careful when executing system commands (Child Process) or deleting files.
Prerequisites
- Node.js installed
- A code editor (VS Code recommended)
- An existing Obsidian Vault for testing
TypeScript is mandatory. Obsidian’s API is typed, and trying to write a plugin in raw JavaScript is prone to errors and lacks autocomplete support.
Project Setup
We will initialize a minimal TypeScript project without relying on heavy bundlers first, to understand the core components.
Initialize the project
Create a new folder and initialize package.json.
mkdir my-obsidian-plugin
cd my-obsidian-plugin
npm init -yInstall dependencies
We need the Obsidian API types and TypeScript.
npm install obsidian
npm install -D typescript tslib @types/nodeConfigure TypeScript (tsconfig.json)
Create a tsconfig.json file. This configuration is crucial to ensure the compiled code is compatible with Obsidian’s environment.
{
"compilerOptions": {
"module": "CommonJS",
"target": "ES6",
"noImplicitAny": true,
"moduleResolution": "node",
"importHelpers": false,
"lib": ["DOM", "ES5", "ES6", "ES7"]
},
"include": ["**/*.ts"]
}importHelpers: falseprevents the “tslib not found” error during runtime.module: CommonJSis required for Obsidian to load themain.js.
Configure Build Script
Open package.json and add the build command under scripts.
"scripts": {
"build": "tsc"
}The Plugin Logic
An Obsidian plugin consists of two main files: manifest.json (metadata) and main.ts (logic).
1. Create the Manifest
Create a file named manifest.json. The id must be unique and will be the folder name later.
{
"id": "my-custom-plugin",
"name": "My Custom Plugin",
"version": "1.0.0",
"minAppVersion": "0.15.0",
"description": "A demo plugin showing menu integrations.",
"author": "Your Name",
"isDesktopOnly": false
}2. Implement the Logic (main.ts)
This is where we hook into the UI. We will register events for both the File Menu and the Editor Menu.
import { Plugin, TFile, Menu, Editor, MarkdownView, Notice } from 'obsidian';
export default class MyCustomPlugin extends Plugin {
async onload() {
console.log('Loading My Custom Plugin...');
// 1. Add item to the File Explorer Context Menu (Right-click on file)
this.registerEvent(
this.app.workspace.on("file-menu", (menu: Menu, file) => {
// Ensure we only show this on Markdown files
if (file instanceof TFile && file.extension === 'md') {
menu.addItem((item) => {
item
.setTitle("My Custom Action")
.setIcon("star")
.onClick(async () => {
new Notice(`Action triggered on file: ${file.basename}`);
// Your custom logic here...
});
});
}
})
);
// 2. Add item to the Editor Menu ("3 dots" top-right)
this.registerEvent(
this.app.workspace.on("editor-menu", (menu: Menu, editor: Editor, view: MarkdownView) => {
menu.addItem((item) => {
item
.setTitle("My Editor Action")
.setIcon("pencil")
.onClick(async () => {
const currentFile = view.file;
new Notice(`Action triggered in editor for: ${currentFile?.basename}`);
});
});
})
);
}
async onunload() {
console.log('Unloading plugin');
}
}Build and Install
Since we are developing locally, we need to manually compile the TypeScript code and place it into the Obsidian vault’s hidden system folder.
1. Compile the code
npm run buildThis generates a main.js file in your project root.
2. Locate Plugin Folder
Navigate to your Obsidian Vault directory. You need to access the hidden .obsidian folder.
- Path:
YourVault/.obsidian/plugins/
3. Create Plugin Directory
Create a new folder inside plugins/ that matches exactly the id from your manifest.json.
- Target:
YourVault/.obsidian/plugins/my-custom-plugin/
4. Deploy Files
Copy the following files into that new folder:
main.js(The compiled code)manifest.json(The metadata)styles.css(Optional, if you have one)
Activation and Debugging
Enable the Plugin
- Open Obsidian Settings.
- Go to Community Plugins.
- Toggle “Restricted mode” OFF.
- Click Refresh installed plugins.
- Find “My Custom Plugin” and toggle it ON.
Debugging (Console)
If your plugin doesn’t load or throws errors, you need to look under the hood. Obsidian has Chrome DevTools built-in.
- Windows/Linux:
Ctrl+Shift+I - macOS:
Cmd+Opt+I
Go to the Console tab to see your console.log outputs or error messages (red text).
Hot Reloading:
While developing, repeating the “Build -> Copy -> Reload” cycle is tedious.
You can install the “Hot Reload” community plugin in Obsidian.
Then, you can simply run tsc -w (watch mode) in your terminal, and output directly to the vault folder.
Created: 25.01.2026
Last Updated: 25.01.2026