tinySQL is an embeddable SQL database engine written in Go. It is useful for learning database internals, local tools, tests, browser/WASM applications, and single-process services that need SQL without operating a database server.
Browser playground · map demo · video
tinySQL is not a drop-in replacement for PostgreSQL, MySQL, or a clustered production database. Review limitations before using it for critical workloads.
tinySQL requires Go 1.26.5+.
go get github.com/SimonWaldherr/tinySQL@latestCreate an in-memory database and run SQL:
package main
import (
"context"
"fmt"
tinysql "github.com/SimonWaldherr/tinySQL"
)
func main() {
ctx := context.Background()
db := tinysql.NewDB()
defer db.Close()
if _, err := tinysql.ExecScript(ctx, db, "default", `
CREATE TABLE users (id INT PRIMARY KEY, name TEXT);
INSERT INTO users VALUES (1, 'Ada'), (2, 'Grace');`); err != nil {
panic(err)
}
// Bind values with ?, $1 or :1 instead of formatting SQL text.
result, err := tinysql.ExecSQLArgs(ctx, db, "default",
"SELECT id, name FROM users WHERE id >= ? ORDER BY id", 1)
if err != nil {
panic(err)
}
for _, row := range result.Rows {
fmt.Println(row["id"], row["name"])
}
}For database/sql, streaming, columnar results, transactions, and the query builder, see developer integration and the driver package.
The same engine embeds into other languages through one C ABI
(bindings/c); see the
language bindings guide.
import tinysql # make -C bindings/python build
with tinysql.connect("./data", mode="wal") as conn:
conn.execute("CREATE TABLE IF NOT EXISTS users (id INT PRIMARY KEY, name TEXT)")
conn.executemany("INSERT INTO users VALUES (?, ?)", [(1, "Ada"), (2, "Grace")])
print(conn.execute("SELECT name FROM users WHERE id = ?", (2,)).fetchone())let db = tinysql::Database::open_in_memory()?; // tinysql = { path = "bindings/rust" }
db.execute_script("CREATE TABLE users (id INT PRIMARY KEY, name TEXT)")?;
db.execute("INSERT INTO users VALUES (?, ?)", tinysql::params![1, "Ada"])?;| Goal | Start with |
|---|---|
| Explore tinySQL interactively | demo, repl, or tinysql |
| Query files or migrate data | query_files, fsql, or migrate |
| Embed a local SQL service | server or tinysqld |
| Build a browser app | query_files_wasm, wasm_browser, or wasm_node |
| Embed in a Swift / Xcode app | Swift package and Apple XCFramework for macOS, iOS and iPadOS |
| Embed in Rust, Python or C | Rust crate, Python package, C ABI |
| Use AI tooling or local RAG | tinysql-mcp-server and the RAG guide |
| Browse every runnable program | command index |
| Area | Includes |
|---|---|
| SQL | DDL/DML, CTEs, joins, grouping, windows, views, triggers, table-valued functions, stored procedures, jobs, and common SQLite-compatible PRAGMAs |
| Data | CSV/TSV, JSON/NDJSON, XML, YAML, Excel, GeoJSON, TopoJSON, KML, OSM XML, routing graphs, Shapefiles, GeoPackage, and MBTiles |
| Search | Full-text, vector, hybrid search, RAG helpers, regex, JSON, URL, HTML, date, math, bitmap, and hash functions |
| Deployment | Pure-Go embedded API, database/sql driver, Rust/Python/Swift/C bindings, CLI, HTTP/gRPC server, browser/WASM builds, and multiple storage backends |
The complete SQL function reference is FUNCTIONS.sql. Runnable feature examples are in example_showcase.sql.
Geometry is stored as GeoJSON or validated GEOMETRY; tinySQL includes measurement, predicates, editing, spatial search, choropleth classification, WKT/WKB, geohash, and Web Mercator helpers. Use the geospatial standards guide for formats, CRS profiles, coordinate conventions, and interoperability limits.
Routing functions run Dijkstra or coordinate-guided A* over ordinary edge tables. The OSM routing guide explains graph import, profiles, turn restrictions, and the HTTP demo.
For tiles, the TILE_, MBTILES_, and TILE_COVER functions support Web Mercator and OGC TileMatrix workflows. tinysqld -tiles can publish an MBTiles-shaped table; see its README and the storage guide for durable artifacts.
Vector, full-text, and hybrid retrieval can be combined with metadata filters and reranking. RAG_WARM and ROUTE_WARM prepare derived serving structures before traffic. The RAG guide covers schema design, ingestion, evaluation, tuning, caching, and context expansion.
Open persistent databases with OpenDB and a StorageConfig:
| Mode | Best fit |
|---|---|
| ModeMemory | Tests, browser/WASM, and temporary data |
| ModeWAL | In-memory tables with write-ahead-log recovery |
| ModeDisk | Per-table GOB files with lazy loading |
| ModeJSON | Human-readable, diffable per-table JSON |
| ModeIndex / ModeHybrid | Disk-backed tables with bounded caching |
| ModePagedIndex | Large equality lookups such as MBTiles |
| ModeSQLite | A .sqlite file interoperable with SQLite tools; requires sqliteimport |
For example, ModeJSON persists each table as readable JSON:
db, err := tinysql.OpenDB(tinysql.StorageConfig{
Mode: tinysql.ModeJSON,
Path: "./data",
})
if err != nil {
panic(err)
}
defer db.Close()The core has no SQLite or Shapefile runtime dependency. Build optional file support only when needed:
go build -tags=sqliteimport ./... # SQLite, GeoPackage, MBTiles
go build -tags=shapefile ./... # ESRI Shapefile and ZIP imports
go build -tags=sqliteimport,shapefile ./...For size-sensitive embeddings such as browser WASM bundles, the
tinysql_minimal tag drops optional features that pull in large
dependencies: the SQL HTTP() function (net/http, crypto/tls),
HTML_TEMPLATE() (html/template, whose reflection use
also keeps otherwise unused methods alive), standards.WriteProblem, and YAML
imports (gopkg.in/yaml.v3). The SQL functions and YAML imports return an error;
standards.WriteProblem is excluded from the API. HTML_ESCAPE(), core SQL, the
database/sql driver and the other importers are unchanged. With Go 1.27 this
shrinks the browser bundle from about 27.46 MB to 15.56 MB (43%)
before wasm-opt with stripped symbols; sizes vary with the toolchain. -tags no_http removes only
the HTTP() function.
GOOS=js GOARCH=wasm go build -tags=tinysql_minimal -trimpath -ldflags='-s -w' -o tinySQL.wasm ./cmd/wasm_browserBrowser and Node build scripts select WASM_PROFILE=minimal by default;
use WASM_PROFILE=full to include optional features. make wasm-smoke checks
both profiles for dependency exclusions, size reduction and JavaScript API
behavior, including transactions and browser snapshot imports.
See the storage guide for DSNs, persistence, read-only serving, backups, encryption scope, and large datasets.
server provides HTTP and gRPC APIs, optional TLS and bearer authentication, plus asynchronous read-only replicas. The cluster guide includes a primary/replica deployment and recovery workflow. tinysqld is the durable DBMS entry point with health, scheduler, and optional tile endpoints.
Both are deliberately smaller than a general-purpose distributed database: replication is asynchronous, and automatic failover, multi-primary writes, and distributed transactions are not implemented.
| Guide | Use it for |
|---|---|
| Developer integration | Go API, database/sql, streaming, and browser embedding |
| Language bindings | Rust, Python, Swift and C: types, transactions, persistence, performance |
| CLI guide | Shells, servers, and file-query tools |
| Storage guide | Backends, DSNs, read-only mode, and large artifacts |
| RAG guide | Vector, hybrid retrieval, reranking, and context |
| Geospatial standards | GIS formats, CRS profiles, and interoperability |
| SQL feature gaps | Supported SQL and current gaps |
| Architecture | Parser, executor, storage, and invariants |
| Development guide | Tests, Make targets, and release workflow |
| API stability | Compatibility guarantees and upgrades |
go test ./...
go vet ./...
make test-bindings # C ABI, Python package and Rust crateThe browser playground build lives in cmd/query_files_wasm:
cd cmd/query_files_wasm
./build.sh --build-only- tinySQL is embedded and single-process. The server offers asynchronous primary/replica reads, not sharding, automatic failover, multi-primary writes, or distributed transactions.
- Composite primary/foreign keys, CHECK, target-bearing ON CONFLICT DO UPDATE, SAVEPOINT, ATTACH/DETACH, VACUUM, partial indexes, generated columns, and persistent ANN index files are not available.
- Secondary indexes accelerate equality/prefix seeks and numeric ranges. Use GEO_SEARCH for indexed point-column bbox/radius queries; ordinary WHERE GEO_DWITHIN(...) predicates are not planner-accelerated.
- GIS validity is structural rather than full topology validation. GEO_DISSOLVE/GEO_UNION_AGG require clean, vertex-aligned adjacent polygons; they are not general polygon-boolean union operations.
- RBAC is coarse and single-table oriented. Encryption does not cover WAL-backed modes or metadata files.
tinySQL is primarily an educational and embeddable engine. It keeps the parser, planner, executor, storage backends, and practical extensions easy to inspect, test, and adapt.