If you’ve followed this blog, you know I have liked using MongoDB for a while – until it went to a service model on big hardware. I’ve written extensively about running MongoDB on Raspberry Pi hardware — from the Pi 3 all the way up to the Pi 5 — and it remains my go-to document database for serious projects– in the form of the Community Edition. MongoDB, though, has a real Achilles heel: it’s a hungry beast. It wants RAM, it wants a proper 64-bit system, and it simply won’t run on some of the smallest, most power-efficient hardware I love to tinker with. Enter NeoSQLite — a Python library that has quietly become one of my favorite tools.
What Is NeoSQLite?
NeoSQLite is a drop-in PyMongo replacement that stores your documents in SQLite rather than a MongoDB server. That should get your attention. It means you write the same insert_one(), find(), update_many(), and aggregation pipeline code you’d write against a real MongoDB instance — but under the hood, everything is persisted to a single database file on disk. No server daemon. No replica sets. No port forwarding. No systemctl start mongod. Just a file.
The project, maintained on GitHub at github.com/cwt/neosqlite, has evolved into something pretty impressive. Recent versions added full GridFS support with the modern GridFSBucket API, comprehensive aggregation pipeline support that runs natively in SQLite where possible — with a Python fallback for more complex operations. The library automatically detects and uses SQLite’s JSONB column type if your system supports it. NeoSQLite requires Python 3.10 or newer and prefers SQLite 3.45.0 or newer.
Why I Use It Across Three Very Different Machines
My use case spans three very different environments: a Raspberry Pi Zero, a headless Ubuntu 22.04 server, and my Mac running macOS 26.3 with Python 3.14. The exact same code runs on all three with zero changes!
On the Pi Zero especially, NeoSQLite is awesome! That little board has 512MB of RAM and no realistic path to running MongoDB — I’ve tried, and it’s not pretty. But NeoSQLite under Raspberry Pi OS– Bookworm or Trixie– installs with a single pip command, uses whatever RAM your documents actually need, and stores everything in a single SQLite file. For one of my astronomy projects, which tracks astronomical objects, observation sessions, and equipment metadata, this is perfect. The data model is naturally document-oriented — each observation is a self-contained JSON blob with nested fields — and NeoSQLite handles it beautifully without forcing me to flatten everything into relational tables.
The Ubuntu server gets the same library, and here it’s useful for a different reason: rapid prototyping. I can develop locally on the Mac, push to the server, and the database layer doesn’t change at all. When and if I ever have a project that grows sufficiently large, or that requires replica sets or shards, i.e. warrants a real MongoDB deployment, migration is straightforward — the query syntax is already MongoDB-compatible.
Getting Started
One quick Mac-specific note before diving in: macOS ships with an old system Python that you should never use for development work, and it won’t meet NeoSQLite’s Python 3.10+ requirement anyway. The cleanest solution is to install a current Python via Homebrew:
brew install python@3.14
After that, use python3.14 and pip3.14 (or set up your shell PATH accordingly) to make sure you’re working with the right version. On the Pi Zero and Ubuntu server, apt or pip installs are straightforward with no such gotcha.
Installation of NeoSQLite itself is simple (but watch out for the need for a virtual environment). I use the not recommended global install as root. You should do better – LOL.
sudo pip install neosqlite --break-system-packages
Here’s a basic example showing how natural the PyMongo-compatible API feels. This could be storing observation sessions from a sky-watching app:
import neosqlite
# Open (or create) a local database file
client = neosqlite.Connection('astro.db')
observations = client.observations
# Insert a document — just like PyMongo
observations.insert_one({
"object": "M42",
"name": "Orion Nebula",
"date": "2026-03-23",
"location": "Redwood City, CA",
"equipment": {
"telescope": "8-inch Dobsonian",
"eyepiece": "25mm Plössl"
},
"seeing": 4,
"notes": "Outstanding detail in the Trapezium cluster tonight."
})
# Query with MongoDB-style syntax
tonight = observations.find({
"seeing": {"$gte": 4},
"equipment.telescope": "8-inch Dobsonian"
})
for obs in tonight:
print(f"{obs['date']} — {obs['name']}: {obs['notes']}")
If you’ve used PyMongo before, that code needs no explanation. If you haven’t, it reads like plain Python working with dictionaries, not SQL joins and schema migrations.
Aggregation Pipelines and More Advanced Usage
NeoSQLite also supports MongoDB’s aggregation pipeline, which is where document databases really shine for analytics. Here’s an example that groups observations by object and counts them — the kind of query you might run to find your most-observed targets:
import neosqlite
client = neosqlite.Connection('astro.db')
observations = client.observations
pipeline = [
{"$match": {"seeing": {"$gte": 3}}},
{"$group": {
"_id": "$object",
"count": {"$sum": 1},
"avg_seeing": {"$avg": "$seeing"}
}},
{"$sort": {"count": -1}},
{"$limit": 5}
]
results = observations.aggregate(pipeline)
print("Most-observed objects (good seeing nights only):")
for r in results:
print(f" {r['_id']}: {r['count']} sessions, avg seeing {r['avg_seeing']:.1f}/5")
NeoSQLite’s aggregation pipeline support compiles these stages to native SQLite SQL where possible — which means it’s genuinely fast, not just a Python-level simulation — and falls back gracefully for more complex operators.
A Few Caveats
NeoSQLite is not MongoDB. If you need multi-node replication, massive concurrent write throughput, or you’re building something that ten developers will hammer simultaneously, you want the real thing. The library itself is transparent about the small number of API differences — for instance, its options() method returns detailed SQLite schema info rather than MongoDB’s empty {} response. And as with any SQLite-backed solution, it’s best suited to single-process access patterns.
But for small projects, Raspberry Pi deployments, development environments, and anything running on memory-constrained hardware, it’s a genuinely excellent tool. The fact that I can write an app’s database layer once and have it run identically on a Pi Zero, an Ubuntu server, and macOS — all without starting up a single server process — is exactly the kind of pragmatic elegance I love in open-source software.
If you’re a MongoDB fan who’s ever been frustrated by hardware constraints or deployment complexity, give NeoSQLite a serious look. You might be surprised how much of your existing PyMongo code just works. If you just want an easy-to-use, No-SQL document database, this is it!