Runtimes
Convex functions can run in two runtimes:
- Default Convex runtime
- Opt-in Node.js runtime
Default Convex runtime
All Convex backend functions are written in JavaScript or TypeScript. By default all functions run in a custom JavaScript runtime very similar to the Cloudflare Workers runtime with access to most web standard globals.
The default runtime has many advantages including:
- No cold starts. The runtime is always up, and ready to handle any function at a moments notice.
- Latest web JavaScript standards. The runtime is based on V8 that also powers Google Chrome. This ensures it provides an interface very similar to your frontend code, allowing further simplification to your code.
- Low overhead access to your data. The runtime is designed to have low overhead access to your data via query & mutation functions, allowing you to access your database via a simple JavaScript interface.
Supported APIs
The default runtime supports most npm libraries that work in the browser, Deno, and Cloudflare workers. If your library isn't supported, you can use an action with the Node.js runtime, or reach out in Discord. We are improving support all the time.
Network APIs
Encoding APIs
Web Stream APIs
- ReadableStream
- ReadableStreamBYOBReader
- ReadableStreamDefaultReader
- TransformStream
- WritableStream
- WritableStreamDefaultWriter
Web Crypto APIs
Restrictions on queries and mutations
Query and mutation functions are further restricted by the runtime to be deterministic. This allows Convex to automatically retry them by the system as necessary.
Determinism means that no matter how many times your function is run, as long as it is given the same arguments, it will have identical side effects and return the same value.
You don't have to think all that much about maintaining these properties of determinism when you write your Convex functions. Convex will provide helpful error messages as you go, so you can't accidentally do something forbidden.
Using randomness and time in queries and mutations
Convex provides a "seeded" strong pseudo-random number generator
at Math.random()
so that it can guarantee the determinism of your function.
The random number generator's seed is an implicit parameter to your function.
Multiple calls to Math.random()
in one function call will return different
random values. Note that Convex does not reevaluate the Javascript modules on
every function run, so a call to Math.random()
stored in a global variable
will not change between function runs.
To ensure the logic within your function is reproducible, the system time used
globally (outside of any function) is "frozen" at deploy time, while the system
time during Convex function execution is "frozen" when the function
begins. Date.now()
will return the same result for the entirety of your
function's execution. For example,
const globalRand = Math.random(); // `globalRand` does not change between runs.
const globalNow = Date.now(); // `globalNow` is the time when Convex functions were deployed.
export const updateSomething = mutation({
handler: () => {
const now1 = Date.now(); // `now1` is the time when the function execution started.
const rand1 = Math.random(); // `rand1` has a new value for each function run.
// implementation
const now2 = Date.now(); // `now2` === `now1`
const rand2 = Math.random(); // `rand1` !== `rand2`
},
});
Actions
Actions are unrestricted by the same rules of determinism as query and mutation
functions. Notably actions are allowed to call third-party HTTP endpoints via
the browser-standard
fetch
function.
By default actions also run in Convex’s custom JavaScript runtime with all of its advantages including no cold starts and a browser-like API environment. They can also live in the same file as your query and mutation functions.
Node.js runtime
Some JavaScript and TypeScript libraries use features that are not included in
the default Convex runtime. This is why Convex actions provide an escape hatch
to Node.js 18 via the "use node"
directive at
the top of a file that contains your action.
Learn more.
Use of the Node.js environment is restricted to action functions only. If
you want to use a library designed for Node.js and interact with the Convex
database, you need to call the Node.js library from an action, and use
runQuery
or
runMutation
helper to call a
query or mutation.
Every .ts
and .js
file in the convex directory
is bundled either for the default Convex
JavaScript runtime or Node.js, even if it contains no Convex functions. So a
convex/utils.ts
file that used Node.js-specific libraries would also need to
have "use node"
at the top to avoid warnings at bundle time.