Redis and SQLite both store data, but they’re built for different jobs: Redis is a key-value server, and SQLite is a SQL database in a file. In this article I’ll walk you through the same tasks in both, so you can see which job each one is built for.
TLDR
- SQLite is a relational SQL database stored in one file and used as a library. Redis is a key-value data-structure server you reach over the network.
- Use SQLite when you need to query data in flexible ways, such as joins, and keep it durably on disk.
- Use Redis for fast lookups by key, including values that expire on their own and counters shared between processes.
- Many apps use both: SQL for the records, and Redis as a fast cache in front of it.
What is SQLite?
SQLite is a relational database engine that runs inside your program and keeps the whole database in one file. You store rows in tables and query them with SQL, including joins and aggregates. It “implements serializable transactions that are atomic, consistent, isolated, and durable” (SQLite is transactional).
What is Redis?
Redis is a key-value data-structure server. You read and write values by key, and a value can be a structure such as a hash or a set. Redis saves its data to disk according to its persistence settings (Redis persistence).
SQLite vs Redis at a glance
The core differences fit in one table:
| SQLite | Redis | |
|---|---|---|
| Model | Tables queried with SQL; column types are a preference unless the table is STRICT | Keys holding values such as strings, hashes and sets |
| Query by a non-key field | Any column, any time (index it for speed) | Only through structures you maintain, such as a set per value |
| Expiring data | A timestamp column plus a DELETE you run | Built in: SET … EX / EXPIRE |
| Counters | UPDATE … SET n = n + 1 in a transaction | INCR, O(1) (INCR) |
| Durability | ACID transactions | Configurable: RDB snapshots and/or an append-only file |
| Access | A library in your process | A server reached over the network |
Differences that matter
To show you the difference, I will run the same tasks against SQLite and a Redis server with its default settings. Lines starting with sqlite> or redis> show the command. redis-cli ran non-interactively, so it prints bare values. There are no speed benchmarks.
Storing and finding records
In SQLite you store rows and filter on any column:
sqlite> CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, country TEXT, logins INTEGER DEFAULT 0);
sqlite> INSERT INTO users (name, country) VALUES ('ada', 'UK'), ('grace', 'US'), ('linus', 'FI'), ('guido', 'NL'), ('margaret', 'US');
sqlite> SELECT name FROM users WHERE country = 'US' ORDER BY name;
name
--------
grace
margaret
In Redis you store each record under a key, often as a hash. There’s no “WHERE country = ‘US’”, so an index you want later has to be maintained by hand. Here it’s a set of user IDs per country:
redis> HSET user:1 name ada country UK
2
redis> HSET user:2 name grace country US
2
redis> HSET user:5 name margaret country US
2
redis> HGETALL user:2
name
grace
country
US
redis> SADD country:US 2 5
2
redis> SMEMBERS country:US
2
5
Counters
Both are safe under concurrency. SQLite updates inside a transaction, and Redis’s INCR “Increments the number stored at key by one” in O(1) (INCR):
sqlite> UPDATE users SET logins = logins + 1 WHERE id = 1 RETURNING logins;
logins
------
1
redis> INCR logins:user:1
1
redis> INCR logins:user:1
2
Expiring data
Redis can “Set a timeout on key” (EXPIRE), and the key disappears on its own. In SQLite you store an expiry time and delete expired rows yourself, here with fixed timestamps:
redis> SET session:abc user:1 EX 60
OK
redis> TTL session:abc
60
sqlite> CREATE TABLE sessions (token TEXT PRIMARY KEY, user_id INTEGER, expires_at INTEGER);
sqlite> INSERT INTO sessions VALUES ('abc', 1, unixepoch('2026-10-06 12:00:00') + 60);
sqlite> DELETE FROM sessions WHERE expires_at < unixepoch('2026-10-06 12:05:00') RETURNING token;
token
-----
abc
The TTL result can read 59 on a slower run.
Ad-hoc questions
Questions you didn’t plan for are where SQL wins. Counting users per country takes one statement in SQLite. In Redis you’d have to maintain a counter or set for that question in advance:
sqlite> SELECT country, count(*) AS users FROM users GROUP BY country HAVING count(*) > 1;
country users
------- -----
US 2
JSON documents
Both can store and query JSON. Redis’s JSON capability “lets you store, update, and retrieve JSON values in a Redis database, similar to any other Redis data type” (Redis JSON). SQLite stores JSON as text and reads it with JSON functions:
redis> JSON.SET profile:1 $ {"name":"ada","tags":["admin","beta"]}
OK
redis> JSON.GET profile:1 $.tags[0]
["admin"]
sqlite> SELECT json_extract('{"name":"ada","tags":["admin","beta"]}', '$.tags[0]') AS first_tag;
first_tag
---------
admin
More in SQLite JSON.
Durability
Redis offers “RDB (Redis Database): RDB persistence performs point-in-time snapshots of your dataset at specified intervals” and “AOF (Append Only File): AOF persistence logs every write operation received by the server” (Redis persistence). The default image used here has the append-only file off, and the snapshot rules 3600 1 300 100 60 10000. Each pair is seconds and a minimum number of changes:
redis> CONFIG GET appendonly
appendonly
no
redis> CONFIG GET save
save
3600 1 300 100 60 10000
A clean stop keeps the data. When Redis receives SIGTERM, “the same shutdown sequence is performed” as for the SHUTDOWN command, which includes “Perform a blocking SAVE if at least one save point is configured” (SHUTDOWN). I restarted my test container, and the key survived:
redis> SET greeting hello
OK
$ docker restart sqldocs-redis # stop and start the Redis server
redis> GET greeting
hello
A crash is different. With snapshots only, the Redis docs warn that “in case of Redis stopping working without a correct shutdown for any reason you should be prepared to lose the latest minutes of data”. Turn on AOF if Redis holds data you can’t rebuild. SQLite’s transactions are durable “even if the transaction is interrupted by a program crash, an operating system crash, or a power failure to the computer” (SQLite is transactional).
When to use SQLite and when to use Redis
Pick by how you look the data up and how long it has to live:
- SQLite: records you query by many fields, and reports that need joins. If many machines write, consider a client/server SQL database (Appropriate Uses For SQLite).
- Redis: sessions and caches shared by several app servers, plus counters and rate limits.
- Both: SQL as the source of truth, with Redis as a fast cache in front of it.
Conclusion
SQLite and Redis aren’t competitors. SQLite is a durable SQL database in a file, and Redis is a server for fast lookups by key and data that expires. Use SQLite for records you need to query, and add Redis when you need shared caches or counters.
Further reading
- SQLite vs PostgreSQL
- SQLite date and time (for expiry columns)
- SQLite CREATE INDEX
- SQLite JSON
- Redis docs: persistence
Tested with SQLite 3.51.0 and Redis 8.10.2 (redis:8-alpine, default settings) on 7 October 2026.
