Skip to content
Tech News
← Back to articles

SQLite in Production: Lessons from Running a Store on a Single File

read original get SQLite Database Management Book → more articles
Why This Matters

Running a production e-commerce store on SQLite demonstrates that, with proper configuration like WAL mode, SQLite can handle real-world, high-traffic applications without the complexity of traditional database servers. This approach simplifies deployment and management, making it appealing for certain use cases, but also introduces unique challenges such as shared storage and concurrency considerations. The experience highlights both the potential and pitfalls of using SQLite in production environments, encouraging developers to weigh its benefits against its limitations.

Key Takeaways

We run a production e-commerce store on SQLite. Not as a proof of concept. Not for a side project with three users. A real store, processing real Stripe payments, serving real customers.

Rails 8 made this a first-class choice. And for most of our operation, it's been excellent — simpler deploys, zero connection pooling headaches, no database server to manage. But "most of our operation" isn't all of it. Here's the part nobody warns you about.

The Setup: Four Databases, One Volume

Our database.yml defines four SQLite databases in production:

production: primary: database: storage/production.sqlite3 cache: database: storage/production_cache.sqlite3 queue: database: storage/production_queue.sqlite3 cable: database: storage/production_cable.sqlite3

Primary handles orders, products, users. Cache is the Rails cache store. Queue runs Solid Queue (background jobs). Cable handles Action Cable connections. All four live in a storage/ directory that maps to a named Docker volume:

# config/deploy.yml volumes: - "ultrathink_storage:/rails/storage"

One Docker volume. Four database files. Every container that mounts this volume shares the same data. This is both the feature and the footgun.

WAL Mode: Why It Works at All

SQLite's default journal mode locks the entire database on writes. One writer blocks all readers. For a web app handling concurrent requests, that's a non-starter.

... continue reading