C-style API

See also: WASM utilities, Gotchas

The C-style API actually has two flavors:

In both cases, the canonical C API documentation applies, with the exception that some APIs in the latter category have extended semantics in JavaScript, as covered throughout this document.

It is not expected that most JS clients will want or need to deal with most of these APIs because doing so can, for some commonly-used features, require careful attention to detail with regards to passing certain data between JS and WASM (notably pointer-to-pointer "output arguments" in the C APIs).

Instead, it is expected that clients will primarily use the oo1 or Worker 1 APIs, possibly falling back to the C-style APIs for innocuous routines like sqlite3_libversion() (noting that the C-style API is not available to clients who "remote-control" database connections via Worker messages).

The C-style API, for the most part, functions like its C counterpart. Most of the APIs behave identically to their native C variants and their JS/WASM bindings are not explicitly documented because the C documentation already serves that purpose. A small handful of exceptions exist, where differences in JS-style and C-style argument handling necessitate slightly different semantics which warrant explicit documention. Such cases are documented below.

Symbolic Constants (SQLITE_...)

The sqlite3 API makes heavy use of symbolic constants for function result codes and flags-style function arguments. All such symbols which are potentially required by WASM-bound C functions are defined in the sqlite3.capi namespace object. For example, sqlite3.capi.SQLITE_ERROR. The entire list of C-side constants is at:


noting that only those relevant to WASM-bound APIs are made available to JS.

The function sqlite3_js_rc_str() accepts an integer argument and returns the JS string form of its corresponding symbolic name, or returns undefined if no match is found.

Even though the SQLITE_... constant values are exceedingly unlikely to ever change, due to backwards compatibility constraints, JS code should avoid using any such numeric values directly in code. The symbolic names should always be preferred.


With only a single exception, the C-level APIs never throw, but some of the higher-level C-style APIs do and the object-oriented APIs use exceptions exclusively to report errors. The one exception (as it were) is sqlite3.wasm.alloc(), which will throw an sqlite3.WasmAllocError if it cannot allocate memory (which can normally be considered a fatal error).

Note that there's a distinction between "C-level" and "C-level-adjacent." The C-level API is specifically the public sqlite3 API functions which are exported directly from WASM to JavaScript. Some of the utility code intended to work with the C-level API does indeed throw, but it does so in ways which will, when properly used, never allow an exception to propagate back through the JS/WASM boundary, as doing so would be disastrous to the C-level code.


An Error subclass specifically for reporting DB-level errors and enabling clients to unambiguously identify such exceptions. Its constructor behaves differently depending on its arguments:

Achtung: Allocators

In C it is always important that dynamically-allocated memory is freed in a manner which corresponds to how it was allocated.

By way of example, either of these two are legal:

void * m = malloc(100);
m = sqlite3_malloc(100);

but neither of these are legal:

void * m = malloc(100);
sqlite3_free(m); // NO!
m = sqlite3_malloc(100);
free(m); // NO!

Depending on how sqlite3_malloc() and sqlite3_free() are defined, which may differ from one build of sqlite3 to the next, they might or might not be simply proxies for malloc() resp. free(). If they are, then the second example would work... until the definition of the former pair changed, in which case the second example leads to undefined behavior.

Depending on how sqlite3.js is built, sqlite3_malloc() might be the module's default allocator. This project's canonical builds all use sqlite3's allocator as the module-wide default since 2022-11-30, and guaranty to do so in all future versions.

However, clients creating custom builds for different WASM environments may change that, in which case any JavaScript code written for such builds needs to be careful about how it uses dynamically-allocated memory, to ensure that different memory management APIs are never intermixed. That is, that calls to malloc(), free(), and realloc() must never intermixed with sqlite3_malloc(), sqlite3_free(), and sqlite3_realloc(). Mixing them will lead to undefined results.

For a real-world example of an sqlite3 API where this distinction is critical, see sqlite3_deserialize().

Argument and Result Type Conversion in the C-style API

See also: api-wasm.md#wasm-type-conversion

Most of the sqlite3.capi.sqlite3_...() routines may perform some type of JS-to-WASM conversion on their arguments or return values. This section covers those.

64-bit Integers (BigInt)

See the build notes for details.

