diff --git a/docs/guide/settings.md b/docs/guide/settings.md
index 7ece6b0..da5f466 100644
--- a/docs/guide/settings.md
+++ b/docs/guide/settings.md
@@ -12,9 +12,6 @@ For example, below are some valid folder names:
 - `imported_notes/apple_books/highlights`
 - `3 - Resources/My Books/Apple Books/Unprocessed`
 
-If the highlight folder is not empty and the [Backup highlights](#backup-highlights) setting is enabled, the plugin will save the existing highlights to a backup folder before importing new highlights. If the setting is disabled, the plugin will overwrite the contents of the highlight folder.
-
-
 ## Import highlights on start
 
 - Default value: Turned off
@@ -24,13 +21,61 @@ Import all highlights from all your books when Obsidian starts. Respects the [Ba
 ## Backup highlights
 
 - Default value: Turned off
-- Backup folder template: `<highlights-folder>-bk-<timestamp>`. For example, `ibooks-highlights-bk-1704060001`.
+- Backup template:
+	- for the highlight folder: `<highlights-folder>-bk-<timestamp>`. For example, `ibooks-highlights-bk-1704060001`.
+	- for a specific book: `<highlights-file>-bk-<timestamp>`. For example, `Building a Second Brain-bk-1704060001`.
+
+Backup highlights before import.
+- When importing all highlights, the [highlight folder](#highlight-folder) contents (see the note below) will be backed up.
+- When importing highlights from a specific book, the specific highlights file will be backed up, if it exists.
+
+The backup name is pre-configured based on the template above and cannot be changed.
+
+::: details Examples
+
+**Import all highlights**
+
+Initial state
+```plaintext
+.
+└── ibooks-highlights
+    ├── Atomic Habits - Tiny Changes, Remarkable Results
+    └── Building a Second Brain
+```
+After import
+```plaintext
+.
+├── ibooks-highlights
+│   └── <newly imported highlights>
+└── ibooks-highlights-bk-1723233525489
+    ├── Atomic Habits - Tiny Changes, Remarkable Results
+    └── Building a Second Brain
+```
+**Import highlights from a specific book**
+
+Initial state
+```plaintext
+.
+└── ibooks-highlights
+    ├── Atomic Habits - Tiny Changes, Remarkable Results
+    └── Building a Second Brain
+```
+After import
+```plaintext
+.
+└── ibooks-highlights
+    ├── Atomic Habits - Tiny Changes, Remarkable Results
+	├── Atomic Habits - Tiny Changes, Remarkable Results-bk-1723234215251
+    └── Building a Second Brain
+```
+
+:::
 
-Backup highlights folder before import. The backup folder name is pre-configured based on the template above and cannot be changed. The backup is created inside the [highlight folder](#highlight-folder).
+> [!NOTE]
+> The plugin will back up only the files that are direct children of the [highlight folder](#highlight-folder). If you (for some reason) have a nested folder structure inside the [highlight folder](#highlight-folder), these folders will not be backed up and will be overwritten on import.
 
-> [!WARNING]
-> If the setting is disabled, the plugin will overwrite the contents of the [highlight folder](#highlight-folder) on import.
-> This behavior will be improved based on the feedback received: [Issue #34](https://github.com/bandantonio/obsidian-apple-books-highlights-plugin/issues/34#issuecomment-2231429171)
+> [!TIP]
+> To prevent accidental data loss when the setting is turned off, the plugin will display a confirmation dialog before overwriting the existing highlights.
 
 ## Highlights sorting criterion
 
diff --git a/main.ts b/main.ts
index 2a26795..1cd5117 100644
--- a/main.ts
+++ b/main.ts
@@ -1,5 +1,5 @@
 import { Notice, Plugin } from 'obsidian';
-import { IBookHighlightsPluginSearchModal } from './src/search';
+import { IBookHighlightsPluginSearchModal, OverwriteBookModal } from './src/search';
 import { aggregateBookAndHighlightDetails } from './src/methods/aggregateDetails';
 import SaveHighlights from './src/methods/saveHighlightsToVault';
 import { AppleBooksHighlightsImportPluginSettings, IBookHighlightsSettingTab } from './src/settings';
@@ -17,12 +17,18 @@ export default class IBookHighlightsPlugin extends Plugin {
 		}
 
 		this.addRibbonIcon('book-open', this.manifest.name, async () => {
-			await this.aggregateAndSaveHighlights().then(() => {
-				new Notice('Apple Books highlights imported successfully');
-			}).catch((error) => {
-				new Notice(`[${this.manifest.name}]:\nError importing highlights. Check console for details (⌥ ⌘ I)`, 0);
+			try {
+				this.settings.backup
+				? await this.aggregateAndSaveHighlights().then(() => {
+					new Notice('Apple Books highlights imported successfully');
+					}).catch((error) => {
+						new Notice(`[${this.manifest.name}]:\nError importing highlights. Check console for details (⌥ ⌘ I)`, 0);
+						console.error(`[${this.manifest.name}]: ${error}`);
+					})
+				: new OverwriteBookModal(this.app, this).open();
+			} catch (error) {
 				console.error(`[${this.manifest.name}]: ${error}`);
-			});
+			}
 		});
 
 		this.addSettingTab(new IBookHighlightsSettingTab(this.app, this));
@@ -32,7 +38,9 @@ export default class IBookHighlightsPlugin extends Plugin {
 			name: 'Import all',
 			callback: async () => {
 				try {
-					await this.aggregateAndSaveHighlights();
+					this.settings.backup
+					? await this.aggregateAndSaveHighlights()
+					: new OverwriteBookModal(this.app, this).open();
 				} catch (error) {
 					new Notice(`[${this.manifest.name}]:\nError importing highlights. Check console for details (⌥ ⌘ I)`, 0);
 					console.error(`[${this.manifest.name}]: ${error}`);
@@ -74,6 +82,6 @@ export default class IBookHighlightsPlugin extends Plugin {
 			throw ('No highlights found. Make sure you made some highlights in your Apple Books.');
 		}
 
-		await this.saveHighlights.saveHighlightsToVault(highlights);
+		await this.saveHighlights.saveAllBooksHighlightsToVault(highlights);
 	}
 }
diff --git a/src/methods/saveHighlightsToVault.ts b/src/methods/saveHighlightsToVault.ts
index b55ea31..dc31dd6 100644
--- a/src/methods/saveHighlightsToVault.ts
+++ b/src/methods/saveHighlightsToVault.ts
@@ -1,9 +1,10 @@
-import { App, Vault } from 'obsidian';
+import { App, TFile, Vault } from 'obsidian';
 import path from 'path';
 import { ICombinedBooksAndHighlights } from '../types';
 import { AppleBooksHighlightsImportPluginSettings } from '../settings';
 import { renderHighlightsTemplate } from './renderHighlightsTemplate';
 import { sortHighlights } from 'src/methods/sortHighlights';
+import BackupHighlights from 'src/utils/backupHighlights';
 
 export default class SaveHighlights {
 	private app: App;
@@ -16,35 +17,47 @@ export default class SaveHighlights {
 		this.settings = settings;
 	}
 
-	async saveHighlightsToVault(highlights: ICombinedBooksAndHighlights[]): Promise<void> {
-		const highlightsFolderPath = this.vault.getAbstractFileByPath(
+	async saveAllBooksHighlightsToVault(highlights: ICombinedBooksAndHighlights[]): Promise<void> {
+		const highlightsFolderPath = this.vault.getFolderByPath(
 			this.settings.highlightsFolder
 		);
 
 		const isBackupEnabled = this.settings.backup;
 
-		// // Backup highlights folder if backup is enabled
 		if (highlightsFolderPath) {
 			if (isBackupEnabled) {
-				const highlightsFilesToBackup = (await this.vault.adapter.list(highlightsFolderPath.path)).files;
+				const backupMethods = new BackupHighlights(this.vault, this.settings);
+				await backupMethods.backupAllHighlights();
+			} else {
+				await this.vault.delete(highlightsFolderPath, true);
+				await this.vault.createFolder(this.settings.highlightsFolder);
+			}
+		} else {
+			await this.vault.createFolder(this.settings.highlightsFolder);
+		}
 
-				const highlightsBackupFolder = `${this.settings.highlightsFolder}-bk-${Date.now()}`;
+		for (const combinedHighlight of highlights) {
+			// Order highlights according to the value in settings
+			const sortedHighlights = sortHighlights(combinedHighlight, this.settings.highlightsSortingCriterion);
 
-				await this.vault.createFolder(highlightsBackupFolder);
+			// Save highlights to vault
+			const renderedTemplate = await renderHighlightsTemplate(sortedHighlights, this.settings.template);
+			const filePath = path.join(this.settings.highlightsFolder, `${combinedHighlight.bookTitle}.md`);
 
-				highlightsFilesToBackup.forEach(async (file: string) => {
-					const fileName = path.basename(file);
+			await this.createNewBookFile(filePath, renderedTemplate);
+		}
+	}
 
-					await this.vault.adapter.copy(file, path.join(highlightsBackupFolder, fileName))
-				});
-			}
+	async saveSingleBookHighlightsToVault(highlights: ICombinedBooksAndHighlights[], shouldCreateFile: boolean): Promise<void> {
+		const highlightsFolderPath = this.vault.getFolderByPath(
+			this.settings.highlightsFolder
+		);
 
-			await this.vault.delete(highlightsFolderPath, true);
+		if (!highlightsFolderPath) {
+			await this.vault.createFolder(this.settings.highlightsFolder);
 		}
 
-		await this.vault.createFolder(this.settings.highlightsFolder);
-
-		highlights.forEach(async (combinedHighlight: ICombinedBooksAndHighlights) => {
+		for (const combinedHighlight of highlights) {
 			// Order highlights according to the value in settings
 			const sortedHighlights = sortHighlights(combinedHighlight, this.settings.highlightsSortingCriterion);
 
@@ -52,10 +65,34 @@ export default class SaveHighlights {
 			const renderedTemplate = await renderHighlightsTemplate(sortedHighlights, this.settings.template);
 			const filePath = path.join(this.settings.highlightsFolder, `${combinedHighlight.bookTitle}.md`);
 
-			await this.vault.create(
-				filePath,
-				renderedTemplate
-			);
-		});
+			if (shouldCreateFile) {
+				await this.createNewBookFile(filePath, renderedTemplate);
+			} else {
+				const isBackupEnabled = this.settings.backup;
+				const backupMethods = new BackupHighlights(this.vault, this.settings);
+
+				const vaultFile = this.vault.getFileByPath(filePath) as TFile;
+
+				if (isBackupEnabled) {
+					backupMethods.backupSingleBookHighlights(combinedHighlight.bookTitle);
+				}
+
+				await this.modifyExistingBookFile(vaultFile, renderedTemplate);
+			}
+		}
+	}
+
+	async modifyExistingBookFile(file: TFile, data: string): Promise<void> {
+		await this.vault.modify(
+			file,
+			data
+		);
+	}
+
+	async createNewBookFile(filePath: string, data: string): Promise<void> {
+		await this.vault.create(
+			filePath,
+			data
+		);
 	}
 }
diff --git a/src/search.ts b/src/search.ts
index 1976265..7997e80 100644
--- a/src/search.ts
+++ b/src/search.ts
@@ -1,33 +1,37 @@
-import { App, Notice, SuggestModal } from 'obsidian';
+import { App, Modal, Notice, Setting, SuggestModal } from 'obsidian';
 import IBookHighlightsPlugin from '../main';
 import { ICombinedBooksAndHighlights } from './types';
 import { aggregateBookAndHighlightDetails } from './methods/aggregateDetails';
+import { checkBookExistence } from './utils/checkBookExistence';
+
 abstract class IBookHighlightsPluginSuggestModal extends SuggestModal<ICombinedBooksAndHighlights> {
     plugin: IBookHighlightsPlugin;
     constructor(
         app: App,
-        plugin: IBookHighlightsPlugin) {
+        plugin: IBookHighlightsPlugin
+    ) {
         super(app);
         this.plugin = plugin;
     }
 }
 
 export class IBookHighlightsPluginSearchModal extends IBookHighlightsPluginSuggestModal {
-    async getSuggestions(query: string): Promise<ICombinedBooksAndHighlights[] > {
-		try {
-			const allBooks = await aggregateBookAndHighlightDetails();
-
-			return allBooks.filter(book => {
-				const titleMatch = book.bookTitle.toLowerCase().includes(query.toLowerCase());
-				const authorMatch = book.bookAuthor.toLowerCase().includes(query.toLowerCase());
-
-				return titleMatch || authorMatch;
-			});
-		} catch (error) {
-			new Notice(`[${this.plugin.manifest.name}]:\nError importing highlights. Check console for details (⌥ ⌘ I)`, 0);
-			console.error(`[${this.plugin.manifest.name}]: ${error}`);
-			return [];
-		}
+    async getSuggestions(query: string): Promise<ICombinedBooksAndHighlights[]> {
+        try {
+            const allBooks = await aggregateBookAndHighlightDetails();
+
+            return allBooks.filter(book => {
+                const titleMatch = book.bookTitle.toLowerCase().includes(query.toLowerCase());
+                const authorMatch = book.bookAuthor.toLowerCase().includes(query.toLowerCase());
+
+                return titleMatch || authorMatch;
+            });
+        }
+        catch (error) {
+            new Notice(`[${this.plugin.manifest.name}]:\nError importing highlights. Check console for details (⌥ ⌘ I)`, 0);
+            console.error(`[${this.plugin.manifest.name}]: ${error}`);
+            return [];
+        }
     }
 
     renderSuggestion(value: ICombinedBooksAndHighlights, el: HTMLElement) {
@@ -36,7 +40,84 @@ export class IBookHighlightsPluginSearchModal extends IBookHighlightsPluginSugge
     }
 
     //eslint-disable-next-line
-    onChooseSuggestion(item: ICombinedBooksAndHighlights, event: MouseEvent | KeyboardEvent) {
-		this.plugin.saveHighlights.saveHighlightsToVault([item]);
+    async onChooseSuggestion(item: ICombinedBooksAndHighlights, event: MouseEvent | KeyboardEvent) {
+        const doesBookFileExist = checkBookExistence(item.bookTitle, this.app.vault, this.plugin.settings);
+
+        const isBackupEnabled = this.plugin.settings.backup;
+
+        if (!doesBookFileExist && !isBackupEnabled ||
+            !doesBookFileExist && isBackupEnabled
+        ) {
+            this.plugin.saveHighlights.saveSingleBookHighlightsToVault([item], true);
+
+        } else if (doesBookFileExist && !isBackupEnabled) {
+            new OverwriteBookModal(this.app, this.plugin, item).open();
+
+        } else if (doesBookFileExist && isBackupEnabled) {
+            this.plugin.saveHighlights.saveSingleBookHighlightsToVault([item], false);
+        } else {
+            this.plugin.saveHighlights.saveSingleBookHighlightsToVault([item], true);
+        }
     }
 }
+
+// This class is used to display a modal that asks for the user's consent
+// to overwrite the existing book in the highlights folder
+// It takes an optional `item` parameter with the selected book highlights
+// When the parameter is not provided, the modal asks for the consent
+// to overwrite all the books
+export class OverwriteBookModal extends Modal {
+    plugin: IBookHighlightsPlugin;
+    item?: ICombinedBooksAndHighlights;
+
+    constructor(
+        app: App,
+        plugin: IBookHighlightsPlugin,
+        item?: ICombinedBooksAndHighlights
+    ) {
+        super(app);
+        this.plugin = plugin;
+        this.item = item;
+    }
+
+    onOpen() {
+        const { contentEl } = this;
+        const bookToOverwrite = this.item;
+
+        if (bookToOverwrite) {
+            contentEl.createEl('p', { text: `The selected book already exists in your highlights folder:` });
+            contentEl.createEl('p', { text: `${bookToOverwrite.bookTitle}`, cls: 'modal-rewrite-book-title'});
+            contentEl.createEl('p', { text: 'Would you like to proceed with the overwrite?' });
+        } else {
+            contentEl.createEl('span', { text: `Bulk import will overwrite` });
+            contentEl.createEl('span', { text: ` ALL THE BOOKS `, cls: 'modal-rewrite-all-books' });
+            contentEl.createEl('span', { text: `in your highlights folder` });
+            contentEl.createEl('p', { text: 'Would you like to proceed with the overwrite?' });
+        }
+
+        new Setting(contentEl)
+            .addButton(YesButton => {
+                YesButton.setButtonText('Yes')
+                    .setCta()
+                    .onClick(() => {
+                        bookToOverwrite
+                            ? this.plugin.saveHighlights.saveSingleBookHighlightsToVault([bookToOverwrite], false)
+                            : this.plugin.aggregateAndSaveHighlights();
+
+                        this.close();
+                    });
+            })
+
+            .addButton(NoButton => {
+                NoButton.setButtonText('No')
+                .onClick(() => {
+                    this.close();
+                });
+            });
+    }
+
+    onClose() {
+        const { contentEl } = this;
+        contentEl.empty();
+    }
+}
\ No newline at end of file
diff --git a/src/settings.ts b/src/settings.ts
index 3e51e5d..76223ba 100644
--- a/src/settings.ts
+++ b/src/settings.ts
@@ -56,7 +56,13 @@ export class IBookHighlightsSettingTab extends PluginSettingTab {
 
         new Setting(containerEl)
             .setName('Backup highlights')
-            .setDesc('Backup highlights folder before import. Backup folder template: <highlights-folder>-bk-<timestamp> (For example, ibooks-highlights-bk-1704060001)')
+            .setDesc(createFragment(el => {
+                el.appendText('Backup highlights before import.')
+                el.createEl('br')
+                el.appendText('- Folder template: <highlights-folder>-bk-<timestamp> (For example, ibooks-highlights-bk-1704060001).')
+                el.createEl('br')
+                el.appendText('- File template: <highlights-file>-bk-<timestamp> (For example, Building a Second Brain-bk-1704060001).')
+            }))
             .addToggle((toggle) => {
                 toggle.setValue(this.plugin.settings.backup)
                     .onChange(async (value) => {
diff --git a/src/utils/backupHighlights.ts b/src/utils/backupHighlights.ts
new file mode 100644
index 0000000..760f5cb
--- /dev/null
+++ b/src/utils/backupHighlights.ts
@@ -0,0 +1,53 @@
+import { TFile, Vault } from 'obsidian';
+import path from 'path';
+import { AppleBooksHighlightsImportPluginSettings } from '../settings';
+
+export default class BackupHighlights {
+    private vault: Vault;
+    private settings: AppleBooksHighlightsImportPluginSettings;
+
+    constructor(vault: Vault, settings: AppleBooksHighlightsImportPluginSettings) {
+        this.vault = vault;
+        this.settings = settings;
+    }
+
+    async backupAllHighlights(): Promise<void> {
+        const highlightsFolder = this.vault.getFolderByPath(
+			this.settings.highlightsFolder
+		);
+
+        if (highlightsFolder) {
+            // adapter.list returns only files that are direct children of the highlights folder.
+            // Only these files will be backed up.
+            const highlightsFilesToBackup = (await this.vault.adapter.list(highlightsFolder.path)).files;
+
+            if (highlightsFilesToBackup.length > 0) {
+                const highlightsBackupFolder = `${this.settings.highlightsFolder}-bk-${Date.now()}`;
+
+                await this.vault.createFolder(highlightsBackupFolder);
+
+                // Instead of copying, it would be easier to move all the contents to the highlightsBackupFolder,
+                // but Obsidian API does not have a method to do it,
+                // so, the workaround is to copy those files.
+                for (const file of highlightsFilesToBackup) {
+                    const fileName = path.basename(file);
+                    await this.vault.adapter.copy(file, path.join(highlightsBackupFolder, fileName));
+                }
+
+                // Remove the highlights folder with all its contents
+                // and recreate it again for the subsequent import
+                await this.vault.delete(highlightsFolder, true);
+                await this.vault.createFolder(this.settings.highlightsFolder);
+            }
+        }
+    }
+
+    async backupSingleBookHighlights(bookTitle: string): Promise<void> {
+        const bookFilePathToBackup = path.join(this.settings.highlightsFolder, `${bookTitle}.md`);
+        const vaultFile = this.vault.getFileByPath(bookFilePathToBackup) as TFile;
+
+        const backupBookTitle = `${bookTitle}-bk-${Date.now()}.md`;
+
+        await this.vault.adapter.copy(vaultFile.path, path.join(this.settings.highlightsFolder, backupBookTitle));
+    }
+}
\ No newline at end of file
diff --git a/src/utils/checkBookExistence.ts b/src/utils/checkBookExistence.ts
new file mode 100644
index 0000000..c63b14f
--- /dev/null
+++ b/src/utils/checkBookExistence.ts
@@ -0,0 +1,10 @@
+import { Vault } from 'obsidian';
+import path from 'path';
+import { AppleBooksHighlightsImportPluginSettings } from '../settings';
+
+export const checkBookExistence = (bookTitle: string, vault: Vault, settings: AppleBooksHighlightsImportPluginSettings): boolean => {
+    const pathToBookFile = path.join(settings.highlightsFolder, `${bookTitle}.md`);
+    const doesBookFileExist = vault.getFileByPath(pathToBookFile);
+
+    return doesBookFileExist ? true : false;
+};
\ No newline at end of file
diff --git a/styles.css b/styles.css
index 118dda0..4d551d5 100644
--- a/styles.css
+++ b/styles.css
@@ -7,3 +7,12 @@
 .ibooks-highlights-folder > .setting-item-control.setting-error > input {
 	border-color: #b00;
 }
+
+.modal-rewrite-book-title {
+    text-align: center;
+    color: var(--interactive-accent);
+}
+
+.modal-rewrite-all-books {
+    color: var(--interactive-accent);
+}
\ No newline at end of file
diff --git a/test/backupHighlights.spec.ts b/test/backupHighlights.spec.ts
new file mode 100644
index 0000000..3a9c3e8
--- /dev/null
+++ b/test/backupHighlights.spec.ts
@@ -0,0 +1,87 @@
+import BackupHighlights from '../src/utils/backupHighlights';
+import { AppleBooksHighlightsImportPluginSettings } from '../src/settings';
+import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
+
+const mockVault = {
+	getFolderByPath: vi.fn(),
+	getFileByPath: vi.fn(),
+    createFolder: vi.fn().mockImplementation(async (folderName: string) => {
+		return;
+	}),
+    adapter: {
+		list: vi.fn(),
+		// eslint-disable-next-line
+		copy: vi.fn().mockImplementation(async (source: string, destination: string) => {
+			return;
+		}),
+	},
+    delete: vi.fn().mockImplementation(async (folderPath: string, force: boolean) => {
+        return;
+    }),
+};
+
+const settings = new AppleBooksHighlightsImportPluginSettings();
+
+beforeEach(() => {
+	Date.now = vi.fn().mockImplementation(() => 1704060001);
+});
+
+afterEach(() => {
+	vi.resetAllMocks();
+});
+
+describe('Backup all highlights', () => {
+    test('Should skip backup if the highlights folder does not exist', async () => {
+        mockVault.getFolderByPath.mockReturnValue(null);
+
+        const backupHighlights = new BackupHighlights(mockVault as any, settings);
+        await backupHighlights.backupAllHighlights();
+
+        expect(mockVault.getFolderByPath).toHaveBeenCalledWith(settings.highlightsFolder);
+        expect(mockVault.createFolder).not.toHaveBeenCalled();
+    });
+
+    test('Should skip backup if the highlights folder is empty', async () => {
+        mockVault.getFolderByPath.mockReturnValue({ path: settings.highlightsFolder });
+        mockVault.adapter.list.mockResolvedValue({ files: [] });
+
+        const backupHighlights = new BackupHighlights(mockVault as any, settings);
+        await backupHighlights.backupAllHighlights();
+
+        expect(mockVault.adapter.list).toHaveBeenCalledWith(settings.highlightsFolder);
+        expect(mockVault.createFolder).not.toHaveBeenCalled();
+        expect(mockVault.delete).not.toHaveBeenCalled();
+    });
+
+    test('Should backup all the content of the highlights folder', async () => {
+        const highlightsFolderPath = { path: settings.highlightsFolder };
+        mockVault.getFolderByPath.mockReturnValue(highlightsFolderPath);
+
+        const highlightsFiles = [`${settings.highlightsFolder}/file1.md`, `${settings.highlightsFolder}/file2.md`];
+        mockVault.adapter.list.mockResolvedValue({ files: highlightsFiles });
+
+        const backupHighlights = new BackupHighlights(mockVault as any, settings);
+        await backupHighlights.backupAllHighlights();
+
+        expect(mockVault.createFolder).toHaveBeenCalledWith(`${settings.highlightsFolder}-bk-1704060001`);
+        expect(mockVault.adapter.copy).toHaveBeenCalledTimes(2); // highlightsFiles.length
+
+        expect(mockVault.delete).toHaveBeenCalledWith(highlightsFolderPath, true);
+        expect(mockVault.createFolder).toHaveBeenCalledWith(settings.highlightsFolder);
+    });
+});
+
+describe('Backup single book highlights', () => {
+    test('Should backup a single book highlights', async () => {
+        const bookTitle = 'Hello-world';
+        const vaultFile = { path: `${settings.highlightsFolder}/${bookTitle}.md` };
+        mockVault.getFileByPath = vi.fn().mockReturnValue(vaultFile);
+
+        const backupBookTitle = `${bookTitle}-bk-1704060001.md`;
+
+        const backupHighlights = new BackupHighlights(mockVault as any, settings);
+        await backupHighlights.backupSingleBookHighlights(bookTitle);
+
+        expect(mockVault.adapter.copy).toHaveBeenCalledWith(vaultFile.path, `${settings.highlightsFolder}/${backupBookTitle}`);
+    });
+});
diff --git a/test/checkBookExistence.spec.ts b/test/checkBookExistence.spec.ts
new file mode 100644
index 0000000..33702c9
--- /dev/null
+++ b/test/checkBookExistence.spec.ts
@@ -0,0 +1,33 @@
+import { checkBookExistence } from '../src/utils/checkBookExistence';
+import { AppleBooksHighlightsImportPluginSettings } from '../src/settings';
+import { beforeEach, describe, expect, test, vi } from 'vitest';
+
+describe('checkBookExistence', () => {
+    const mockVault = {
+        getFileByPath: vi.fn(),
+    };
+
+    const settings = new AppleBooksHighlightsImportPluginSettings();
+
+    beforeEach(() => {
+        vi.resetAllMocks();
+    });
+
+    test('Should return false if the book file does not exist', () => {
+        const bookTitle = 'Hello World';
+        mockVault.getFileByPath.mockReturnValue(null);
+
+        const checkResult = checkBookExistence(bookTitle, mockVault as any, settings);
+
+        expect(checkResult).toBe(false);
+    });
+
+    test('Should return true if the book file exists', () => {
+        const bookTitle = 'Hello World';
+        mockVault.getFileByPath.mockReturnValue({ path: `${settings.highlightsFolder}/${bookTitle}.md` });
+
+        const checkResult = checkBookExistence(bookTitle, mockVault as any, settings);
+
+        expect(checkResult).toBe(true);
+    });
+});
diff --git a/test/saveHighlightsToVault.spec.ts b/test/saveHighlightsToVault.spec.ts
index 9e0c8d1..154e2d8 100644
--- a/test/saveHighlightsToVault.spec.ts
+++ b/test/saveHighlightsToVault.spec.ts
@@ -4,6 +4,7 @@ import timezone from 'dayjs/plugin/timezone';
 import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
 import SaveHighlights from '../src/methods/saveHighlightsToVault';
 import { AppleBooksHighlightsImportPluginSettings } from '../src/settings';
+import defaultTemplate from '../src/template';
 import { rawCustomTemplateMock, rawCustomTemplateMockWithWrappedTextBlockContainingNewlines } from './mocks/rawTemplates';
 import { aggregatedUnsortedHighlights } from './mocks/aggregatedDetailsData';
 import {
@@ -14,7 +15,8 @@ import {
 import { ICombinedBooksAndHighlights } from '../src/types'
 
 const mockVault = {
-	getAbstractFileByPath: vi.fn(),
+	getFileByPath: vi.fn(),
+	getFolderByPath: vi.fn(),
 	// eslint-disable-next-line
 	createFolder: vi.fn().mockImplementation(async (folderName: string) => {
 		return;
@@ -23,6 +25,9 @@ const mockVault = {
 	create: vi.fn().mockImplementation(async (filePath: string, data: string) => {
 		return;
 	}),
+	modify: vi.fn().mockImplementation(async (file: any, data: string) => {
+		return;
+	}),
 	// eslint-disable-next-line
 	delete: vi.fn().mockImplementation(async (folderPath: string, force: boolean) => {
 		return;
@@ -38,6 +43,7 @@ const mockVault = {
 
 beforeEach(() => {
 	Date.now = vi.fn().mockImplementation(() => 1704060001);
+	settings.template = defaultTemplate;
 });
 
 afterEach(() => {
@@ -46,7 +52,7 @@ afterEach(() => {
 
 const settings = new AppleBooksHighlightsImportPluginSettings();
 
-describe('Save highlights to vault', () => {
+describe('Save all highlights to vault', () => {
 	dayjs.extend(utc);
 	dayjs.extend(timezone);
 	const tzSpy = vi.spyOn(dayjs.tz, 'guess');
@@ -54,12 +60,12 @@ describe('Save highlights to vault', () => {
 	test('Should save highlights to vault using the default template', async () => {
 		// eslint-disable-next-line
 		const saveHighlights = new SaveHighlights({ vault: mockVault } as any, settings);
-		const spyGetAbstractFileByPath = vi.spyOn(mockVault, 'getAbstractFileByPath').mockReturnValue('ibooks-highlights');
+		const spyGetFolderByPath = vi.spyOn(mockVault, 'getFolderByPath').mockReturnValue('ibooks-highlights');
 
-		await saveHighlights.saveHighlightsToVault(aggregatedUnsortedHighlights as ICombinedBooksAndHighlights[]);
+		await saveHighlights.saveAllBooksHighlightsToVault(aggregatedUnsortedHighlights as ICombinedBooksAndHighlights[]);
 
-		expect(spyGetAbstractFileByPath).toHaveBeenCalledTimes(1);
-		expect(spyGetAbstractFileByPath).toHaveBeenCalledWith('ibooks-highlights');
+		expect(spyGetFolderByPath).toHaveBeenCalledTimes(1);
+		expect(spyGetFolderByPath).toHaveBeenCalledWith('ibooks-highlights');
 
 		expect(mockVault.delete).toHaveBeenCalledTimes(1);
 		expect(mockVault.delete).toHaveBeenCalledWith('ibooks-highlights', true);
@@ -81,12 +87,12 @@ describe('Save highlights to vault', () => {
 
 		// eslint-disable-next-line
 		const saveHighlights = new SaveHighlights({ vault: mockVault } as any, settings);
-		const spyGetAbstractFileByPath = vi.spyOn(mockVault, 'getAbstractFileByPath').mockReturnValue('ibooks-highlights');
+		const spyGetFolderByPath = vi.spyOn(mockVault, 'getFolderByPath').mockReturnValue('ibooks-highlights');
 
-		await saveHighlights.saveHighlightsToVault(aggregatedUnsortedHighlights as ICombinedBooksAndHighlights[]);
+		await saveHighlights.saveAllBooksHighlightsToVault(aggregatedUnsortedHighlights as ICombinedBooksAndHighlights[]);
 
-		expect(spyGetAbstractFileByPath).toHaveBeenCalledTimes(1);
-		expect(spyGetAbstractFileByPath).toHaveBeenCalledWith('ibooks-highlights');
+		expect(spyGetFolderByPath).toHaveBeenCalledTimes(1);
+		expect(spyGetFolderByPath).toHaveBeenCalledWith('ibooks-highlights');
 
 		expect(mockVault.delete).toHaveBeenCalledTimes(1);
 		expect(mockVault.delete).toHaveBeenCalledWith('ibooks-highlights', true);
@@ -105,12 +111,12 @@ describe('Save highlights to vault', () => {
 		settings.template = rawCustomTemplateMockWithWrappedTextBlockContainingNewlines;
 		// eslint-disable-next-line
 		const saveHighlights = new SaveHighlights({ vault: mockVault } as any, settings);
-		const spyGetAbstractFileByPath = vi.spyOn(mockVault, 'getAbstractFileByPath').mockReturnValue('ibooks-highlights');
+		const spyGetFolderByPath = vi.spyOn(mockVault, 'getFolderByPath').mockReturnValue('ibooks-highlights');
 
-		await saveHighlights.saveHighlightsToVault(aggregatedUnsortedHighlights as ICombinedBooksAndHighlights[]);
+		await saveHighlights.saveAllBooksHighlightsToVault(aggregatedUnsortedHighlights as ICombinedBooksAndHighlights[]);
 
-		expect(spyGetAbstractFileByPath).toHaveBeenCalledTimes(1);
-		expect(spyGetAbstractFileByPath).toHaveBeenCalledWith('ibooks-highlights');
+		expect(spyGetFolderByPath).toHaveBeenCalledTimes(1);
+		expect(spyGetFolderByPath).toHaveBeenCalledWith('ibooks-highlights');
 
 		expect(mockVault.delete).toHaveBeenCalledTimes(1);
 		expect(mockVault.delete).toHaveBeenCalledWith('ibooks-highlights', true);
@@ -128,12 +134,12 @@ describe('Save highlights to vault', () => {
 	test('Should skip saving highlights to vault if highlights are not found', async () => {
 		// eslint-disable-next-line
 		const saveHighlights = new SaveHighlights({ vault: mockVault } as any, { ...settings, highlightsFolder: '' });
-		const spyGetAbstractFileByPath = vi.spyOn(mockVault, 'getAbstractFileByPath').mockReturnValue('');
+		const spyGetFolderByPath = vi.spyOn(mockVault, 'getFolderByPath').mockReturnValue('');
 
-		await saveHighlights.saveHighlightsToVault(aggregatedUnsortedHighlights as ICombinedBooksAndHighlights[]);
+		await saveHighlights.saveAllBooksHighlightsToVault(aggregatedUnsortedHighlights as ICombinedBooksAndHighlights[]);
 
-		expect(spyGetAbstractFileByPath).toHaveBeenCalledTimes(1);
-		expect(spyGetAbstractFileByPath).toHaveBeenCalledWith('');
+		expect(spyGetFolderByPath).toHaveBeenCalledTimes(1);
+		expect(spyGetFolderByPath).toHaveBeenCalledWith('');
 
 		expect(mockVault.delete).toHaveBeenCalledTimes(0);
 
@@ -145,7 +151,7 @@ describe('Save highlights to vault', () => {
 		// eslint-disable-next-line
 		const saveHighlights = new SaveHighlights({ vault: mockVault } as any, { ...settings, backup: true });
 
-		vi.spyOn(mockVault, 'getAbstractFileByPath').mockReturnValue('ibooks-highlights');
+		vi.spyOn(mockVault, 'getFolderByPath').mockReturnValue('ibooks-highlights');
 		// eslint-disable-next-line
 		const spyList = vi.spyOn(mockVault.adapter, 'list').mockImplementation(async (folderPath: string) => {
 			return {
@@ -156,7 +162,7 @@ describe('Save highlights to vault', () => {
 			};
 		});
 
-		await saveHighlights.saveHighlightsToVault(aggregatedUnsortedHighlights as ICombinedBooksAndHighlights[]);
+		await saveHighlights.saveAllBooksHighlightsToVault(aggregatedUnsortedHighlights as ICombinedBooksAndHighlights[]);
 
 		expect(spyList).toHaveBeenCalledTimes(1);
 		expect(spyList).toReturnWith({
@@ -174,3 +180,75 @@ describe('Save highlights to vault', () => {
 		expect(mockVault.adapter.copy).toHaveBeenNthCalledWith(2, 'ibooks-highlights/Goodbye-world.md', 'ibooks-highlights-bk-1704060001/Goodbye-world.md');
 	});
 });
+
+describe('Save single book highlights to vault', () => {
+	test('Should save a single book when the book doesn\'t exist and backups are turned off', async () => {
+		const saveHighlights = new SaveHighlights({ vault: mockVault } as any, settings);
+
+		await saveHighlights.saveSingleBookHighlightsToVault((aggregatedUnsortedHighlights as ICombinedBooksAndHighlights[]), true);
+
+		expect(mockVault.createFolder).toHaveBeenCalledTimes(1);
+		expect(mockVault.createFolder).toHaveBeenCalledWith('ibooks-highlights');
+
+		expect(mockVault.create).toHaveBeenCalledTimes(1);
+		expect(mockVault.create).toHaveBeenCalledWith(
+			`ibooks-highlights/Apple iPhone - User Guide - Instructions - with - restricted - symbols - in - title.md`,
+			defaultTemplateMockWithAnnotationsSortedByDefault
+		);
+	});
+
+	test('Should save a single book when the book doesn\'t exist and backups are turned on', async () => {
+		const saveHighlights = new SaveHighlights({ vault: mockVault } as any, { ...settings, backup: true });
+
+		await saveHighlights.saveSingleBookHighlightsToVault((aggregatedUnsortedHighlights as ICombinedBooksAndHighlights[]), true);
+
+		expect(mockVault.createFolder).toHaveBeenCalledTimes(1);
+		expect(mockVault.createFolder).toHaveBeenCalledWith('ibooks-highlights');
+
+		expect(mockVault.create).toHaveBeenCalledTimes(1);
+		expect(mockVault.create).toHaveBeenCalledWith(
+			`ibooks-highlights/Apple iPhone - User Guide - Instructions - with - restricted - symbols - in - title.md`,
+			defaultTemplateMockWithAnnotationsSortedByDefault
+		);
+
+		expect(mockVault.adapter.copy).toHaveBeenCalledTimes(0);
+		expect(mockVault.delete).toHaveBeenCalledTimes(0);
+	});
+
+	test('Should modify a single book when it already exists in vault and backups are turned off', async () => {
+		const saveHighlights = new SaveHighlights({ vault: mockVault } as any, settings);
+		vi.spyOn(mockVault, 'getFileByPath').mockReturnValue({
+			path: 'ibooks-highlights/Apple iPhone - User Guide - Instructions - with - restricted - symbols - in - title.md'
+		});
+
+		vi.spyOn(saveHighlights, 'modifyExistingBookFile');
+
+		await saveHighlights.saveSingleBookHighlightsToVault((aggregatedUnsortedHighlights as ICombinedBooksAndHighlights[]), false);
+
+		expect(saveHighlights.modifyExistingBookFile).toHaveBeenCalledTimes(1);
+		expect(saveHighlights.modifyExistingBookFile).toHaveBeenCalledWith({
+			path: 'ibooks-highlights/Apple iPhone - User Guide - Instructions - with - restricted - symbols - in - title.md'
+		},
+			defaultTemplateMockWithAnnotationsSortedByDefault
+		);
+	});
+
+	test('Should modify a single book when it already exists in vault and backups are turned on', async () => {
+		const saveHighlights = new SaveHighlights({ vault: mockVault } as any, { ...settings, backup: true });
+		vi.spyOn(mockVault, 'getFolderByPath').mockReturnValue('ibooks-highlights');
+		vi.spyOn(mockVault, 'getFileByPath').mockReturnValue({
+			path: 'ibooks-highlights/Apple iPhone - User Guide - Instructions - with - restricted - symbols - in - title.md'
+		});
+
+		await saveHighlights.saveSingleBookHighlightsToVault((aggregatedUnsortedHighlights as ICombinedBooksAndHighlights[]), false);
+
+		expect(mockVault.getFileByPath).toHaveBeenCalledTimes(2);
+		expect(mockVault.getFileByPath).toHaveBeenCalledWith('ibooks-highlights/Apple iPhone - User Guide - Instructions - with - restricted - symbols - in - title.md');
+
+		expect(mockVault.adapter.copy).toHaveBeenCalledTimes(1);
+		expect(mockVault.adapter.copy).toHaveBeenCalledWith(
+			'ibooks-highlights/Apple iPhone - User Guide - Instructions - with - restricted - symbols - in - title.md',
+			'ibooks-highlights/Apple iPhone - User Guide - Instructions - with - restricted - symbols - in - title-bk-1704060001.md'
+		);
+	});
+});
diff --git a/test/search.spec.ts b/test/search.spec.ts
new file mode 100644
index 0000000..80a7955
--- /dev/null
+++ b/test/search.spec.ts
@@ -0,0 +1,13 @@
+import { describe, test } from 'vitest';
+
+// This functionality uses the Obsidian API which is hard to replicate in tests.
+// Will be revisited later.
+describe.todo('IBookHighlightsPluginSearchModal', () => {
+    test.todo('Should filter books based on query');
+    test.todo('Should handle errors in getSuggestions');
+});
+
+describe.todo('OverwriteBookModal', () => {
+    test.todo('Should show a modal window for bulk import');
+    test.todo('Should show a modal window with book details');
+});
\ No newline at end of file
diff --git a/vitest.config.mjs b/vitest.config.mjs
index ce1a81a..d46c675 100644
--- a/vitest.config.mjs
+++ b/vitest.config.mjs
@@ -9,12 +9,12 @@ export default defineConfig({
 			enabled: true,
 			provider: 'istanbul',
 			reporter: ['lcov'],
+			include: [
+				'main.ts',
+				'src/**/*.ts'
+			],
 			exclude: [
-				'src/template.ts',
-				'drizzle.config.ts',
-				'esbuild.config.mjs',
-				'version-bump.mjs',
-				'test/mocks/**/*',
+				'src/search.ts',
 				'src/db/**/*',
 			]
 		},