Mahamudul Hasan Rubel
HomeAboutProjectsSkillsExperienceBlogPhotosContact
Mahamudul Hasan Rubel

Senior Software Engineer crafting high-performance web applications and SaaS platforms.

Navigation

  • Home
  • About
  • Projects
  • Skills
  • Experience
  • Blog
  • Photos
  • Contact

Get in Touch

Available for senior/lead roles and consulting.

bd.mhrubel@gmail.comHire Me

© 2026 Mahamudul Hasan Rubel. All rights reserved.

Built with using Next.js 16 & Tailwind v4

Back to Blog
Tech NewsJune 21, 20264 min read

Bun runtime SQLite performance: In-memory vs. Persistent storage

Master Bun runtime SQLite performance by choosing between in-memory and persistent storage. Learn how to optimize your backend database strategy today.

BunSQLiteBackendPerformanceDatabasesNode.jsNewsTrendsIndustry

I recently spent three days refactoring a high-throughput microservice that was struggling with disk I/O latency. We were running on the Bun runtime, and while the speed of the engine itself was impressive, our database layer—SQLite—was becoming the bottleneck.

It’s easy to assume that because SQLite is "fast," it’s always the right choice for every workload. But when you’re pushing thousands of requests per second, the distinction between an in-memory database and a persistent file-backed one becomes critical to your database optimization strategy.

Understanding the Bun Runtime and SQLite

The Bun runtime includes a high-performance, built-in SQLite driver that is significantly faster than standard better-sqlite3 implementations in Node.js. It’s designed to handle concurrent reads and writes with minimal overhead. However, the storage medium you choose dictates how that speed translates into real-world latency.

In our case, we were seeing p99 latencies jump to around 280ms during traffic spikes. We initially assumed the issue was our query complexity, but after killing N+1 queries at the database layer, we realized the I/O wait times were still too high. We were writing to a standard NVMe drive, but the synchronous commits were killing our throughput.

When to Use In-Memory SQLite

If you’re building a cache, a temporary session store, or a scratchpad for data processing, in-memory SQLite is a superpower. Since the data lives entirely in RAM, you eliminate the physical disk latency entirely.

Here is how you initialize an in-memory database in Bun:

JAVASCRIPT
import { Database } from "bun:sqlite";

// The special CE9178">':memory:' string tells SQLite to keep it in RAM
const db = new Database(":memory:");

db.query("CREATE TABLE cache(key TEXT PRIMARY KEY, value TEXT)").run();

The performance gain here is massive—usually an order of magnitude faster for write-heavy operations. However, the trade-off is durability. If your process crashes, your data is gone. I’ve found that using this for anything other than ephemeral data is a recipe for a 3 AM pager alert. If you're dealing with complex analytical data, you might instead prefer materialized views for database performance in complex analytical queries to cache results without losing persistence.

Balancing SQLite Performance with Persistence

For most production apps, you need data that survives a restart. This is where SQLite performance tuning becomes more of an art. When you move to a persistent file, you are at the mercy of your filesystem's sync speed.

We initially tried to "fix" our slow writes by disabling fsync entirely, which is a dangerous move. Instead, we shifted our configuration to use Write-Ahead Logging (WAL) mode. WAL allows multiple readers and one writer to operate simultaneously without blocking each other.

JAVASCRIPT
const db = new Database("prod_data.db");
db.exec("PRAGMA journal_mode = WAL;");
db.exec("PRAGMA synchronous = NORMAL;");

By switching to NORMAL synchronous mode, we told SQLite to only sync the data to disk at critical moments. This gave us roughly a 1.8x speed increase in write operations without sacrificing the integrity of the data in the event of a power failure.

Choosing Your Path

When deciding between these two approaches, ask yourself these three questions:

  1. Is the data disposable? If you can recreate it from a source of truth (like an API or a primary DB), use :memory:.
  2. How high is the write volume? If you are logging events at high frequency, consider batching them in an in-memory buffer before flushing them to a persistent store.
  3. Is disk I/O the bottleneck? If your monitoring shows high "iowait," stop trying to optimize the queries and start optimizing the storage configuration.

We also looked into database schema design: implementing shadow columns for soft deletes to keep our persistent tables lean, which helped reduce the amount of data the engine had to scan during lookups.

Final Thoughts

Working with the Bun runtime has shifted how I view Node.js alternatives. The native integration of SQLite is cleaner, but it doesn't absolve you from understanding how the engine interacts with your OS.

Next time, I’d likely experiment with mounting the database file on a tmpfs (RAM disk) instead of using the :memory: flag. This would give us the performance of memory with the ability to perform manual backups by simply copying the file. It’s a middle ground that provides a safety net while keeping the performance metrics well within our SLAs.

Frequently Asked Questions

Does Bun’s SQLite driver support multi-threading? Bun’s SQLite driver is designed for its event-loop model. While it handles concurrent requests well, SQLite itself is a single-writer engine. If you need massive write concurrency, you might need to reconsider your architecture.

Is it safe to use in-memory SQLite in a serverless environment? Only if your data is truly transient. Remember that serverless environments can spin down at any time, and you will lose all data in the memory space immediately.

Can I switch from in-memory to persistent later? Yes, but it requires significant code changes to handle the initialization and potential migration logic. It’s better to choose your storage strategy during the early design phase.

Back to Blog

Similar Posts

Runner's feet on track lane 5 at the finish line, symbolizing completion and success.
Tech NewsJune 20, 20264 min read

Bun runtime performance: Why it’s the shift you need

Bun runtime performance is changing how we build apps. Discover if this high-speed alternative to Node.js is ready for your production environment today.

Read more
Close-up of a hand adjusting a chess clock during a timed chess game indoors.
Tech News
June 20, 2026
4 min read

Postgres logical decoding for real-time CDC: A Practical Guide

Master Postgres logical decoding for real-time CDC. Learn how to stream database changes effectively to build robust, event-driven architectures today.

Read more
Close-up of JavaScript code on a laptop screen, showcasing programming in progress.
Tech NewsJune 20, 20263 min read

React 19 upgrades: What you actually need to know for production

React 19 upgrades matter for your production apps. Learn what’s changing, how to handle the migration, and whether it’s time to move your codebase today.

Read more