TONL vs SQLite for Local Structured Data and LLM Apps
SQLite gives you a query engine in a file; TONL gives you queries, schema, streaming, and an LLM-ready text format with zero dependencies. Here's how to choose between them.
Use SQLite when you need multi-table relational queries, ACID transactions, or concurrent writes. Use TONL when your data must also feed directly into an LLM prompt — TONL saves 32–50% of tokens versus JSON, ships a SQL-like query API with sub-0.1ms indexed lookups, and streams 50GB-plus files in under 100MB of memory, all with zero runtime dependencies.
What Problem Does Each Tool Actually Solve?
SQLite and TONL look similar from a distance — both let you store structured data locally without a server, query it with filter expressions, and validate schemas. But they were designed for fundamentally different constraints, and the difference shows up the moment you need to feed your data to a language model.
SQLite is a mature, battle-tested relational database engine. Its storage format is a binary B-tree file optimized for concurrent reads and writes, multi-table joins, and ACID-compliant transactions. It has been embedded in browsers, phones, and operating systems for over two decades. It knows nothing about token counts, LLM context windows, or prompt efficiency.
TONL (Token-Optimized Notation Language) is a text-first format designed from the ground up to be both machine-queryable and LLM-promptable. The same bytes you store on disk are the bytes you drop into a prompt. There is no serialization step between "query the data" and "feed the data to the model." That property is architecturally significant for AI applications: the fewer transformation steps between storage and the prompt, the less room for bugs and the less latency in your pipeline.
For a deeper look at TONL's design, see the introduction to TONL and the architecture overview.
Side-by-Side: The Same Query in TONL and SQL
To make the comparison concrete, consider a local product catalog — 500 records, each with an ID, name, category, price, and availability flag. You want all in-stock electronics priced under $100. Here is the same operation expressed as a TONL query and as the equivalent SQLite SQL:
// === The dataset ===
// SQLite — stored as a binary .db file; you must open a connection,
// run the query, fetch rows, then serialize to text before prompting an LLM.
CREATE TABLE products (
id INTEGER PRIMARY KEY,
name TEXT,
category TEXT,
price REAL,
in_stock INTEGER -- 1 = true, 0 = false
);
SELECT id, name, price
FROM products
WHERE category = 'electronics'
AND in_stock = 1
AND price < 100
ORDER BY price ASC;
// Then: serialize result rows to JSON/CSV/text → insert into prompt.
// Extra step. Extra code. Extra latency.
// === TONL — stored as a .tonl text file ===
// The stored format IS the prompt format. No intermediate serialization.
products[500]{id:u32, name:str, category:str, price:f32, in_stock:bool}:
1, "Wireless Mouse", electronics, 29.99, true
2, "HDMI Cable 2m", electronics, 12.49, true
3, "4K Monitor 27in", electronics, 349.00, true
4, "USB-C Hub", electronics, 49.99, true
// ... 496 more rows ...
// TONL query — same intent, runs in the same process, result is TONL text
QUERY products
SELECT id, name, price
WHERE category = "electronics"
AND in_stock = true
AND price < 100
ORDER BY price ASC
// Result is already TONL — paste directly into the LLM prompt.The TONL query result is TONL text. You pass it straight to the model. With SQLite you have an extra step: fetch rows as a language-native data structure, then serialize that structure to whatever text format you want in the prompt. For a one-off script that step is trivial. For a production pipeline called thousands of times per day, it is a maintenance surface.
TONL vs SQLite: Full Feature Comparison
| Dimension | TONL | SQLite |
|---|---|---|
| Storage form | Plain text (.tonl) — human-readable, diff-friendly, version-control friendly | Binary B-tree file (.db / .sqlite) — not human-readable, not diff-friendly |
| Query engine | Built-in SQL-like query API; sub-0.1ms indexed lookups; filtering, projection, aggregation | Full SQL (SELECT, JOIN, GROUP BY, subqueries, CTEs, window functions); mature and battle-tested |
| LLM-promptable directly | Yes — stored format is the prompt format; no serialization step | No — binary format must be serialized to text (JSON, CSV, etc.) before prompting |
| Token efficiency vs JSON | 32–50% fewer tokens; up to ~60% with optional compression layers | Not applicable — binary format; token cost depends on how you serialize the query result |
| Schema & types | Type hints (u32, str, bool, f32); schema validation at parse time; auto TypeScript generation | Column types (INTEGER, TEXT, REAL, BLOB, NUMERIC); strict mode optional; no TypeScript generation |
| Runtime dependencies | Zero (tonl npm package is self-contained) | Requires a SQLite binding (better-sqlite3, sql.js, node:sqlite in Node 22+) |
| Streaming large files | 50GB+ files in under 100MB memory via built-in streaming API | Streaming via cursor/iterator; memory use depends on result set size |
| CRUD & change-tracking | Full CRUD with change-tracking and rollback built into the package | Full CRUD; transactions and rollback via SQL; no built-in change-tracking log |
| Multi-table joins | Not supported — single-block or multi-block, no foreign-key joins | Full JOIN support (INNER, LEFT, CROSS, etc.) |
| Concurrent write access | Single-writer model (text file); concurrent reads are fine | WAL mode supports one writer + multiple concurrent readers; full transaction isolation |
| Best workload | Single-process read-heavy apps where data feeds LLM prompts; AI pipelines; edge/serverless | Relational apps; multi-table normalized schemas; heavy write workloads; non-LLM use cases |
Where SQLite Wins: Be Honest About the Trade-offs
SQLite is a better choice in several situations, and pretending otherwise would be misleading.
Multi-table relational data. If your schema has foreign keys, normalized tables, and queries that join across them, SQLite's full SQL engine is irreplaceable. TONL has no JOIN operation. You could flatten the data before writing it to TONL, but that trades normalization for convenience — a decision only you can make based on your write patterns.
High write throughput. TONL uses a text file as its backing store, which means write operations involve reading, modifying, and rewriting file sections. SQLite's B-tree engine is purpose-built for efficient random writes and WAL-mode concurrency. If your application writes thousands of rows per second from multiple processes, SQLite wins by a large margin.
Existing SQL tooling. The ecosystem around SQLite is vast: DB Browser for SQLite, Beekeeper Studio, Datasette, countless ORMs and query builders. If your team already operates in that ecosystem, the switching cost to TONL is real.
Non-LLM applications. If your local data never touches an LLM, TONL's primary differentiator — LLM-ready text representation — does not matter to you. SQLite is the more mature general-purpose choice.
Where TONL Wins: LLM Apps, Edge, and Zero-Dependency Pipelines
TONL's advantages are most pronounced in a specific class of application: one where the same dataset is both queried programmatically and fed to a language model.
Prompt efficiency. Every token you remove from a prompt reduces cost and increases the headroom for instructions, retrieved context, and model reasoning. According to tonl.dev, TONL saves 32–50% of tokens versus JSON. Even at the conservative end, cutting input tokens by a third on every call adds up quickly in a high-volume pipeline. The optional compression layers can push savings to roughly 60% for datasets with repeated strings, sequential timestamps, or small-range integers.
No serialization gap. The TONL query result is TONL text. You pass the output of QUERY products SELECT ... WHERE ... directly into the prompt. There is no intermediary step of calling JSON.stringify, writing a CSV serializer, or building a markdown table. The format that lives on disk is the format the model reads.
Edge and serverless environments. Zero runtime dependencies means TONL installs as a single npm package with no native bindings, no platform-specific build step, and no .node file that causes deployment failures on Lambda, Cloudflare Workers, or Vercel Edge Functions. SQLite bindings like better-sqlite3 require native compilation and cannot run in all serverless environments.
Version-controlled datasets. TONL files are plain text. They diff cleanly in Git, can be reviewed in pull requests, and are editable in any text editor. SQLite binary files do not diff, which makes reviewing data changes in code review impossible without a specialized tool.
For the TOON vs TONL comparison — including when to use the lighter-weight TOON format instead — see the TOON vs TONL guide.
A Practical Decision Framework
The choice between TONL and SQLite is not about which tool is technically superior — it is about which constraints matter most for your specific application. Work through these questions:
- Does the data need to go into an LLM prompt? If yes, TONL's native text representation removes an entire transformation layer and saves 32–50% of tokens.
- Do you need multi-table JOINs? If yes, SQLite. TONL has no JOIN support.
- Are you on a serverless or edge platform? If yes, TONL's zero-dependency model is significantly easier to deploy.
- Do you have high concurrent write throughput? If yes, SQLite's WAL engine handles this better than a text file.
- Does your team need to review data changes in Git? TONL files are diffable; SQLite binary files are not.
- Do you need 50GB-plus file streaming? TONL's built-in streaming API handles this in under 100MB of memory per tonl.dev. SQLite can handle large files too, but through a different cursor-based mechanism.
For many AI applications the answer is "TONL for the LLM-facing data layer, SQLite (or Postgres) for the relational business logic layer." They are not mutually exclusive. A common pattern is to query your SQLite database, project the columns you need, and serialize that slice to TONL for the prompt — combining the relational power of SQL with the token efficiency of TONL for the context window.
To see how TONL looks compared to simpler formats like TOON, read the introduction to TOON before committing to the fuller TONL stack.
Frequently Asked Questions
Should I use TONL or SQLite for local data?
Use SQLite when you need multi-table relational queries, ACID transactions, or concurrent writes from multiple processes. Use TONL when you also need to feed the data directly into an LLM prompt without a serialization step — TONL saves 32–50% of tokens versus JSON and ships a SQL-like query API with sub-0.1ms indexed lookups.
Can TONL replace a database for small LLM apps?
For single-process read-heavy apps where the data also needs to go into an LLM context, yes. TONL's built-in query API supports filtering, field selection, and aggregation with sub-0.1ms indexed lookups. It also supports CRUD with change-tracking and rollback. For multi-table joins, concurrent writes, or large write-heavy workloads, SQLite remains the better choice.
How does TONL handle large files compared to SQLite?
TONL's streaming API processes files larger than 50GB in under 100MB of memory, according to tonl.dev. SQLite also handles large databases well but requires loading query results into memory and then re-serializing to a text format before feeding an LLM. TONL eliminates that re-serialization step since the stored format is already LLM-ready.
Does TONL have schema validation like SQLite column types?
Yes. TONL supports type hints (u32, str, bool, f32) that enable schema validation at parse time and automatic TypeScript type generation. The type hints add roughly 20 tokens to a block header but keep the total representation 32% smaller than untyped JSON, according to tonl.dev.
Is TONL suitable for production use without a database?
TONL v2.5.2 ships with 2,300-plus tests passing and zero runtime dependencies, as documented on tonl.dev and the GitHub repository. Its query API, streaming, schema validation, and CRUD with change-tracking are all covered by that test suite. Whether it replaces a database depends on your write patterns and whether you need relational joins — not on stability.
Recommended Reading
Querying Data Without a Database: TONL's SQL-Like Query API
TONL ships a SQL-like query API with sub-0.1ms indexed lookups. Learn how to filter, aggregate, and join structured data without spinning up a database.
Inside TONL Compression: Dictionary, Delta, RLE & Bit Packing
TONL's optional compression layers push token savings toward 60%. A tour of Dictionary, Delta, RLE, Bit Packing, Column Reorder, and Quantizer—and when each one pays off.
Why LLMs Agree With You (And How TONL Helps)
Understand the 'sycophancy' problem in LLMs and learn how the TONL data platform provides the ground truth needed to build assertive, reliable AI systems.