The Vault API provides a comprehensive interface for working with files and folders in Obsidian. This guide covers the essential operations for file management.
Vault Overview
The Vault class is accessible via this.app.vault and provides methods for all file operations:
import { Plugin , TFile , TFolder } from 'obsidian' ;
export default class FilePlugin extends Plugin {
async onload () {
const vault = this . app . vault ;
// Access vault methods here
}
}
Reading Files
Read Text Files
Use read() for files you intend to modify, or cachedRead() for read-only access:
// Read file for modification
const file = this . app . vault . getAbstractFileByPath ( 'note.md' ) as TFile ;
if ( file ) {
const content = await this . app . vault . read ( file );
console . log ( content );
}
// Cached read (faster, for display only)
const cachedContent = await this . app . vault . cachedRead ( file );
Use read() if you plan to modify the file content. Use cachedRead() for better performance when only displaying content.
Read Binary Files
For images, PDFs, and other binary files:
const imageFile = this . app . vault . getAbstractFileByPath ( 'image.png' ) as TFile ;
if ( imageFile ) {
const arrayBuffer = await this . app . vault . readBinary ( imageFile );
// Process binary data
}
Writing Files
Create New Files
Create plaintext or binary files:
// Create text file
const newFile = await this . app . vault . create (
'folder/new-note.md' ,
'# New Note \n\n Content here'
);
// Create binary file
const imageBuffer = new ArrayBuffer ( 1024 );
const binaryFile = await this . app . vault . createBinary (
'folder/image.png' ,
imageBuffer
);
Paths should be normalized using normalizePath() before passing to vault methods.
Modify Existing Files
Update file content:
const file = this . app . vault . getAbstractFileByPath ( 'note.md' ) as TFile ;
if ( file ) {
await this . app . vault . modify ( file , 'Updated content' );
}
// Modify binary file
await this . app . vault . modifyBinary ( file , arrayBuffer );
Append to Files
Add content to the end of a file:
// Append text
await this . app . vault . append ( file , ' \n\n New paragraph' );
// Append binary data
await this . app . vault . appendBinary ( file , dataBuffer );
Atomic Operations
Process File Content
Atomically read, modify, and save:
const result = await this . app . vault . process ( file , ( content ) => {
// Modify content
return content . replace ( 'old' , 'new' );
});
console . log ( 'Saved content:' , result );
The process() method ensures atomic updates - the file is read, modified, and written as a single operation.
File and Folder Management
Get Files and Folders
// Get file by path
const file = this . app . vault . getFileByPath ( 'note.md' );
// Get folder by path
const folder = this . app . vault . getFolderByPath ( 'folder' );
// Get either file or folder
const abstractFile = this . app . vault . getAbstractFileByPath ( 'path' );
// Check type
if ( abstractFile instanceof TFile ) {
console . log ( 'File:' , abstractFile . basename );
} else if ( abstractFile instanceof TFolder ) {
console . log ( 'Folder:' , abstractFile . name );
}
Get All Files
// Get all markdown files
const markdownFiles = this . app . vault . getMarkdownFiles ();
// Get all files
const allFiles = this . app . vault . getFiles ();
// Get all folders
const folders = this . app . vault . getAllFolders ();
// Get all files and folders
const everything = this . app . vault . getAllLoadedFiles ();
Create Folders
try {
const folder = await this . app . vault . createFolder ( 'new-folder' );
console . log ( 'Created folder:' , folder . path );
} catch ( error ) {
console . error ( 'Folder already exists' );
}
File Operations
Rename Files
For proper link updating, use FileManager.renameFile():
// Using FileManager (recommended - updates links)
await this . app . fileManager . renameFile ( file , 'new-name.md' );
// Using Vault (no link updates)
await this . app . vault . rename ( file , 'new-path/new-name.md' );
Copy Files
const copiedFile = await this . app . vault . copy ( file , 'backup/note-copy.md' );
Delete Files
// Delete permanently
await this . app . vault . delete ( file );
// Move to trash (respects user settings)
await this . app . vault . trash ( file , true );
// Or use FileManager for confirmation prompt
const confirmed = await this . app . fileManager . promptForDeletion ( file );
if ( confirmed ) {
await this . app . fileManager . trashFile ( file );
}
TFile and TFolder Classes
TFile Properties
const file : TFile ;
console . log ( file . path ); // "folder/note.md"
console . log ( file . name ); // "note.md"
console . log ( file . basename ); // "note"
console . log ( file . extension ); // "md"
console . log ( file . parent ); // TFolder instance
console . log ( file . stat . size ); // File size in bytes
console . log ( file . stat . ctime ); // Creation time (ms)
console . log ( file . stat . mtime ); // Modification time (ms)
TFolder Properties
const folder : TFolder ;
console . log ( folder . path ); // "folder"
console . log ( folder . name ); // "folder"
console . log ( folder . children ); // Array of TFile and TFolder
console . log ( folder . isRoot ()); // boolean
Vault Events
Listen to File Changes
onload () {
// File created
this . registerEvent (
this . app . vault . on ( 'create' , ( file ) => {
console . log ( 'Created:' , file . path );
})
);
// File modified
this . registerEvent (
this . app . vault . on ( 'modify' , ( file ) => {
console . log ( 'Modified:' , file . path );
})
);
// File deleted
this . registerEvent (
this . app . vault . on ( 'delete' , ( file ) => {
console . log ( 'Deleted:' , file . path );
})
);
// File renamed
this . registerEvent (
this . app . vault . on ( 'rename' , ( file , oldPath ) => {
console . log ( `Renamed: ${ oldPath } -> ${ file . path } ` );
})
);
}
Create events are fired when the vault first loads. To avoid processing existing files, register handlers inside Workspace.onLayoutReady.
Working with Frontmatter
Process Frontmatter
Use FileManager.processFrontMatter() for safe YAML updates:
await this . app . fileManager . processFrontMatter ( file , ( frontmatter ) => {
frontmatter [ 'tags' ] = [ 'new-tag' ];
frontmatter [ 'modified' ] = new Date (). toISOString ();
delete frontmatter [ 'old-key' ];
});
Get Frontmatter Info
import { getFrontMatterInfo } from 'obsidian' ;
const content = await this . app . vault . read ( file );
const fmInfo = getFrontMatterInfo ( content );
console . log ( fmInfo . exists ); // Has frontmatter?
console . log ( fmInfo . frontmatter ); // Frontmatter string
console . log ( fmInfo . from ); // Start offset
console . log ( fmInfo . to ); // End offset
console . log ( fmInfo . contentStart ); // Where content begins
Best Practices
Always normalize paths before using them:
import { normalizePath } from 'obsidian' ;
const path = normalizePath ( 'folder//file.md' ); // "folder/file.md"
const file = this . app . vault . getFileByPath ( path );
try {
await this . app . vault . create ( 'note.md' , 'content' );
} catch ( error ) {
if ( error . message . includes ( 'already exists' )) {
console . log ( 'File exists, using existing file' );
} else {
throw error ;
}
}
Use FileManager for User-Facing Operations
FileManager provides higher-level operations with proper link updates:
// Generate proper markdown links
const link = this . app . fileManager . generateMarkdownLink (
file ,
'source.md' ,
'#heading' ,
'Display Text'
);
// Get proper attachment path
const attachmentPath = await this . app . fileManager . getAvailablePathForAttachment (
'image.png' ,
'source.md'
);
Creating Views Build custom views for your files
Editor Integration Work with the editor API