Emby large library slow, high memory
Big libraries are where media servers start to drag: the poster wall pauses, filters make you wait, memory keeps climbing. People have been reporting constant time-outs with large libraries on Emby's forum for years. This is the first in a short series on the choices behind Kryspal Media.
Why big libraries slow down
Every screen in a player is a query: the first 50 movies by name, only the unwatched ones, the episodes of one season. If the server has to look at every title to answer, the cost grows with the library. The fix is to never look at most of it.

Indexes built for the questions players ask
Kryspal Media keeps titles, people, tags and watch history in PostgreSQL, with one composite index for each common query: browsing by name, by date added, release date and rating, seasons and episodes, and cast and tags in both directions. "Continue watching" uses a partial index, an index over only the rows that match a condition, here the items you have started and not finished, so it stays small at any library size. The server reads the answer in index order and stops after one page.

Pages that do not count rows
Offset pagination, "skip the first 40,000 and give me 50", must walk past those 40,000 rows, so deep pages get slower. Kryspal Media uses keyset pagination, also called cursor pagination: it remembers the sort key and ID of the last item and reads the next 50 straight from the index, so the cost does not depend on depth. Players that only ask by position are served from a short-lived sorted list of IDs.

Two databases, two designs
Emby stores its library in SQLite: a single file inside the server process, with one writer at a time. SQLite’s built-in full-text search splits text at spaces, so part of a word, like "stellar" in "Interstellar", or a Chinese title with no spaces, can't be found through the index.
Kryspal Media uses PostgreSQL. Reads and writes run side by side (MVCC, multi-version concurrency control), so a scan never stalls browsing. A bigram index (pg_bigm) splits text into pairs of characters, so any part of a title, even one or two Chinese characters, is found straight from the index. The bigger the library, the bigger the gap.

A restart that does not start over
The library lives in the database, so a restart does not rescan your files or reload every title. Memory settings for the server and the database are calculated at startup from the memory the container has.

High memory usage: a fixed upper limit
The server (written in Go) reads the container's memory at startup and sets the Go runtime's soft memory limit (GOMEMLIMIT) to about a quarter of it, within fixed bounds; a value you set yourself wins. Near the limit, garbage collection runs more often and idle memory goes back to the operating system.
The database (PostgreSQL) sizes shared_buffers, its page cache, from the available memory and keeps it fixed. When it is full, clock-sweep evicts the least recently used pages, so the cache does not grow with uptime; a query's work_mem is released when the query ends.
On a real library of about 177,000 titles, the server uses about 140 MB and the database about 1 GB including its buffers. On a synthetic library of about 21,000 titles, a first scan with 1 GB of memory finished without running out of memory, with the same screen latency as with 4 GB.

What you get

- Browsing and filtering up to 30× faster than Emby 4.10; the Compare page has the details.
- On a library of about 200,000 movies, browsing answers in under 50 ms.
- After a restart, the server is ready in under 5 seconds, even with a huge library.
It is the same on the free plan.
Move over without starting from zero
Install Kryspal Media with Docker next to Emby, point it at the same folders, and open your big library in both. The import is guided and read-only: libraries, members, metadata, images, watch history, favorites and tags come across as they are, and Infuse, SenPlayer and VidHub connect the way they do to Emby. See the migration guide.

Test setup: a home NAS (Intel i5-1235U) with the database on an NVMe SSD; a real library of about 177,000 titles, with the browse comparison run on a 68,000-movie library within it; October 2026.