Polyglot
Languages SQLite io
SQLite § io

The shell and C API

This page documents the two principal interfaces to SQLite: the sqlite3 command-line shell and the C API. The shell is the canonical interactive client, useful for ad-hoc queries, schema inspection, import and export, and benchmarking. The C API is the engine’s programmatic interface, the lowest layer through which every application — including the high-level language bindings — reads and writes the database. Understanding both gives a working programmer the full surface.

The sqlite3 shell

The sqlite3 shell is a small, statically linked executable that ships with the SQLite distribution. It is invoked with the database file as an argument:

sqlite3 example.db

The shell opens the database (creating it if absent), enters interactive mode, and accepts SQL statements. A statement ends with a semicolon; the shell executes it and prints the result. Multi-line statements are accumulated until the semicolon is read. The prompts sqlite> and ...> indicate top-level and continuation respectively.

SQLite version 3.46.0 2026-04-15 …
Enter ".help" for usage hints.
sqlite> SELECT count(*) FROM customer;
12
sqlite> CREATE TABLE event (
   ...> id INTEGER PRIMARY KEY,
   ...> payload TEXT
   ...> );
sqlite> .quit

A non-interactive form takes the SQL from stdin or from a file:

echo 'SELECT count(*) FROM customer;' | sqlite3 example.db
sqlite3 example.db < migrations/001-initial.sql
sqlite3 example.db 'SELECT count(*) FROM customer'

The shell’s exit status reflects the result of the last statement; a non-zero exit indicates an error.

Dot commands

Dot commands are shell directives, not SQL. They begin with a period at the start of the line and are processed by the shell rather than the engine. The principal dot commands:

