How SQLite made Notion 30% Faster
Notion made a tough bet on emerging tech, and it paid off in a big way
It's difficult to explain exactly what Notion is.
A tool for note-taking, documentation, project management, and more. All wrapped up with great collaboration features and a beautiful UI.
It has over 30 million users, 4 million of whom are paying for it. Not bad.
But if there was one common criticism of Notion, it was that it felt slow. Specifically when navigating between pages.
The team managed to make it faster with a few interesting techniques.
Let's go through it.
Estimated reading time: 4 minutes 35 seconds
What Made Notion Slow?
If you created a few blank pages in Notion, navigating between them would feel lightning fast.
But, if you added some images, tables, charts, and other complex widgets. Navigation would feel very slow.
There are no articles saying what caused this slowness. But we can make some assumptions from technical posts they've written:
Notion depended on many third-party scripts. Possibly for collaboration features, analytics, and third-party assets like images.
Frequent API calls being made to Notion's servers. This was because there was no or very limited caching in the browser.
CPU cores not being used for processing tasks. Most people have between 4 and 8 cores, which means 4 to 8 tasks could be processed at the same time. Notion wasn’t taking advantage of this.
Some previous attempts were made to fix these issues. The team used LocalStorage to cache data in the browser. But this had limited storage, which wasn't great for users with lots of pages.
They then tried using IndexedDB for caching. This was never shipped because it didn't improve performance. In fact, on certain devices it was even slower than LocalStorage.
Sidenote: LocalStorage vs IndexedDB
Both LocalStorage and IndexedDB are ways to store data in the browser.
This also means the data will get saved on a user's device. Meaning it will exist after closing a tab or restarting the browser.
But there are a few differences between them.
Because IndexedDB is different across browsers, fixing browser-specific bugs .
Also, some users would have Notion open on different tabs in the same browser. Notion had fine-grained data. This means if a page had a wall of text, each paragraph would have its own database row.
So lots of data being changed between tabs with IndexedDB would cause major performance issues.
The team improved performance for the desktop and mobile apps by using an SQLite database to cache data. So it made sense to try it on the browser.
To their surprise, it worked really well.
Why SQLite Worked
SQLite is a database like MySQL and Postgres, using SQL as its query language.
But it's different from them because it holds all its data in a single file and doesn't have a server.
Databases tend to use servers to manage data access, prevent conflicts, and control user permissions.
The lack of a server limits SQLite compared to other databases. But it was ideal for Notion's caching needs.
SQLite isn't natively supported in browsers. But it does have a WebAssembly version.
Sidenote: WebAssembly (WASM)
WebAssembly allows you to run code written in languages other than JavaScript in the browser.
If I wrote a really fast complex calculation in C++ and wanted to run it in the browser.
Instead of rewriting it in JavaScript, I could keep the C++ code, compile it to WebAssembly, and run it in the browser.
Because SQLite is written in C, it can be compiled into WebAssembly.
But a user will have to download all of SQLite before it can be used.
Unfortunately, Notion couldn't just drop SQLite into their project and call it a day. They had to make a bunch of changes first.
Problems with SQLite
As well as WebAssembly, SQLite uses a few other web technologies.
It uses a Web Worker to handle reading and writing to the database.
Web Workers allow code to run in the background, meaning they won't block actions on the main site.
The SQLite file was stored on the Origin Private File System (OPFS). Browsers cannot access a user's file system without their permission.
So OPFS provides an isolated file system only for the browser. This is separate from the main file system.
But OPFS has a crucial limitation. If one tab is reading or writing to a file, it locks the file to that tab, meaning changes made by other tabs will not work.
To fix this, Notion created a system where changes made by other tabs went to a single worker that had access to the database file. This was the Active Worker.
A SharedWorker was created to figure out which tab would have the active worker.
So if the active worker tab was closed. The SharedWorker would make another web worker active.
Sidenote: The two types of WASM SQLite
SQLite can interact with the OPFS virtual file system (VFS) in two different ways.
1. OPFS sqlite3_vfs
2. OPFS SyncAccessHandle Pool VFS
Note, OPFS isn't really a virtual file system; it's just an isolated environment which is where the term virtual comes from.
The first one, sqlite3_vfs, does support running on many tabs. But only works with cross-origin isolation. Cross-origin isolation puts the browser in a 'protective bubble' that gives it extra security.
But this restricts it from sharing data with other websites.
This didn't work for Notion because they depended on third-party scripts.
So they chose OPFS SyncAccessHandle Pool VFS.
This can only run in one tab. But is supported in all major browsers and has slightly better performance than sqlite3_vfs.
Another issue the team had with this approach was that pages loaded slower at first.
This was because a user would have to download SQLite if they didn't have it. It wasn't huge, under 1 MB. But on slower connections, it was noticeable.
To fix this, the team changed the way SQLite was loaded. Instead of loading it together with the site, they would wait for the page to finish loading first before downloading SQLite.
This meant that the initial page data wasn't coming from the cache. But the slight speed increase from loading initial data with SQLite wasn't worth the complication.
In general, the move to SQLite in the browser was a success.
The Notion site in certain parts of the world benefited from a 33% speed increase when navigating between pages.
Wrapping Things Up
I would love to have seen if this improved signups or kept users on the site for longer. Maybe Notion is holding off these metrics for another article.
Anyway, I hope you enjoyed this and learned something new. I certainly did.
If you want more details on this topic, you can check out the original article.
Until then, be sure to subscribe to get the next article as soon as it’s released.
PS: Enjoyed this newsletter? Please forward it to a pal or follow us on socials (LinkedIn, Twitter, YouTube, Instagram). It only takes 10 seconds. Making this one took 22 hours.