How to place SQLite database outside of NFS Persistent Volume
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
SQLite relies on file-level locking for concurrency control, but NFS (Network File System) uses advisory locks that do not provide the guarantees SQLite requires. Running SQLite on an NFS-mounted volume leads to database corruption, "database is locked" errors, and data loss under concurrent access. The solution is to place the SQLite database on a local filesystem — either a local Persistent Volume (PV), a hostPath volume, an emptyDir, or a block storage volume (EBS, Persistent Disk) that provides proper POSIX file locking semantics.
Why SQLite Fails on NFS
SQLite uses POSIX advisory locks (fcntl()) to coordinate read/write access. NFS has several problems with this:
- Advisory locks are not enforced: NFS advisory locks do not prevent other processes from writing. A second process can modify the database file even while it is locked.
- Lock state can be lost silently: If the NFS server restarts or the network connection drops, lock state is lost without notification. SQLite believes it still holds the lock.
- Stale file handles: NFS caches file data aggressively. SQLite may read stale data after another process writes, leading to corruption.
Solution 1: Local Persistent Volume
Use a local PersistentVolume backed by a disk on a specific Kubernetes node.
Solution 2: Cloud Block Storage (EBS, Persistent Disk)
Cloud block storage volumes (AWS EBS, GCP Persistent Disk, Azure Disk) attach as local block devices and provide proper file locking.
Solution 3: hostPath Volume (Development Only)
hostPath uses the node's local filesystem directly. This is simple but the data is tied to a specific node and lost if the pod moves.
Solution 4: emptyDir (Ephemeral)
emptyDir provides a local filesystem but data is deleted when the pod is removed. Use this only for caches or temporary databases that can be rebuilt.
SQLite Configuration for Kubernetes
Common Pitfalls
- Running multiple replicas with SQLite: SQLite supports only one writer at a time. Running multiple pod replicas all writing to the same database causes "database is locked" errors or corruption. Use
replicas: 1or switch to PostgreSQL/MySQL for multi-replica deployments. - Using
ReadWriteManyaccess mode:ReadWriteMany(RWX) volumes are typically NFS or CephFS — exactly the filesystems that break SQLite. SQLite requiresReadWriteOnce(RWO) volumes with local or block storage. - Forgetting node affinity with local PVs: Local PersistentVolumes are tied to a specific node. Without node affinity configuration, the pod may be scheduled on a different node where the volume does not exist, causing the pod to stay in
Pendingstate. - Not setting
PRAGMA journal_mode=WAL: The default journal mode (DELETE) is slower and more prone to lock contention. WAL (Write-Ahead Logging) mode allows concurrent readers while writing and is strongly recommended for any server-side SQLite usage. - Data loss with
emptyDiron pod restart:emptyDirdata is deleted when the pod is removed (not just restarted in place). For persistent data, use a PersistentVolumeClaim withlocalor block storage. Only useemptyDirfor caches or throwaway data.
Summary
- Never use SQLite on NFS — advisory locks do not provide the guarantees SQLite needs
- Use local PersistentVolumes or cloud block storage (EBS, Persistent Disk) with
ReadWriteOnceaccess mode - Limit SQLite deployments to single-replica pods (one writer)
- Enable WAL journal mode and set
busy_timeoutfor better concurrency handling - For multi-replica or high-concurrency workloads, switch to a client-server database like PostgreSQL
Related reading
- How to point ApiGateway to a specific Lambda alias
- How to prevent a DynamoDB item being overwritten if an entry already exists
- How to prevent a DynamoDB item being overwritten if an entry already exists
- How to prevent duplicate SQS Messages?
- How to post messages to RabbitMQ from SQL Server?
- How to prepend a string to a column value in MySQL?
- How to process SQS queue with lambda function not via scheduled events?
- How to properly delete with AWS CDK

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.