String Conversion

The JS bindings of the C APIs which live in the sqlite3.capi namespace are configured to do automatic conversion of string arguments to and from WASM/JS. Thus:

const v = capi.sqlite3_vfs_find("foo");

will convert "foo" to a C-style string before calling the WASM-bound function and will free the associated memory before returning. Similary, result values of C-style strings will be converted to JS:


Where such APIs accept C-string arguments, they may be passed either a JS string or a WASM-side string pointer, noting that such uses must be NUL-terminated or results are undefined. The JS/WASM compatibility glue will treat numeric arguments to string parameters as WASM pointers. When used that way, it is up to the caller to ensure that they are passing valid pointers. Unlike C compilers, which have at least a moderate degree of type safety when passing pointers around, WASM's only notion of pointers is equivalent to a void* in C. That is, pointers completely lack any type information, making it easy to "shoot oneself in the foot," as the saying goes.

UTF-8 Only!

C-style strings in arguments and results are always assumed to be UTF-8 encoded and results are undefined if any WASM-bound sqlite3 API is passed, or returns, a string which has a different encoding. That differs from JS strings, which use JS's native 16-bit encoding (which is either UTF-16 or UCS-2 (see also)).

Though the sqlite3 C API has routines for working with UTF-16, this API targets only the web and UTF-8 is the encoding of the web. There are no current plans to expose the UTF-16 APIs via the JS interface.

"Flexible Strings"

Certain WASM-bound APIs, where explicitly noted, have additional string-type argument conversions colloquially known as "flexible strings." Such string arguments may be in any of these forms:


Functions which are declared as taking a sqlite3* argument may perform the following argument-type conversions:


Functions which are declared as taking a sqlite3_vfs* argument may perform the following argument-type conversions:

No conversion is performed on sqlite3_vfs* result values.

WASM APIs which Differ from their C Counterparts

Every effort is made to keep the WASM bindings of the C APIs working as closely to their C counterparts as is feasible for the sake of consistency and the ability to use the C-level documentation with the WASM API. Some APIs, however, benefit greatly from the addition of custom wrappers which simplify particular cases which are unduly onerous to handle at the client-code level in JS.

This section describes sqlite3.capi member APIs which have semantics which, depending on how they are used, may differ from their C counterparts.

In all cases, when passed arguments which are directly compatible with their native forms, they behave exactly like the C documentation says they do. When passed certain JS types, however, they may behave differently, either gaining or losing features, depending on the context.

The affected APIs are listed below in alphabetical oder.

Certain more general aspects of these APIs, such as how to deal with output pointers from JS, are detailed in the WASM utilities doc.

sqlite3_create_function() and friends

C reference: www:/c3ref/create_function.html

The argument names used below refer directly to the argument names from the native C documentation:

