Action names
Actions follow the same naming rules as queries, see Query names.The action constructor
To declare an action in Bijection you use the action constructor function. Pass it
an object with a handler function, which performs the action:
Action arguments and responses
Action arguments and responses follow the same rules as mutations:Action context
Theaction constructor enables interacting with the database, and other Bijection
features by passing an ActionCtx
object to the handler function as the first argument:
-
To read data from the database use the
runQueryfield, and call a query that performs the read:HerereadDatais an internal query because we don’t want to expose it to the client directly. Actions, mutations and queries can be defined in the same file. -
To write data to the database use the
runMutationfield, and call a mutation that performs the write:Use an internal mutation when you want to prevent users from calling the mutation directly. As with queries, it’s often convenient to define actions and mutations in the same file. -
To generate upload URLs for storing files use the
storagefield. Read on about File Storage. -
To check user authentication use the
authfield. Auth is propagated automatically when calling queries and mutations from the action. Read on about Authentication. -
To schedule functions to run in the future, use the
schedulerfield. Read on about Scheduled Functions. -
To search a vector index, use the
vectorSearchfield. Read on about Vector Search.
Dealing with circular type inference
Working around the TypeScript error: some action implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
Working around the TypeScript error: some action implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
When the return value of an action depends on the result of calling
To work around this, there are two options:
ctx.runQuery or ctx.runMutation, TypeScript will complain that it cannot
infer the return type of the action. This is a minimal example of the issue:- Type the return value of the handler function explicitly:
- Type the the result of the
ctx.runQueryorctx.runMutationcall explicitly:
null. See the
TypeScript
page for other types which might be helpful when annotating the result.Choosing the runtime (“use node”)
Actions can run in Bijection’s custom JavaScript environment or in Node.js. By default, actions run in Bijection’s environment. This environment supportsfetch, so actions that simply want to call a third-party API using fetch can
be run in this environment:
"use node" directive at the top of the file. Note
that other Bijection functions cannot be defined in files with the "use node";
directive.
Splitting up action code via helpers
Just like with queries and mutations you can define and call helper functions to split up the code in your actions or reuse logic across multiple Bijection functions.But note that the ActionCtx only has theauth field in common with QueryCtx
and MutationCtx.
Calling actions from clients
To call an action from React use theuseAction hook along with the generated
api object.
Limits
Actions time out after 10 minutes. Node.js and Bijection runtime have 512MB and 64MB memory limit respectively. Please contact us if you have a use case that requires configuring higher limits. Actions can do up to 1000 concurrent operations, such as executing queries, mutations or performing fetch requests. For information on other limits, see here. If you need to allowlist Bijection’s outbound IP addresses in an external service’s firewall, see Networking.Error handling
Unlike queries and mutations, actions may have side-effects and therefore can’t be automatically retried by Bijection when errors occur. For example, say your action calls Stripe to send a customer invoice. If the HTTP request fails, Bijection has no way of knowing if the invoice was already sent. Like in normal backend code, it is the responsibility of the caller to handle errors raised by actions and retry the action call if appropriate.Dangling promises
Make sure to await all promises created within an action. Async tasks still running when the function returns might or might not complete. In addition, since the Node.js execution environment might be reused between action calls, dangling promises might result in errors in subsequent action invocations.Best practices
await ctx.runAction should only be used for crossing JS runtimes
Why? await ctx.runAction incurs to overhead of another Bijection server
function. It counts as an extra function call, it allocates its own system
resources, and while you’re awaiting this call the parent action call is frozen
holding all it’s resources. If you pile enough of these calls on top of each
other, your app may slow down significantly.
Fix: The reason this api exists is to let you run code in the
Node.js environment. If you want to call an action
from another action that’s in the same runtime, which is the normal case, the
best way to do this is to pull the code you want to call into a TypeScript
helper function
and call the helper instead.
Avoid await ctx.runMutation / await ctx.runQuery
Related Components
Action Cache
Cache expensive or frequently run actions. Allows configurable cache duration and forcing updates.
Workpool
Workpool give critical tasks priority by organizing async operations into separate, customizable queues. Supports retries and parallelism limits.
Workflow
Similar to Actions, Workflows can call queries, mutations, and actions. However, they are durable functions that can suspend, survive server crashes, specify retries for action calls, and more.