CommandPurpose
.helpShow the dot-command reference.
.tables [pattern]List tables (with optional glob pattern).
.schema [table]Show the CREATE TABLE statement.
.indexes [table]List indexes.
.databasesList attached databases.
.headers on/offToggle column-header output.
.mode <mode>Set output mode (column, csv, tabs, json, markdown, table, box, quote, insert, tcl, line, list).
.separator <s>Column separator (default `
.read <file>Execute SQL from a file.
.dump [table]Output the schema and data as SQL.
.import <file> <table>Import a CSV or other-formatted file.
.output <file>Redirect output to a file (or stdout to revert).
.timer on/offShow wall-clock and CPU time per statement.
.eqp on/offEnable EXPLAIN QUERY PLAN for every statement.
.changes on/offShow the count of rows changed by INSERT/UPDATE/DELETE.
.load <library>Load an extension.
.open <file>Switch to a different database file.
.shell <cmd>Run a shell command (and .system <cmd>).
.quit, .exitExit the shell.
sqlite> .mode column
sqlite> .headers on
sqlite> SELECT id, name FROM customer LIMIT 3;
id  name
--  ----
1   Ada
2   Donald
3   Grace

sqlite> .mode json
sqlite> SELECT id, name FROM customer LIMIT 1;
[{"id":1,"name":"Ada"}]

sqlite> .timer on
sqlite> SELECT count(*) FROM event;
1234567
Run Time: real 0.045 user 0.034000 sys 0.011000

The .mode markdown and .mode table modes produce nicely formatted output suitable for documentation; .mode csv is the conventional export format. The full set is at sqlite.org/cli.html.

Importing and exporting

The shell is a convenient mechanism for moving data between SQLite and CSV:

# Export
sqlite> .headers on
sqlite> .mode csv
sqlite> .output customers.csv
sqlite> SELECT * FROM customer;
sqlite> .output stdout

# Import
sqlite> .mode csv
sqlite> .import customers.csv customer

The .import command creates the table if it does not exist (using the first row as column names if .headers on) or appends to an existing table.

For a full database export — a self-contained SQL script that recreates the schema and data — the .dump command produces a complete reproduction:

sqlite3 example.db .dump > backup.sql
sqlite3 restored.db < backup.sql

The output is a sequence of CREATE TABLE and INSERT statements wrapped in a transaction; restoring is a matter of feeding the script to a new database. The .dump form is the canonical text-based backup.

For a binary backup — a copy of the database file — VACUUM INTO is the recommended mechanism (see Schemas and ATTACH). It produces a compacted, consistent snapshot that opens identically to the original.

Configuration files and pragmas

The shell reads ~/.sqliterc (or the file pointed to by $SQLITE_HISTORY) at startup and executes its contents. The conventional content sets pleasant defaults:

.mode column
.headers on
.timer on
PRAGMA foreign_keys = ON;

Every connection then opens with the configured pragmas and presentation. The shell also reads command-line flags -bail, -readonly, -batch, -init <file>, and others; the manual page enumerates them.

The C API

The C API is the engine’s programmatic surface. The principal entry points fall into three groups: connection management, statement execution, and result inspection.

Opening a connection

sqlite3 *db;
int rc = sqlite3_open_v2("example.db", &db,
                         SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
                         NULL);
if (rc != SQLITE_OK) {
    fprintf(stderr, "open failed: %s\n", sqlite3_errmsg(db));
    sqlite3_close(db);
    return 1;
}

sqlite3_open_v2 takes a flag set: SQLITE_OPEN_READONLY, SQLITE_OPEN_READWRITE, SQLITE_OPEN_CREATE (auto-create), SQLITE_OPEN_URI (interpret the filename as a URI), SQLITE_OPEN_FULLMUTEX (full thread safety), and others. The simpler sqlite3_open defaults to READWRITE | CREATE and is the historical entry point.

sqlite3_close releases the connection. The matching call sqlite3_close_v2 accepts unfinalised statements; it is the recommended form for application code.

Executing a statement

The conventional pattern: prepare, bind, step, finalise.

sqlite3_stmt *stmt;
rc = sqlite3_prepare_v2(db,
    "INSERT INTO customer (name, email) VALUES (?, ?)",
    -1, &stmt, NULL);
if (rc != SQLITE_OK) { /* … */ }

sqlite3_bind_text(stmt, 1, "Ada Lovelace", -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 2, "ada@example.com", -1, SQLITE_STATIC);

rc = sqlite3_step(stmt);
if (rc != SQLITE_DONE) { /* … */ }

sqlite3_finalize(stmt);

The sqlite3_prepare_v2 call compiles the SQL into a reusable virtual-machine program. The sqlite3_bind_* calls supply parameter values. The sqlite3_step call runs the program; for a statement that returns rows (a SELECT), each step returns SQLITE_ROW until the rows are exhausted. The sqlite3_finalize call releases the prepared statement.

The bind functions take a 1-based parameter index and a value:

FunctionParameter type
sqlite3_bind_int(stmt, i, v)32-bit integer
sqlite3_bind_int64(stmt, i, v)64-bit integer
sqlite3_bind_double(stmt, i, v)Double-precision float
sqlite3_bind_text(stmt, i, s, n, free)UTF-8 string
sqlite3_bind_text16(stmt, i, s, n, free)UTF-16 string
sqlite3_bind_blob(stmt, i, b, n, free)BLOB
sqlite3_bind_null(stmt, i)NULL
sqlite3_bind_zeroblob(stmt, i, n)A zero-filled BLOB of n bytes

The free parameter is SQLITE_STATIC if the buffer outlives the statement, SQLITE_TRANSIENT if SQLite should make a private copy, or a function pointer that SQLite calls to release the buffer.

Reading rows

sqlite3_prepare_v2(db, "SELECT id, name FROM customer", -1, &stmt, NULL);
while (sqlite3_step(stmt) == SQLITE_ROW) {
    int  id   = sqlite3_column_int(stmt, 0);
    const unsigned char *name = sqlite3_column_text(stmt, 1);
    printf("%d %s\n", id, name);
}
sqlite3_finalize(stmt);

The column functions take a 0-based index and return the value:

FunctionReturns
sqlite3_column_int32-bit integer
sqlite3_column_int6464-bit integer
sqlite3_column_doubleDouble
sqlite3_column_textUTF-8 text (lifetime: until next step or finalize)
sqlite3_column_blobBLOB
sqlite3_column_bytesLength of text or BLOB
sqlite3_column_typeOne of SQLITE_INTEGER, SQLITE_FLOAT, SQLITE_TEXT, SQLITE_BLOB, SQLITE_NULL

The buffers returned by sqlite3_column_text and sqlite3_column_blob are owned by the engine and are valid only until the next sqlite3_step or sqlite3_finalize. A caller that needs the value after the statement must copy it.

Convenience: sqlite3_exec

For one-off statements that do not return rows or where the result is processed by a callback, sqlite3_exec is a convenient shortcut:

char *err = NULL;
rc = sqlite3_exec(db,
    "BEGIN; INSERT INTO event (payload) VALUES ('x'); COMMIT;",
    NULL, NULL, &err);
if (rc != SQLITE_OK) {
    fprintf(stderr, "exec failed: %s\n", err);
    sqlite3_free(err);
}

sqlite3_exec accepts multiple semicolon-separated statements and runs each in turn. It is convenient for schema scripts and one-shot maintenance; for application queries that take parameters, the prepare/bind/step pattern is preferred.

Errors

Every API call returns a status code. The principal codes:

CodeMeaning
SQLITE_OKSuccess.
SQLITE_ROWA row is available (from sqlite3_step).
SQLITE_DONEStatement complete (from sqlite3_step).
SQLITE_ERRORGeneric error; check sqlite3_errmsg.
SQLITE_BUSYLock contention.
SQLITE_LOCKEDSelf-deadlock (same connection, multiple statements).
SQLITE_CONSTRAINTConstraint violation.
SQLITE_MISUSEAPI misuse.
SQLITE_NOTFOUNDObject (table, index, function) not found.
SQLITE_IOERRI/O error.
SQLITE_CORRUPTDatabase file is corrupted.

sqlite3_errmsg(db) returns a human-readable error string for the most recent error on the connection.

Language bindings

Every widely used programming language has a binding to the SQLite C API. The bindings layer a high-level interface — typically a connection and cursor abstraction — over the raw API. The principal bindings:

Python (sqlite3, in standard library)

import sqlite3

conn = sqlite3.connect('example.db')
conn.row_factory = sqlite3.Row
conn.execute('PRAGMA foreign_keys = ON')

with conn:                                      # implicit BEGIN/COMMIT
    cur = conn.execute(
        'INSERT INTO customer (name, email) VALUES (?, ?) RETURNING id',
        ('Ada Lovelace', 'ada@example.com'))
    new_id = cur.fetchone()[0]

for row in conn.execute('SELECT id, name FROM customer'):
    print(row['id'], row['name'])

conn.close()

Node.js (better-sqlite3)

const Database = require('better-sqlite3');
const db = new Database('example.db');
db.pragma('foreign_keys = ON');

const insert = db.prepare(
    'INSERT INTO customer (name, email) VALUES (?, ?)');
const result = insert.run('Ada Lovelace', 'ada@example.com');
console.log(result.lastInsertRowid);

const rows = db.prepare('SELECT id, name FROM customer').all();
for (const row of rows) console.log(row.id, row.name);

better-sqlite3 is the recommended Node binding; it is synchronous (a deliberate design choice that matches SQLite’s blocking API) and substantially faster than the asynchronous node-sqlite3.

Go (mattn/go-sqlite3)

import (
    "database/sql"
    _ "github.com/mattn/go-sqlite3"
)

db, _ := sql.Open("sqlite3", "example.db?_foreign_keys=on")
defer db.Close()

result, _ := db.Exec(
    `INSERT INTO customer (name, email) VALUES (?, ?)`,
    "Ada Lovelace", "ada@example.com")
id, _ := result.LastInsertId()

rows, _ := db.Query(`SELECT id, name FROM customer`)
defer rows.Close()
for rows.Next() {
    var id int
    var name string
    rows.Scan(&id, &name)
    fmt.Println(id, name)
}

mattn/go-sqlite3 uses cgo. The pure-Go alternative modernc.org/sqlite is a transpiled C-to-Go port; it is slower but builds without cgo, which is convenient for cross-compilation.

Rust (rusqlite)

use rusqlite::{Connection, params};

let conn = Connection::open("example.db")?;
conn.execute_batch("PRAGMA foreign_keys = ON;")?;

conn.execute(
    "INSERT INTO customer (name, email) VALUES (?1, ?2)",
    params!["Ada Lovelace", "ada@example.com"])?;

let mut stmt = conn.prepare("SELECT id, name FROM customer")?;
let rows = stmt.query_map([], |row| {
    Ok((row.get::<_, i64>(0)?, row.get::<_, String>(1)?))
})?;
for row in rows {
    let (id, name) = row?;
    println!("{} {}", id, name);
}

rusqlite is the conventional Rust binding; the alternative sqlx provides a higher-level query-builder surface and async support.

Other bindings

LanguageBinding
Javasqlite-jdbc (the canonical JDBC driver)
Rubysqlite3 gem
C# / .NETMicrosoft.Data.Sqlite (or System.Data.SQLite)
PHPPDO with the sqlite driver
Swiftsqlite3 (in the standard library since iOS 8)
KotlinThe Java JDBC driver, or platform-specific bindings on Android
Lualsqlite3 (LuaRocks)

The bindings expose substantially the same surface — connection, prepared statement, parameter binding, row iteration — over the underlying C API. A programmer who has learned SQLite through one binding will recognise the others.

File format

The on-disk database file is a fixed format documented at sqlite.org/fileformat2.html. The file consists of fixed-size pages (default 4096 bytes), the first of which is the header containing the format version, page size, encoding, and pointers to root pages of system tables. Subsequent pages hold table B-trees, index B-trees, free pages, and overflow chains for large rows.

The format has been backward-compatible since version 3.0 (2004): a database file written by SQLite 3.0 opens unchanged in version 3.46, and a database written by 3.46 (using only features compatible with the older version) opens in 3.0. The format is also forward-compatible in a defined sense: a database that uses a newer feature opens in older versions, with the newer feature recognised but not used. This is one of the project’s notable engineering achievements and is the basis of SQLite’s role as an application file format: a database file written today will be readable in twenty years’ time without modification.