int sqlite3_create_function(
  sqlite3 *db,
  const char *zFunctionName,
  int nArg,
  int eTextRep,
  void *pApp,
  void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
  void (*xStep)(sqlite3_context*,int,sqlite3_value**),
  void (*xFinal)(sqlite3_context*)
int sqlite3_create_function_v2(
  sqlite3 *db,
  const char *zFunctionName,
  int nArg,
  int eTextRep,
  void *pApp,
  void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
  void (*xStep)(sqlite3_context*,int,sqlite3_value**),
  void (*xFinal)(sqlite3_context*),
int sqlite3_create_window_function(
  sqlite3 *db,
  const char *zFunctionName,
  int nArg,
  int eTextRep,
  void *pApp,
  void (*xStep)(sqlite3_context*,int,sqlite3_value**),
  void (*xFinal)(sqlite3_context*),
  void (*xValue)(sqlite3_context*),
  void (*xInverse)(sqlite3_context*,int,sqlite3_value**),

sqlite3_create_function(), sqlite3_create_function_v2(), and sqlite3_create_window_function() differ from their native counterpart only in the following ways:

  1. The fourth argument (eTextRep) argument must not specify any encoding other than sqlite3.SQLITE_UTF8. The JS API does not currently support any other encoding and likely never will.

  2. Any of the function pointer arguments may be either WASM pointers (assumed to be function pointers) or JS Functions. In the latter case, each gets bound to WASM using sqlite3.wasm.installFunction() and that wrapper is passed on to the native implementation.

The semantics of generated JS wrappers are:

Note that:

For xFunc(), xStep(), xInverse(), and xFinal():

If any JS-side bound functions throw, those exceptions are intercepted and converted to database-side errors with the exception of xDestroy(): any exception from it is ignored, possibly generating a console.error() message. Destructors must not throw.

Once installed, there is currently no way to uninstall the automatically-converted WASM-bound JS functions from WASM. They can be uninstalled from the database as documented in the C API, but this wrapper currently has no infrastructure in place to also free the WASM-bound JS wrappers, effectively resulting in a memory leak if the client uninstalls the UDF. Removing client-installed UDFs is rare in practice. If this factor is relevant for a given client, they can create WASM-bound JS functions themselves, hold on to their pointers, and pass the pointers in to here. Later on, they can free those pointers (using wasm.uninstallFunction() or equivalent).

Clients who wish more control over their bindings can create their own WASM-bound JS functions using sqlite3.wasm.installFunction(). The helper methods described in the following subsections can assist with that and are exposed as properties of all 3 of the create-function functions to assist such implementations.

Design note: including the pCtx argument to the JS-bound wrappers was a painful decision but it boiled down to API consistency. By and large, that argument is irrelevant for JS bindings, so is just noise for most client-side UDFs. If it were elided, however, more advanced uses of UDFs would be much more painful to write, forcing the users to write their own WASM-bound wrappers to get at that argument. Including it in the JS callback interface ensures that the interface is more consistent with the C callback interface (sans the way SQL-side arguments are provided to them) and enables Power User use cases to be developed. It is expected, however, that folks will often forget to add it, which will cause their UDF argument lists to be "off by one." It is hoped that having to add that seemingly extraneous argument to client-side UDF signatures will soon seem like second nature to folks writing UDFs, in the same way that Python programmers have to add an explicit self argument to their object-oriented methods (whereas C++, JavaScript, and most other languages make that argument implicit).


array udfConvertArgs(int argc, sqlite3_value**argv)

When passed the (argc,argv) values from the UDF-related functions which receive them (xFunc(), xStep(), xInverse()), it creates a JS array representing those arguments, converting each to JS in a manner appropriate to its data type: numeric, text, blob (Uint8Array), or null.

Results are undefined if it's passed anything other than those two arguments from those specific contexts.

Thus an argc of 4 will result in a length-4 array containing the converted values from the corresponding argv.

The conversion will throw only on allocation error or an internal error.


void udfSetError(sqlite3_context *pCtx, errorObject)

A helper for UDFs implemented in JS and bound to WASM by the client. It expects to be a passed (sqlite3_context*, Error) (an exception object or message string). And it sets the current UDF's result to sqlite3_result_error_nomem() or sqlite3_result_error(), depending on whether the 2nd argument is a sqlite3.WasmAllocError object or not.


void udfSetResult(sqlite3_context *pCtx, value)

Calls one of the sqlite3_result_xyz(pCtx,...) routines, depending on the type of its 2nd argument:

Anything else triggers sqlite3_result_error() with a description of the problem.


sqlite3_deserialize() does not differ from its C-side counterpart but does have considerable caveats regarding memory allocation.

The documentation regarding allocators covers this issue in more abstract terms, but sqlite3_deserialize() provides a concrete example of a case where it is critical that one be aware the definition of the environment's C-level memory allocator.

Depending on how sqlite3_deserialize() is used, the memory passed to it may be required to come from sqlite3_malloc(), sqlite3_realloc(), or their 64-bit counterparts.

The sqlite3.capi.SQLITE_DESERIALIZE_RESIZEABLE flag can be passed to this function to enable automatic growth of the new in-memory databases on demand but the memory passed to sqlite3_deserialize() in that case must come from sqlite3_malloc() or sqlite3_realloc() (or their 64-bit counterparts) or else results are undefined.

For example, let's consider this snippet which downloads a remote database and deserializes it:

// Do not copy/paste without reading the docs below!
const db = new sqlite3.oo1.DB();
await fetch('my.db')
  .then(response => response.arrayBuffer())
  .then(arrayBuffer => {
    const bytes = new Uint8Array(arrayBuffer);
    const p = sqlite3.wasm.allocFromTypedArray(bytes);
    db.onclose = {after: function(){sqlite3.wasm.dealloc(p)}};
    const rc = sqlite3.capi.sqlite3_deserialize(
      db.pointer, 'main', p, bytes.length, bytes.length,

That use of sqlite3_deserialize() is legal, but only because it defines a fixed-sized memory region of memory not managed by sqlite3. In this scenario, sqlite3 is a read-only user of memory owned by the client application.

If the SQLITE_DESERIALIZE_FREEONCLOSE and/or SQLITE_DESERIALIZE_RESIZEABLE flags were used in the final argument to the deserialize call above, the result would, abstractly speaking, be undefined behavior (but see below for why it may not be).

Abstractly speaking, sqlite3.wasm.allocFromTypedArray() uses the system-level allocator, and it is not semantically legal to pass memory alloced from sqlite3.wasm.alloc() (i.e. from C's malloc()) to sqlite3_free() or sqlite3_realloc(). In order to support the above-mentioned flags in the example above, the call to allocFromTypedArray() would need to be replaced by an equivalent function which allocates the memory using sqlite3_alloc(). However, as of 2022-11-30, this project's canonical builds use the sqlite3_malloc() family of functions as the module-wide allocator, meaning that this is a non-issue in canonical builds but might be an issue in custom builds, depending on how they're constructed.


C reference: www:/c3ref/exec.html

sqlite3_exec(), if called with a non-Function object as its 3rd argument:

sqlite3_exec(myDbPtr, "drop table x", 0, 0, 0);

works exactly like all other WASM-bound functions, including the automatic conversion of its 2nd argument (SQL), which supports flexible string conversion.

If, however, it is called with a JS function as its 3rd argument then it performs the following translations...

For the duration of the sqlite3_exec() call, it installs a WASM-side function which hooks the provided callback into WASM. That binding is removed immediately before sqlite3_exec() returns.

The callback's C signature is:

callback(void *, int colCount, char** pColValues, char** pColNames)

but the callback's WASM-bound proxy calls it like:

callback(void *, int colCount, array colValues, array colNames)

i.e. it converts the C-style string arrays to JS arrays of strings.

The first two arguments to the callback don't have much value in JS but are retained in order to keep the general shape of the C-style JS API as close to the original C API as possible.

If the callback throws or returns any non-0 value, the proxy catches that and converts it to a C result, which the native sqlite3_exec() implementation will translate to a SQLITE_ABORT result. If it does not throw, its return value is coerced to be a 32-bit integer. Thus an implicit return (the undefined value) equates to a result code of 0 (i.e. success).


const db = new sqlite3.oo1.DB().exec(
  "create table t(a); insert into t(a) values(3),(6),(9)"
  "select a from t",
  0, 0

Will output:

a 3
a 6
a 9

sqlite3_prepare_v2() and sqlite3_prepare_v3()

C reference: www:/c3ref/prepare.html

Like in the C API, sqlite3_prepare_v2() is simply a proxy for sqlite3_prepare_v3() which passes on a default set of flags to that function. sqlite3_prepare_v3(), due to disparities between JS and C, has two distinctly different usages

As a point of reference, the native signatures of these functions are:

int sqlite3_prepare_v2(
  sqlite3 *db,            /* Database handle */
  const char *zSql,       /* SQL statement, UTF-8 encoded */
  int nByte,              /* Maximum length of zSql in bytes. */
  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
  const char **pzTail     /* OUT: Pointer to unused portion of zSql */
int sqlite3_prepare_v3(
  sqlite3 *db,            /* Database handle */
  const char *zSql,       /* SQL statement, UTF-8 encoded */
  int nByte,              /* Maximum length of zSql in bytes. */
  unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */
  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
  const char **pzTail     /* OUT: Pointer to unused portion of zSql */

The sqlite3_prepare_v3() binding handles two different uses with differing JS/WASM semantics:

  1. For the cases that the SQL argument is a JS string:
    int sqlite3_prepare_v3(pDb, sqlString, -1, prepFlags, ppStmt , null)
    The SQL length argument (the 3rd argument) must always be negative because it must be a byte length and that value is expensive to calculate from JS (where only the character length of strings is readily available). It is retained in this API's interface for code/documentation compatibility reasons but is currently always ignored except as noted below.

  2. For the case that the SQL argument is a WASM pointer to a C-string.
    int sqlite3_prepare_v3(pDb, sqlPointer, sqlByteLen, prepFlags, ppStmt, sqlPointerToPointer)
    The 3rd argument is used as-is but it is still critical that the C-style input string (2nd argument) be terminated with a 0 byte.

In usage (1), if the second the 2nd argument must be a flexible string other than a WASM pointer. If it is, sqlite3_prepare_v3() assumes case (1) and calls the underyling C function with the equivalent of:

(pDb, sqlAsString, -1, prepFlags, ppStmt, null)

The final argument, pzTail, is ignored in this case because its result is meaningless when a string-type value is passed through: the string goes through another level of internal conversion for WASM's sake and the result pointer would refer to that transient conversion's memory, not the passed-in string.

If the SQL is a Uint8Array or Int8Array then it is assumed to hold a UTF-8 string, is converted to a C-string, and the byte array's length is used as the sqlByteLen argument.

If the SQL argument is not a string or one of the above-mentioned array types, it must be a pointer to a NUL-terminated string which was allocated in WASM memory (e.g. using wasm.alloc(), from the C stack, or equivalent). In that case, the final argument may be 0/null/undefined or must be a pointer to which the "tail" of the compiled SQL is written, as documented for the C-side sqlite3_prepare_v3(). In case (2), the underlying C function is called with the equivalent of:

(pDb, sqlAsPointer, sqlByteLen, prepFlags, ppStmt, pzTail)

It returns its result and compiled statement as documented in the C API.

Fetching the output pointers (5th and 6th parameters) requires using wasm.getMemValue() (or equivalent - see below) and the pzTail will point to an address relative to the sqlAsPointer value.

If passed an invalid 2nd argument type, this function will return SQLITE_MISUSE and capi.sqlite3_errmsg() will contain a string describing the problem.

Side-note: if given an empty string, or one which contains only comments or an empty SQL expression, 0 is returned but the result output pointer will be NULL.


C reference: www:/c3ref/randomness.html


If passed a single argument which appears to be a byte-oriented TypedArray (Int8Array or Uint8Array), this function treats that TypedArray as an output target, fetches theArray.byteLength bytes of randomness, and populates the whole array with it. As a special case, if the array's length is 0, this function behaves as if it were passed (0,0). When called this way, it returns its argument, else it returns the undefined value.

If called with any other arguments, they are passed on as-is to the C API. Results are undefined if passed any incompatible values.

WASM-Specific C-style Functions

This section documents C-style functions which live in the sqlite3.capi namespace but are specific to the WASM/JS APIs. Note that the sqlite3.wasm API has some C-like functions which are not documented here because they are not part of the public API and are not intended for use outside of this project's own code.


pointer sqlite3_js_aggregate_context(pCtx, n)

A thin wrapper around sqlite3.capi.sqlite3_aggregate_context() which behaves the same except that if that function returns 0 and n is truthy, it throws a WasmAllocError. If n is falsy, it simply returns 0 if that function returns 0. That behavior is intended to assist in developing xFinal() implementations.

Example, using the OO1 API:

const capi = sqlite3.capi, wasm = sqlite3.wasm;
const sjac = capi.sqlite3_js_aggregate_context;
  name: 'summer',
  xStep: (pCtx, n)=>{
    const ac = sjac(pCtx, 4);
    wasm.setMemValue(ac, wasm.getMemValue(ac,'i32') + Number(n), 'i32');
  xFinal: (pCtx)=>{
    const ac = sjac(pCtx, 0);
    return ac ? wasm.getMemValue(ac,'i32') : 0;


Uint8Array sqlite3_js_db_export(pDb [, schema=0])

A convenience wrapper around sqlite3_serialize() which serializes the given sqlite3* pointer or sqlite3.oo1.DB instance to a Uint8Array.

On success it returns a Uint8Array. If the schema is empty, an empty array is returned.

schema is the schema to serialize. It may be a WASM C-string pointer or a JS string. If it is falsy, it defaults to "main".

On error it throws with a description of the problem.


boolean sqlite3_js_db_uses_vfs(pDb, vfsName, dbName)

Given an sqlite3*, an sqlite3_vfs name, and an optional db name (defaults to "main"), returns a truthy value (see below) if that db handle uses that VFS, else returns false. If pDb is falsy then the 3rd argument is ignored and this function returns a truthy value if the default VFS name matches that of the 2nd argument. Results are undefined if pDb is truthy but refers to an invalid pointer. The 3rd argument specifies the database name of the given database connection to check, defaulting to the main db.

The 2nd and 3rd arguments may either be a JS string or a WASM C-string. If the 2nd argument is a NULL WASM pointer, the default VFS is assumed.

The truthy value it returns is a pointer to the sqlite3_vfs object.

To permit safe use of this function from APIs which may be called via the C stack (like SQL UDFs), this function does not throw: if bad arguments cause a conversion error when passing into wasm-space, false is returned.


pointer sqlite3_js_db_vfs(dbPointer, dbName=0)

Given a sqlite3* and a database name (JS string or WASM C-string pointer, which may be 0), returns a pointer to the sqlite3_vfs responsible for it. If the given db name is null/0, or not provided, then "main" is assumed.


See the KVVFS docs for details of the KVVFS-specific functions.


boolean sqlite3_js_db_uses_vfs(pDb,vfsName,dbName=0)

Given an sqlite3*, an sqlite3_vfs name, and an optional db name (defaulting to "main"), returns a truthy value (see below) if that db uses that VFS, else returns false. If pDb is falsy then the 3rd argument is ignored and this function returns a truthy value if the default VFS name matches that of the 2nd argument. Results are undefined if pDb is truthy but refers to an invalid pointer. The 3rd argument specifies the database name of the given database connection to check, defaulting to the main db.

The 2nd and 3rd arguments may either be a JS string or a WASM C-string. If the 2nd argument is a NULL WASM pointer, the default VFS is assumed. If the 3rd is a NULL WASM pointer, "main" is assumed.

The truthy value it returns is a pointer to the sqlite3_vfs object.

To permit safe use of this function from APIs which may be called via the C stack (like SQL UDFs), this function does not throw: if bad arguments cause a conversion error when passing into wasm-space, false is returned.


string sqlite3_js_rc_str(int)

Given one of the SQLITE_... constant values, this function returns the string form of that constant, or undefined if no match is found, noting that some constants available in the C API are not exported to WASM because they simply are not used there. Example:

sqlite3_js_rc_str(sqlite3.capi.SQLITE_ERROR); // ==> "SQLITE_ERROR"



Creates (or overwrites) a file using the storage appropriate for the given sqlite3_vfs. The first argument may be a VFS name (JS string only, NOT a WASM C-string), WASM-managed sqlite3_vfs*, or a capi.sqlite3_vfs instance. Pass 0 (a NULL pointer) to use the default VFS. If passed a string which does not resolve using sqlite3_vfs_find(), an exception is thrown. (Note that a WASM C-string is not accepted because it is impossible to distinguish from a C-level sqlite3_vfs*.)

The second argument, the filename, must be a JS or WASM C-string.

The 3rd may either be falsy, a valid WASM memory pointer, an ArrayBuffer, or Uint8Array. The 4th must be the length, in bytes, of the data array to copy. If the 3rd argument is a Uint8Array or ArrayBuffer and the 4th is not a positive integer then the 4th defaults to the array's byteLength value.

If data is falsy then a file is created with dataLen bytes filled with uninitialized data (whatever truncate() leaves there). If data is not falsy then a file is created or truncated and it is filled with the first dataLen bytes of the data source.

Throws if any arguments are invalid or if creating or writing to the file fails.

Note that most VFSes do not automatically create directory parts of filenames, nor do all VFSes have a concept of directories. If the given filename is not valid for the given VFS, an exception will be thrown. This function exists primarily to assist in implementing file-upload capability, with the caveat that clients must have some idea of the VFS into which they want to upload and that VFS must support the operation.

VFS-specific notes:


array sqlite3_js_vfs_list()

Returns an array of the names of all currently-registered sqlite3 VFSes.