What is TinyDB?
TinyDB is a pure-Python, document-oriented database that stores your data as a single human-readable JSON file — with no server, no schema definition, and no dependencies beyond the standard library. You install it with pip install tinydb, create a database with one line (db = TinyDB('data.json')), and immediately insert, query, update, and delete Python dictionaries. It is the right tool for prototypes, command-line utilities, config storage, and small apps holding up to roughly 10,000 documents; past that point its maintainers explicitly recommend moving to SQLite, because TinyDB loads and rewrites the whole file in Python rather than using indexes.
That's the summary an AI Overview can give you. What it can't show you is where TinyDB fits versus the alternatives you'll actually compare it against, the exact five-step lifecycle of a TinyDB app, and the one API change that breaks almost every older tutorial online. Those are below — a decision table, an animated flow diagram, and a working end-to-end script tested against the current TinyDB 4.x API.
TinyDB vs. SQLite vs. shelve vs. a plain JSON file
The real question is never "how do I use TinyDB" — it's "should I use TinyDB or one of the three things it's usually mistaken for." Here is the honest comparison:
| Factor | TinyDB | SQLite (sqlite3) | shelve | Plain JSON file |
|---|---|---|---|---|
| Storage format | Human-readable JSON | Binary .db file | Binary pickle | Human-readable JSON |
| Query language | Python Query objects | Full SQL | Key lookup only | Manual dict/list code |
| Indexes / speed at scale | None — linear scan | B-tree indexes, very fast | Key-based only | None |
| Schema required | No | Yes (tables/columns) | No | No |
| Dependencies | pip install tinydb | Built into Python | Built into Python | Built into Python |
| Concurrent writes | Not safe (rewrites file) | Safe (locking, WAL) | Not safe | Not safe |
| Practical ceiling | ~10,000 documents | Millions of rows | Small key sets | A few hundred KB |
| Use it when… | You want queryable, readable storage for a small app or prototype fast | You need speed, indexes, or concurrent access | You just need to persist Python objects by key | You have static config or a tiny flat list |
The short version: if you're reaching for a JSON file and finding yourself writing loops to filter it, TinyDB is the upgrade. If you're pushing past ~10k records, feeling slow queries, or need multiple writers, SQLite is the upgrade from TinyDB.
The TinyDB lifecycle at a glance
Every TinyDB program follows the same five-stage loop. This diagram shows it end to end:
Key advantages of TinyDB include:
- Zero configuration required
- Human-readable JSON storage format
- Built-in query system
- Thread-safe operations
- Pure Python implementation
Installing TinyDB
Before installing TinyDB, it's recommended to set up a virtual environment for your Python project. This ensures clean dependency management and prevents conflicts with other projects.
# For Python 3
pip install tinydb
# Alternative for systems with both Python 2 and 3
pip3 install tinydb
If you don't have pip installed or are unsure which Python version you're using, check out our comprehensive Python Basics guide for setup instructions.
Getting Started with TinyDB
TinyDB operates entirely with JSON data structures using key/value pairs. For this tutorial, we'll build a to-do list application that stores:
- Task description
- Due date
- Completion status
- Category classification
Basic Setup
# Import TinyDB and Query modules
from tinydb import TinyDB, Query
# Create database instance (creates todolist.json file)
db = TinyDB('todolist.json')
# Define sample records
item1 = {'Status':'New','DueDate': '5/12/18', 'Category': 'Work','Description':'Send that Email'}
item2 = {'Status':'New','DueDate': '5/11/18', 'Category': 'Home','Description':'Do the Laundry'}
item3 = {'Status':'New','DueDate': '5/11/18', 'Category': 'Home','Description':'Do the Dishes'}
Inserting Records
Adding data to TinyDB is straightforward using the insert() method. You can insert predefined variables or create records directly within the function call:
# Insert using predefined variables
db.insert(item1)
db.insert(item2)
db.insert(item3)
# Insert directly without variables
db.insert({'Status':'New','DueDate': '5/14/18', 'Category': 'Work','Description':'Request a Promotion'})
# Verify insertion by displaying all records
print(db.all())
Searching and Querying Records
TinyDB provides powerful search capabilities for filtering records based on specific criteria. Here are common search patterns:
# Create Query object
Todo = Query()
# Single criteria search
home_tasks = db.search(Todo.Category == 'Home')
# Multiple criteria with AND condition
work_urgent = db.search((Todo.Category == 'Work') & (Todo.DueDate == '5/14/18'))
# Multiple criteria with OR condition
urgent_or_home = db.search((Todo.Category == 'Home') | (Todo.DueDate == '5/14/18'))
# Store search results and iterate
results = db.search(Todo.Category == 'Home')
for result in results:
print(result)
Updating and Deleting Records
TinyDB makes it easy to update existing records or remove completed tasks from your database:
Updating Records
# Update all Home category tasks to Done status
db.update({'Status': 'Done'}, Todo.Category == 'Home')
Deleting Records
# Remove all completed tasks
db.remove(Todo.Status == 'Done')
# Clear entire database (useful for testing)
db.truncate()
Watch out — the
db.purge()trap. If you follow an older tutorial, you'll seedb.purge()used to empty the database. That method was removed in TinyDB 4.0 (February 2020) and now raisesAttributeError: 'TinyDB' object has no attribute 'purge'. On any current version (4.x and later), usedb.truncate()to clear all records. This single rename is the most common reason copied TinyDB snippets fail today.
Complete Example Script
Here's a comprehensive example that demonstrates all TinyDB operations in a single script:
# Complete TinyDB example script
from tinydb import TinyDB, Query
# Initialize database
db = TinyDB('todolist.json')
Todo = Query()
# Create sample data
item1 = {'Status':'New','DueDate': '5/12/18', 'Category': 'Work','Description':'Send that Email'}
item2 = {'Status':'New','DueDate': '5/11/18', 'Category': 'Home','Description':'Do the Laundry'}
item3 = {'Status':'New','DueDate': '5/11/18', 'Category': 'Home','Description':'Do the Dishes'}
# Insert records
db.insert(item1)
db.insert(item2)
db.insert(item3)
db.insert({'Status':'New','DueDate': '5/14/18', 'Category': 'Work','Description':'Request a Promotion'})
# Display all records
print("All records:")
print(db.all())
# Update Home category tasks to Done
db.update({'Status': 'Done'}, Todo.Category == 'Home')
# Search and display Home category tasks
print("\nHome category tasks:")
results = db.search(Todo.Category == 'Home')
for result in results:
print(result)
# Remove completed tasks
db.remove(Todo.Status == 'Done')
# Show remaining records
print("\nRemaining records:")
print(db.all())
Best Practices and Tips
💡 Pro Tips for TinyDB Success
- Use descriptive field names for better code readability
- Implement data validation before inserting records
- Consider using TinyDB's memory storage for temporary data
- Back up your JSON files regularly in production environments
- Use the
truncate()method (not the removedpurge()) during testing to reset your database - Move to SQLite once you cross ~10,000 documents or need concurrent writers — see the comparison table above
When to graduate off TinyDB
TinyDB earns its place at the start of a project. The moment you notice queries lagging, the JSON file ballooning past a megabyte or two, or a second process trying to write at the same time, those are the signals to migrate. Python's built-in sqlite3 module is the natural next step: it keeps your data in a single file like TinyDB, needs no server, but adds real indexes, SQL, and safe concurrent access. Because your TinyDB records are already plain dictionaries, exporting them to SQLite rows or to CSV is usually a short loop — and if you're moving between formats often, our JSON-to-CSV conversion guide covers the round trip.