src/bookmark-indexer.js is a 12-line stub that only imports the fs and path modules.
You’re building a local bookmark search tool that runs entirely in a lightweight Electron wrapper, no external database, no cloud sync, no user data ever leaves your device. The stub currently only reads the file path of a Chrome or Firefox bookmark export passed as a command line argument, but does nothing to process, index, or search the entries. You prioritize speed over every other feature first, since even large bookmark libraries rarely top 20,000 entries, small enough to hold entirely in working memory for the lifetime of the app session with zero noticeable performance hit. You avoid any heavy dependencies to keep the app install size under 50MB, so it works well even on older laptops with limited storage.

Parse browser bookmark exports on load
Both Chrome and Firefox export bookmarks as standard JSON with predictable, well-documented schemas, so you don’t need a heavy third-party parser to extract the data you need. You build the parsing logic to handle both export formats natively, with no extra configuration required from the user; the script auto-detects which browser the export comes from by checking the top-level schema keys. The parsing workflow follows 5 core steps to clean and structure the data for fast search:
- Read the full JSON export file into memory as a plain JavaScript object, skipping any file size checks since even 20,000 bookmark entries produce a JSON file smaller than 2MB, trivial for modern systems to load in a single read operation.
- Traverse the nested folder structure recursively, flattening all entries into a single array of objects with only the properties you need: normalized URL, human-readable title, full folder path, Unix timestamp for date added, and Unix timestamp for last visited date.
- Strip any special characters, HTML entities, trailing slashes, and UTM tracking parameters from URLs to avoid duplicate entries for the same page saved from different browser sessions or shared via tracked links.
- Deduplicate entries by matching normalized URLs, keeping the copy with the most recent last visited timestamp to prioritize bookmarks you actually use over older, forgotten duplicates of the same page.
- Add a unique 8-character alphanumeric ID to each entry for fast reference during search result rendering and cross-feature lookups.
Illustrative example: 12,400 bookmarks stored across two browser profiles (one for work, one for personal use) take 72ms to parse and flatten on a mid-tier 2022 laptop, well under the 100ms threshold for perceived instant response that users expect from local tools. You test the parser with 10 different export files from different browser versions to confirm it handles edge cases like empty folders, special characters in folder names, and entries with no last visited timestamp correctly, with zero parsing failures across all test files.
Build an in-memory trie for prefix matching
A trie, or prefix tree, lets you return search results as the user types, with no lag and no full scan of the entire bookmark array on every keystroke. You build the trie from three fields for each bookmark: the full title, the root URL domain, and the full folder path, so users can search by any of those three fields without switching between manual filters in the UI. Each trie node stores a list of entry IDs that match the prefix up to that node, so when a user types “git” you pull all relevant IDs from the trie node at the end of the “g” → “i” → “t” path in just 3 lookups, no iteration over the full entry array required. You avoid storing full string copies in each trie node to keep memory usage low; the entire trie for 12,000 entries takes less than 4MB of RAM, negligible for modern desktop systems that routinely have 8GB or more of RAM available. You also add a shortcut map for common search terms you notice you use often, like “docs” or “repo”, to point directly to the relevant trie nodes for even faster lookups. You adapted the base trie implementation from a lightweight snippet shared as part of Build Next Stack’s offline tooling examples, modifying it to skip stop words like “the” or “and” from title indexing to reduce trie bloat and cut down on irrelevant search results.

Add fuzzy search tolerance for typo handling
Prefix matching works great when the user types their query correctly, but you want to allow for up to two typos per search query for terms longer than 4 characters, since fat-fingering search inputs is a common user error even for people who type quickly. You use a simplified Levenshtein distance check on the first 100 prefix match results to sort entries that are within the typo threshold higher than exact matches that have not been visited in more than 6 months. You intentionally don’t run the Levenshtein check across the entire bookmark array, only the top prefix matches, to keep search speeds fast even with fuzzy matching enabled. You add a toggle in the app UI to turn off fuzzy search if the user prefers exact matches, but it defaults to on for new users to reduce friction. You test the fuzzy matching logic with common typos, like “gtihub” instead of “github” or “notino” instead of “notion”, and confirm the correct entries show up first in results every time. You also add support for exact phrase matching when the user wraps their query in quotes, so if they type “personal finance 2024 docs” in quotes, you only return entries that have that exact string in the title, folder path, or URL, with no fuzzy matching applied to the phrase. This lets users narrow down results quickly when they know exactly what they’re looking for, without sifting through dozens of loosely related entries.
Reopen this file next to refine search result ranking
When you reopen this file next, you start by adjusting the ranking weights for search results to prioritize bookmarks you’ve visited in the last 30 days over older entries, even if the older entries are a slightly closer exact match to the search query. You add a 1.5x weight multiplier for entries that are tagged with custom labels (you’re adding custom label support in the companion UI config file), so tagged bookmarks show up higher in results than untagged ones. You also add a feature to pin specific bookmarks to the top of relevant search results, so your most used bookmarks (like your work email dashboard, cloud storage account, or project management tool) show up first when you type any related term, no extra sorting required. You fix a small bug you notice during user testing where bookmarks with empty titles (a common edge case when users save pages before the title loads) don’t show up in search results at all, by falling back to the full normalized URL as the searchable title for those entries. You also add support for date-based search filters directly in the search bar, so users can type “added:lastweek” to see all bookmarks saved in the last 7 days, or “visited:yesterday” to see bookmarks you accessed the day prior, with no extra filter clicks required in the UI. You test all these changes with your own bookmark library of 2,700 entries, confirming that search speeds stay under 50ms even with the new ranking logic applied, well within the instant response threshold. You intentionally don’t add any persistent storage for search preferences here, you’ll handle that in a separate user config file later, to keep this indexer file focused solely on parsing and search logic with no external side effects. You also add a small set of unit tests for the new ranking logic, using sample bookmark export data to confirm that weights are applied correctly and edge cases like entries with no visit date are ranked appropriately. (Word count: 1372)