When I started building Bookmash, one architectural decision shaped almost everything else: the browser stays the source of truth.
No import step. No Bookmash-side copy of your bookmarks. The extension talks directly to the browser's native bookmarks API, and the dashboard reads and writes through that same layer.
Bookmash doesn't store your bookmarks, or its own representation of them, in a database. The only user data stored server-side is what's needed for the account itself, such as the user's email to give access to the dashboard.
That constraint sounds simple. It wasn't free because of how browser's bookmark tree is handled.
Here's what it meant when building features like Collections and MyMash without introducing a second bookmark model.
The problem with the native bookmark tree
Chrome and Firefox expose bookmarks as a tree through their extension APIs.
That tree reflects the browser's own structure: bookmarks live inside folders, which in turn live under browser-defined roots such as the bookmarks bar and other bookmarks.
For example:
Browser bookmarks
├── Bookmarks Bar
│ ├── Development
│ └── Daily
│
└── Other Bookmarks
├── Design
└── Research
That separation makes sense for the browser UI, but it doesn't necessarily represent how I want to navigate those bookmarks inside another interface.
I wanted Bookmash to provide a different view over that same data without reorganizing it into a Bookmash-specific structure.
That meant the problem wasn't:
How do I import this tree into Bookmash?
It was:
How do I derive a more useful interface from the tree that already exists?
Collections: a view computed from the tree
Bookmash reads the current bookmark tree from the browser and runs a flattening operation over it.
Conceptually:
Browser tree
Bookmarks Bar
├── Development
└── Daily
Other Bookmarks
├── Design
└── Research
↓ flatten
Bookmash
├── Development
├── Daily
├── Design
└── Research
The browser's top-level separation disappears from the Bookmash view, while the meaningful folder hierarchy underneath it remains intact.
Nothing needs to be copied into a Bookmash database to make that happen.
The Collection view is the result of an operation over the current tree.
Every time Bookmash needs that view, it starts with what the browser says exists now and derives the representation from it.
If a folder is renamed, moved or deleted using the browser itself, Bookmash doesn't have a second version of that folder to reconcile.
It reads the tree again. This approach makes the dashboard always fresh.
There is no:
browser state
↕
sync layer
↕
Bookmash bookmark state
There is only:
browser state
↓
Bookmash view
That distinction ended up removing an entire category of synchronization problems.
The cost: computation moves to read time
Of course, not storing a derived bookmark model doesn't make the work disappear.
It moves the work.
A more traditional architecture could normalize the bookmark tree once, store the result, index it and query that representation later.
Bookmash instead reads the current tree and transforms it when it needs to display it.
So the trade-off becomes:
store and synchronize state on writes
versus
recompute a view from the source on reads.
I chose the second.
For bookmark-sized datasets, the cost has been small enough that I prefer doing the computation to maintaining another stateful representation of data that already exists somewhere else.
If that assumption ever stops being true, the performance side can be revisited.
But I didn't want to introduce synchronization complexity before there was a reason to.
MyMash follows the same idea
MyMash is Bookmash's quick-access view for bookmarks you use frequently.
The important part architecturally is that adding something to MyMash doesn't create a second copy of that bookmark in a Bookmash database.
The bookmark remains part of the browser's native bookmark structure.
MyMash is another way of presenting and accessing that structure through Bookmash rather than a separate library of bookmarks owned by the application.
That distinction matters because I wanted features like MyMash to change how you interact with your bookmarks, not where your bookmarks live.
The browser still owns the bookmark data.
Bookmash provides another interface over it.
Chrome and Firefox: similar APIs don't mean identical behavior
One thing I underestimated was how much browser-specific behavior would still matter.
Chrome and Firefox expose comparable bookmark APIs, so initially I expected most tree-related bugs to reproduce in roughly the same way.
They didn't.
Folder-structure edge cases and the behavior around bookmark updates were different enough that the same transformation logic could surface problems in one browser and not the other.
So "works in Chrome" was never a safe proxy for "works in Firefox," even when both implementations were built around the same basic WebExtensions model.
That reinforced another part of the architecture: the transformation layer should make as few assumptions as possible about what the tree should look like.
Read what the browser gives you, normalize what the UI actually needs, and preserve the underlying structure everywhere else.
Why this mattered more than it might seem
None of this is about avoiding a database out of purity.
Bookmash has server-side concerns — authentication, for example — where persistent storage makes perfect sense.
Bookmarks are different.
The browser already stores them. Bookmash doesn't need to store them again.
The moment Bookmash stores its own copy of the bookmark structure, it takes on responsibility for keeping that copy correct relative to a tree the user can change without going through Bookmash at all.
They can edit it from the native bookmark manager.
Another extension can change it.
Browser sync can change it.
Bookmash would then need to decide which state is current and how discrepancies should be resolved.
By treating the browser tree as the source of truth and computing Bookmash's views from it, that synchronization problem largely disappears.
The trade-off is that more work happens when the data is read.
And that's the architectural lesson I've taken from building it:
If you're building a UI on top of data that already has an authoritative owner, think carefully before creating your own representation of that data.
You can store your own model and own the synchronization problem.
Or you can derive your model from the source of truth and own the computation problem.
For Bookmash, I chose the second.
So far, it's been the simpler problem to own.
Bookmash is a bookmark manager for Chrome and Firefox built around this architecture. There's also a public demo if you want to see how the browser tree is presented without installing anything.
I'm also happy to write a follow-up about the extension-to-dashboard communication layer or the differences I ran into between Chrome and Firefox.



Top comments (0)