[Skip to main content](https://docs.convex.dev/home#docusaurus_skipToContent_fallback) Convex is an all-in-one backend platform with thoughtful, product-centric APIs. Use [TypeScript](https://docs.convex.dev/understanding/best-practices/typescript) to write [queries as\\\\ code](https://docs.convex.dev/functions/query-functions) that are [automatically\\\\ cached](https://docs.convex.dev/realtime#automatic-caching) and [realtime](https://docs.convex.dev/realtime), with an acid compliant [relational database](https://docs.convex.dev/database). [Learn Convex by creating a chat app](https://docs.convex.dev/tutorial) ## Quickstarts [​](https://docs.convex.dev/home\\#quickstarts \"Direct link to Quickstarts\") Quickly get up and running with your favorite frontend tooling or language: [React Logo\\\\ **React**](https://docs.convex.dev/quickstart/react) [**Next.js**](https://docs.convex.dev/quickstart/nextjs) [**Remix**](https://docs.convex.dev/quickstart/remix) [**TanStack Start**](https://docs.convex.dev/quickstart/tanstack-start) [**React Native**](https://docs.convex.dev/quickstart/react-native) [**Vue**](https://docs.convex.dev/quickstart/vue) [**Svelte**](https://docs.convex.dev/quickstart/svelte) [**Node.js**](https://docs.convex.dev/quickstart/nodejs) [Bun Logo\\\\ **Bun**](https://docs.convex.dev/quickstart/bun) [HTML5 Logo\\\\ **Script tag**](https://docs.convex.dev/quickstart/script-tag) [**Python**](https://docs.convex.dev/quickstart/python) [**iOS Swift**](https://docs.convex.dev/quickstart/swift) [**Android Kotlin**](https://docs.convex.dev/quickstart/android) [**Rust**](https://docs.convex.dev/quickstart/rust) ## Why Convex? [​](https://docs.convex.dev/home\\#why-convex \"Direct link to Why Convex?\") [Backends Should be Designed for Product Developers](https://www.youtube.com/watch?v=Xjud1weG4z8) [Why I use Convex over Supabase as my BaaS](https://www.youtube.com/watch?v=O_HXVAMPEbc) Read the team's Perspectives on [Stack](https://stack.convex.dev/): [**Convex vs Relational Databases**](https://stack.convex.dev/convex-vs-relational-databases) [**Convex vs Firebase**](https://stack.convex.dev/convex-vs-firebase) [**It's not you, it's SQL**](https://stack.convex.dev/not-sql) [**How Convex Works**](https://stack.convex.dev/how-convex-works) [**The Software-Defined Database**](https://stack.convex.dev/the-software-defined-database) [**Convex Perspectives**](https://stack.convex.dev/tag/Perspectives) ## Learn Convex [​](https://docs.convex.dev/home\\#learn-convex \"Direct link to Learn Convex\") [A quick start guide for using Convex with Next.js](https://www.youtube.com/watch?v=vaQZYRSiimI) [Fullstack Notion Clone: Next.js 13, React, Convex, Tailwind \\| Full Course 2023](https://www.youtube.com/watch?v=0OaDyjB9Ib8) [Watch on YouTube](https://www.youtube.com/watch?v=0OaDyjB9Ib8 \"Watch on YouTube\") [Build and Deploy a Saas Podcast Platform in Next.js](https://www.youtube.com/watch?v=zfAb95tJvZQ) [Building a Subscription Based SaaS with my Favorite Tech Stack (Next.js, Stripe, Convex, Clerk)](https://www.youtube.com/watch?v=Vjtn9pWAZDI) See more walkthroughs and patterns on [Stack](https://stack.convex.dev/) [**Build AI Apps**](https://stack.convex.dev/tag/AI) [**Convex Patterns**](https://stack.convex.dev/tag/Patterns) [**Convex Walkthroughs**](https://stack.convex.dev/tag/Walkthroughs) [Skip to main content](https://docs.convex.dev/error#docusaurus_skipToContent_fallback) On this page # Errors and Warnings This page explains specific errors thrown by Convex. See [Error Handling](https://docs.convex.dev/functions/error-handling/) to learn about handling errors in general. ## Write conflict: Optimistic concurrency control [​](https://docs.convex.dev/error\\#1 \"Direct link to Write conflict: Optimistic concurrency control\") This system error is thrown when a mutation repeatedly fails due to conflicting changes from parallel mutation executions. ### Example A [​](https://docs.convex.dev/error\\#example-a \"Direct link to Example A\") A mutation `updateCounter` always updates the same document: ```codeBlockLines_zEuJ export const updateCounter = mutation({ args: {}, handler: async (ctx) => { const doc = await ctx.db.get(process.env.COUNTER_ID); await ctx.db.patch(doc._id, { value: doc.value + 1 }); }, }); ``` If this mutation is called many times per second, many of its executions will conflict with each other. Convex internally does several retries to mitigate this concern, but if the mutation is called more rapidly than Convex can execute it, some of the invocations will eventually throw this error: > failure `updateCounter` > > Documents read from or written to the table \"counters\" changed while this > mutation was being run and on every subsequent retry. Another call to this > mutation changed the document with ID \"123456789101112\". The error message will note the table name, which mutation caused the conflict (in this example its another call to the same mutation), and one document ID which was part of the conflicting change. ### Example B [​](https://docs.convex.dev/error\\#example-b \"Direct link to Example B\") Mutation `writeCount` depends on the entire `tasks` table: ```codeBlockLines_zEuJ export const writeCount = mutation({ args: { target: v.id(\"counts\"), }, handler: async (ctx, args) => { const tasks = await ctx.db.query(\"tasks\").collect(); await ctx.db.patch(args.target, { value: tasks }); }, }); export const addTask = mutation({ args: { text: v.string(), }, handler: async (ctx, args) => { await ctx.db.insert(\"tasks\", { text: args.text }); }, }); ``` If the mutation `writeCount` is called at the same time as many calls to `addTask` are made, either of the mutations can fail with this error. This is because any change to the `\"tasks\"` table will conflict with the `writeCount` mutation: > failure `writeCount` > > Documents read from or written to the table \"tasks\" changed while this > mutation was being run and on every subsequent retry. A call to \"addTask\" > changed the document with ID \"123456789101112\". ### Remediation [​](https://docs.convex.dev/error\\#remediation \"Direct link to Remediation\") To fix this issue: 1. Make sure that your mutations only read the data they need. Consider reducing the amount of data read by using indexed queries with [selective index range expressions](https://docs.convex.dev/database/indexes/). 2. Make sure you are not calling a mutation an unexpected number of times, perhaps from an action inside a loop. 3. Design your data model such that it doesn't require making many writes to the same document. ### Resources [​](https://docs.convex.dev/error\\#resources \"Direct link to Resources\") - Learn more about [optimistic concurrency control](https://docs.convex.dev/database/advanced/occ). - See this [Stack post](https://stack.convex.dev/waitlist) for an example of designing an app to avoid mutation conflicts. - [Write conflict: Optimistic concurrency control](https://docs.convex.dev/error#1) - [Example A](https://docs.convex.dev/error#example-a) - [Example B](https://docs.convex.dev/error#example-b) - [Remediation](https://docs.convex.dev/error#remediation) - [Resources](https://docs.convex.dev/error#resources) [Skip to main content](https://docs.convex.dev/auth#docusaurus_skipToContent_fallback) Authentication allows you to identify users and restrict what data they can see and edit. Convex is compatible with most authentication providers because it uses OpenID Connect (based on OAuth) ID tokens in the form of JWTs to authenticate WebSocket connections or RPCs. These JWTs can be provided by any service implementing the appropriate OAuth endpoints to verify them, including your own Convex backend. ## Third-party authentication platforms [​](https://docs.convex.dev/auth\\#third-party-authentication-platforms \"Direct link to Third-party authentication platforms\") Leveraging a Convex integration with a third-party auth provider provides the most comprehensive authentication solutions. Integrating another service provides a ton of functionality like passkeys, two-factor auth, spam protection, and more on top of the authentication basics. - [Clerk](https://docs.convex.dev/auth/clerk) is newer and has better Next.js and React Native support - [Auth0](https://docs.convex.dev/auth/auth0) is more established with more bells and whistles - [Custom Auth Integration](https://docs.convex.dev/auth/advanced/custom-auth) allow any OpenID Connect-compatible identity provider to be used for authentication After you integrate one of these, learn more about accessing authentication information in [Functions](https://docs.convex.dev/auth/functions-auth) and storing user information in the [Database](https://docs.convex.dev/auth/database-auth). ## Convex Auth [​](https://docs.convex.dev/auth\\#convex-auth \"Direct link to Convex Auth\") For client-side React and React Native mobile apps you can implement auth directly in Convex with the [Convex Auth](https://docs.convex.dev/auth/convex-auth) library. This [npm package](https://github.com/get-convex/convex-auth) runs on your Convex deployment and helps you build a custom sign-up/sign-in flow via social identity providers, one-time email or SMS access codes, or via passwords. Convex Auth is in beta (it isn't complete and may change in backward-incompatible ways) and doesn't provide as many features as third party auth integrations. Since it doesn't require signing up for another service it's the quickest way to get auth up and running. Convex Auth is in beta Convex Authis currently a [beta\\\\ feature](https://docs.convex.dev/production/state/#beta-features). If you have feedback or feature requests, [let us know on Discord](https://convex.dev/community)! Support for Next.js is under active development. If you'd like to help test this experimental support please [give it a try](https://labs.convex.dev/auth)! ## Debugging [​](https://docs.convex.dev/auth\\#debugging \"Direct link to Debugging\") If you run into issues consult the [Debugging](https://docs.convex.dev/auth/debug) guide. ## Service Authentication [​](https://docs.convex.dev/auth\\#service-authentication \"Direct link to Service Authentication\") Servers you control or third party services can call Convex functions but may not be able to obtain OpenID JWTs and often do not represent the actions of a specific user. Say you're running some inference on a [Modal](https://modal.com/) server written in Python. When that server subscribes to a Convex query it doesn't do so with credentials of a particular end-user, rather it's looking for relevant tasks for any users that need that inference task, say summarizing and translating a conversation, completed. To provide access to Convex queries, mutations, and actions to an external service you can write public functions accessible to the internet that check a shared secret, for example from an environment variable, before doing anything else. Related posts from [![Stack](https://docs.convex.dev/img/stack-logo-dark.svg)![Stack](https://docs.convex.dev/img/stack-logo-light.svg)](https://stack.convex.dev/) [Skip to main content](https://docs.convex.dev/zen#docusaurus_skipToContent_fallback) # Page Not Found We could not find what you were looking for. Please contact the owner of the site that linked you to the original URL and let them know their link is broken. [Skip to main content](https://docs.convex.dev/quickstarts#docusaurus_skipToContent_fallback) Quickly get up and running with your favorite frontend tooling or language: [React Logo\\\\ **React**](https://docs.convex.dev/quickstart/react) [**Next.js**](https://docs.convex.dev/quickstart/nextjs) [**Remix**](https://docs.convex.dev/quickstart/remix) [**TanStack Start**](https://docs.convex.dev/quickstart/tanstack-start) [**React Native**](https://docs.convex.dev/quickstart/react-native) [**Vue**](https://docs.convex.dev/quickstart/vue) [**Svelte**](https://docs.convex.dev/quickstart/svelte) [**Node.js**](https://docs.convex.dev/quickstart/nodejs) [Bun Logo\\\\ **Bun**](https://docs.convex.dev/quickstart/bun) [HTML5 Logo\\\\ **Script tag**](https://docs.convex.dev/quickstart/script-tag) [**Python**](https://docs.convex.dev/quickstart/python) [**iOS Swift**](https://docs.convex.dev/quickstart/swift) [**Android Kotlin**](https://docs.convex.dev/quickstart/android) [**Rust**](https://docs.convex.dev/quickstart/rust) [Skip to main content](https://docs.convex.dev/api#docusaurus_skipToContent_fallback) # Convex TypeScript/JavaScript client libraries and CLI for Convex. Convex is the backend application platform with everything you need to build your product. Get started at [docs.convex.dev](https://docs.convex.dev/)! Or see [Convex demos](https://github.com/get-convex/convex-demos). Open discussions and issues in this repository about Convex TypeScript/JavaScript clients, the Convex CLI, or the Convex platform in general. Also feel free to share feature requests, product feedback, or general questions in the [Convex Discord Community](https://convex.dev/community). # Structure This package includes several entry points for building apps on Convex: - [`convex/server`](https://docs.convex.dev/api/modules/server): Helpers for implementing Convex functions and defining a database schema. - [`convex/react`](https://docs.convex.dev/api/modules/react): Hooks and a `ConvexReactClient` for integrating Convex into React applications. - [`convex/browser`](https://docs.convex.dev/api/modules/browser): A `ConvexHttpClient` for using Convex in other browser environments. - [`convex/values`](https://docs.convex.dev/api/modules/values): Utilities for working with values stored in Convex. - [`convex/react-auth0`](https://docs.convex.dev/api/modules/react_auth0): A React component for authenticating users with Auth0. - [`convex/react-clerk`](https://docs.convex.dev/api/modules/react_clerk): A React component for authenticating users with Clerk. This package also includes [`convex`](https://docs.convex.dev/using/cli), the command-line interface for managing Convex projects. # Building `npm pack` produces a public build with internal types removed. [Skip to main content](https://docs.convex.dev/cli#docusaurus_skipToContent_fallback) On this page The Convex command-line interface (CLI) is your interface for managing Convex projects and Convex functions. To install the CLI, run: ```codeBlockLines_zEuJ npm install convex ``` You can view the full list of commands with: ```codeBlockLines_zEuJ npx convex ``` ## Configure [​](https://docs.convex.dev/cli\\#configure \"Direct link to Configure\") ### Create a new project [​](https://docs.convex.dev/cli\\#create-a-new-project \"Direct link to Create a new project\") The first time you run ```codeBlockLines_zEuJ npx convex dev ``` it will ask you to log in your device and create a new Convex project. It will then create: 1. The `convex/` directory: This is the home for your query and mutation functions. 2. `.env.local` with `CONVEX_DEPLOYMENT` variable: This is the main configuration for your Convex project. It is the name of your development deployment. ### Recreate project configuration [​](https://docs.convex.dev/cli\\#recreate-project-configuration \"Direct link to Recreate project configuration\") Run ```codeBlockLines_zEuJ npx convex dev ``` in a project directory without a set `CONVEX_DEPLOYMENT` to configure a new or existing project. ### Log out [​](https://docs.convex.dev/cli\\#log-out \"Direct link to Log out\") ```codeBlockLines_zEuJ npx convex logout ``` Remove the existing Convex credentials from your device, so subsequent commands like `npx convex dev` can use a different Convex account. ## Develop [​](https://docs.convex.dev/cli\\#develop \"Direct link to Develop\") ### Run the Convex dev server [​](https://docs.convex.dev/cli\\#run-the-convex-dev-server \"Direct link to Run the Convex dev server\") ```codeBlockLines_zEuJ npx convex dev ``` Watches the local filesystem. When you change a [function](https://docs.convex.dev/functions) or the [schema](https://docs.convex.dev/database/schemas), the new versions are pushed to your dev deployment and the [generated types](https://docs.convex.dev/generated-api/) in `convex/_generated` are updated. ### Open the dashboard [​](https://docs.convex.dev/cli\\#open-the-dashboard \"Direct link to Open the dashboard\") ```codeBlockLines_zEuJ npx convex dashboard ``` Open the [Convex dashboard](https://docs.convex.dev/dashboard). ### Open the docs [​](https://docs.convex.dev/cli\\#open-the-docs \"Direct link to Open the docs\") ```codeBlockLines_zEuJ npx convex docs ``` Get back to these docs! ### Run Convex functions [​](https://docs.convex.dev/cli\\#run-convex-functions \"Direct link to Run Convex functions\") ```codeBlockLines_zEuJ npx convex run [args] ``` Run a public or internal Convex query, mutation, or action on your development deployment. Arguments are specified as a JSON object. ```codeBlockLines_zEuJ npx convex run messages:send '{\"body\": \"hello\", \"author\": \"me\"}' ``` Add `--watch` to live update the results of a query. Add `--push` to push local code to the deployment before running the function. Use `--prod` to run functions in the production deployment for a project. ### Tail deployment logs [​](https://docs.convex.dev/cli\\#tail-deployment-logs \"Direct link to Tail deployment logs\") ```codeBlockLines_zEuJ npx convex logs ``` This pipes logs from your dev deployment to your console. This can be followed with `--prod` to tail the prod deployment logs instead. You can also simultaneously deploy code to the Convex dev deployment, watching for filesystem changes, and pipe logs generated on your dev deployment to your console: ```codeBlockLines_zEuJ npx convex dev --tail-logs ``` ### Import data from a file [​](https://docs.convex.dev/cli\\#import-data-from-a-file \"Direct link to Import data from a file\") ```codeBlockLines_zEuJ npx convex import --table npx convex import .zip ``` See description and use-cases: [data import](https://docs.convex.dev/database/import-export/import). ### Export data to a file [​](https://docs.convex.dev/cli\\#export-data-to-a-file \"Direct link to Export data to a file\") ```codeBlockLines_zEuJ npx convex export --path npx convex export --path .zip npx convex export --include-file-storage --path ``` See description and use-cases: [data export](https://docs.convex.dev/database/import-export/export). ### Display data from tables [​](https://docs.convex.dev/cli\\#display-data-from-tables \"Direct link to Display data from tables\") ```codeBlockLines_zEuJ npx convex data # lists tables npx convex data ``` Display a simple view of the [dashboard data page](https://docs.convex.dev/dashboard/deployments/data) in the command line. The command supports `--limit` and `--order` flags to change data displayed. For more complex filters, use the dashboard data page or write a [query](https://docs.convex.dev/database/reading-data/). The `npx convex data
` command works with [system tables](https://docs.convex.dev/database/advanced/system-tables), such as `_storage`, in addition to your own tables. ### Read and write environment variables [​](https://docs.convex.dev/cli\\#read-and-write-environment-variables \"Direct link to Read and write environment variables\") ```codeBlockLines_zEuJ npx convex env list npx convex env get npx convex env set npx convex env remove ``` See and update the deployment environment variables which you can otherwise manage on the dashboard [environment variables settings page](https://docs.convex.dev/dashboard/deployments/deployment-settings#environment-variables). ## Deploy [​](https://docs.convex.dev/cli\\#deploy \"Direct link to Deploy\") ### Deploy Convex functions to production [​](https://docs.convex.dev/cli\\#deploy-convex-functions-to-production \"Direct link to Deploy Convex functions to production\") ```codeBlockLines_zEuJ npx convex deploy ``` The target deployment to push to is determined like this: 1. If the `CONVEX_DEPLOY_KEY` environment variable is set (typical in CI), then it is the deployment associated with that key. 2. If the `CONVEX_DEPLOYMENT` environment variable is set (typical during local development), then the target deployment is the production deployment of the project that the deployment specified by `CONVEX_DEPLOYMENT` belongs to. This allows you to deploy to your prod deployment while developing against your dev deployment. This command will: 1. Run a command if specified with `--cmd`. The command will have CONVEX\\_URL (or similar) environment variable available: ```codeBlockLines_zEuJ npx convex deploy --cmd \"npm run build\" ``` You can customize the URL environment variable name with `--cmd-url-env-var-name`: ```codeBlockLines_zEuJ npx convex deploy --cmd 'npm run build' --cmd-url-env-var-name CUSTOM_CONVEX_URL ``` 2. Typecheck your Convex functions. 3. Regenerate the [generated code](https://docs.convex.dev/generated-api/) in the `convex/_generated` directory. 4. Bundle your Convex functions and their dependencies. 5. Push your functions, [indexes](https://docs.convex.dev/database/reading-data/indexes/), and [schema](https://docs.convex.dev/database/schemas) to production. Once this command succeeds the new functions will be available immediately. ### Deploy Convex functions to a [preview deployment](https://docs.convex.dev/production/hosting/preview-deployments) [​](https://docs.convex.dev/cli\\#deploy-convex-functions-to-a-preview-deployment \"Direct link to deploy-convex-functions-to-a-preview-deployment\") ```codeBlockLines_zEuJ npx convex deploy ``` When run with the `CONVEX_DEPLOY_KEY` environment variable containing a Preview Deploy Key, this command will: 1. Create a deployment with the specified name. `npx convex deploy` will infer the Git branch name for Vercel, Netlify, GitHub, and GitLab environments, but the `--preview-create` option can be used to customize the name associated with the newly created deployment. ```codeBlockLines_zEuJ npx convex deploy --preview-create my-branch-name ``` 2. Run a command if specified with `--cmd`. The command will have CONVEX\\_URL (or similar) environment variable available: ```codeBlockLines_zEuJ npx convex deploy --cmd \"npm run build\" ``` You can customize the URL environment variable name with `--cmd-url-env-var-name`: ```codeBlockLines_zEuJ npx convex deploy --cmd 'npm run build' --cmd-url-env-var-name CUSTOM_CONVEX_URL ``` 3. Typecheck your Convex functions. 4. Regenerate the [generated code](https://docs.convex.dev/generated-api/) in the `convex/_generated` directory. 5. Bundle your Convex functions and their dependencies. 6. Push your functions, [indexes](https://docs.convex.dev/database/reading-data/indexes/), and [schema](https://docs.convex.dev/database/schemas) to the deployment. 7. Run a function specified by `--preview-run` (similar to the `--run` option for `npx convex dev`). ```codeBlockLines_zEuJ npx convex deploy --preview-run myFunction ``` See the [Vercel](https://docs.convex.dev/production/hosting/vercel#preview-deployments) or [Netlify](https://docs.convex.dev/production/hosting/netlify#deploy-previews) hosting guide for setting up frontend and backend previews together. ### Update generated code [​](https://docs.convex.dev/cli\\#update-generated-code \"Direct link to Update generated code\") ```codeBlockLines_zEuJ npx convex codegen ``` Update the [generated code](https://docs.convex.dev/generated-api/) in `convex/_generated` without pushing. This can be useful for orchestrating build steps in CI. - [Configure](https://docs.convex.dev/cli#configure) - [Create a new project](https://docs.convex.dev/cli#create-a-new-project) - [Recreate project configuration](https://docs.convex.dev/cli#recreate-project-configuration) - [Log out](https://docs.convex.dev/cli#log-out) - [Develop](https://docs.convex.dev/cli#develop) - [Run the Convex dev server](https://docs.convex.dev/cli#run-the-convex-dev-server) - [Open the dashboard](https://docs.convex.dev/cli#open-the-dashboard) - [Open the docs](https://docs.convex.dev/cli#open-the-docs) - [Run Convex functions](https://docs.convex.dev/cli#run-convex-functions) - [Tail deployment logs](https://docs.convex.dev/cli#tail-deployment-logs) - [Import data from a file](https://docs.convex.dev/cli#import-data-from-a-file) - [Export data to a file](https://docs.convex.dev/cli#export-data-to-a-file) - [Display data from tables](https://docs.convex.dev/cli#display-data-from-tables) - [Read and write environment variables](https://docs.convex.dev/cli#read-and-write-environment-variables) - [Deploy](https://docs.convex.dev/cli#deploy) - [Deploy Convex functions to production](https://docs.convex.dev/cli#deploy-convex-functions-to-production) - [Deploy Convex functions to a preview deployment](https://docs.convex.dev/cli#deploy-convex-functions-to-a-preview-deployment) - [Update generated code](https://docs.convex.dev/cli#update-generated-code) [Skip to main content](https://docs.convex.dev/database#docusaurus_skipToContent_fallback) The Convex database provides a relational data model, stores JSON-like documents, and can be used with or without a schema. It \"just works,\" giving you predictable query performance in an easy-to-use interface. Query and mutation [functions](https://docs.convex.dev/functions) read and write data through a lightweight JavaScript API. There is nothing to set up and no need to write any SQL. Just use JavaScript to express your app's needs. Start by learning about the basics of [tables](https://docs.convex.dev/database#tables), [documents](https://docs.convex.dev/database#documents) and [schemas](https://docs.convex.dev/database#schemas) below, then move on to [Reading Data](https://docs.convex.dev/database/reading-data/) and [Writing Data](https://docs.convex.dev/database/writing-data). As your app grows more complex you'll need more from your database: - Relational data modeling with [Document IDs](https://docs.convex.dev/database/document-ids) - Fast querying with [Indexes](https://docs.convex.dev/database/reading-data/indexes/) - Exposing large datasets with [Paginated Queries](https://docs.convex.dev/database/pagination) - Type safety by [Defining a Schema](https://docs.convex.dev/database/schemas) - Interoperability with data [Import & Export](https://docs.convex.dev/database/import-export/) ## Tables [​](https://docs.convex.dev/database\\#tables \"Direct link to Tables\") Your Convex deployment contains tables that hold your app's data. Initially, your deployment contains no tables or documents. Each table springs into existence as soon as you add the first document to it. ```codeBlockLines_zEuJ // `friends` table doesn't exist. await ctx.db.insert(\"friends\", { name: \"Jamie\" }); // Now it does, and it has one document. ``` You do not have to specify a schema upfront or create tables explicitly. ## Documents [​](https://docs.convex.dev/database\\#documents \"Direct link to Documents\") Tables contain documents. Documents are very similar to JavaScript objects. They have fields and values, and you can nest arrays or objects within them. These are all valid Convex documents: ```codeBlockLines_zEuJ {} {\"name\": \"Jamie\"} {\"name\": {\"first\": \"Ari\", \"second\": \"Cole\"}, \"age\": 60} ``` They can also contain references to other documents in other tables. See [Data Types](https://docs.convex.dev/database/types) to learn more about the types supported in Convex and [Document IDs](https://docs.convex.dev/database/document-ids) to learn about how to use those types to model your data. ## Schemas [​](https://docs.convex.dev/database\\#schemas \"Direct link to Schemas\") Though optional, schemas ensure that your data looks exactly how you want. For a simple chat app, the schema will look like this: ```codeBlockLines_zEuJ import { defineSchema, defineTable } from \"convex/server\"; import { v } from \"convex/values\"; // @snippet start schema export default defineSchema({ messages: defineTable({ author: v.id(\"users\"), body: v.string(), }), }); ``` You can choose to be as flexible as you want by using types such as `v.any()` or as specific as you want by precisely describing a `v.object()`. See [the schema documentation](https://docs.convex.dev/database/schemas) to learn more about schemas. [**Next: Reading Data** \\\\ \\\\ Query and](https://docs.convex.dev/database/reading-data) Related posts from [![Stack](https://docs.convex.dev/img/stack-logo-dark.svg)![Stack](https://docs.convex.dev/img/stack-logo-light.svg)](https://stack.convex.dev/) [Skip to main content](https://docs.convex.dev/auth/functions-auth#docusaurus_skipToContent_fallback) On this page _If you're using Convex Auth, see the_ _[authorization doc](https://labs.convex.dev/auth/authz#use-authentication-state-in-backend-functions)._ Within a Convex [function](https://docs.convex.dev/functions), you can access information about the currently logged-in user by using the [`auth`](https://docs.convex.dev/api/interfaces/server.Auth) property of the [`QueryCtx`](https://docs.convex.dev/api/interfaces/server.GenericQueryCtx), [`MutationCtx`](https://docs.convex.dev/api/interfaces/server.GenericMutationCtx), or [`ActionCtx`](https://docs.convex.dev/api/modules/server#actionctx) object: convex/myFunctions.ts TS ```codeBlockLines_zEuJ import { mutation } from \"./_generated/server\"; export const myMutation = mutation({ args: { // ... }, handler: async (ctx, args) => { const identity = await ctx.auth.getUserIdentity(); if (identity === null) { throw new Error(\"Unauthenticated call to mutation\"); } //... }, }); ``` ## User identity fields [​](https://docs.convex.dev/auth/functions-auth\\#user-identity-fields \"Direct link to User identity fields\") The [UserIdentity](https://docs.convex.dev/api/interfaces/server.UserIdentity) object returned by `getUserIdentity` is guaranteed to have `tokenIdentifier`, `subject` and `issuer` fields. Which other fields it will include depends on the identity provider used and the configuration of JWT tokens and [OpenID scopes](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims). `tokenIdentifier` is a combination of `subject` and `issuer` to ensure uniqueness even when multiple providers are used. If you followed one of our integrations with Clerk or Auth0 at least the following fields will be present: `familyName`, `givenName`, `nickname`, `pictureUrl`, `updatedAt`, `email`, `emailVerified`. See their corresponding standard definition in the [OpenID docs](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims). convex/myFunctions.ts TS ```codeBlockLines_zEuJ import { mutation } from \"./_generated/server\"; export const myMutation = mutation({ args: { // ... }, handler: async (ctx, args) => { const identity = await ctx.auth.getUserIdentity(); const { tokenIdentifier, name, email } = identity!; //... }, }); ``` ### Clerk claims configuration [​](https://docs.convex.dev/auth/functions-auth\\#clerk-claims-configuration \"Direct link to Clerk claims configuration\") If you're using Clerk, the fields returned by `getUserIdentity` are determined by your JWT template's _Claims_ config. If you've set custom claims, they will be returned by `getUserIdentity` as well. ## HTTP Actions [​](https://docs.convex.dev/auth/functions-auth\\#http-actions \"Direct link to HTTP Actions\") You can also access the user identity from an HTTP action [`ctx.auth.getUserIdentity()`](https://docs.convex.dev/api/interfaces/server.Auth#getuseridentity), by calling your endpoint with an `Authorization` header including a JWT token: myPage.ts TS ```codeBlockLines_zEuJ const jwtToken = \"...\"; fetch(\"https://.convex.site/myAction\", { headers: { Authorization: `Bearer ${jwtToken}`, }, }); ``` Related posts from [![Stack](https://docs.convex.dev/img/stack-logo-dark.svg)![Stack](https://docs.convex.dev/img/stack-logo-light.svg)](https://stack.convex.dev/) - [User identity fields](https://docs.convex.dev/auth/functions-auth#user-identity-fields) - [Clerk claims configuration](https://docs.convex.dev/auth/functions-auth#clerk-claims-configuration) - [HTTP Actions](https://docs.convex.dev/auth/functions-auth#http-actions) [Skip to main content](https://docs.convex.dev/quickstart/remix#docusaurus_skipToContent_fallback) Learn how to query data from Convex in a Remix app. 1. Create a Remix site Create a Remix site using the `npx create-remix@latest` command. ```codeBlockLines_zEuJ npx create-remix@latest my-remix-app ``` 2. Install the Convex library To get started, install the `convex` package. ```codeBlockLines_zEuJ cd my-remix-app && npm install convex ``` 3. Set up a Convex dev deployment Next, run `npx convex dev`. This will prompt you to log in with GitHub, create a project, and save your production and deployment URLs. It will also create a `convex/` folder for you to write your backend API functions in. The `dev` command will then continue running to sync your functions with your dev deployment in the cloud. ```codeBlockLines_zEuJ npx convex dev ``` 4. Create sample data for your database In a new terminal window, create a `sampleData.jsonl` file with some sample data. sampleData.jsonl ```codeBlockLines_zEuJ {\"text\": \"Buy groceries\", \"isCompleted\": true} {\"text\": \"Go for a swim\", \"isCompleted\": true} {\"text\": \"Integrate Convex\", \"isCompleted\": false} ``` 5. Add the sample data to your database Now that your project is ready, add a `tasks` table with the sample data into your Convex database with the `import` command. ```codeBlockLines_zEuJ npx convex import --table tasks sampleData.jsonl ``` 6. Expose a database query Add a new file `tasks.ts` in the `convex/` folder with a query function that loads the data. Exporting a query function from this file declares an API function named after the file and the export name, `api.tasks.get`. convex/tasks.ts ```codeBlockLines_zEuJ import { query } from \"./_generated/server\"; export const get = query({ args: {}, handler: async (ctx) => { return await ctx.db.query(\"tasks\").collect(); }, }); ``` 7. Wire up the ConvexProvider Modify `app/root.tsx` to set up the Convex client there to make it available on every page of your app. app/root.tsx ```codeBlockLines_zEuJ import { Links, Meta, Outlet, Scripts, ScrollRestoration, json, useLoaderData, } from \"@remix-run/react\"; import { ConvexProvider, ConvexReactClient } from \"convex/react\"; import { useState } from \"react\"; export async function loader() { const CONVEX_URL = process.env[\"CONVEX_URL\"]!; return json({ ENV: { CONVEX_URL } }); } export function Layout({ children }: { children: React.ReactNode }) { const { ENV } = useLoaderData(); const [convex] = useState(() => new ConvexReactClient(ENV.CONVEX_URL)); return ( {children} ); } export default function App() { return ; } ``` 8. Display the data in your app In `app/routes/_index.tsx` use `useQuery` to subscribe your `api.tasks.get` API function. app/routes/\\_index.tsx ```codeBlockLines_zEuJ import type { MetaFunction } from \"@remix-run/node\"; import { api } from \"convex/_generated/api\"; import { useQuery } from \"convex/react\"; export const meta: MetaFunction = () => { return [\\ { title: \"New Remix App\" },\\ { name: \"description\", content: \"Welcome to Remix!\" },\\ ]; }; export default function Index() { const tasks = useQuery(api.tasks.get); return (

Welcome to Remix

{tasks === undefined ? \"loading...\" : tasks.map(({ _id, text }) =>
{text}
)}
); } ``` 9. Start the app Start the app, open [http://localhost:5173](http://localhost:5173/) in a browser, and see the list of tasks. ```codeBlockLines_zEuJ npm run dev ``` [Skip to main content](https://docs.convex.dev/auth/debug#docusaurus_skipToContent_fallback) On this page # Debugging Authentication You have followed one of our authentication guides but something is not working. You have double checked that you followed all the steps, and that you used the correct secrets, but you are still stuck. ## Frequently encountered issues [​](https://docs.convex.dev/auth/debug\\#frequently-encountered-issues \"Direct link to Frequently encountered issues\") ### `ctx.auth.getUserIdentity()` returns `null` in a query [​](https://docs.convex.dev/auth/debug\\#ctxauthgetuseridentity-returns-null-in-a-query \"Direct link to ctxauthgetuseridentity-returns-null-in-a-query\") This often happens when subscribing to queries via `useQuery` in React, without waiting for the client to be authenticated. Even if the user has been logged-in previously, it takes some time for the client to authenticate with the Convex backend. Therefore on page load, `ctx.auth.getUserIdentity()` called within a query returns `null`. To handle this, you can either: 1. Use the `Authenticated` component from `convex/react` to wrap the component that includes the `useQuery` call (see the last two steps in the [Clerk guide](https://docs.convex.dev/auth/clerk#get-started)) 2. Or return `null` or some other \"sentinel\" value from the query and handle it on the client If you are using `fetchQuery` for [Next.js Server Rendering](https://docs.convex.dev/client/react/nextjs/server-rendering), make sure you are explicitly passing in a JWT token as documented [here](https://docs.convex.dev/client/react/nextjs/server-rendering#server-side-authentication). If this hasn't helped, follow the steps below to resolve your issue. ## Step 1: Check whether authentication works on the backend [​](https://docs.convex.dev/auth/debug\\#step-1-check-whether-authentication-works-on-the-backend \"Direct link to Step 1: Check whether authentication works on the backend\") 1. Add the following code to the _beginning_ of your function (query, mutation, action or http action): ```codeBlockLines_zEuJ console.log(\"server identity\", await ctx.auth.getUserIdentity()); ``` 2. Then call this function from whichever client you're using to talk to Convex. 3. Open the [logs page on your dashboard](https://dashboard.convex.dev/deployment/logs). 4. What do you see on the logs page? **Answer: I don't see anything**: - Potential cause: You don't have the right dashboard open. Confirm that the Deployment URL on _Settings_ \\> _URL and Deploy Key_ page matches how your client is configured. - Potential cause: Your client is not connected to Convex. Check your client logs (browser logs) for errors. Reload the page / restart the client. - Potential cause: The code has not been pushed. For dev deployments make sure you have `npx convex dev` running. For prod deployments make sure you successfully pushed via `npx convex deploy`. Go to the _Functions_ page on the dashboard and check that the code shown there includes the `console.log` line you added. When you resolved the cause you should see the log appear. **Answer: I see a log with `'server identity' null`**: - Potential cause: The client is not supplying an auth token. - Potential cause: Your deployment is misconfigured. - Potential cause: Your client is misconfigured. Proceed to [step 2](https://docs.convex.dev/auth/debug#step-2-check-whether-authentication-works-on-the-frontend). **Answer: I see a log with `'server identity' { tokenIdentifier: '... } `** Great, you are all set! ## Step 2: Check whether authentication works on the frontend [​](https://docs.convex.dev/auth/debug\\#step-2-check-whether-authentication-works-on-the-frontend \"Direct link to Step 2: Check whether authentication works on the frontend\") No matter which client you use, it must pass a JWT token to your backend for authentication to work. The most bullet-proof way of ensuring your client is passing the token to the backend, is to inspect the traffic between them. 1. If you're using a client from the web browser, open the _Network_ tab in your browser's developer tools. 2. Check the token - For Websocket-based clients ( `ConvexReactClient` and `ConvexClient`), filter for the `sync` name and select `WS` as the type of traffic. Check the `sync` items. After the client is initialized (commonly after loading the page), it will send a message (check the _Messages_ tab) with `type: \"Authenticate\"`, and `value` will be the authentication token. ![Network tab inspecting Websocket messages](https://docs.convex.dev/screenshots/auth-ws.png) - For HTTP based clients ( `ConvexHTTPClient` and the [HTTP API](https://docs.convex.dev/http-api/)), select `Fetch/XHR` as the type of traffic. You should see an individual network request for each function call, with an `Authorization` header with value `Bearer ` followed by the authentication token. ![Network tab inspecting HTTP headers](https://docs.convex.dev/screenshots/auth-http.png) 3. Do you see the authentication token in the traffic? **Answer: No**: - Potential cause: The Convex client is not configured to get/fetch a JWT token. You're not using `ConvexProviderWithClerk`/ `ConvexProviderWithAuth0`/ `ConvexProviderWithAuth` with the `ConvexReactClient` or you forgot to call `setAuth` on `ConvexHTTPClient` or `ConvexClient`. - Potential cause: You are not signed in, so the token is `null` or `undefined` and the `ConvexReactClient` skipped authentication altogether. Verify that you are signed in via `console.log` ing the token from whichever auth provider you are using: - Clerk: ```codeBlockLines_zEuJ // import { useAuth } from \"@clerk/nextjs\"; // for Next.js import { useAuth } from \"@clerk/clerk-react\"; const { getToken } = useAuth(); console.log(getToken({ template: \"convex\" })); ``` - Auth0: ```codeBlockLines_zEuJ import { useAuth0 } from \"@auth0/auth0-react\"; const { getAccessTokenSilently } = useAuth0(); const response = await getAccessTokenSilently({ detailedResponse: true, }); const token = response.id_token; console.log(token); ``` - Custom: However you implemented `useAuthFromProviderX` If you don't see a long string that looks like a token, check the browser logs for errors from your auth provider. If there are none, check the Network tab to see whether requests to your provider are failing. Perhaps the auth provider is misconfigured. Double check the auth provider configuration (in the corresponding React provider or however your auth provider is configured for the client). Try clearing your cookies in the browser (in dev tools _Application_ \\> _Cookies_ \\> _Clear all cookies_ button). **Answer: Yes, I see a long string that looks like a JWT**: Great, copy the whole token (there can be `.` s in it, so make sure you're not copying just a portion of it). 4. Open [https://jwt.io/](https://jwt.io/), scroll down and paste the token in the Encoded textarea on the left of the page. On the right you should see: - In _HEADER_, `\"typ\": \"JWT\"` - in _PAYLOAD_, a valid JSON with at least `\"aud\"`, `\"iss\"` and `\"sub\"` fields. If you see gibberish in the payload you probably didn't copy the token correctly or it's not a valid JWT token. If you see a valid JWT token, repeat [step 1](https://docs.convex.dev/auth/debug#step-1-check-whether-authentication-works-on-the-backend). If you still don't see correct identity, proceed to step 3. ## Step 3: Check that backend configuration matches frontend configuration [​](https://docs.convex.dev/auth/debug\\#step-3-check-that-backend-configuration-matches-frontend-configuration \"Direct link to Step 3: Check that backend configuration matches frontend configuration\") You have a valid JWT token on the frontend, and you know that it is being passed to the backend, but the backend is not validating it. 1. Open the _Settings_ \\> _Authentication_ on your dashboard. What do you see? **Answer: I see** **`This deployment has no configured authentication providers`**: - Cause: You do not have an `auth.config.ts` (or `auth.config.js`) file in your `convex` directory, or you haven't pushed your code. Follow the authentication guide to create a valid auth config file. For dev deployments make sure you have `npx convex dev` running. For prod deployments make sure you successfully pushed via `npx convex deploy`. \\*\\*Answer: I see one or more _Domain_ and _Application ID_ pairs. Great, let's check they match the JWT token. 2. Look at the `iss` field in the JWT token payload at [https://jwt.io/](https://jwt.io/). Does it match a _Domain_ on the _Authentication_ page? **Answer: No, I don't see the `iss` URL on the Convex dashboard**: - Potential cause: You copied the wrong value into your `auth.config.ts` 's `domain`, or into the environment variable that is used there. Go back to the authentication guide and make sure you have the right URL from your auth provider. - Potential cause: Your client is misconfigured: - Clerk: You have the wrong `publishableKey` configured. The key must belong to the Clerk instance that you used to configure your `auth.config.ts`. - Also make sure that the JWT token in Clerk is called `convex`, as that's the name `ConvexProviderWithClerk` uses to fetch the token! - Auth0: You have the wrong `domain` configured (on the client!). The domain must belong to the Auth0 instance that you used to configure your `auth.config.ts`. - Custom: Make sure that your client is correctly configured to match your `auth.config.ts`. **Answer: Yes, I do see the `iss` URL**: Great, let's move one. 3. Look at the `aud` field in the JWT token payload at [https://jwt.io/](https://jwt.io/). Does it match the _Application ID_ under the correct _Domain_ on the _Authentication_ page? **Answer: No, I don't see the `aud` value in the _Application ID_ field**: - Potential cause: You copied the wrong value into your `auth.config.ts`'s `applicationID`, or into the environment variable that is used there. Go back to the authentication guide and make sure you have the right value from your auth provider. - Potential cause: Your client is misconfigured: - Clerk: You have the wrong `publishableKey` configured.The key must belong to the Clerk instance that you used to configure your `auth.config.ts`. - Auth0: You have the wrong `clientId` configured. Make sure you're using the right `clientId` for the Auth0 instance that you used to configure your `auth.config.ts`. - Custom: Make sure that your client is correctly configured to match your `auth.config.ts`. **Answer: Yes, I do see the `aud` value in the _Application ID_ field**: Great, repeat [step 1](https://docs.convex.dev/auth/debug#step-1-check-whether-authentication-works-on-the-backend) and you should be all set! - [Frequently encountered issues](https://docs.convex.dev/auth/debug#frequently-encountered-issues) - [`ctx.auth.getUserIdentity()` returns `null` in a query](https://docs.convex.dev/auth/debug#ctxauthgetuseridentity-returns-null-in-a-query) - [Step 1: Check whether authentication works on the backend](https://docs.convex.dev/auth/debug#step-1-check-whether-authentication-works-on-the-backend) - [Step 2: Check whether authentication works on the frontend](https://docs.convex.dev/auth/debug#step-2-check-whether-authentication-works-on-the-frontend) - [Step 3: Check that backend configuration matches frontend configuration](https://docs.convex.dev/auth/debug#step-3-check-that-backend-configuration-matches-frontend-configuration) [Skip to main content](https://docs.convex.dev/production/hosting/vercel#docusaurus_skipToContent_fallback) On this page Hosting your Convex app on Vercel allows you to automatically re-deploy both your backend and your frontend whenever you push your code. ## Deploying to Vercel [​](https://docs.convex.dev/production/hosting/vercel\\#deploying-to-vercel \"Direct link to Deploying to Vercel\") This guide assumes you already have a working React app with Convex. If not follow the [Convex React Quickstart](https://docs.convex.dev/quickstart/react) first. Then: 1. Create a Vercel account If you haven't done so, create a [Vercel](https://vercel.com/) account. This is free for small projects and should take less than a minute to set up. 2. Link your project on Vercel Create a Vercel project at [https://vercel.com/new](https://vercel.com/new) and link it to the source code repository for your project on GitHub or other Git platform. ![Vercel import project](https://docs.convex.dev/assets/images/vercel_import-ea7ec18cd8c5e5575158bcf032698bc7.png) 3. Override the Build command Override the \"Build command\" to be `npx convex deploy --cmd 'npm run build'`. If your project lives in a subdirectory of your repository you'll also need to change _Root Directory_ above accordingly. ![Vercel build settings](https://docs.convex.dev/assets/images/vercel_build_command-236a66a2e7e2091d610883c56954dcb9.png) 4. Set up the CONVEX\\_DEPLOY\\_KEY environment variable On your [Convex Dashboard](https://dashboard.convex.dev/) go to your project's _Settings_ page. Click the _Generate Production Deploy Key_ button to generate a **Production** deploy key. Then click the copy button to copy the key. In Vercel, click _Environment Variables_. Create an environment variable named `CONVEX_DEPLOY_KEY` and paste in your deploy key. Under _Environment_, uncheck all except _Production_ and click _Save_. ![Vercel environment variable CONVEX_DEPLOY_KEY](https://docs.convex.dev/assets/images/vercel_prod_deploy_key-df730e5f65427ae68f68b48af225995b.png) 5. Deploy your site Now click the _Deploy_ button and your work here is done! Vercel will automatically publish your site to an URL like `https://.vercel.app`, shown on the page after deploying. Every time you push to your Git repository, Vercel will automatically deploy your Convex functions and publish your site changes. Using a Custom Domain? If you're using a custom domain to serve your Convex functions, you'll need additional configuration. See [Custom\\\\ Domains](https://docs.convex.dev/production/hosting/custom#hosting-with-a-custom-domain) for more information. ### How it works [​](https://docs.convex.dev/production/hosting/vercel\\#how-it-works \"Direct link to How it works\") In Vercel, we overrode the _Build Command_ to be `npx convex deploy --cmd 'npm run build'`. `npx convex deploy` will read `CONVEX_DEPLOY_KEY` from the environment and use it to set the `CONVEX_URL` (or similarly named) environment variable to point to your **production** deployment. Your frontend framework of choice invoked by `npm run build` will read the `CONVEX_URL` (or similarly named) environment variable to point your deployed site (via `ConvexReactClient`) at your **production** deployment. Finally, `npx convex deploy` will push your Convex functions to your production deployment. Now, your production deployment has your newest functions and your app is configured to connect to it. You can use `--cmd-url-env-var-name` to customize the variable name used by your frontend code if the `deploy` command cannot infer it, like ```codeBlockLines_zEuJ npx convex deploy --cmd-url-env-var-name CUSTOM_CONVEX_URL --cmd 'npm run build' ``` ### Authentication [​](https://docs.convex.dev/production/hosting/vercel\\#authentication \"Direct link to Authentication\") You will want to configure your [authentication](https://docs.convex.dev/auth) provider (Clerk, Auth0 or other) to accept your production URL. Note that Clerk does not support `https://.vercel.app`, so you'll have to configure a custom domain. ## Preview Deployments [​](https://docs.convex.dev/production/hosting/vercel\\#preview-deployments \"Direct link to Preview Deployments\") Vercel Preview Deployments allow you to preview changes to your app before they're merged in. In order to preview both changes to frontend code and Convex functions, you can set up [Convex preview deployments](https://docs.convex.dev/production/hosting/preview-deployments). This will create a fresh Convex backend for each preview and leave your production and development deployments unaffected. This assumes you have already followed the steps in [Deploying to Vercel](https://docs.convex.dev/production/hosting/vercel#deploying-to-vercel) above. 1. Set up the CONVEX\\_DEPLOY\\_KEY environment variable On your [Convex Dashboard](https://dashboard.convex.dev/) go to your project's _Settings_ page. Click the _Generate Preview Deploy Key_ button to generate a **Preview** deploy key. Then click the copy button to copy the key. In Vercel, click _Environment Variables_. Create an environment variable named `CONVEX_DEPLOY_KEY` and paste in your deploy key. Under _Environment_, uncheck all except _Preview_ and click _Save_. ![Vercel environment variable CONVEX_DEPLOY_KEY](https://docs.convex.dev/assets/images/vercel_preview_deploy_key-bb1badeb35323ef9c06516982aa5c8c7.png) 2. (optional) Set up default environment variables If your app depends on certain Convex environment variables, you can set up [default\\\\ environment variables](https://docs.convex.dev/production/environment-variables#project-environment-variable-defaults) for preview and development deployments in your project. ![Project Default Environment Variables](https://docs.convex.dev/assets/images/project_default_environment_variables-94be77c692d0a3c9564cb7f642b6cb64.png) 3. (optional) Run a function to set up initial data Vercel Preview Deployments run against fresh Convex backends, which do not share data with development or production Convex deployments. You can call a Convex function to set up data by adding `--preview-run 'functionName'` to the `npx convex deploy` command. This function will only be run for preview deployments, and will be ignored when deploying to production. Vercel > Settings > Build & Development settings > Build Command ```codeBlockLines_zEuJ npx convex deploy --cmd 'npm run build' --preview-run 'functionName' ``` 4. Now test out creating a PR and generating a Preview Deployment! You can find the Convex deployment for your branch in the Convex dashboard. ![Preview Deployment in Deployment Picker](https://docs.convex.dev/assets/images/preview_deployment_deployment_picker-bc5b5e7cd3ac7e0e44ec7ed4c8b40c1c.png) ### How it works [​](https://docs.convex.dev/production/hosting/vercel\\#how-it-works-1 \"Direct link to How it works\") For Preview Deployments, `npx convex deploy` will read `CONVEX_DEPLOY_KEY` from the environment, and use it to create a Convex deployment associated with the Git branch name for the Vercel Preview Deployment. It will set the `CONVEX_URL` (or similarly named) environment variable to point to the new Convex deployment. Your frontend framework of choice invoked by `npm run build` will read the `CONVEX_URL` environment variable and point your deployed site (via `ConvexReactClient`) at the Convex preview deployment. Finally, `npx convex deploy` will push your Convex functions to the preview deployment and run the `--preview-run` function (if provided). This deployment has separate functions, data, crons and all other configuration from any other deployments. `npx convex deploy` will infer the Git branch name for Vercel, Netlify, GitHub, and GitLab environments, but the `--preview-create` option can be used to customize the name associated with the newly created deployment. Production deployments will work exactly the same as before. - [Deploying to Vercel](https://docs.convex.dev/production/hosting/vercel#deploying-to-vercel) - [How it works](https://docs.convex.dev/production/hosting/vercel#how-it-works) - [Authentication](https://docs.convex.dev/production/hosting/vercel#authentication) - [Preview Deployments](https://docs.convex.dev/production/hosting/vercel#preview-deployments) - [How it works](https://docs.convex.dev/production/hosting/vercel#how-it-works-1) [Skip to main content](https://docs.convex.dev/functions#docusaurus_skipToContent_fallback) Functions run on the backend and are written in JavaScript (or TypeScript). They are automatically available as APIs accessed through [client libraries](https://docs.convex.dev/client/react). Everything you do in the Convex backend starts from functions. There are three types of functions: - [Queries](https://docs.convex.dev/functions/query-functions) read data from your Convex database and are automatically cached and subscribable (realtime, reactive). - [Mutations](https://docs.convex.dev/functions/mutation-functions) write data to the database and run as a transaction. - [Actions](https://docs.convex.dev/functions/actions) can call OpenAI, Stripe, Twilio, or any other service or API you need to make your app work. You can also build [HTTP actions](https://docs.convex.dev/functions/http-actions) when you want to call your functions from a webhook or a custom client. Here's an overview of the three different types of Convex functions and what they can do: | | Queries | Mutations | Actions | | --- | --- | --- | --- | | Database access | Yes | Yes | No | | Transactional | Yes | Yes | No | | Cached | Yes | No | No | | Real-time Updates | Yes | No | No | | External API Calls (fetch) | No | No | Yes | [Skip to main content](https://docs.convex.dev/generated-api/api#docusaurus_skipToContent_fallback) On this page This code is generated These exports are not directly available in the `convex` package! Instead you need to run `npx convex dev` to create `convex/_generated/api.js` and `convex/_generated/api.d.ts`. These types require running code generation because they are specific to the Convex functions you define for your app. If you aren't using code generation, you can use [`makeFunctionReference`](https://docs.convex.dev/api/modules/server#makefunctionreference) instead. ### api [​](https://docs.convex.dev/generated-api/api\\#api \"Direct link to api\") An object of type `API` describing your app's public Convex API. Its `API` type includes information about the arguments and return types of your app's Convex functions. The api object is used by client-side React hooks and Convex functions that run or schedule other functions. src/App.jsx ```codeBlockLines_zEuJ import { api } from \"../convex/_generated/api\"; import { useQuery } from \"convex/react\"; const data = useQuery(api.messages.list); ``` ### internal [​](https://docs.convex.dev/generated-api/api\\#internal \"Direct link to internal\") Another object of type `API` describing your app's internal Convex API. convex/upgrade.js ```codeBlockLines_zEuJ import { action } from \"../_generated/server\"; import { internal } from \"../_generated/api\"; export default action(async ({ runMutation }, { planId, ... }) => { // Call out to payment provider (e.g. Stripe) to charge customer const response = await fetch(...); if (response.ok) { // Mark the plan as \"professional\" in the Convex DB await runMutation(internal.plans.markPlanAsProfessional, { planId }); } }); ``` - [api](https://docs.convex.dev/generated-api/api#api) - [internal](https://docs.convex.dev/generated-api/api#internal) [Skip to main content](https://docs.convex.dev/client/react-native#docusaurus_skipToContent_fallback) To use Convex in [React Native](https://reactnative.dev/) use the [Convex React client library](https://docs.convex.dev/client/react). Follow the [React Native Quickstart](https://docs.convex.dev/quickstart/react-native) for the different configuration needed specifically for React Native. You can also clone a working [Convex React Native demo](https://github.com/get-convex/convex-demos/tree/main/react-native). [Skip to main content](https://docs.convex.dev/testing/ci#docusaurus_skipToContent_fallback) On this page Continuous integration allows your team to move fast by combining changes from all team members and automatically testing them on a remote machine. ## Testing in GitHub Actions [​](https://docs.convex.dev/testing/ci\\#testing-in-github-actions \"Direct link to Testing in GitHub Actions\") It's easy if you're using [GitHub](https://docs.github.com/en/actions) to set up [CI](https://docs.github.com/en/actions/automating-builds-and-tests/about-continuous-integration) workflow for running your test suite: .github/workflows/test.yml ```codeBlockLines_zEuJ name: Run Tests on: [pull_request, push] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 - run: npm ci - run: npm run test ``` After you commit and push this file to your repository, GitHub will run `npm run test` every time you create a pull request or push a new commit. - [Testing in GitHub Actions](https://docs.convex.dev/testing/ci#testing-in-github-actions) [Skip to main content](https://docs.convex.dev/functions/validation#docusaurus_skipToContent_fallback) On this page Argument and return value validators ensure that [queries](https://docs.convex.dev/functions/query-functions), [mutations](https://docs.convex.dev/functions/mutation-functions), and [actions](https://docs.convex.dev/functions/actions) are called with the correct types of arguments and return the expected types of return values. **This is important for security!** Without argument validation, a malicious user can call your public functions with unexpected arguments and cause surprising results. [TypeScript](https://docs.convex.dev/understanding/best-practices/typescript) alone won't help because TypeScript types aren't present at runtime. We recommend adding argument validation for all public functions in production apps. For non-public functions that are not called by clients, we recommend [internal functions](https://docs.convex.dev/functions/internal-functions) and optionally validation. **Example:** [Argument Validation](https://github.com/get-convex/convex-demos/tree/main/args-validation) ## Adding validators [​](https://docs.convex.dev/functions/validation\\#adding-validators \"Direct link to Adding validators\") To add argument validation to your functions, pass an object with `args` and `handler` properties to the `query`, `mutation` or `action` constructor. To add return value validation, use the `returns` property in this object: convex/message.ts TS ```codeBlockLines_zEuJ import { mutation, query } from \"./_generated/server\"; import { v } from \"convex/values\"; export const send = mutation({ args: { body: v.string(), author: v.string(), }, returns: v.null(), handler: async (ctx, args) => { const { body, author } = args; await ctx.db.insert(\"messages\", { body, author }); }, }); ``` If you define your function with an argument validator, there is no need to include [TypeScript](https://docs.convex.dev/understanding/best-practices/typescript) type annotations! The type of your function will be inferred automatically. Similarly, if you define a return value validator, the return type of your function will be inferred from the validator, and TypeScript will check that it matches the inferred return type of the `handler` function. Unlike TypeScript, validation for an object will throw if the object contains properties that are not declared in the validator. If the client supplies arguments not declared in `args`, or if the function returns a value that does not match the validator declared in `returns`. This is helpful to prevent bugs caused by mistyped names of arguments or returning more data than intended to a client. Even `args: {}` is a helpful use of validators because TypeScript will show an error on the client if you try to pass any arguments to the function which doesn't expect them. ## Supported types [​](https://docs.convex.dev/functions/validation\\#supported-types \"Direct link to Supported types\") All functions, both public and internal, can accept and return the following data types. Each type has a corresponding validator that can be accessed on the [`v`](https://docs.convex.dev/api/modules/values#v) object imported from `\"convex/values\"`. The [database](https://docs.convex.dev/database) can store the exact same set of [data types](https://docs.convex.dev/database/types). Additionally you can also express type unions, literals, `any` types, and optional fields. ### Convex values [​](https://docs.convex.dev/functions/validation\\#convex-values \"Direct link to Convex values\") Convex supports the following types of values: | Convex Type | TS/JS Type | Example Usage | Validator for [Argument Validation](https://docs.convex.dev/functions/validation) and [Schemas](https://docs.convex.dev/database/schemas) | `json` Format for [Export](https://docs.convex.dev/database/import-export) | Notes | | --- | --- | --- | --- | --- | --- | | Id | [string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#string_type) | `doc._id` | `v.id(tableName)` | string | See [Document IDs](https://docs.convex.dev/database/document-ids). | | Null | [null](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#null_type) | `null` | `v.null()` | null | JavaScript's `undefined` is not a valid Convex value. Functions the return `undefined` or do not return will return `null` when called from a client. Use `null` instead. | | Int64 | [bigint](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#bigint_type) | `3n` | `v.int64()` | string (base10) | Int64s only support BigInts between -2^63 and 2^63-1. Convex supports `bigint` s in [most modern browsers](https://caniuse.com/bigint). | | Float64 | [number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#number_type) | `3.1` | `v.number()` | number / string | Convex supports all IEEE-754 double-precision floating point numbers (such as NaNs). Inf and NaN are JSON serialized as strings. | | Boolean | [boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#boolean_type) | `true` | `v.boolean()` | bool | | | String | [string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#string_type) | `\"abc\"` | `v.string()` | string | Strings are stored as UTF-8 and must be valid Unicode sequences. Strings must be smaller than the 1MB total size limit when encoded as UTF-8. | | Bytes | [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) | `new ArrayBuffer(8)` | `v.bytes()` | string (base64) | Convex supports first class bytestrings, passed in as `ArrayBuffer` s. Bytestrings must be smaller than the 1MB total size limit for Convex types. | | Array | [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) | `[1, 3.2, \"abc\"]` | `v.array(values)` | array | Arrays can have at most 8192 values. | | Object | [Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#objects) | `{a: \"abc\"}` | `v.object({property: value})` | object | Convex only supports \"plain old JavaScript objects\" (objects that do not have a custom prototype). Convex includes all [enumerable properties](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties). Objects can have at most 1024 entries. Field names must be nonempty and not start with \"$\" or \"\\_\". | | Record | [Record](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type) | `{\"a\": \"1\", \"b\": \"2\"}` | `v.record(keys, values)` | object | Records are objects at runtime, but can have dynamic keys. Keys must be only ASCII characters, nonempty, and not start with \"$\" or \"\\_\". | ### Unions [​](https://docs.convex.dev/functions/validation\\#unions \"Direct link to Unions\") You can describe fields that could be one of multiple types using `v.union`: ```codeBlockLines_zEuJ import { mutation } from \"./_generated/server\"; import { v } from \"convex/values\"; export default mutation({ args: { stringOrNumber: v.union(v.string(), v.number()), }, handler: async ({ db }, { stringOrNumber }) => { //... }, }); ``` ### Literals [​](https://docs.convex.dev/functions/validation\\#literals \"Direct link to Literals\") Fields that are a constant can be expressed with `v.literal`. This is especially useful when combined with unions: ```codeBlockLines_zEuJ import { mutation } from \"./_generated/server\"; import { v } from \"convex/values\"; export default mutation({ args: { oneTwoOrThree: v.union( v.literal(\"one\"), v.literal(\"two\"), v.literal(\"three\"), ), }, handler: async ({ db }, { oneTwoOrThree }) => { //... }, }); ``` ### Record objects [​](https://docs.convex.dev/functions/validation\\#record-objects \"Direct link to Record objects\") You can describe objects that map arbitrary keys to values with `v.record`: ```codeBlockLines_zEuJ import { mutation } from \"./_generated/server\"; import { v } from \"convex/values\"; export default mutation({ args: { simpleMapping: v.record(v.string(), v.boolean()), }, handler: async ({ db }, { simpleMapping }) => { //... }, }); ``` You can use other types of string validators for the keys: ```codeBlockLines_zEuJ defineTable({ userIdToValue: v.record(v.id(\"users\"), v.boolean()), }); ``` Notes: - This type corresponds to the [Record](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type) type in TypeScript - You cannot use string literals as a `record` key - Using `v.string()` as a `record` key validator will only allow ASCII characters ### Any [​](https://docs.convex.dev/functions/validation\\#any \"Direct link to Any\") Fields that could take on any value can be represented with `v.any()`: ```codeBlockLines_zEuJ import { mutation } from \"./_generated/server\"; import { v } from \"convex/values\"; export default mutation({ args: { anyValue: v.any(), }, handler: async ({ db }, { anyValue }) => { //... }, }); ``` This corresponds to the `any` type in TypeScript. ### Optional fields [​](https://docs.convex.dev/functions/validation\\#optional-fields \"Direct link to Optional fields\") You can describe optional fields by wrapping their type with `v.optional(...)`: ```codeBlockLines_zEuJ import { mutation } from \"./_generated/server\"; import { v } from \"convex/values\"; export default mutation({ args: { optionalString: v.optional(v.string()), optionalNumber: v.optional(v.number()), }, handler: async ({ db }, { optionalString, optionalNumber }) => { //... }, }); ``` This corresponds to marking fields as optional with `?` in TypeScript. ## Extracting TypeScript types [​](https://docs.convex.dev/functions/validation\\#extracting-typescript-types \"Direct link to Extracting TypeScript types\") The [`Infer`](https://docs.convex.dev/api/modules/values#infer) type allows you to turn validator calls into TypeScript types. This can be useful to remove duplication between your validators and TypeScript types: ```codeBlockLines_zEuJ import { mutation } from \"./_generated/server\"; import { Infer, v } from \"convex/values\"; const nestedObject = v.object({ property: v.string(), }); // Resolves to `{property: string}`. export type NestedObject = Infer; export default mutation({ args: { nested: nestedObject, }, handler: async ({ db }, { nested }) => { //... }, }); ``` - [Adding validators](https://docs.convex.dev/functions/validation#adding-validators) - [Supported types](https://docs.convex.dev/functions/validation#supported-types) - [Convex values](https://docs.convex.dev/functions/validation#convex-values) - [Unions](https://docs.convex.dev/functions/validation#unions) - [Literals](https://docs.convex.dev/functions/validation#literals) - [Record objects](https://docs.convex.dev/functions/validation#record-objects) - [Any](https://docs.convex.dev/functions/validation#any) - [Optional fields](https://docs.convex.dev/functions/validation#optional-fields) - [Extracting TypeScript types](https://docs.convex.dev/functions/validation#extracting-typescript-types) [Skip to main content](https://docs.convex.dev/home#docusaurus_skipToContent_fallback) Convex is an all-in-one backend platform with thoughtful, product-centric APIs. Use [TypeScript](https://docs.convex.dev/understanding/best-practices/typescript) to write [queries as\\\\ code](https://docs.convex.dev/functions/query-functions) that are [automatically\\\\ cached](https://docs.convex.dev/realtime#automatic-caching) and [realtime](https://docs.convex.dev/realtime), with an acid compliant [relational database](https://docs.convex.dev/database). [**Learn Convex by creating a chat app** \\\\ \\\\ Convex provides you with a fully featured backend with cloud functions,](https://docs.convex.dev/tutorial) ## Quickstarts [​](https://docs.convex.dev/home\\#quickstarts \"Direct link to Quickstarts\") Quickly get up and running with your favorite frontend tooling or language: [React Logo\\\\ **React**](https://docs.convex.dev/quickstart/react) [**Next.js**](https://docs.convex.dev/quickstart/nextjs) [**Remix**](https://docs.convex.dev/quickstart/remix) [**TanStack Start**](https://docs.convex.dev/quickstart/tanstack-start) [**React Native**](https://docs.convex.dev/quickstart/react-native) [**Vue**](https://docs.convex.dev/quickstart/vue) [**Svelte**](https://docs.convex.dev/quickstart/svelte) [**Node.js**](https://docs.convex.dev/quickstart/nodejs) [Bun Logo\\\\ **Bun**](https://docs.convex.dev/quickstart/bun) [HTML5 Logo\\\\ **Script tag**](https://docs.convex.dev/quickstart/script-tag) [**Python**](https://docs.convex.dev/quickstart/python) [**iOS Swift**](https://docs.convex.dev/quickstart/swift) [**Android Kotlin**](https://docs.convex.dev/quickstart/android) [**Rust**](https://docs.convex.dev/quickstart/rust) ## Why Convex? [​](https://docs.convex.dev/home\\#why-convex \"Direct link to Why Convex?\") YouTube ## Backends Should be Designed for Product Developers Intro to Convex - YouTube Convex 2.07K subscribers [Intro to Convex](https://www.youtube.com/watch?v=UVvd7BF99-4) Convex Search Info Shopping Tap to unmute If playback doesn't begin shortly, try restarting your device. Share Include playlist An error occurred while retrieving sharing information. Please try again later. Watch later Share Copy link 0:00 / •Live • [Watch on YouTube](https://www.youtube.com/watch?v=UVvd7BF99-4 \"Watch on YouTube\") ## Intro to Convex Supercharge your Application with a Reactive Database - YouTube Convex 2.07K subscribers [Supercharge your Application with a Reactive Database](https://www.youtube.com/watch?v=V6En7UO4Ui0) Convex Search Info Shopping Tap to unmute If playback doesn't begin shortly, try restarting your device. You're signed out Videos you watch may be added to the TV's watch history and influence TV recommendations. To avoid this, cancel and sign in to YouTube on your computer. CancelConfirm Share Include playlist An error occurred while retrieving sharing information. Please try again later. Watch later Share Copy link Watch on 0:00 / •Live • [Watch on YouTube](https://www.youtube.com/watch?v=V6En7UO4Ui0 \"Watch on YouTube\") ## Supercharging your app with a reactive backend Why I use Convex over Supabase as my BaaS - YouTube Web Dev Cody 246K subscribers [Why I use Convex over Supabase as my BaaS](https://www.youtube.com/watch?v=O_HXVAMPEbc) Web Dev Cody Search Info Shopping Tap to unmute If playback doesn't begin shortly, try restarting your device. You're signed out Videos you watch may be added to the TV's watch history and influence TV recommendations. To avoid this, cancel and sign in to YouTube on your computer. CancelConfirm Share Include playlist An error occurred while retrieving sharing information. Please try again later. Watch later Share Copy link Watch on 0:00 / •Live • [Watch on YouTube](https://www.youtube.com/watch?v=O_HXVAMPEbc \"Watch on YouTube\") ## Why I use Convex over Supabase as my BaaS Read the team's Perspectives on [Stack](https://stack.convex.dev/): [**Convex vs Relational Databases**](https://stack.convex.dev/convex-vs-relational-databases) [**Convex vs Firebase**](https://stack.convex.dev/convex-vs-firebase) [**It's not you, it's SQL**](https://stack.convex.dev/not-sql) [**How Convex Works**](https://stack.convex.dev/how-convex-works) [**The Software-Defined Database**](https://stack.convex.dev/the-software-defined-database) [**Convex Perspectives**](https://stack.convex.dev/tag/Perspectives) ## Learn Convex [​](https://docs.convex.dev/home\\#learn-convex \"Direct link to Learn Convex\") A quick start guide for using Convex with Next.js - YouTube Web Dev Cody 246K subscribers [A quick start guide for using Convex with Next.js](https://www.youtube.com/watch?v=vaQZYRSiimI) Web Dev Cody Search Info Shopping Tap to unmute If playback doesn't begin shortly, try restarting your device. You're signed out Videos you watch may be added to the TV's watch history and influence TV recommendations. To avoid this, cancel and sign in to YouTube on your computer. CancelConfirm Share Include playlist An error occurred while retrieving sharing information. Please try again later. Watch later Share Copy link Watch on 0:00 / •Live • [Watch on YouTube](https://www.youtube.com/watch?v=vaQZYRSiimI \"Watch on YouTube\") ## A quick start guide for using Convex with Next.js Fullstack Notion Clone: Next.js 13, React, Convex, Tailwind \\| Full Course 2023 - YouTube Code With Antonio 371K subscribers [Fullstack Notion Clone: Next.js 13, React, Convex, Tailwind \\| Full Course 2023](https://www.youtube.com/watch?v=0OaDyjB9Ib8) Code With Antonio Search Info Shopping Tap to unmute If playback doesn't begin shortly, try restarting your device. You're signed out Videos you watch may be added to the TV's watch history and influence TV recommendations. To avoid this, cancel and sign in to YouTube on your computer. CancelConfirm Share Include playlist An error occurred while retrieving sharing information. Please try again later. Watch later Share Copy link Watch on 0:00 / •Live • [Watch on YouTube](https://www.youtube.com/watch?v=0OaDyjB9Ib8 \"Watch on YouTube\") ## Fullstack Notion Clone: Next.js 13, React, Convex, Tailwind Build and Deploy a Saas Podcast Platform in Next.js - YouTube JavaScript Mastery 1.03M subscribers [Build and Deploy a Saas Podcast Platform in Next.js](https://www.youtube.com/watch?v=zfAb95tJvZQ) JavaScript Mastery Search Info Shopping Tap to unmute If playback doesn't begin shortly, try restarting your device. You're signed out Videos you watch may be added to the TV's watch history and influence TV recommendations. To avoid this, cancel and sign in to YouTube on your computer. CancelConfirm Share Include playlist An error occurred while retrieving sharing information. Please try again later. Watch later Share Copy link Watch on 0:00 / •Live • [Watch on YouTube](https://www.youtube.com/watch?v=zfAb95tJvZQ \"Watch on YouTube\") ## Build and Deploy a Saas Podcast Platform in Next.js Building a Subscription Based SaaS with my Favorite Tech Stack (Next.js, Stripe, Convex, Clerk) - YouTube Web Dev Cody 246K subscribers [Building a Subscription Based SaaS with my Favorite Tech Stack (Next.js, Stripe, Convex, Clerk)](https://www.youtube.com/watch?v=Vjtn9pWAZDI) Web Dev Cody Search Info Shopping Tap to unmute If playback doesn't begin shortly, try restarting your device. You're signed out Videos you watch may be added to the TV's watch history and influence TV recommendations. To avoid this, cancel and sign in to YouTube on your computer. CancelConfirm Share Include playlist An error occurred while retrieving sharing information. Please try again later. Watch later Share Copy link Watch on 0:00 / •Live • [Watch on YouTube](https://www.youtube.com/watch?v=Vjtn9pWAZDI \"Watch on YouTube\") ## Building a Subscription Based SaaS with Stripe See more walkthroughs and patterns on [Stack](https://stack.convex.dev/) [**Build AI Apps**](https://stack.convex.dev/tag/AI) [**Convex Patterns**](https://stack.convex.dev/tag/Patterns) [**Convex Walkthroughs**](https://stack.convex.dev/tag/Walkthroughs) reCAPTCHA Recaptcha requires verification. [Privacy](https://www.google.com/intl/en/policies/privacy/) \\- [Terms](https://www.google.com/intl/en/policies/terms/) protected by **reCAPTCHA** [Privacy](https://www.google.com/intl/en/policies/privacy/) \\- [Terms](https://www.google.com/intl/en/policies/terms/)[Skip to main content](https://docs.convex.dev/scheduling/scheduled-functions#docusaurus_skipToContent_fallback) On this page Convex allows you to schedule functions to run in the future. This allows you to build powerful durable workflows without the need to set up and maintain queues or other infrastructure. Scheduled functions are stored in the database. This means you can schedule functions minutes, days, and even months in the future. Scheduling is resilient against unexpected downtime or system restarts. **Example:** [Scheduling](https://github.com/get-convex/convex-demos/tree/main/scheduling) ## Scheduling functions [​](https://docs.convex.dev/scheduling/scheduled-functions\\#scheduling-functions \"Direct link to Scheduling functions\") You can schedule public functions and [internal functions](https://docs.convex.dev/functions/internal-functions) from mutations and actions via the [scheduler](https://docs.convex.dev/api/interfaces/server.Scheduler) provided in the respective function context. - [runAfter](https://docs.convex.dev/api/interfaces/server.Scheduler#runafter) schedules a function to run after a delay (measured in milliseconds). - [runAt](https://docs.convex.dev/api/interfaces/server.Scheduler#runat) schedules a function run at a date or timestamp (measured in milliseconds elapsed since the epoch). The rest of the arguments are the path to the function and its arguments, similar to invoking a function from the client. For example, here is how to send a message that self-destructs in five seconds. convex/messages.ts TS ```codeBlockLines_zEuJ import { mutation, internalMutation } from \"./_generated/server\"; import { internal } from \"./_generated/api\"; import { v } from \"convex/values\"; export const sendExpiringMessage = mutation({ args: { body: v.string(), author: v.string() }, handler: async (ctx, args) => { const { body, author } = args; const id = await ctx.db.insert(\"messages\", { body, author }); await ctx.scheduler.runAfter(5000, internal.messages.destruct, { messageId: id, }); }, }); export const destruct = internalMutation({ args: { messageId: v.id(\"messages\"), }, handler: async (ctx, args) => { await ctx.db.delete(args.messageId); }, }); ``` A single function can schedule up to 1000 functions with total argument size of 8MB. ### Scheduling from mutations [​](https://docs.convex.dev/scheduling/scheduled-functions\\#scheduling-from-mutations \"Direct link to Scheduling from mutations\") Scheduling functions from [mutations](https://docs.convex.dev/functions/mutation-functions#transactions) is atomic with the rest of the mutation. This means that if the mutation succeeds, the scheduled function is guaranteed to be scheduled. On the other hand, if the mutations fails, no function will be scheduled, even if the function fails after the scheduling call. ### Scheduling from actions [​](https://docs.convex.dev/scheduling/scheduled-functions\\#scheduling-from-actions \"Direct link to Scheduling from actions\") Unlike mutations, [actions](https://docs.convex.dev/functions/actions) don't execute as a single database transaction and can have side effects. Thus, scheduling from actions does not depend on the outcome of the function. This means that an action might succeed to schedule some functions and later fail due to transient error or a timeout. The scheduled functions will still be executed. ### Scheduling immediately [​](https://docs.convex.dev/scheduling/scheduled-functions\\#scheduling-immediately \"Direct link to Scheduling immediately\") Using `runAfter()` with delay set to 0 is used to immediately add a function to the event queue. This usage may be familiar to you if you're used to calling `setTimeout(fn, 0)`. As noted above, actions are not atomic and are meant to cause side effects. Scheduling immediately becomes useful when you specifically want to trigger an action from a mutation that is conditional on the mutation succeeding. [This post](https://stack.convex.dev/pinecone-and-embeddings#kick-off-a-background-action) goes over a direct example of this in action, where the application depends on an external service to fill in information to the database. ## Retrieving scheduled function status [​](https://docs.convex.dev/scheduling/scheduled-functions\\#retrieving-scheduled-function-status \"Direct link to Retrieving scheduled function status\") Every scheduled function is reflected as a document in the `\"_scheduled_functions\"` system table. `runAfter()` and `runAt()` return the id of scheduled function. You can read data from system tables using the `db.system.get` and `db.system.query` methods, which work the same as the standard `db.get` and `db.query` methods. convex/messages.ts TS ```codeBlockLines_zEuJ export const listScheduledMessages = query({ args: {}, handler: async (ctx, args) => { return await ctx.db.system.query(\"_scheduled_functions\").collect(); }, }); export const getScheduledMessage = query({ args: { id: v.id(\"_scheduled_functions\"), }, handler: async (ctx, args) => { return await ctx.db.system.get(args.id); }, }); ``` This is an example of the returned document: ```codeBlockLines_zEuJ { \"_creationTime\": 1699931054642.111, \"_id\": \"3ep33196167235462543626ss0scq09aj4gqn9kdxrdr\", \"args\": [{}], \"completedTime\": 1699931054690.366, \"name\": \"messages.js:destruct\", \"scheduledTime\": 1699931054657, \"state\": { \"kind\": \"success\" } } ``` The returned document has the following fields: - `name`: the path of the scheduled function - `args`: the arguments passed to the scheduled function - `scheduledTime`: the timestamp of when the function is scheduled to run (measured in milliseconds elapsed since the epoch) - `completedTime`: the timestamp of when the function finished running, if it has completed (measured in milliseconds elapsed since the epoch) - `state`: the status of the scheduled function. Here are the possible states a scheduled function can be in: - `Pending`: the function has not been started yet - `InProgress`: the function has started running is not completed yet (only applies to actions) - `Success`: the function finished running successfully with no errors - `Failed`: the function hit an error while running, which can either be a user error or an internal server error - `Canceled`: the function was canceled via the dashboard, `ctx.scheduler.cancel`, or recursively by a parent scheduled function that was canceled while in progress Scheduled function results are available for 7 days after they have completed. ## Canceling scheduled functions [​](https://docs.convex.dev/scheduling/scheduled-functions\\#canceling-scheduled-functions \"Direct link to Canceling scheduled functions\") You can cancel a previously scheduled function with [`cancel`](https://docs.convex.dev/api/interfaces/server.Scheduler#cancel) via the [scheduler](https://docs.convex.dev/api/interfaces/server.Scheduler) provided in the respective function context. convex/messages.ts TS ```codeBlockLines_zEuJ export const cancelMessage = mutation({ args: { id: v.id(\"_scheduled_functions\"), }, handler: async (ctx, args) => { await ctx.scheduler.cancel(args.id); }, }); ``` What `cancel` does depends on the state of the scheduled function: - If it hasn't started running, it won't run. - If it already started, it will continue to run, but any functions it schedules will not run. ## Debugging [​](https://docs.convex.dev/scheduling/scheduled-functions\\#debugging \"Direct link to Debugging\") You can view logs from previously executed scheduled functions in the Convex dashboard [Logs view](https://docs.convex.dev/dashboard#logs-view). You can view and cancel yet to be executed functions in the [Functions view](https://docs.convex.dev/dashboard#functions-view). ## Error handling [​](https://docs.convex.dev/scheduling/scheduled-functions\\#error-handling \"Direct link to Error handling\") Once scheduled, mutations are guaranteed to be executed exactly once. Convex will automatically retry any internal Convex errors, and only fail on developer errors. See [Error Handling](https://docs.convex.dev/functions/error-handling/) for more details on different error types. Since actions may have side effects, they are not automatically retried by Convex. Thus, actions will be executed at most once, and permanently fail if there are transient errors while executing them. Developers can retry those manually by scheduling a mutation that checks if the desired outcome has been achieved and if not schedule the action again. ## Auth [​](https://docs.convex.dev/scheduling/scheduled-functions\\#auth \"Direct link to Auth\") The auth is not propagated from the scheduling to the scheduled function. If you want to authenticate or check authorization, you'll have to pass the requisite user information in as a parameter. - [Scheduling functions](https://docs.convex.dev/scheduling/scheduled-functions#scheduling-functions) - [Scheduling from mutations](https://docs.convex.dev/scheduling/scheduled-functions#scheduling-from-mutations) - [Scheduling from actions](https://docs.convex.dev/scheduling/scheduled-functions#scheduling-from-actions) - [Scheduling immediately](https://docs.convex.dev/scheduling/scheduled-functions#scheduling-immediately) - [Retrieving scheduled function status](https://docs.convex.dev/scheduling/scheduled-functions#retrieving-scheduled-function-status) - [Canceling scheduled functions](https://docs.convex.dev/scheduling/scheduled-functions#canceling-scheduled-functions) - [Debugging](https://docs.convex.dev/scheduling/scheduled-functions#debugging) - [Error handling](https://docs.convex.dev/scheduling/scheduled-functions#error-handling) - [Auth](https://docs.convex.dev/scheduling/scheduled-functions#auth) [Skip to main content](https://docs.convex.dev/search/text-search#docusaurus_skipToContent_fallback) On this page Full text search allows you to find Convex documents that approximately match a search query. Unlike normal [document queries](https://docs.convex.dev/database/reading-data/#querying-documents), search queries look _within_ a string field to find the keywords. Search queries are useful for building features like searching for messages that contain certain words. Search queries are automatically reactive, consistent, transactional, and work seamlessly with pagination. They even include new documents created with a mutation! **Example:** [Search App](https://github.com/get-convex/convex-demos/tree/main/search) To use full text search you need to: 1. Define a search index. 2. Run a search query. Search indexes are built and queried using Convex's multi-segment search algorithm on top of [Tantivy](https://github.com/quickwit-oss/tantivy), a powerful, open-source, full-text search library written in Rust. Search is in beta Searchis currently a [beta\\\\ feature](https://docs.convex.dev/production/state/#beta-features). If you have feedback or feature requests, [let us know on Discord](https://convex.dev/community)! ## Defining search indexes [​](https://docs.convex.dev/search/text-search\\#defining-search-indexes \"Direct link to Defining search indexes\") Like [database indexes](https://docs.convex.dev/database/reading-data/indexes/), search indexes are a data structure that is built in advance to enable efficient querying. Search indexes are defined as part of your Convex [schema](https://docs.convex.dev/database/schemas). Every search index definition consists of: 1. A name. - Must be unique per table. 2. A `searchField` - This is the field which will be indexed for full text search. - It must be of type `string`. 3. \\[Optional\\] A list of `filterField` s - These are additional fields that are indexed for fast equality filtering within your search index. To add a search index onto a table, use the [`searchIndex`](https://docs.convex.dev/api/classes/server.TableDefinition#searchindex) method on your table's schema. For example, if you want an index which can search for messages matching a keyword in a channel, your schema could look like: convex/schema.ts ```codeBlockLines_zEuJ import { defineSchema, defineTable } from \"convex/server\"; import { v } from \"convex/values\"; export default defineSchema({ messages: defineTable({ body: v.string(), channel: v.string(), }).searchIndex(\"search_body\", { searchField: \"body\", filterFields: [\"channel\"], }), }); ``` You can specify search and filter fields on nested documents by using a dot-separated path like `properties.name`. ## Running search queries [​](https://docs.convex.dev/search/text-search\\#running-search-queries \"Direct link to Running search queries\") A query for \"10 messages in channel '#general' that best match the query 'hello hi' in their body\" would look like: ```codeBlockLines_zEuJ const messages = await ctx.db .query(\"messages\") .withSearchIndex(\"search_body\", (q) => q.search(\"body\", \"hello hi\").eq(\"channel\", \"#general\"), ) .take(10); ``` This is just a normal [database read](https://docs.convex.dev/database/reading-data/) that begins by querying the search index! The [`.withSearchIndex`](https://docs.convex.dev/api/interfaces/server.QueryInitializer#withsearchindex) method defines which search index to query and how Convex will use that search index to select documents. The first argument is the name of the index and the second is a _search filter expression_. A search filter expression is a description of which documents Convex should consider when running the query. A search filter expression is always a chained list of: 1. 1 search expression against the index's search field defined with [`.search`](https://docs.convex.dev/api/interfaces/server.SearchFilterBuilder#search). 2. 0 or more equality expressions against the index's filter fields defined with [`.eq`](https://docs.convex.dev/api/interfaces/server.SearchFilterFinalizer#eq). ### Search expressions [​](https://docs.convex.dev/search/text-search\\#search-expressions \"Direct link to Search expressions\") Search expressions are issued against a search index, filtering and ranking documents by their relevance to the search expression's query. Internally, Convex will break up the query into separate words (called _terms_) and approximately rank documents matching these terms. In the example above, the expression `search(\"body\", \"hello hi\")` would internally be split into `\"hi\"` and `\"hello\"` and matched against words in your document (ignoring case and punctuation). The behavior of search incorporates [prefix matching rules](https://docs.convex.dev/search/text-search#search-behavior). ### Equality expressions [​](https://docs.convex.dev/search/text-search\\#equality-expressions \"Direct link to Equality expressions\") Unlike search expressions, equality expressions will filter to only documents that have an exact match in the given field. In the example above, `eq(\"channel\", \"#general\")` will only match documents that have exactly `\"#general\"` in their `channel` field. Equality expressions support fields of any type (not just text). To filter to documents that are missing a field, use `q.eq(\"fieldName\", undefined)`. ### Other filtering [​](https://docs.convex.dev/search/text-search\\#other-filtering \"Direct link to Other filtering\") Because search queries are normal database queries, you can also [filter results](https://docs.convex.dev/database/reading-data/#filtering) using the [`.filter` method](https://docs.convex.dev/api/interfaces/server.Query#filter)! Here's a query for \"messages containing 'hi' sent in the last 10 minutes\": ```codeBlockLines_zEuJ const messages = await ctx.db .query(\"messages\") .withSearchIndex(\"search_body\", (q) => q.search(\"body\", \"hi\")) .filter((q) => q.gt(q.field(\"_creationTime\", Date.now() - 10 * 60000))) .take(10); ``` **For performance, always put as many of your filters as possible into** **`.withSearchIndex`.** Every search query is executed by: 1. First, querying the search index using the search filter expression in `withSearchIndex`. 2. Then, filtering the results one-by-one using any additional `filter` expressions. Having a very specific search filter expression will make your query faster and less likely to hit Convex's limits because Convex will use the search index to efficiently cut down on the number of results to consider. ### Retrieving results and paginating [​](https://docs.convex.dev/search/text-search\\#retrieving-results-and-paginating \"Direct link to Retrieving results and paginating\") Just like ordinary database queries, you can [retrieve the results](https://docs.convex.dev/database/reading-data/#retrieving-results) using [`.collect()`](https://docs.convex.dev/api/interfaces/server.Query#collect), [`.take(n)`](https://docs.convex.dev/api/interfaces/server.Query#take), [`.first()`](https://docs.convex.dev/api/interfaces/server.Query#first), and [`.unique()`](https://docs.convex.dev/api/interfaces/server.Query#unique). Additionally, search results can be [paginated](https://docs.convex.dev/database/pagination) using [`.paginate(paginationOpts)`](https://docs.convex.dev/api/interfaces/server.OrderedQuery#paginate). Note that `collect()` will throw an exception if it attempts to collect more than the limit of 1024 documents. It is often better to pick a smaller limit and use `take(n)` or paginate the results. ### Ordering [​](https://docs.convex.dev/search/text-search\\#ordering \"Direct link to Ordering\") Search queries always return results in [relevance order](https://docs.convex.dev/search/text-search#relevance-order) based on how well the document matches the search query. Different ordering of results are not supported. ## Search Behavior [​](https://docs.convex.dev/search/text-search\\#search-behavior \"Direct link to Search Behavior\") ### Typeahead Search [​](https://docs.convex.dev/search/text-search\\#typeahead-search \"Direct link to Typeahead Search\") Convex full-text search is designed to power as-you-type search experiences. In your search queries, the final search term has _prefix search_ enabled, matching any term that is a prefix of the original term. For example, the expression `search(\"body\", \"r\")` would match the documents: - `\"rabbit\"` - `\"send request\"` Fuzzy search matches are deprecated. After January 15, 2025, search results will not include `\"snake\"` for a typo like `\"stake\"`. ### Relevance order [​](https://docs.convex.dev/search/text-search\\#relevance-order \"Direct link to Relevance order\") **Relevance order is subject to change.** The relevance of search results and the exact typo-tolerance rules Convex applies is subject to change to improve the quality of search results. Search queries return results in relevance order. Internally, Convex ranks the relevance of a document based on a combination of its [BM25 score](https://en.wikipedia.org/wiki/Okapi_BM25) and several other criteria such as the number of typos of matched terms in the document, the proximity of matches, the number of exact matches, and more. The BM25 score takes into account: - How many words in the search query appear in the field? - How many times do they appear? - How long is the text field? If multiple documents have the same score, the newest documents are returned first. ## Limits [​](https://docs.convex.dev/search/text-search\\#limits \"Direct link to Limits\") Search indexes work best with English or other Latin-script languages. Text is tokenized using Tantivy's [`SimpleTokenizer`](https://docs.rs/tantivy/latest/tantivy/tokenizer/struct.SimpleTokenizer.html), which splits on whitespace and punctuation. We also limit terms to 32 characters in length and lowercase them. Search indexes must have: - Exactly 1 search field. - Up to 16 filter fields. Search indexes count against the [limit of 32 indexes per table](https://docs.convex.dev/database/reading-data/indexes/#limits). Search queries can have: - Up to 16 terms (words) in the search expression. - Up to 8 filter expressions. Additionally, search queries can scan up to 1024 results from the search index. The source of truth for these limits is our [source code](https://github.com/get-convex/convex-backend/blob/main/crates/search/src/constants.rs). For information on other limits, see [here](https://docs.convex.dev/production/state/limits). - [Defining search indexes](https://docs.convex.dev/search/text-search#defining-search-indexes) - [Running search queries](https://docs.convex.dev/search/text-search#running-search-queries) - [Search expressions](https://docs.convex.dev/search/text-search#search-expressions) - [Equality expressions](https://docs.convex.dev/search/text-search#equality-expressions) - [Other filtering](https://docs.convex.dev/search/text-search#other-filtering) - [Retrieving results and paginating](https://docs.convex.dev/search/text-search#retrieving-results-and-paginating) - [Ordering](https://docs.convex.dev/search/text-search#ordering) - [Search Behavior](https://docs.convex.dev/search/text-search#search-behavior) - [Typeahead Search](https://docs.convex.dev/search/text-search#typeahead-search) - [Relevance order](https://docs.convex.dev/search/text-search#relevance-order) - [Limits](https://docs.convex.dev/search/text-search#limits) [Skip to main content](https://docs.convex.dev/realtime#docusaurus_skipToContent_fallback) On this page Turns out Convex is automatically realtime! You don’t have to do anything special if you are already using [query functions](https://docs.convex.dev/functions/query-functions), [database](https://docs.convex.dev/database), and [client libraries](https://docs.convex.dev/client/react/) in your app. Convex tracks the dependencies to your query functions, including database changes, and triggers the subscription in the client libraries. ![Convex is automatically reactive and realtime](https://docs.convex.dev/assets/images/realtime-3197272a21b075792f6ac922af228378.gif) Aside from building a highly interactive app with ease, there are other benefits to the realtime architecture of Convex: ## Automatic caching [​](https://docs.convex.dev/realtime\\#automatic-caching \"Direct link to Automatic caching\") Convex automatically caches the result of your query functions so that future calls just read from the cache. The cache is updated if the data ever changes. You don't get charged for database bandwidth for cached reads. This requires no work or bookkeeping from you. ## Consistent data across your app [​](https://docs.convex.dev/realtime\\#consistent-data-across-your-app \"Direct link to Consistent data across your app\") Every client subscription gets updated simultaneously to the same snapshot of the database. Your app always displays the most consistent view of your data. This avoids bugs like increasing the number of items in the shopping cart and not showing that an item is sold out. ## Learn more [​](https://docs.convex.dev/realtime\\#learn-more \"Direct link to Learn more\") Learn how to work with realtime and reactive queries in Convex on [Stack](https://stack.convex.dev/tag/Reactivity). Related posts from [![Stack](https://docs.convex.dev/img/stack-logo-dark.svg)![Stack](https://docs.convex.dev/img/stack-logo-light.svg)](https://stack.convex.dev/) - [Automatic caching](https://docs.convex.dev/realtime#automatic-caching) - [Consistent data across your app](https://docs.convex.dev/realtime#consistent-data-across-your-app) - [Learn more](https://docs.convex.dev/realtime#learn-more) [Skip to main content](https://docs.convex.dev/client/javascript#docusaurus_skipToContent_fallback) On this page # Convex JavaScript Clients Convex applications can be accessed from Node.js or any JavaScript runtime that implements [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/fetch) or [`WebSocket`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket). The reactive [Convex Client](https://docs.convex.dev/api/classes/browser.ConvexClient) allows web applications and long-running Node.js servers to subscribe to updates on Convex queries, while the [Convex HTTP client](https://docs.convex.dev/api/classes/browser.ConvexHttpClient) is typically used for server-side rendering, migrations, administrative scripts, and serverless functions to run queries at a single point in time. If you're using React, see the dedicated [`ConvexReactClient`](https://docs.convex.dev/api/classes/browser.ConvexClient) described in [React](https://docs.convex.dev/client/react). ## Convex Client [​](https://docs.convex.dev/client/javascript\\#convex-client \"Direct link to Convex Client\") The [`ConvexClient`](https://docs.convex.dev/api/classes/browser.ConvexClient) provides subscriptions to queries in Node.js and any JavaScript environment that supports WebSockets. script.ts TS ```codeBlockLines_zEuJ import { ConvexClient } from \"convex/browser\"; import { api } from \"../convex/_generated/api\"; const client = new ConvexClient(process.env.CONVEX_URL!); // subscribe to query results client.onUpdate(api.messages.listAll, {}, (messages) => console.log(messages.map((msg) => msg.body)), ); // execute a mutation function hello() { client.mutation(api.messages.sendAnon, { body: `hello at ${new Date()}`, }); } ``` The Convex client is open source and available on [GitHub](https://github.com/get-convex/convex-js). See the [Script Tag Quickstart](https://docs.convex.dev/quickstart/script-tag) to get started. ## HTTP client [​](https://docs.convex.dev/client/javascript\\#http-client \"Direct link to HTTP client\") The [`ConvexHttpClient`](https://docs.convex.dev/api/classes/browser.ConvexHttpClient) works in the browser, Node.js, and any JavaScript environment with `fetch`. See the [Node.js Quickstart](https://docs.convex.dev/quickstart/nodejs). script.ts TS ```codeBlockLines_zEuJ import { ConvexHttpClient } from \"convex/browser\"; import { api } from \"./convex/_generated/api\"; const client = new ConvexHttpClient(process.env[\"CONVEX_URL\"]); // either this const count = await client.query(api.counter.get); // or this client.query(api.counter.get).then((count) => console.log(count)); ``` ## Using Convex without generated `convex/_generated/api.js` [​](https://docs.convex.dev/client/javascript\\#using-convex-without-generated-convex_generatedapijs \"Direct link to using-convex-without-generated-convex_generatedapijs\") If the source code for your Convex function isn't located in the same project or in the same monorepos you can use the untyped `api` object called `anyApi`. script.ts TS ```codeBlockLines_zEuJ import { ConvexClient } from \"convex/browser\"; import { anyApi } from \"convex/server\"; const CONVEX_URL = \"http://happy-otter-123\"; const client = new ConvexClient(CONVEX_URL); client.onUpdate(anyApi.messages.list, {}, (messages) => console.log(messages.map((msg) => msg.body)), ); setInterval( () => client.mutation(anyApi.messages.send, { body: `hello at ${new Date()}`, author: \"me\", }), 5000, ); ``` - [Convex Client](https://docs.convex.dev/client/javascript#convex-client) - [HTTP client](https://docs.convex.dev/client/javascript#http-client) - [Using Convex without generated `convex/_generated/api.js`](https://docs.convex.dev/client/javascript#using-convex-without-generated-convex_generatedapijs) [Skip to main content](https://docs.convex.dev/functions/actions#docusaurus_skipToContent_fallback) On this page Actions can call third party services to do things such as processing a payment with [Stripe](https://stripe.com/). They can be run in Convex's JavaScript environment or in Node.js. They can interact with the database indirectly by calling [queries](https://docs.convex.dev/functions/query-functions) and [mutations](https://docs.convex.dev/functions/mutation-functions). **Example:** [GIPHY Action](https://github.com/get-convex/convex-demos/tree/main/giphy-action) ## Action names [​](https://docs.convex.dev/functions/actions\\#action-names \"Direct link to Action names\") Actions follow the same naming rules as queries, see [Query names](https://docs.convex.dev/functions/query-functions#query-names). ## The `action` constructor [​](https://docs.convex.dev/functions/actions\\#the-action-constructor \"Direct link to the-action-constructor\") To declare an action in Convex you use the action constructor function. Pass it an object with a `handler` function, which performs the action: convex/myFunctions.ts TS ```codeBlockLines_zEuJ import { action } from \"./_generated/server\"; export const doSomething = action({ handler: () => { // implementation goes here // optionally return a value return \"success\"; }, }); ``` Unlike a query, an action can but does not have to return a value. ### Action arguments and responses [​](https://docs.convex.dev/functions/actions\\#action-arguments-and-responses \"Direct link to Action arguments and responses\") Action arguments and responses follow the same rules as [mutations](https://docs.convex.dev/functions/mutation-functions#mutation-arguments-and_responses): convex/myFunctions.ts TS ```codeBlockLines_zEuJ import { action } from \"./_generated/server\"; import { v } from \"convex/values\"; export const doSomething = action({ args: { a: v.number(), b: v.number() }, handler: (_, args) => { // do something with `args.a` and `args.b` // optionally return a value return \"success\"; }, }); ``` The first argument to the handler function is reserved for the action context. ### Action context [​](https://docs.convex.dev/functions/actions\\#action-context \"Direct link to Action context\") The `action` constructor enables interacting with the database, and other Convex features by passing an [ActionCtx](https://docs.convex.dev/api/interfaces/server.GenericActionCtx) object to the handler function as the first argument: convex/myFunctions.ts TS ```codeBlockLines_zEuJ import { action } from \"./_generated/server\"; import { v } from \"convex/values\"; export const doSomething = action({ args: { a: v.number(), b: v.number() }, handler: (ctx, args) => { // do something with `ctx` }, }); ``` Which part of that action context is used depends on what your action needs to do: - To read data from the database use the `runQuery` field, and call a query that performs the read: convex/myFunctions.ts TS ```codeBlockLines_zEuJ import { action, internalQuery } from \"./_generated/server\"; import { internal } from \"./_generated/api\"; import { v } from \"convex/values\"; export const doSomething = action({ args: { a: v.number() }, handler: async (ctx, args) => { const data = await ctx.runQuery(internal.myFunctions.readData, { a: args.a, }); // do something with `data` }, }); export const readData = internalQuery({ args: { a: v.number() }, handler: async (ctx, args) => { // read from `ctx.db` here }, }); ``` Here `readData` is an [internal query](https://docs.convex.dev/functions/internal-functions) 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 `runMutation` field, and call a mutation that performs the write: convex/myFunctions.ts TS ```codeBlockLines_zEuJ import { v } from \"convex/values\"; import { action } from \"./_generated/server\"; import { internal } from \"./_generated/api\"; export const doSomething = action({ args: { a: v.number() }, handler: async (ctx, args) => { const data = await ctx.runMutation(internal.myMutations.writeData, { a: args.a, }); // do something else, optionally use `data` }, }); ``` Use an [internal mutation](https://docs.convex.dev/functions/internal-functions) 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 `storage` field. Read on about [File Storage](https://docs.convex.dev/file-storage). - To check user authentication use the `auth` field. Auth is propagated automatically when calling queries and mutations from the action. Read on about [Authentication](https://docs.convex.dev/auth). - To schedule functions to run in the future, use the `scheduler` field. Read on about [Scheduled Functions](https://docs.convex.dev/scheduling/scheduled-functions). - To search a vector index, use the `vectorSearch` field. Read on about [Vector Search](https://docs.convex.dev/search/vector-search). #### Dealing with circular type inference [​](https://docs.convex.dev/functions/actions\\#dealing-with-circular-type-inference \"Direct link to 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.` When the return value of an action depends on the result of calling `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: convex/myFunctions.ts ```codeBlockLines_zEuJ // TypeScript reports an error on `myAction` export const myAction = action({ args: {}, handler: async (ctx) => { return await ctx.runQuery(api.myFunctions.getSomething); }, }); export const getSomething = query({ args: {}, handler: () => { return null; }, }); ``` To work around this, you should store the result of the `ctx.runQuery` or `ctx.runMutation` call in a variable with a type annotation: convex/myFunctions.ts ```codeBlockLines_zEuJ export const myAction = action({ args: {}, handler: async (ctx) => { const result: null = await ctx.runQuery(api.myFunctions.getSomething); return result; }, }); ``` TypeScript will check that the type annotation matches what the called query or mutation returns, so you don't lose any type safety. In this trivial example the return type of the query was `null`. See the [TypeScript](https://docs.convex.dev/understanding/best-practices/typescript#type-annotating-server-side-helpers) page for other types which might be helpful when annotating the result. ## Choosing the runtime (\"use node\") [​](https://docs.convex.dev/functions/actions\\#choosing-the-runtime-use-node \"Direct link to Choosing the runtime (\\\"use node\\\")\") Actions can run in Convex's custom JavaScript environment or in Node.js. By default, actions run in Convex's environment. This environment supports `fetch`, so actions that simply want to call a third-party API using `fetch` can be run in this environment: convex/myFunctions.ts TS ```codeBlockLines_zEuJ import { action } from \"./_generated/server\"; export const doSomething = action({ args: {}, handler: async () => { const data = await fetch(\"https://api.thirdpartyservice.com\"); // do something with data }, }); ``` Actions running in Convex's environment are faster compared to Node.js, since they don't require extra time to start up before running your action (cold starts). They can also be defined in the same file as other Convex functions. Like queries and mutations they can import NPM packages, but not all are supported. Actions needing unsupported NPM packages or Node.js APIs can be configured to run in Node.js by adding the `\"use node\"` directive at the top of the file. Note that other Convex functions cannot be defined in files with the `\"use node\";` directive. convex/myAction.ts TS ```codeBlockLines_zEuJ \"use node\"; import { action } from \"./_generated/server\"; import SomeNpmPackage from \"some-npm-package\"; export const doSomething = action({ args: {}, handler: () => { // do something with SomeNpmPackage }, }); ``` Learn more about the two [Convex Runtimes](https://docs.convex.dev/functions/runtimes). ## Splitting up action code via helpers [​](https://docs.convex.dev/functions/actions\\#splitting-up-action-code-via-helpers \"Direct link to Splitting up action code via helpers\") Just like with [queries](https://docs.convex.dev/functions/query-functions#splitting-up-query-code-via-helpers) and [mutations](https://docs.convex.dev/functions/mutation-functions#splitting-up-query-code-via-helpers) you can define and call helper TypeScript functions to split up the code in your actions or reuse logic across multiple Convex functions. But note that the [ActionCtx](https://docs.convex.dev/api/interfaces/server.GenericActionCtx) only has the `auth` field in common with [QueryCtx](https://docs.convex.dev/generated-api/server#queryctx) and [MutationCtx](https://docs.convex.dev/generated-api/server#mutationctx). ## Calling actions from clients [​](https://docs.convex.dev/functions/actions\\#calling-actions-from-clients \"Direct link to Calling actions from clients\") To call an action from [React](https://docs.convex.dev/client/react) use the [`useAction`](https://docs.convex.dev/api/modules/react#useaction) hook along with the generated [`api`](https://docs.convex.dev/generated-api/api) object. src/myApp.tsx TS ```codeBlockLines_zEuJ import { useAction } from \"convex/react\"; import { api } from \"../convex/_generated/api\"; export function MyApp() { const performMyAction = useAction(api.myFunctions.doSomething); const handleClick = () => { performMyAction({ a: 1 }); }; // pass `handleClick` to a button // ... } ``` Unlike [mutations](https://docs.convex.dev/client/react), actions from a single client are parallelized. Each action will be executed as soon as it reaches the server (even if other actions and mutations from the same client are running). If your app relies on actions running after other actions or mutations, make sure to only trigger the action after the relevant previous function completes. **Note:** In most cases calling an action directly from a client **is an** **anti-pattern**. Instead, have the client call a [mutation](https://docs.convex.dev/functions/mutation-functions) which captures the user intent by writing into the database and then [schedules](https://docs.convex.dev/scheduling/scheduled-functions) an action: convex/myFunctions.ts TS ```codeBlockLines_zEuJ import { v } from \"convex/values\"; import { internal } from \"./_generated/api\"; import { internalAction, mutation } from \"./_generated/server\"; export const mutationThatSchedulesAction = mutation({ args: { text: v.string() }, handler: async (ctx, { text }) => { const taskId = await ctx.db.insert(\"tasks\", { text }); await ctx.scheduler.runAfter(0, internal.myFunctions.actionThatCallsAPI, { taskId, text, }); }, }); export const actionThatCallsAPI = internalAction({ args: { taskId: v.id(\"tasks\"), text: v.string() }, handler: (_, args): void => { // do something with `taskId` and `text`, like call an API // then run another mutation to store the result }, }); ``` This way the mutation can enforce invariants, such as preventing the user from executing the same action twice. ## Limits [​](https://docs.convex.dev/functions/actions\\#limits \"Direct link to Limits\") Actions time out after 10 minutes. [Node.js](https://docs.convex.dev/functions/runtimes#nodejs-runtime) and [Convex runtime](https://docs.convex.dev/functions/runtimes#default-convex-runtime) have 512MB and 64MB memory limit respectively. Please [contact us](https://docs.convex.dev/production/contact) 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](https://docs.convex.dev/functions/runtimes#nodejs-runtime). ## Error handling [​](https://docs.convex.dev/functions/actions\\#error-handling \"Direct link to Error handling\") Unlike queries and mutations, actions may have side-effects and therefore can't be automatically retried by Convex when errors occur. For example, say your action calls Stripe to send a customer invoice. If the HTTP request fails, Convex 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 [​](https://docs.convex.dev/functions/actions\\#error-handling \"Direct link to Error handling\") 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 [​](https://docs.convex.dev/functions/actions\\#dangling-promises \"Direct link to Dangling promises\") ### `await ctx.runAction` should only be used for crossing JS runtimes [​](https://docs.convex.dev/functions/actions\\#await-ctxrunaction-should-only-be-used-for-crossing-js-runtimes \"Direct link to await-ctxrunaction-should-only-be-used-for-crossing-js-runtimes\") **Why?** `await ctx.runAction` incurs to overhead of another Convex server function. It counts as an extra function call, it allocates it's 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](https://docs.convex.dev/functions/runtimes). 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](https://docs.convex.dev/understanding/best-practices/#use-helper-functions-to-write-shared-code) and call the helper instead. ### Avoid `await ctx.runMutation` / `await ctx.runQuery` [​](https://docs.convex.dev/functions/actions\\#avoid-await-ctxrunmutation--await-ctxrunquery \"Direct link to avoid-await-ctxrunmutation--await-ctxrunquery\") ```codeBlockLines_zEuJ // ❌ const foo = await ctx.runQuery(...) const bar = await ctx.runQuery(...) // ✅ const fooAndBar = await ctx.runQuery(...) ``` **Why?** Multiple runQuery / runMutations execute in separate transactions and aren’t guaranteed to be consistent with each other (e.g. foo and bar could read the same document and return two different results), while a single runQuery / runMutation will always be consistent. Additionally, you’re paying for multiple function calls when you don’t have to. **Fix:** Make a new internal query / mutation that does both things. Refactoring the code for the two functions into helpers will make it easy to create a new internal function that does both things while still keeping around the original functions. Potentially try and refactor your action code to “batch” all the database access. Caveats: Separate runQuery / runMutation calls are valid when intentionally trying to process more data than fits in a single transaction (e.g. running a migration, doing a live aggregate). - [Action names](https://docs.convex.dev/functions/actions#action-names) - [The `action` constructor](https://docs.convex.dev/functions/actions#the-action-constructor) - [Action arguments and responses](https://docs.convex.dev/functions/actions#action-arguments-and-responses) - [Action context](https://docs.convex.dev/functions/actions#action-context) - [Choosing the runtime (\"use node\")](https://docs.convex.dev/functions/actions#choosing-the-runtime-use-node) - [Splitting up action code via helpers](https://docs.convex.dev/functions/actions#splitting-up-action-code-via-helpers) - [Calling actions from clients](https://docs.convex.dev/functions/actions#calling-actions-from-clients) - [Limits](https://docs.convex.dev/functions/actions#limits) - [Error handling](https://docs.convex.dev/functions/actions#error-handling) - [Dangling promises](https://docs.convex.dev/functions/actions#dangling-promises) - [Best practices](https://docs.convex.dev/functions/actions#best-practices) - [`await ctx.runAction` should only be used for crossing JS runtimes](https://docs.convex.dev/functions/actions#await-ctxrunaction-should-only-be-used-for-crossing-js-runtimes) - [Avoid `await ctx.runMutation` / `await ctx.runQuery`](https://docs.convex.dev/functions/actions#avoid-await-ctxrunmutation--await-ctxrunquery) [Skip to main content](https://docs.convex.dev/home#docusaurus_skipToContent_fallback) Convex is an all-in-one backend platform with thoughtful, product-centric APIs. Use [TypeScript](https://docs.convex.dev/understanding/best-practices/typescript) to write [queries as\\\\ code](https://docs.convex.dev/functions/query-functions) that are [automatically\\\\ cached](https://docs.convex.dev/realtime#automatic-caching) and [realtime](https://docs.convex.dev/realtime), with an acid compliant [relational database](https://docs.convex.dev/database). [**Learn Convex by creating a chat app** \\\\ \\\\ Convex provides you with a fully featured backend with cloud functions,](https://docs.convex.dev/tutorial) ## Quickstarts [​](https://docs.convex.dev/home\\#quickstarts \"Direct link to Quickstarts\") Quickly get up and running with your favorite frontend tooling or language: [React Logo\\\\ **React**](https://docs.convex.dev/quickstart/react) [**Next.js**](https://docs.convex.dev/quickstart/nextjs) [**Remix**](https://docs.convex.dev/quickstart/remix) [**TanStack Start**](https://docs.convex.dev/quickstart/tanstack-start) [**React Native**](https://docs.convex.dev/quickstart/react-native) [**Vue**](https://docs.convex.dev/quickstart/vue) [**Svelte**](https://docs.convex.dev/quickstart/svelte) [**Node.js**](https://docs.convex.dev/quickstart/nodejs) [Bun Logo\\\\ **Bun**](https://docs.convex.dev/quickstart/bun) [HTML5 Logo\\\\ **Script tag**](https://docs.convex.dev/quickstart/script-tag) [**Python**](https://docs.convex.dev/quickstart/python) [**iOS Swift**](https://docs.convex.dev/quickstart/swift) [**Android Kotlin**](https://docs.convex.dev/quickstart/android) [**Rust**](https://docs.convex.dev/quickstart/rust) ## Why Convex? [​](https://docs.convex.dev/home\\#why-convex \"Direct link to Why Convex?\") ## Backends Should be Designed for Product Developers YouTube ## Intro to Convex Supercharge your Application with a Reactive Database - YouTube Convex 2.07K subscribers [Supercharge your Application with a Reactive Database](https://www.youtube.com/watch?v=V6En7UO4Ui0) Convex Search Info Shopping Tap to unmute If playback doesn't begin shortly, try restarting your device. Share Include playlist An error occurred while retrieving sharing information. Please try again later. Watch later Share Copy link 0:00 / •Live • [Watch on YouTube](https://www.youtube.com/watch?v=V6En7UO4Ui0 \"Watch on YouTube\") ## Supercharging your app with a reactive backend Why I use Convex over Supabase as my BaaS - YouTube Web Dev Cody 246K subscribers [Why I use Convex over Supabase as my BaaS](https://www.youtube.com/watch?v=O_HXVAMPEbc) Web Dev Cody Search Info Shopping Tap to unmute If playback doesn't begin shortly, try restarting your device. Share Include playlist An error occurred while retrieving sharing information. Please try again later. Watch later Share Copy link 0:00 / •Live • [Watch on YouTube](https://www.youtube.com/watch?v=O_HXVAMPEbc \"Watch on YouTube\") ## Why I use Convex over Supabase as my BaaS Read the team's Perspectives on [Stack](https://stack.convex.dev/): [**Convex vs Relational Databases**](https://stack.convex.dev/convex-vs-relational-databases) [**Convex vs Firebase**](https://stack.convex.dev/convex-vs-firebase) [**It's not you, it's SQL**](https://stack.convex.dev/not-sql) [**How Convex Works**](https://stack.convex.dev/how-convex-works) [**The Software-Defined Database**](https://stack.convex.dev/the-software-defined-database) [**Convex Perspectives**](https://stack.convex.dev/tag/Perspectives) ## Learn Convex [​](https://docs.convex.dev/home\\#learn-convex \"Direct link to Learn Convex\") A quick start guide for using Convex with Next.js - YouTube Web Dev Cody 246K subscribers [A quick start guide for using Convex with Next.js](https://www.youtube.com/watch?v=vaQZYRSiimI) Web Dev Cody Search Info Shopping Tap to unmute If playback doesn't begin shortly, try restarting your device. You're signed out Videos you watch may be added to the TV's watch history and influence TV recommendations. To avoid this, cancel and sign in to YouTube on your computer. CancelConfirm Share Include playlist An error occurred while retrieving sharing information. Please try again later. Watch later Share Copy link Watch on 0:00 / •Live • [Watch on YouTube](https://www.youtube.com/watch?v=vaQZYRSiimI \"Watch on YouTube\") ## A quick start guide for using Convex with Next.js Fullstack Notion Clone: Next.js 13, React, Convex, Tailwind \\| Full Course 2023 - YouTube Code With Antonio 371K subscribers [Fullstack Notion Clone: Next.js 13, React, Convex, Tailwind \\| Full Course 2023](https://www.youtube.com/watch?v=0OaDyjB9Ib8) Code With Antonio Search Info Shopping Tap to unmute If playback doesn't begin shortly, try restarting your device. You're signed out Videos you watch may be added to the TV's watch history and influence TV recommendations. To avoid this, cancel and sign in to YouTube on your computer. CancelConfirm Share Include playlist An error occurred while retrieving sharing information. Please try again later. Watch later Share Copy link Watch on 0:00 / •Live • [Watch on YouTube](https://www.youtube.com/watch?v=0OaDyjB9Ib8 \"Watch on YouTube\") ## Fullstack Notion Clone: Next.js 13, React, Convex, Tailwind Build and Deploy a Saas Podcast Platform in Next.js - YouTube JavaScript Mastery 1.03M subscribers [Build and Deploy a Saas Podcast Platform in Next.js](https://www.youtube.com/watch?v=zfAb95tJvZQ) JavaScript Mastery Search Info Shopping Tap to unmute If playback doesn't begin shortly, try restarting your device. You're signed out Videos you watch may be added to the TV's watch history and influence TV recommendations. To avoid this, cancel and sign in to YouTube on your computer. CancelConfirm Share Include playlist An error occurred while retrieving sharing information. Please try again later. Watch later Share Copy link Watch on 0:00 / •Live • [Watch on YouTube](https://www.youtube.com/watch?v=zfAb95tJvZQ \"Watch on YouTube\") ## Build and Deploy a Saas Podcast Platform in Next.js Building a Subscription Based SaaS with my Favorite Tech Stack (Next.js, Stripe, Convex, Clerk) - YouTube Web Dev Cody 246K subscribers [Building a Subscription Based SaaS with my Favorite Tech Stack (Next.js, Stripe, Convex, Clerk)](https://www.youtube.com/watch?v=Vjtn9pWAZDI) Web Dev Cody Search Info Shopping Tap to unmute If playback doesn't begin shortly, try restarting your device. You're signed out Videos you watch may be added to the TV's watch history and influence TV recommendations. To avoid this, cancel and sign in to YouTube on your computer. CancelConfirm Share Include playlist An error occurred while retrieving sharing information. Please try again later. Watch later Share Copy link Watch on 0:00 / •Live • [Watch on YouTube](https://www.youtube.com/watch?v=Vjtn9pWAZDI \"Watch on YouTube\") ## Building a Subscription Based SaaS with Stripe See more walkthroughs and patterns on [Stack](https://stack.convex.dev/) [**Build AI Apps**](https://stack.convex.dev/tag/AI) [**Convex Patterns**](https://stack.convex.dev/tag/Patterns) [**Convex Walkthroughs**](https://stack.convex.dev/tag/Walkthroughs) reCAPTCHA Recaptcha requires verification. [Privacy](https://www.google.com/intl/en/policies/privacy/) \\- [Terms](https://www.google.com/intl/en/policies/terms/) protected by **reCAPTCHA** [Privacy](https://www.google.com/intl/en/policies/privacy/) \\- [Terms](https://www.google.com/intl/en/policies/terms/)[Skip to main content](https://docs.convex.dev/understanding/best-practices#docusaurus_skipToContent_fallback) On this page This is a list of best practices and common anti-patterns around using Convex. We recommend going through this list before broadly releasing your app to production. You may choose to try using all of these best practices from the start, or you may wait until you've gotten major parts of your app working before going through and adopting the best practices here. ## Await all Promises [​](https://docs.convex.dev/understanding/best-practices\\#await-all-promises \"Direct link to Await all Promises\") ### Why? [​](https://docs.convex.dev/understanding/best-practices\\#why \"Direct link to Why?\") Convex functions use async / await. If you don't await all your promises (e.g. `await ctx.scheduler.runAfter`, `await ctx.db.patch`), you may run into unexpected behavior (e.g. failing to schedule a function) or miss handling errors. ### How? [​](https://docs.convex.dev/understanding/best-practices\\#how \"Direct link to How?\") We recommend the [no-floating-promises](https://typescript-eslint.io/rules/no-floating-promises/) eslint rule with TypeScript. ## Avoid `.filter` on database queries [​](https://docs.convex.dev/understanding/best-practices\\#avoid-filter-on-database-queries \"Direct link to avoid-filter-on-database-queries\") ### Why? [​](https://docs.convex.dev/understanding/best-practices\\#why-1 \"Direct link to Why?\") Filtering in code instead of using the `.filter` syntax has the same performance, and is generally easier code to write. Conditions in `.withIndex` or `.withSearchIndex` are more efficient than `.filter` or filtering in code, so almost all uses of `.filter` should either be replaced with a `.withIndex` or `.withSearchIndex` condition, or written as TypeScript code. Read through the [indexes documentation](https://docs.convex.dev/database/reading-data/indexes/indexes-and-query-perf) for an overview of how to define indexes and how they work. ### Examples [​](https://docs.convex.dev/understanding/best-practices\\#examples \"Direct link to Examples\") convex/messages.ts TS ```codeBlockLines_zEuJ // ❌ const tomsMessages = ctx.db .query(\"messages\") .filter((q) => q.eq(q.field(\"author\"), \"Tom\")) .collect(); // ✅ // Option 1: Use an index const tomsMessages = await ctx.db .query(\"messages\") .withIndex(\"by_author\", (q) => q.eq(\"author\", \"Tom\")) .collect(); // Option 2: Filter in code const allMessages = await ctx.db.query(\"messages\").collect(); const tomsMessages = allMessages.filter((m) => m.author === \"Tom\"); ``` ### How? [​](https://docs.convex.dev/understanding/best-practices\\#how-1 \"Direct link to How?\") Search for `.filter` in your Convex codebase — a regex like `\\.filter\\(\\(?q` will probably find all the ones on database queries. Decide whether they should be replaced with a `.withIndex` condition — per [this section](https://docs.convex.dev/understanding/best-practices/#only-use-collect-with-a-small-number-of-results), if you are filtering over a large (1000+) or potentially unbounded number of documents, you should use an index. If not using a `.withIndex` / `.withSearchIndex` condition, consider replacing them with a filter in code for more readability and flexibility. See [this article](https://stack.convex.dev/complex-filters-in-convex) for more strategies for filtering. ### Exceptions [​](https://docs.convex.dev/understanding/best-practices\\#exceptions \"Direct link to Exceptions\") Using `.filter` on a paginated query ( `.paginate`) has advantages over filtering in code. The paginated query will return the number of documents requested, including the `.filter` condition, so filtering in code afterwards can result in a smaller page or even an empty page. Using `.withIndex` on a paginated query will still be more efficient than a `.filter`. ## Only use `.collect` with a small number of results [​](https://docs.convex.dev/understanding/best-practices\\#only-use-collect-with-a-small-number-of-results \"Direct link to only-use-collect-with-a-small-number-of-results\") ### Why? [​](https://docs.convex.dev/understanding/best-practices\\#why-2 \"Direct link to Why?\") All results returned from `.collect` count towards database bandwidth (even ones filtered out by `.filter`). It also means that if any document in the result changes, the query will re-run or the mutation will hit a conflict. If there's a chance the number of results is large (say 1000+ documents), you should use an index to filter the results further before calling `.collect`, or find some other way to avoid loading all the documents such as using pagination, denormalizing data, or changing the product feature. ### Example [​](https://docs.convex.dev/understanding/best-practices\\#example \"Direct link to Example\") **Using an index:** convex/movies.ts TS ```codeBlockLines_zEuJ // ❌ -- potentially unbounded const allMovies = await ctx.db.query(\"movies\").collect(); const moviesByDirector = allMovies.filter( (m) => m.director === \"Steven Spielberg\", ); // ✅ -- small number of results, so `collect` is fine const moviesByDirector = await ctx.db .query(\"movies\") .withIndex(\"by_director\", (q) => q.eq(\"director\", \"Steven Spielberg\")) .collect(); ``` **Using pagination:** convex/movies.ts TS ```codeBlockLines_zEuJ // ❌ -- potentially unbounded const watchedMovies = await ctx.db .query(\"watchedMovies\") .withIndex(\"by_user\", (q) => q.eq(\"user\", \"Tom\")) .collect(); // ✅ -- using pagination, showing recently watched movies first const watchedMovies = await ctx.db .query(\"watchedMovies\") .withIndex(\"by_user\", (q) => q.eq(\"user\", \"Tom\")) .order(\"desc\") .paginate(paginationOptions); ``` **Using a limit or denormalizing:** convex/movies.ts TS ```codeBlockLines_zEuJ // ❌ -- potentially unbounded const watchedMovies = await ctx.db .query(\"watchedMovies\") .withIndex(\"by_user\", (q) => q.eq(\"user\", \"Tom\")) .collect(); const numberOfWatchedMovies = watchedMovies.length; // ✅ -- Show \"99+\" instead of needing to load all documents const watchedMovies = await ctx.db .query(\"watchedMovies\") .withIndex(\"by_user\", (q) => q.eq(\"user\", \"Tom\")) .take(100); const numberOfWatchedMovies = watchedMovies.length === 100 ? \"99+\" : watchedMovies.length.toString(); // ✅ -- Denormalize the number of watched movies in a separate table const watchedMoviesCount = await ctx.db .query(\"watchedMoviesCount\") .withIndex(\"by_user\", (q) => q.eq(\"user\", \"Tom\")) .unique(); ``` ### How? [​](https://docs.convex.dev/understanding/best-practices\\#how-2 \"Direct link to How?\") Search for `.collect` in your Convex codebase (a regex like `\\.collect\\(` will probably find these). And think through whether the number of results is small. This function health page in the dashboard can also help surface these. The [aggregate component](https://www.npmjs.com/package/@convex-dev/aggregate) or [database triggers](https://stack.convex.dev/triggers) can be helpful patterns for denormalizing data. ### Exceptions [​](https://docs.convex.dev/understanding/best-practices\\#exceptions-1 \"Direct link to Exceptions\") If you're doing something that requires loading a large number of documents (e.g. performing a migration, making a summary), you may want to use an action to load them in batches via separate queries / mutations. ## Check for redundant indexes [​](https://docs.convex.dev/understanding/best-practices\\#check-for-redundant-indexes \"Direct link to Check for redundant indexes\") ### Why? [​](https://docs.convex.dev/understanding/best-practices\\#why-3 \"Direct link to Why?\") Indexes like `by_foo` and `by_foo_and_bar` are usually redundant (you only need `by_foo_and_bar`). Reducing the number of indexes saves on database storage and reduces the overhead of writing to the table. convex/teams.ts TS ```codeBlockLines_zEuJ // ❌ const allTeamMembers = await ctx.db .query(\"teamMembers\") .withIndex(\"by_team\", (q) => q.eq(\"team\", teamId)) .collect(); const currentUserId = /* get current user id from `ctx.auth` */ const currentTeamMember = await ctx.db .query(\"teamMembers\") .withIndex(\"by_team_and_user\", (q) => q.eq(\"team\", teamId).eq(\"user\", currentUserId), ) .unique(); // ✅ // Just don't include a condition on `user` when querying for results on `team` const allTeamMembers = await ctx.db .query(\"teamMembers\") .withIndex(\"by_team_and_user\", (q) => q.eq(\"team\", teamId)) .collect(); const currentUserId = /* get current user id from `ctx.auth` */ const currentTeamMember = await ctx.db .query(\"teamMembers\") .withIndex(\"by_team_and_user\", (q) => q.eq(\"team\", teamId).eq(\"user\", currentUserId), ) .unique(); ``` ### How? [​](https://docs.convex.dev/understanding/best-practices\\#how-3 \"Direct link to How?\") Look through your indexes, either in your `schema.ts` file or in the dashboard, and look for any indexes where one is a prefix of another. ### Exceptions [​](https://docs.convex.dev/understanding/best-practices\\#exceptions-2 \"Direct link to Exceptions\") `.index(\"by_foo\", [\"foo\"])` is really an index on the properties `foo` and `_creationTime`, while `.index(\"by_foo_and_bar\", [\"foo\", \"bar\"])` is an index on the properties `foo`, `bar`, and `_creationTime`. If you have queries that need to be sorted by `foo` and then `_creationTime`, then you need both indexes. For example, `.index(\"by_channel\", [\"channel\"])` on a table of messages can be used to query for the most recent messages in a channel, but `.index(\"by_channel_and_author\", [\"channel\", \"author\"])` could not be used for this since it would first sort the messages by `author`. ## Use argument validators for all public functions [​](https://docs.convex.dev/understanding/best-practices\\#use-argument-validators-for-all-public-functions \"Direct link to Use argument validators for all public functions\") ### Why? [​](https://docs.convex.dev/understanding/best-practices\\#why-4 \"Direct link to Why?\") Public functions can be called by anyone, including potentially malicious attackers trying to break your app. [Argument validators](https://docs.convex.dev/functions/validation) (as well as return value validators) help ensure you're getting the traffic you expect. ### Example [​](https://docs.convex.dev/understanding/best-practices\\#example-1 \"Direct link to Example\") convex/messages.ts TS ```codeBlockLines_zEuJ // ❌ -- could be used to update any document (not just `messages`) export const updateMessage = mutation({ handler: async (ctx, { id, update }) => { await ctx.db.patch(id, update); }, }); // ✅ -- can only be called with an ID from the messages table, and can only update // the `body` and `author` fields export const updateMessage = mutation({ args: { id: v.id(\"messages\"), update: v.object({ body: v.optional(v.string()), author: v.optional(v.string()), }), }, handler: async (ctx, { id, update }) => { await ctx.db.patch(id, update); }, }); ``` ### How? [​](https://docs.convex.dev/understanding/best-practices\\#how-4 \"Direct link to How?\") Search for `query`, `mutation`, and `action` in your Convex codebase, and ensure that all of them have argument validators (and optionally return value validators). If you have `httpAction` s, you may want to use something like `zod` to validate that the HTTP request is the shape you expect. ## Use some form of access control for all public functions [​](https://docs.convex.dev/understanding/best-practices\\#use-some-form-of-access-control-for-all-public-functions \"Direct link to Use some form of access control for all public functions\") ### Why? [​](https://docs.convex.dev/understanding/best-practices\\#why-5 \"Direct link to Why?\") Public functions can be called by anyone, including potentially malicious attackers trying to break your app. If portions of your app should only be accessible when the user is signed in, make sure all these Convex functions check that `ctx.auth.getUserIdentity()` is set. You may also have specific checks, like only loading messages that were sent to or from the current user, which you'll want to apply in every relevant public function. Favoring more granular functions like `setTeamOwner` over `updateTeam` allows more granular checks for which users can do what. Access control checks should either use `ctx.auth.getUserIdentity()` or a function argument that is unguessable (e.g. a UUID, or a Convex ID, provided that this ID is never exposed to any client but the one user). In particular, don't use a function argument which could be spoofed (e.g. email) for access control checks. ### Example [​](https://docs.convex.dev/understanding/best-practices\\#example-2 \"Direct link to Example\") convex/teams.ts TS ```codeBlockLines_zEuJ // ❌ -- no checks! anyone can update any team if they get the ID export const updateTeam = mutation({ args: { id: v.id(\"teams\"), update: v.object({ name: v.optional(v.string()), owner: v.optional(v.id(\"users\")), }), }, handler: async (ctx, { id, update }) => { await ctx.db.patch(id, update); }, }); // ❌ -- checks access, but uses `email` which could be spoofed export const updateTeam = mutation({ args: { id: v.id(\"teams\"), update: v.object({ name: v.optional(v.string()), owner: v.optional(v.id(\"users\")), }), email: v.string(), }, handler: async (ctx, { id, update, email }) => { const teamMembers = /* load team members */ if (!teamMembers.some((m) => m.email === email)) { throw new Error(\"Unauthorized\"); } await ctx.db.patch(id, update); }, }); // ✅ -- checks access, and uses `ctx.auth`, which cannot be spoofed export const updateTeam = mutation({ args: { id: v.id(\"teams\"), update: v.object({ name: v.optional(v.string()), owner: v.optional(v.id(\"users\")), }), }, handler: async (ctx, { id, update }) => { const user = await ctx.auth.getUserIdentity(); if (user === null) { throw new Error(\"Unauthorized\"); } const isTeamMember = /* check if user is a member of the team */ if (!isTeamMember) { throw new Error(\"Unauthorized\"); } await ctx.db.patch(id, update); }, }); // ✅ -- separate functions which have different access control export const setTeamOwner = mutation({ args: { id: v.id(\"teams\"), owner: v.id(\"users\"), }, handler: async (ctx, { id, owner }) => { const user = await ctx.auth.getUserIdentity(); if (user === null) { throw new Error(\"Unauthorized\"); } const isTeamOwner = /* check if user is the owner of the team */ if (!isTeamOwner) { throw new Error(\"Unauthorized\"); } await ctx.db.patch(id, { owner: owner }); }, }); export const setTeamName = mutation({ args: { id: v.id(\"teams\"), name: v.string(), }, handler: async (ctx, { id, name }) => { const user = await ctx.auth.getUserIdentity(); if (user === null) { throw new Error(\"Unauthorized\"); } const isTeamMember = /* check if user is a member of the team */ if (!isTeamMember) { throw new Error(\"Unauthorized\"); } await ctx.db.patch(id, { name: name }); }, }); ``` ### How? [​](https://docs.convex.dev/understanding/best-practices\\#how-5 \"Direct link to How?\") Search for `query`, `mutation`, `action`, and `httpAction` in your Convex codebase, and ensure that all of them have some form of access control. [Custom functions](https://github.com/get-convex/convex-helpers/blob/main/packages/convex-helpers/README.md#custom-functions) like [`authenticatedQuery`](https://stack.convex.dev/custom-functions#modifying-the-ctx-argument-to-a-server-function-for-user-auth) can be helpful. Some apps use Row Level Security (RLS) to check access to each document automatically whenever it's loaded, as described in [this article](https://stack.convex.dev/row-level-security). Alternatively, you can check access in each Convex function instead of checking access for each document. Helper functions for common checks and common operations can also be useful -- e.g. `isTeamMember`, `isTeamAdmin`, `loadTeam` (which throws if the current user does not have access to the team). ## Only schedule and `ctx.run*` internal functions [​](https://docs.convex.dev/understanding/best-practices\\#only-schedule-and-ctxrun-internal-functions \"Direct link to only-schedule-and-ctxrun-internal-functions\") ### Why? [​](https://docs.convex.dev/understanding/best-practices\\#why-6 \"Direct link to Why?\") Public functions can be called by anyone, including potentially malicious attackers trying to break your app, and should be carefully audited to ensure they can't be used maliciously. Functions that are only called within Convex can be marked as internal, and relax these checks since Convex will ensure that internal functions can only be called within Convex. ### How? [​](https://docs.convex.dev/understanding/best-practices\\#how-6 \"Direct link to How?\") Search for `ctx.runQuery`, `ctx.runMutation`, and `ctx.runAction` in your Convex codebase. Also search for `ctx.scheduler` and check the `crons.ts` file. Ensure all of these use `internal.foo.bar` functions instead of `api.foo.bar` functions. If you have code you want to share between a public Convex function and an internal Convex function, create a helper function that can be called from both. The public function will likely have additional access control checks. Alternatively, make sure that `api` from `_generated/api.ts` is never used in your Convex functions directory. ### Examples [​](https://docs.convex.dev/understanding/best-practices\\#examples-1 \"Direct link to Examples\") convex/teams.ts TS ```codeBlockLines_zEuJ // ❌ -- using `api` export const sendMessage = mutation({ args: { body: v.string(), author: v.string(), }, handler: async (ctx, { body, author }) => { // add message to the database }, }); // crons.ts crons.daily( \"send daily reminder\", { hourUTC: 17, minuteUTC: 30 }, api.messages.sendMessage, { author: \"System\", body: \"Share your daily update!\" }, ); // ✅ Using `internal` import { MutationCtx } from './_generated/server'; async function sendMessageHelper( ctx: MutationCtx, args: { body: string; author: string }, ) { // add message to the database } export const sendMessage = mutation({ args: { body: v.string(), }, handler: async (ctx, { body }) => { const user = await ctx.auth.getUserIdentity(); if (user === null) { throw new Error(\"Unauthorized\"); } await sendMessageHelper(ctx, { body, author: user.name ?? \"Anonymous\" }); }, }); export const sendInternalMessage = internalMutation({ args: { body: v.string(), // don't need to worry about `author` being spoofed since this is an internal function author: v.string(), }, handler: async (ctx, { body, author }) => { await sendMessageHelper(ctx, { body, author }); }, }); // crons.ts crons.daily( \"send daily reminder\", { hourUTC: 17, minuteUTC: 30 }, internal.messages.sendInternalMessage, { author: \"System\", body: \"Share your daily update!\" }, ); ``` ## Use helper functions to write shared code [​](https://docs.convex.dev/understanding/best-practices\\#use-helper-functions-to-write-shared-code \"Direct link to Use helper functions to write shared code\") ### Why? [​](https://docs.convex.dev/understanding/best-practices\\#why-7 \"Direct link to Why?\") Most logic should be written as plain TypeScript functions, with the `query`, `mutation`, and `action` wrapper functions being a thin wrapper around one or more helper function. Concretely, most of your code should live in a directory like `convex/model`, and your public API, which is defined with `query`, `mutation`, and `action`, should have very short functions that mostly just call into `convex/model`. Organizing your code this way makes several of the refactors mentioned in this list easier to do. See the [TypeScript page](https://docs.convex.dev/understanding/best-practices/typescript) for useful types. ### Example [​](https://docs.convex.dev/understanding/best-practices\\#example-3 \"Direct link to Example\") **❌** This example overuses `ctx.runQuery` and `ctx.runMutation`, which is discussed more in the [Avoid sequential `ctx.runMutation` / `ctx.runQuery` from actions](https://docs.convex.dev/understanding/best-practices/#avoid-sequential-ctx-runmutation-ctx-runquery-from-actions) section. convex/users.ts TS ```codeBlockLines_zEuJ export const getCurrentUser = query({ args: {}, handler: async (ctx) => { const userIdentity = await ctx.auth.getUserIdentity(); if (userIdentity === null) { throw new Error(\"Unauthorized\"); } const user = /* query ctx.db to load the user */ const userSettings = /* load other documents related to the user */ return { user, settings: userSettings }; }, }); ``` convex/conversations.ts TS ```codeBlockLines_zEuJ export const listMessages = query({ args: { conversationId: v.id(\"conversations\"), }, handler: async (ctx, { conversationId }) => { const user = await ctx.runQuery(api.users.getCurrentUser); const conversation = await ctx.db.get(conversationId); if (conversation === null || !conversation.members.includes(user._id)) { throw new Error(\"Unauthorized\"); } const messages = /* query ctx.db to load the messages */ return messages; }, }); export const summarizeConversation = action({ args: { conversationId: v.id(\"conversations\"), }, handler: async (ctx, { conversationId }) => { const messages = await ctx.runQuery(api.conversations.listMessages, { conversationId, }); const summary = /* call some external service to summarize the conversation */ await ctx.runMutation(api.conversations.addSummary, { conversationId, summary, }); }, }); ``` **✅** Most of the code here is now in the `convex/model` directory. The API for this application is in `convex/conversations.ts`, which contains very little code itself. convex/model/users.ts TS ```codeBlockLines_zEuJ import { QueryCtx } from '../_generated/server'; export async function getCurrentUser(ctx: QueryCtx) { const userIdentity = await ctx.auth.getUserIdentity(); if (userIdentity === null) { throw new Error(\"Unauthorized\"); } const user = /* query ctx.db to load the user */ const userSettings = /* load other documents related to the user */ return { user, settings: userSettings }; } ``` convex/model/conversations.ts TS ```codeBlockLines_zEuJ import { QueryCtx, MutationCtx } from '../_generated/server'; import * as Users from './users'; export async function ensureHasAccess( ctx: QueryCtx, { conversationId }: { conversationId: Id<\"conversations\"> }, ) { const user = await Users.getCurrentUser(ctx); const conversation = await ctx.db.get(conversationId); if (conversation === null || !conversation.members.includes(user._id)) { throw new Error(\"Unauthorized\"); } return conversation; } export async function listMessages( ctx: QueryCtx, { conversationId }: { conversationId: Id<\"conversations\"> }, ) { await ensureHasAccess(ctx, { conversationId }); const messages = /* query ctx.db to load the messages */ return messages; } export async function addSummary( ctx: MutationCtx, { conversationId, summary, }: { conversationId: Id<\"conversations\">; summary: string }, ) { await ensureHasAccess(ctx, { conversationId }); await ctx.db.patch(conversationId, { summary }); } export async function generateSummary( messages: Doc<\"messages\">[], conversationId: Id<\"conversations\">, ) { const summary = /* call some external service to summarize the conversation */ return summary; } ``` convex/conversations.ts TS ```codeBlockLines_zEuJ import * as Conversations from './model/conversations'; export const addSummary = internalMutation({ args: { conversationId: v.id(\"conversations\"), summary: v.string(), }, handler: async (ctx, { conversationId, summary }) => { await Conversations.addSummary(ctx, { conversationId, summary }); }, }); export const listMessages = internalQuery({ args: { conversationId: v.id(\"conversations\"), }, handler: async (ctx, { conversationId }) => { return Conversations.listMessages(ctx, { conversationId }); }, }); export const summarizeConversation = action({ args: { conversationId: v.id(\"conversations\"), }, handler: async (ctx, { conversationId }) => { const messages = await ctx.runQuery(internal.conversations.listMessages, { conversationId, }); const summary = await Conversations.generateSummary( messages, conversationId, ); await ctx.runMutation(internal.conversations.addSummary, { conversationId, summary, }); }, }); ``` ## Use `runAction` only when using a different runtime [​](https://docs.convex.dev/understanding/best-practices\\#use-runaction-only-when-using-a-different-runtime \"Direct link to use-runaction-only-when-using-a-different-runtime\") ### Why? [​](https://docs.convex.dev/understanding/best-practices\\#why-8 \"Direct link to Why?\") Calling `runAction` has more overhead than calling a plain TypeScript function. It counts as an extra function call with its own memory and CPU usage, while the parent action is doing nothing except waiting for the result. Therefore, `runAction` should almost always be replaced with calling a plain TypeScript function. However, if you want to call code that requires Node.js from a function in the Convex runtime (e.g. using a library that requires Node.js), then you can use `runAction` to call the Node.js code. ### Example [​](https://docs.convex.dev/understanding/best-practices\\#example-4 \"Direct link to Example\") convex/scrape.ts TS ```codeBlockLines_zEuJ // ❌ -- using `runAction` export const scrapeWebsite = action({ args: { siteMapUrl: v.string(), }, handler: async (ctx, { siteMapUrl }) => { const siteMap = await fetch(siteMapUrl); const pages = /* parse the site map */ await Promise.all( pages.map((page) => ctx.runAction(internal.scrape.scrapeSinglePage, { url: page }), ), ); }, }); ``` convex/model/scrape.ts TS ```codeBlockLines_zEuJ import { ActionCtx } from '../_generated/server'; // ✅ -- using a plain TypeScript function export async function scrapeSinglePage( ctx: ActionCtx, { url }: { url: string }, ) { const page = await fetch(url); const text = /* parse the page */ await ctx.runMutation(internal.scrape.addPage, { url, text }); } ``` convex/scrape.ts TS ```codeBlockLines_zEuJ import * as Scrape from './model/scrape'; export const scrapeWebsite = action({ args: { siteMapUrl: v.string(), }, handler: async (ctx, { siteMapUrl }) => { const siteMap = await fetch(siteMapUrl); const pages = /* parse the site map */ await Promise.all( pages.map((page) => Scrape.scrapeSinglePage(ctx, { url: page })), ); }, }); ``` ### How? [​](https://docs.convex.dev/understanding/best-practices\\#how-7 \"Direct link to How?\") Search for `runAction` in your Convex codebase, and see if the function it calls uses the same runtime as the parent function. If so, replace the `runAction` with a plain TypeScript function. You may want to structure your functions so the Node.js functions are in a separate directory so it's easier to spot these. ## Avoid sequential `ctx.runMutation` / `ctx.runQuery` calls from actions [​](https://docs.convex.dev/understanding/best-practices\\#avoid-sequential-ctxrunmutation--ctxrunquery-calls-from-actions \"Direct link to avoid-sequential-ctxrunmutation--ctxrunquery-calls-from-actions\") ### Why? [​](https://docs.convex.dev/understanding/best-practices\\#why-9 \"Direct link to Why?\") Each `ctx.runMutation` or `ctx.runQuery` runs in its own transaction, which means if they're called separately, they may not be consistent with each other. If instead we call a single `ctx.runQuery` or `ctx.runMutation`, we're guaranteed that the results we get are consistent. ### How? [​](https://docs.convex.dev/understanding/best-practices\\#how-8 \"Direct link to How?\") Audit your calls to `ctx.runQuery` and `ctx.runMutation` in actions. If you see multiple in a row with no other code between them, replace them with a single `ctx.runQuery` or `ctx.runMutation` that handles both things. Refactoring your code to use helper functions will make this easier. ### Example: Queries [​](https://docs.convex.dev/understanding/best-practices\\#example-queries \"Direct link to Example: Queries\") convex/teams.ts TS ```codeBlockLines_zEuJ // ❌ -- this assertion could fail if the team changed between running the two queries const team = await ctx.runQuery(internal.teams.getTeam, { teamId }); const teamOwner = await ctx.runQuery(internal.teams.getTeamOwner, { teamId }); assert(team.owner === teamOwner._id); ``` convex/teams.ts TS ```codeBlockLines_zEuJ import * as Teams from './model/teams'; import * as Users from './model/users'; export const sendBillingReminder = action({ args: { teamId: v.id(\"teams\"), }, handler: async (ctx, { teamId }) => { // ✅ -- this will always pass const teamAndOwner = await ctx.runQuery(internal.teams.getTeamAndOwner, { teamId, }); assert(teamAndOwner.team.owner === teamAndOwner.owner._id); // send a billing reminder email to the owner }, }); export const getTeamAndOwner = internalQuery({ args: { teamId: v.id(\"teams\"), }, handler: async (ctx, { teamId }) => { const team = await Teams.load(ctx, { teamId }); const owner = await Users.load(ctx, { userId: team.owner }); return { team, owner }; }, }); ``` ### Example: Loops [​](https://docs.convex.dev/understanding/best-practices\\#example-loops \"Direct link to Example: Loops\") convex/teams.ts TS ```codeBlockLines_zEuJ import * as Users from './model/users'; export const importTeams = action({ args: { teamId: v.id(\"teams\"), }, handler: async (ctx, { teamId }) => { // Fetch team members from an external API const teamMembers = await fetchTeamMemberData(teamId); // ❌ This will run a separate mutation for inserting each user, // which means you lose transaction guarantees like atomicity. for (const member of teamMembers) { await ctx.runMutation(internal.teams.insertUser, member); } }, }); export const insertUser = internalMutation({ args: { name: v.string(), email: v.string() }, handler: async (ctx, { name, email }) => { await Users.insert(ctx, { name, email }); }, }); ``` convex/teams.ts TS ```codeBlockLines_zEuJ import * as Users from './model/users'; export const importTeams = action({ args: { teamId: v.id(\"teams\"), }, handler: async (ctx, { teamId }) => { // Fetch team members from an external API const teamMembers = await fetchTeamMemberData(teamId); // ✅ This action runs a single mutation that inserts all users in the same transaction. await ctx.runMutation(internal.teams.insertUsers, teamMembers); }, }); export const insertUsers = internalMutation({ args: { users: v.array(v.object({ name: v.string(), email: v.string() })) }, handler: async (ctx, { users }) => { for (const { name, email } of users) { await Users.insert(ctx, { name, email }); } }, }); ``` ### Exceptions [​](https://docs.convex.dev/understanding/best-practices\\#exceptions-3 \"Direct link to Exceptions\") If you're intentionally trying to process more data than fits in a single transaction, like running a migration or aggregating data, then it makes sense to have multiple sequential `ctx.runMutation` / `ctx.runQuery` calls. Multiple `ctx.runQuery` / `ctx.runMutation` calls are often necessary because the action does a side effect in between them. For example, reading some data, feeding it to an external service, and then writing the result back to the database. ## Use `ctx.runQuery` and `ctx.runMutation` sparingly in queries and mutations [​](https://docs.convex.dev/understanding/best-practices\\#use-ctxrunquery-and-ctxrunmutation-sparingly-in-queries-and-mutations \"Direct link to use-ctxrunquery-and-ctxrunmutation-sparingly-in-queries-and-mutations\") ### Why? [​](https://docs.convex.dev/understanding/best-practices\\#why-10 \"Direct link to Why?\") While these queries and mutations run in the same transaction, and will give consistent results, they have extra overhead compared to plain TypeScript functions. Wanting a TypeScript helper function is much more common than needing `ctx.runQuery` or `ctx.runMutation`. ### How? [​](https://docs.convex.dev/understanding/best-practices\\#how-9 \"Direct link to How?\") Audit your calls to `ctx.runQuery` and `ctx.runMutation` in queries and mutations. Unless one of the exceptions below applies, replace them with a plain TypeScript function. ### Exceptions [​](https://docs.convex.dev/understanding/best-practices\\#exceptions-4 \"Direct link to Exceptions\") - If you're using components, these require `ctx.runQuery` or `ctx.runMutation`. - If you want partial rollback on an error, you will want `ctx.runMutation` instead of a plain TypeScript function. convex/messages.ts TS ```codeBlockLines_zEuJ export const trySendMessage = mutation({ args: { body: v.string(), author: v.string(), }, handler: async (ctx, { body, author }) => { try { await ctx.runMutation(internal.messages.sendMessage, { body, author }); } catch (e) { // Record the failure, but rollback any writes from `sendMessage` await ctx.db.insert(\"failures\", { kind: \"MessageFailed\", body, author, error: `Error: ${e}`, }); } }, }); ``` - [Await all Promises](https://docs.convex.dev/understanding/best-practices#await-all-promises) - [Avoid `.filter` on database queries](https://docs.convex.dev/understanding/best-practices#avoid-filter-on-database-queries) - [Only use `.collect` with a small number of results](https://docs.convex.dev/understanding/best-practices#only-use-collect-with-a-small-number-of-results) - [Check for redundant indexes](https://docs.convex.dev/understanding/best-practices#check-for-redundant-indexes) - [Use argument validators for all public functions](https://docs.convex.dev/understanding/best-practices#use-argument-validators-for-all-public-functions) - [Use some form of access control for all public functions](https://docs.convex.dev/understanding/best-practices#use-some-form-of-access-control-for-all-public-functions) - [Only schedule and `ctx.run*` internal functions](https://docs.convex.dev/understanding/best-practices#only-schedule-and-ctxrun-internal-functions) - [Use helper functions to write shared code](https://docs.convex.dev/understanding/best-practices#use-helper-functions-to-write-shared-code) - [Use `runAction` only when using a different runtime](https://docs.convex.dev/understanding/best-practices#use-runaction-only-when-using-a-different-runtime) - [Avoid sequential `ctx.runMutation` / `ctx.runQuery` calls from actions](https://docs.convex.dev/understanding/best-practices#avoid-sequential-ctxrunmutation--ctxrunquery-calls-from-actions) - [Use `ctx.runQuery` and `ctx.runMutation` sparingly in queries and mutations](https://docs.convex.dev/understanding/best-practices#use-ctxrunquery-and-ctxrunmutation-sparingly-in-queries-and-mutations) [Skip to main content](https://docs.convex.dev/client/android#docusaurus_skipToContent_fallback) On this page Convex Android client library enables your Android application to interact with your Convex backend. It allows your frontend code to: 1. Call your [queries](https://docs.convex.dev/functions/query-functions), [mutations](https://docs.convex.dev/functions/mutation-functions) and [actions](https://docs.convex.dev/functions/actions) 2. Authenticate users using [Auth0](https://docs.convex.dev/auth/auth0) The library is open source and [available on GitHub](https://github.com/get-convex/convex-mobile/tree/main/android). Follow the [Android Quickstart](https://docs.convex.dev/quickstart/android) to get started. ## Installation [​](https://docs.convex.dev/client/android\\#installation \"Direct link to Installation\") You'll need to make the following changes to your app's `build.gradle[.kts]` file. ```codeBlockLines_zEuJ plugins { // ... existing plugins kotlin(\"plugin.serialization\") version \"1.9.0\" } dependencies { // ... existing dependencies implementation(\"dev.convex:android-convexmobile:0.4.1@aar\") { isTransitive = true } implementation(\"org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3\") } ``` After that, sync Gradle to pick up those changes. Your app will now have access to the Convex for Android library as well as Kotlin's JSON serialization which is used to communicate between your code and the Convex backend. ## Connecting to a backend [​](https://docs.convex.dev/client/android\\#connecting-to-a-backend \"Direct link to Connecting to a backend\") The `ConvexClient` is used to establish and maintain a connect between your application and the Convex backend. First you need to create an instance of the client by giving it your backend deployment URL: ```codeBlockLines_zEuJ package com.example.convexapp import dev.convex.android.ConvexClient val convex = ConvexClient(\"https://.convex.cloud\") ``` You should create and use one instance of the `ConvexClient` for the lifetime of your application process. It can be convenient to create a custom Android [`Application`](https://developer.android.com/reference/android/app/Application) subclass and initialize it there: ```codeBlockLines_zEuJ package com.example.convexapp import android.app.Application import dev.convex.android.ConvexClient class MyApplication : Application() { lateinit var convex: ConvexClient override fun onCreate() { super.onCreate() convex = ConvexClient(\"https://.convex.cloud\") } } ``` Once you've done that, you can access the client from a Jetpack Compose `@Composable` function like this: ```codeBlockLines_zEuJ val convex = (application as MyApplication).convex ``` ## Fetching data [​](https://docs.convex.dev/client/android\\#fetching-data \"Direct link to Fetching data\") Convex for Android gives you access to the Convex [reactor](https://docs.convex.dev/tutorial/reactor), which enables real-time _subscriptions_ to query results. You subscribe to queries with the `subscribe` method on `ConvexClient` which returns a `Flow`. The contents of the `Flow` will change over time as the underlying data backing the query changes. All methods on `ConvexClient` suspend, and need to be called from a `CoroutineScope` or another `suspend` function. A simple way to consume a query that returns a list of strings from a `@Composable` is to use a combination of mutable state containing a list and `LaunchedEffect`: ```codeBlockLines_zEuJ var workouts: List by remember { mutableStateOf(listOf()) } LaunchedEffect(\"onLaunch\") { client.subscribe>(\"workouts:get\").collect { result -> result.onSuccess { receivedWorkouts -> workouts = receivedWorkouts } } } ``` Any time the data that powers the backend `\"workouts:get\"` query changes, a new `Result>` will be emitted into the `Flow` and the `workouts` list will refresh with the new data. Any UI that uses `workouts` will then rebuild, giving you a fully reactive UI. Note: you may prefer to put the subscription logic wrapped a Repository as described in the [Android architecture patterns](https://developer.android.com/topic/architecture/data-layer). ### Query arguments [​](https://docs.convex.dev/client/android\\#query-arguments \"Direct link to Query arguments\") You can pass arguments to `subscribe` and they will be supplied to the associated backend `query` function. The arguments are typed as `Map`. The values in the map must be primitive values or other maps and lists. ```codeBlockLines_zEuJ val favoriteColors = mapOf(\"favoriteColors\" to listOf(\"blue\", \"red\")) client.subscribe>(\"users:list\", args = favoriteColors) ``` Assuming a backend query that accepts a `favoriteColors` argument, the value can be received and used to perform logic in the query function. tip Use serializable [Kotlin Data classes](https://docs.convex.dev/client/android/data-types#custom-data-types) to automatically convert Convex objects to Kotlin model classes. caution - There are important gotchas when [sending and receiving numbers](https://docs.convex.dev/client/android/data-types#numerical-types) between Kotlin and Convex. - `_` is a used to signify private fields in Kotlin. If you want to use a `_creationTime` and `_id` Convex fields directly without warnings you'll have to [convert the field name in Kotlin](https://docs.convex.dev/client/android/data-types#field-name-conversion). - Depending on your backend functions, you may need to deal with [reserved Kotlin keywords](https://docs.convex.dev/client/android/data-types#field-name-conversion). ### Subscription lifetime [​](https://docs.convex.dev/client/android\\#subscription-lifetime \"Direct link to Subscription lifetime\") The `Flow` returned from `subscribe` will persist as long as something is waiting to consume results from it. When a `@Composable` or `ViewModel` with a subscription goes out of scope, the underlying query subscription to Convex will be canceled. ## Editing data [​](https://docs.convex.dev/client/android\\#editing-data \"Direct link to Editing data\") You can use the `mutation` method on `ConvexClient` to trigger a backend [mutation](https://docs.convex.dev/functions/mutation-functions). You'll need to use it in another `suspend` function or a `CoroutineScope`. Mutations can return a value or not. If you expect a type in the response, indicate it in the call signature. Mutations can also receive arguments, just like queries. Here's an example of returning a type from a mutation with arguments: ```codeBlockLines_zEuJ val recordsDeleted = convex.mutation<@ConvexNum Int>( \"messages:cleanup\", args = mapOf(\"keepLatest\" to 100) ) ``` If an error occurs during a call to `mutation`, it will throw an exception. Typically you may want to catch [`ConvexError`](https://docs.convex.dev/functions/error-handling/application-errors) and `ServerError` and handle them however is appropriate in your application. See documentation on [error handling](https://docs.convex.dev/functions/error-handling/) for more details. ## Calling third-party APIs [​](https://docs.convex.dev/client/android\\#calling-third-party-apis \"Direct link to Calling third-party APIs\") You can use the `action` method on `ConvexClient` to trigger a backend [action](https://docs.convex.dev/functions/actions). Calls to `action` can accept arguments, return values and throw exceptions just like calls to `mutation`. Even though you can call actions from Android, it's not always the right choice. See the action docs for tips on [calling actions from clients](https://docs.convex.dev/functions/actions#calling-actions-from-clients). ## Authentication with Auth0 [​](https://docs.convex.dev/client/android\\#authentication-with-auth0 \"Direct link to Authentication with Auth0\") You can use `ConvexClientWithAuth` in place of `ConvexClient` to configure authentication with [Auth0](https://auth0.com/). You'll need the `convex-android-auth0` library to do that, as well as an Auth0 account and application configuration. See the [README](https://github.com/get-convex/convex-android-auth0/blob/main/README.md) in the `convex-android-auth0` repo for more detailed setup instructions, and the [Workout example app](https://github.com/get-convex/android-convex-workout) which is configured for Auth0. The overall [Convex authentication docs](https://docs.convex.dev/auth) are a good resource as well. It should also be possible to integrate other similar OpenID Connect authentication providers. See the [`AuthProvider`](https://github.com/get-convex/convex-mobile/blob/5babd583631a7ff6d739e1a2ab542039fd532548/android/convexmobile/src/main/java/dev/convex/android/ConvexClient.kt#L291) interface in the `convex-mobile` repo for more info. ## Production and dev deployments [​](https://docs.convex.dev/client/android\\#production-and-dev-deployments \"Direct link to Production and dev deployments\") When you're ready to move toward [production](https://docs.convex.dev/production) for your app, you can setup your Android build system to point different builds or flavors of your application to different Convex deployments. One fairly simple way to do it is by passing different values (e.g. deployment URL) to different build targets or flavors. Here's a simple example that shows using different deployment URLs for release and debug builds: ```codeBlockLines_zEuJ // In the android section of build.gradle.kts: buildTypes { release { // Snip various other config like ProGuard ... resValue(\"string\", \"convex_url\", \"YOUR_PROD.convex.cloud\") } debug { resValue(\"string\", \"convex_url\", \"YOUR_DEV.convex.cloud\") } } ``` Then you can build your `ConvexClient` using a single resource in code, and it will get the right value at compile time. ```codeBlockLines_zEuJ val convex = ConvexClient(context.getString(R.string.convex_url)) ``` tip You may not want these urls checked into your repository. One pattern is to create a custom `my_app.properties` file that is configured to be ignored in your `.gitignore` file. You can then read this file in your `build.gradle.kts` file. You can see this pattern in use in the [workout sample app](https://github.com/get-convex/android-convex-workout?tab=readme-ov-file#configuration). ## Structuring your application [​](https://docs.convex.dev/client/android\\#structuring-your-application \"Direct link to Structuring your application\") The examples shown in this guide are intended to be brief, and don't provide guidance on how to structure a whole application. The official [Android application architecture](https://developer.android.com/topic/architecture/intro) docs cover best practices for building applications, and Convex also has a [sample open source application](https://github.com/get-convex/android-convex-workout/tree/main) that attempts to demonstrate what a small multi-screen application might look like. In general, do the following: 1. Embrace Flows and [unidirectional data flow](https://developer.android.com/develop/ui/compose/architecture#udf) 2. Have a clear [data layer](https://developer.android.com/topic/architecture/data-layer) (use Repository classes with `ConvexClient` as your data source) 3. Hold UI state in a [ViewModel](https://developer.android.com/topic/architecture/recommendations#viewmodel) ## Testing [​](https://docs.convex.dev/client/android\\#testing \"Direct link to Testing\") `ConvexClient` is an `open` class so it can be mocked or faked in unit tests. If you want to use more of the real client, you can pass a fake `MobileConvexClientInterface` in to the `ConvexClient` constructor. Just be aware that you'll need to provide JSON in Convex's undocumented [JSON format](https://github.com/get-convex/convex-mobile/blob/5babd583631a7ff6d739e1a2ab542039fd532548/android/convexmobile/src/main/java/dev/convex/android/jsonhelpers.kt#L47). You can also use the full `ConvexClient` in Android instrumentation tests. You can setup a special backend instance for testing or run a local Convex server and run full integration tests. ## Under the hood [​](https://docs.convex.dev/client/android\\#under-the-hood \"Direct link to Under the hood\") Convex for Android is built on top of the official [Convex Rust client](https://docs.convex.dev/client/rust). It handles maintaining a WebSocket connection with the Convex backend and implements the full Convex protocol. All method calls on `ConvexClient` are handled via a Tokio async runtime on the Rust side and are safe to call from the application's main thread. `ConvexClient` also makes heavy use of [Kotlin's serialization framework](https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serialization-guide.md), and most of the functionality in that framework is available for you to use in your applications. Internally, `ConvexClient` enables the JSON [`ignoreUnknownKeys`](https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/json.md#ignoring-unknown-keys) and [`allowSpecialFloatingPointValues`](https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/json.md#allowing-special-floating-point-values) features. - [Installation](https://docs.convex.dev/client/android#installation) - [Connecting to a backend](https://docs.convex.dev/client/android#connecting-to-a-backend) - [Fetching data](https://docs.convex.dev/client/android#fetching-data) - [Query arguments](https://docs.convex.dev/client/android#query-arguments) - [Subscription lifetime](https://docs.convex.dev/client/android#subscription-lifetime) - [Editing data](https://docs.convex.dev/client/android#editing-data) - [Calling third-party APIs](https://docs.convex.dev/client/android#calling-third-party-apis) - [Authentication with Auth0](https://docs.convex.dev/client/android#authentication-with-auth0) - [Production and dev deployments](https://docs.convex.dev/client/android#production-and-dev-deployments) - [Structuring your application](https://docs.convex.dev/client/android#structuring-your-application) - [Testing](https://docs.convex.dev/client/android#testing) - [Under the hood](https://docs.convex.dev/client/android#under-the-hood) [Skip to main content](https://docs.convex.dev/database/backup-restore#docusaurus_skipToContent_fallback) On this page Convex supports Backup & Restore of data via the [dashboard](https://dashboard.convex.dev/deployment/settings/backups). ![Backups Page](https://docs.convex.dev/assets/images/backups-7e17da1541fc3eb26194a96ab33414ea.png) # Backups A backup is a consistent snapshot of your table data and file storage made at the time of your request. Take a backup by pressing the \"Backup Now\" button. This may take a few seconds to a few hours, depending on how much data is in your deployment. Backups are stored for 7 days. You can download or delete backups via this page. Deployment configuration and other data (code, environment variables, scheduled functions, etc.) will not be included. ### Periodic Backups [​](https://docs.convex.dev/database/backup-restore\\#periodic-backups \"Direct link to Periodic Backups\") Schedule a periodic daily backup by checking the \"Backup automatically\" box. You can select what time of day to have the backup occur. Periodic backups require a Convex Pro plan. Periodic backupsrequire a Convex Pro plan. [Learn\\\\ more](https://convex.dev/pricing) about our plans or [upgrade](https://dashboard.convex.dev/team/settings/billing). ### Restoring from backup [​](https://docs.convex.dev/database/backup-restore\\#restoring-from-backup \"Direct link to Restoring from backup\") Restore from a backup by selecting restore from the submenu of an individual. You can restore from backups in the same deployment or from other deployments on the same team by using the deployment selector on the backups page. Restores may take a few seconds to a few hours depending on how much data is in your backup. Note that restoring is a destructive operation that wipes your existing data and replaces it with that from the backup. It's recommended that you generate an additional backup before doing a restore. ### Restoring in an emergency [​](https://docs.convex.dev/database/backup-restore\\#restoring-in-an-emergency \"Direct link to Restoring in an emergency\") If your production deployment ends up in a bad state, you may want to consider doing a restore to return to a good state. Note that getting your data to a good state may not be enough. Consider whether you may need each of the following actions. Depending on the nature of your emergency, these may be required. - Take an additional backup prior to restore, since restores are destructive - Do a restore from a good backup - to restore data - Use `npx convex dev` to push a known version of good code. - Use `npx convex env` or the dashboard to restore to a good set of env vars - Use the dashboard to make any manual fixes to the database for your app. - Write mutations to make required (more programmatic) manual fixes to the database for your app. # Downloading a backup You can download your manual and periodic backups from the dashboard via the download button in the menu. Alternatively, you can generate an export in the same format with the [command line](https://docs.convex.dev/cli#export-data-to-a-file): ```codeBlockLines_zEuJ npx convex export --path ~/Downloads ``` The backup comes as a generated a ZIP file with all documents in all Convex tables in your deployment. The ZIP file's name has the format `snapshot_{ts}.zip` where `ts` is a UNIX timestamp of the snapshot in nanoseconds. The export ZIP file contains documents for each table at `/documents.jsonl`, with one document per line. Exported ZIP files also contain data from [file storage](https://docs.convex.dev/file-storage) in a `_storage` folder, with metadata like IDs and checksums in `_storage/documents.jsonl` and each file as `_storage/`. ### Using the downloaded backup. [​](https://docs.convex.dev/database/backup-restore\\#using-the-downloaded-backup \"Direct link to Using the downloaded backup.\") Downloaded ZIP files can be imported into the same deployment or a different deployment with the [CLI](https://docs.convex.dev/database/import-export/import#import-data-from-a-snapshot-zip-file). ## FAQ [​](https://docs.convex.dev/database/backup-restore\\#faq \"Direct link to FAQ\") ### Are there any limitations? [​](https://docs.convex.dev/database/backup-restore\\#are-there-any-limitations \"Direct link to Are there any limitations?\") Each backup is accessible for up to 7 days. On the Starter plan, up to two backups can stored per deployment at a time. Paid plan deployments can have many backups with standard usage based pricing. ### How are they priced? [​](https://docs.convex.dev/database/backup-restore\\#how-are-they-priced \"Direct link to How are they priced?\") Backups uses database bandwidth to read all documents, and file bandwidth to include user files. The generation and storage of the backup itself is billed with the same bandwidth and storage pricing as user file storage. You can observe this bandwidth and storage cost in the [usage dashboard](https://dashboard.convex.dev/team/settings/usage). Check the [limits docs](https://docs.convex.dev/production/state/limits#database) for pricing details. ### What does the backup not contain? [​](https://docs.convex.dev/database/backup-restore\\#what-does-the-backup-not-contain \"Direct link to What does the backup not contain?\") The backup only contains the documents for your tables and files in file storage. In particular it lacks: 1. Your deployment's code and configuration. Convex functions, crons.ts, auth.config.js, schema.ts, etc. are configured in your source code. 2. Pending scheduled functions. You can access pending scheduled functions in the [`_scheduled_functions`](https://docs.convex.dev/database/advanced/system-tables) system table. 3. Environment variables. Environment variables can be copied from Settings in the Convex dashboard. - [Periodic Backups](https://docs.convex.dev/database/backup-restore#periodic-backups) - [Restoring from backup](https://docs.convex.dev/database/backup-restore#restoring-from-backup) - [Restoring in an emergency](https://docs.convex.dev/database/backup-restore#restoring-in-an-emergency) - [Using the downloaded backup.](https://docs.convex.dev/database/backup-restore#using-the-downloaded-backup) - [FAQ](https://docs.convex.dev/database/backup-restore#faq) - [Are there any limitations?](https://docs.convex.dev/database/backup-restore#are-there-any-limitations) - [How are they priced?](https://docs.convex.dev/database/backup-restore#how-are-they-priced) - [What does the backup not contain?](https://docs.convex.dev/database/backup-restore#what-does-the-backup-not-contain) [Skip to main content](https://docs.convex.dev/production/contact#docusaurus_skipToContent_fallback) On this page Convex is a rapidly developing platform and we're always eager to hear your feedback. ## Feedback and Support [​](https://docs.convex.dev/production/contact\\#feedback-and-support \"Direct link to Feedback and Support\") Please share any general questions, feature requests, or product feedback in our [Convex Discord Community](https://convex.dev/community). We're particularly excited to see what you build on Convex! Any specific support questions that aren't able to be adequately addressed on our Discord channel can be directed to [support@convex.dev](mailto:support@convex.dev). ## Following Convex [​](https://docs.convex.dev/production/contact\\#following-convex \"Direct link to Following Convex\") Release notes are shared on [Convex News](https://news.convex.dev/tag/releases) and the [Convex Discord Community](https://convex.dev/community). Product announcements, articles and demos are posted on [Stack](https://stack.convex.dev/), [News](https://news.convex.dev/), [our YouTube channel](https://www.youtube.com/channel/UCoC_9mdiPwIu1sDxDtGQggQ), and [X (fka Twitter)](https://x.com/convex_dev). ## Vulnerability Disclosure [​](https://docs.convex.dev/production/contact\\#vulnerability-disclosure \"Direct link to Vulnerability Disclosure\") If you believe you've discovered a bug in Convex's security, please get in touch at [security@convex.dev](mailto:security@convex.dev) and we'll get back to you within 24 hours. We request that you not publicly disclose the issue until we have had a chance to address it. - [Feedback and Support](https://docs.convex.dev/production/contact#feedback-and-support) - [Following Convex](https://docs.convex.dev/production/contact#following-convex) - [Vulnerability Disclosure](https://docs.convex.dev/production/contact#vulnerability-disclosure) [Skip to main content](https://docs.convex.dev/database/types#docusaurus_skipToContent_fallback) On this page All Convex documents are defined as Javascript objects. These objects can have field values of any of the types below. You can codify the shape of documents within your tables by [defining a schema](https://docs.convex.dev/database/schemas). ## Convex values [​](https://docs.convex.dev/database/types\\#convex-values \"Direct link to Convex values\") Convex supports the following types of values: | Convex Type | TS/JS Type | Example Usage | Validator for [Argument Validation](https://docs.convex.dev/functions/validation) and [Schemas](https://docs.convex.dev/database/schemas) | `json` Format for [Export](https://docs.convex.dev/database/import-export) | Notes | | --- | --- | --- | --- | --- | --- | | Id | [string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#string_type) | `doc._id` | `v.id(tableName)` | string | See [Document IDs](https://docs.convex.dev/database/document-ids). | | Null | [null](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#null_type) | `null` | `v.null()` | null | JavaScript's `undefined` is not a valid Convex value. Functions the return `undefined` or do not return will return `null` when called from a client. Use `null` instead. | | Int64 | [bigint](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#bigint_type) | `3n` | `v.int64()` | string (base10) | Int64s only support BigInts between -2^63 and 2^63-1. Convex supports `bigint` s in [most modern browsers](https://caniuse.com/bigint). | | Float64 | [number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#number_type) | `3.1` | `v.number()` | number / string | Convex supports all IEEE-754 double-precision floating point numbers (such as NaNs). Inf and NaN are JSON serialized as strings. | | Boolean | [boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#boolean_type) | `true` | `v.boolean()` | bool | | | String | [string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#string_type) | `\"abc\"` | `v.string()` | string | Strings are stored as UTF-8 and must be valid Unicode sequences. Strings must be smaller than the 1MB total size limit when encoded as UTF-8. | | Bytes | [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) | `new ArrayBuffer(8)` | `v.bytes()` | string (base64) | Convex supports first class bytestrings, passed in as `ArrayBuffer` s. Bytestrings must be smaller than the 1MB total size limit for Convex types. | | Array | [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) | `[1, 3.2, \"abc\"]` | `v.array(values)` | array | Arrays can have at most 8192 values. | | Object | [Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#objects) | `{a: \"abc\"}` | `v.object({property: value})` | object | Convex only supports \"plain old JavaScript objects\" (objects that do not have a custom prototype). Convex includes all [enumerable properties](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties). Objects can have at most 1024 entries. Field names must be nonempty and not start with \"$\" or \"\\_\". | | Record | [Record](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type) | `{\"a\": \"1\", \"b\": \"2\"}` | `v.record(keys, values)` | object | Records are objects at runtime, but can have dynamic keys. Keys must be only ASCII characters, nonempty, and not start with \"$\" or \"\\_\". | ## System fields [​](https://docs.convex.dev/database/types\\#system-fields \"Direct link to System fields\") Every document in Convex has two automatically-generated system fields: - `_id`: The [document ID](https://docs.convex.dev/database/document-ids) of the document. - `_creationTime`: The time this document was created, in milliseconds since the Unix epoch. ## Limits [​](https://docs.convex.dev/database/types\\#limits \"Direct link to Limits\") Convex values must be less than 1MB in total size. This is an approximate limit for now, but if you're running into these limits and would like a more precise method to calculate a document's size, [reach out to us](https://convex.dev/community). Documents can have nested values, either objects or arrays that contain other Convex types. Convex types can have at most 16 levels of nesting, and the cumulative size of a nested tree of values must be under the 1MB limit. Table names may contain alphanumeric characters (\"a\" to \"z\", \"A\" to \"Z\", and \"0\" to \"9\") and underscores (\"\\_\"), and they cannot start with an underscore. For information on other limits, see [here](https://docs.convex.dev/production/state/limits). If any of these limits don't work for you, [let us know](https://convex.dev/community)! ## Working with `undefined` [​](https://docs.convex.dev/database/types\\#working-with-undefined \"Direct link to working-with-undefined\") The TypeScript value `undefined` is not a valid Convex value, so it cannot be used in Convex function arguments or return values, or in stored documents. 1. Objects/records with `undefined` values are the same as if the field were missing: `{a: undefined}` is transformed into `{}` when passed to a function or stored in the database. You can think of Convex function calls and the Convex database as serializing the data with `JSON.stringify`, which similarly removes `undefined` values. 2. Validators for object fields can use `v.optional(...)` to indicate that the field might not be present. - If an object's field \"a\" is missing, i.e. `const obj = {};`, then `obj.a === undefined`. This is a property of TypeScript/JavaScript, not specific to Convex. 3. You can use `undefined` in filters and index queries, and it will match documents that do not have the field. i.e. `.withIndex(\"by_a\", q=>q.eq(\"a\", undefined))` matches document `{}` and `{b: 1}`, but not `{a: 1}` or `{a: null, b: 1}`. - In Convex's ordering scheme, `undefined < null < all other values`, so you can match documents that _have_ a field via `q.gte(\"a\", null as any)`. 4. There is exactly one case where `{a: undefined}` is different from `{}`: when passed to `ctx.db.patch`. Passing `{a: undefined}` removes the field \"a\" from the document, while passing `{}` does not change the field \"a\". See [Updating existing documents](https://docs.convex.dev/database/writing-data#updating-existing-documents). 5. Since `undefined` gets stripped from function arguments but has meaning in `ctx.db.patch`, there are some tricks to pass patch's argument from the client. - If the client passing `args={}` (or `args={a: undefined}` which is equivalent) should leave the field \"a\" unchanged, use `ctx.db.patch(id, args)`. - If the client passing `args={}` should remove the field \"a\", use `ctx.db.patch(id, {a: undefined, ...args})`. - If the client passing `args={}` should leave the field \"a\" unchanged and `args={a: null}` should remove it, you could do ```codeBlockLines_zEuJ if (args.a === null) { args.a = undefined; } await ctx.db.patch(id, args); ``` 6. Functions that return a plain `undefined`/ `void` are treated as if they returned `null`. 7. Arrays containing `undefined` values, like `[undefined]`, throw an error when used as Convex values. If you would prefer to avoid the special behaviors of `undefined`, you can use `null` instead, which _is_ a valid Convex value. ## Working with dates and times [​](https://docs.convex.dev/database/types\\#working-with-dates-and-times \"Direct link to Working with dates and times\") Convex does not have a special data type for working with dates and times. How you store dates depends on the needs of your application: 1. If you only care about a point in time, you can store a [UTC timestamp](https://en.wikipedia.org/wiki/Unix_time). We recommend following the `_creationTime` field example, which stores the timestamp as a `number` in milliseconds. In your functions and on the client you can create a JavaScript `Date` by passing the timestamp to its constructor: `new Date(timeInMsSinceEpoch)`. You can then print the date and time in the desired time zone (such as your user's machine's configured time zone). - To get the current UTC timestamp in your function and store it in the database, use `Date.now()` 2. If you care about a calendar date or a specific clock time, such as when implementing a booking app, you should store the actual date and/or time as a string. If your app supports multiple timezones you should store the timezone as well. [ISO8601](https://en.wikipedia.org/wiki/ISO_8601) is a common format for storing dates and times together in a single string like `\"2024-03-21T14:37:15Z\"`. If your users can choose a specific time zone you should probably store it in a separate `string` field, usually using the [IANA time zone name](https://en.wikipedia.org/wiki/Tz_database#Names_of_time_zones) (although you could concatenate the two fields with unique character like `\"|\"`). For more sophisticated printing (formatting) and manipulation of dates and times use one of the popular JavaScript libraries: [date-fns](https://date-fns.org/), [Day.js](https://day.js.org/), [Luxon](https://moment.github.io/luxon/) or [Moment.js](https://momentjs.com/). - [Convex values](https://docs.convex.dev/database/types#convex-values) - [System fields](https://docs.convex.dev/database/types#system-fields) - [Limits](https://docs.convex.dev/database/types#limits) - [Working with `undefined`](https://docs.convex.dev/database/types#working-with-undefined) - [Working with dates and times](https://docs.convex.dev/database/types#working-with-dates-and-times) [Skip to main content](https://docs.convex.dev/quickstart/python#docusaurus_skipToContent_fallback) Learn how to query data from Convex in a Python app. 1. Create a Python script folder Create a folder for your Python script with a virtual environment. ```codeBlockLines_zEuJ python3 -m venv my-app/venv ``` 2. Install the Convex client and server libraries To get started, install the `convex` npm package which enables you to write your backend. And also install the `convex` Python client library and `python-dotenv` for working with `.env` files. ```codeBlockLines_zEuJ cd my-app && npm init -y && npm install convex && venv/bin/pip install convex python-dotenv ``` 3. Set up a Convex dev deployment Next, run `npx convex dev`. This will prompt you to log in with GitHub, create a project, and save your production and deployment URLs. It will also create a `convex/` folder for you to write your backend API functions in. The `dev` command will then continue running to sync your functions with your dev deployment in the cloud. ```codeBlockLines_zEuJ npx convex dev ``` 4. Create sample data for your database In a new terminal window, create a `sampleData.jsonl` file with some sample data. sampleData.jsonl ```codeBlockLines_zEuJ {\"text\": \"Buy groceries\", \"isCompleted\": true} {\"text\": \"Go for a swim\", \"isCompleted\": true} {\"text\": \"Integrate Convex\", \"isCompleted\": false} ``` 5. Add the sample data to your database Now that your project is ready, add a `tasks` table with the sample data into your Convex database with the `import` command. ```codeBlockLines_zEuJ npx convex import --table tasks sampleData.jsonl ``` 6. Expose a database query Add a new file `tasks.js` in the `convex/` folder with a query function that loads the data. Exporting a query function from this file declares an API function named after the file and the export name, `\"tasks:get\"`. convex/tasks.js ```codeBlockLines_zEuJ import { query } from \"./_generated/server\"; export const get = query({ handler: async ({ db }) => { return await db.query(\"tasks\").collect(); }, }); ``` 7. Create a script to load data from Convex In a new file `main.py`, create a `ConvexClient` and use it to fetch from your `\"tasks:get\"` API. main.py ```codeBlockLines_zEuJ import os from dotenv import load_dotenv from convex import ConvexClient load_dotenv(\".env.local\") CONVEX_URL = os.getenv(\"CONVEX_URL\") # or you can hardcode your deployment URL instead # CONVEX_URL = \"https://happy-otter-123.convex.cloud\" client = ConvexClient(CONVEX_URL) print(client.query(\"tasks:get\")) for tasks in client.subscribe(\"tasks:get\"): print(tasks) # this loop lasts forever, ctrl-c to exit it ``` 8. Run the script Run the script and see the serialized list of tasks. ```codeBlockLines_zEuJ venv/bin/python -m main ``` See the [docs on PyPI](https://pypi.org/project/convex/) for more details. [Skip to main content](https://docs.convex.dev/quickstart/react#docusaurus_skipToContent_fallback) To get setup quickly with Convex and React run **`npm create convex@latest`** **``** or follow the guide below. * * * Learn how to query data from Convex in a React app using Vite and TypeScript 01. Create a React app Create a React app using the `create vite` command. ```codeBlockLines_zEuJ npm create vite@latest my-app -- --template react-ts ``` 02. Install the Convex client and server library To get started, install the `convex` package which provides a convenient interface for working with Convex from a React app. Navigate to your app directory and install `convex`. ```codeBlockLines_zEuJ cd my-app && npm install convex ``` 03. Set up a Convex dev deployment Next, run `npx convex dev`. This will prompt you to log in with GitHub, create a project, and save your production and deployment URLs. It will also create a `convex/` folder for you to write your backend API functions in. The `dev` command will then continue running to sync your functions with your dev deployment in the cloud. ```codeBlockLines_zEuJ npx convex dev ``` 04. Create sample data for your database In a new terminal window, create a `sampleData.jsonl` file with some sample data. sampleData.jsonl ```codeBlockLines_zEuJ {\"text\": \"Buy groceries\", \"isCompleted\": true} {\"text\": \"Go for a swim\", \"isCompleted\": true} {\"text\": \"Integrate Convex\", \"isCompleted\": false} ``` 05. Add the sample data to your database Now that your project is ready, add a `tasks` table with the sample data into your Convex database with the `import` command. ```codeBlockLines_zEuJ npx convex import --table tasks sampleData.jsonl ``` 06. (optional) Define a schema Add a new file `schema.ts` in the `convex/` folder with a description of your data. This will declare the types of your data for optional typechecking with TypeScript, and it will be also enforced at runtime. Alternatively remove the line `'plugin:@typescript-eslint/recommended-requiring-type-checking',` from the `.eslintrc.cjs` file to lower the type checking strictness. convex/schema.ts ```codeBlockLines_zEuJ import { defineSchema, defineTable } from \"convex/server\"; import { v } from \"convex/values\"; export default defineSchema({ tasks: defineTable({ text: v.string(), isCompleted: v.boolean(), }), }); ``` 07. Expose a database query Add a new file `tasks.ts` in the `convex/` folder with a query function that loads the data. Exporting a query function from this file declares an API function named after the file and the export name, `api.tasks.get`. convex/tasks.ts TS ```codeBlockLines_zEuJ import { query } from \"./_generated/server\"; export const get = query({ args: {}, handler: async (ctx) => { return await ctx.db.query(\"tasks\").collect(); }, }); ``` 08. Connect the app to your backend In `src/main.tsx`, create a `ConvexReactClient` and pass it to a `ConvexProvider` wrapping your app. src/main.tsx TS ```codeBlockLines_zEuJ import React from \"react\"; import ReactDOM from \"react-dom/client\"; import App from \"./App\"; import \"./index.css\"; import { ConvexProvider, ConvexReactClient } from \"convex/react\"; const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL as string); ReactDOM.createRoot(document.getElementById(\"root\")!).render( , ); ``` 09. Display the data in your app In `src/App.tsx`, use the `useQuery` hook to fetch from your `api.tasks.get` API function and display the data. src/App.tsx TS ```codeBlockLines_zEuJ import \"./App.css\"; import { useQuery } from \"convex/react\"; import { api } from \"../convex/_generated/api\"; function App() { const tasks = useQuery(api.tasks.get); return (
{tasks?.map(({ _id, text }) =>
{text}
)}
); } export default App; ``` 10. Start the app Start the app, open [http://localhost:5173/](http://localhost:5173/) in a browser, and see the list of tasks. ```codeBlockLines_zEuJ npm run dev ``` Using `create-react-app`? See the [Create React App](https://docs.convex.dev/client/react/quickstart-create-react-app) version of this guide. [Skip to main content](https://docs.convex.dev/client/javascript/node#docusaurus_skipToContent_fallback) On this page Convex supports point-in-time queries (see [HTTP client](https://docs.convex.dev/api/classes/browser.ConvexHttpClient)) and query subscriptions (see [ConvexClient](https://docs.convex.dev/api/classes/browser.ConvexClient)) in Node.js. If your JavaScript code uses import/export syntax, calling Convex functions works just like in a browser. ```codeBlockLines_zEuJ import { ConvexHttpClient, ConvexClient } from \"convex/browser\"; import { api } from \"./convex/_generated/api.js\"; // HTTP client const httpClient = new ConvexHttpClient(CONVEX_URL_GOES_HERE); httpClient.query(api.messages.list).then(console.log); // Subscription client const client = new ConvexClient(CONVEX_URL_GOES_HERE); client.onUpdate(api.messages.list, {}, (messages) => console.log(messages)); ``` ## TypeScript [​](https://docs.convex.dev/client/javascript/node\\#typescript \"Direct link to TypeScript\") Just like bundling for the browser, bundling TypeScript code for Node.js with webpack, esbuild, rollup, vite, and others usually allow you import from code that uses import/export syntax with no extra setup. If you use TypeScript to _compile_ your code (this is rare for web projects but more common with Node.js), add `\"allowJs\": true` to `tsconfig.json` compiler options so that TypeScript will compile the `api.js` file as well. ## TypeScript without a compile step [​](https://docs.convex.dev/client/javascript/node\\#typescript-without-a-compile-step \"Direct link to TypeScript without a compile step\") If you want to run your TypeScript script directly without a compile step, installing [ts-node-esm](https://www.npmjs.com/package/ts-node) and running your script with ts-node-esm should work if you use `\"type\": \"module\"` in your `package.json`. ## JavaScript with CommonJS ( `require()` syntax) [​](https://docs.convex.dev/client/javascript/node\\#javascript-with-commonjs-require-syntax \"Direct link to javascript-with-commonjs-require-syntax\") If you don't use `\"type\": \"module\"` in the `package.json` of your project you'll need to use `require()` syntax and Node.js will not be able to import the `convex/_generated/api.js` file directly. In the same directory as your `package.json`, create or edit [`convex.json`](https://docs.convex.dev/production/project-configuration#convex.json): ```codeBlockLines_zEuJ { \"generateCommonJSApi\": true } ``` When the `convex dev` command generates files in `convex/_generated/` a new `api_cjs.cjs` file will be created which can be imported from CommonJS code. ```codeBlockLines_zEuJ const { ConvexHttpClient, ConvexClient } = require(\"convex/browser\"); const { api } = require(\"./convex/_generated/api_cjs.cjs\"); const httpClient = new ConvexHttpClient(CONVEX_URL_GOES_HERE); ``` ## TypeScript with CommonJS without a compile step [​](https://docs.convex.dev/client/javascript/node\\#typescript-with-commonjs-without-a-compile-step \"Direct link to TypeScript with CommonJS without a compile step\") Follow the steps above for CommonJS and use [`ts-node`](https://www.npmjs.com/package/ts-node) to run you code. Be sure your `tsconfig.json` is configured for CommonJS output. ## Using Convex with Node.js without codegen [​](https://docs.convex.dev/client/javascript/node\\#using-convex-with-nodejs-without-codegen \"Direct link to Using Convex with Node.js without codegen\") You can always use the `anyApi` object or strings if you don't have the Convex functions and api file handy. An api reference like `api.folder.file.exportName` becomes `anyApi.folder.file.exportName` or `\"folder/file:exportName\"`. - [TypeScript](https://docs.convex.dev/client/javascript/node#typescript) - [TypeScript without a compile step](https://docs.convex.dev/client/javascript/node#typescript-without-a-compile-step) - [JavaScript with CommonJS ( `require()` syntax)](https://docs.convex.dev/client/javascript/node#javascript-with-commonjs-require-syntax) - [TypeScript with CommonJS without a compile step](https://docs.convex.dev/client/javascript/node#typescript-with-commonjs-without-a-compile-step) - [Using Convex with Node.js without codegen](https://docs.convex.dev/client/javascript/node#using-convex-with-nodejs-without-codegen) [Skip to main content](https://docs.convex.dev/api/modules/server#docusaurus_skipToContent_fallback) On this page Utilities for implementing server-side Convex query and mutation functions. ## Usage [​](https://docs.convex.dev/api/modules/server\\#usage \"Direct link to Usage\") ### Code Generation [​](https://docs.convex.dev/api/modules/server\\#code-generation \"Direct link to Code Generation\") This module is typically used alongside generated server code. To generate the server code, run `npx convex dev` in your Convex project. This will create a `convex/_generated/server.js` file with the following functions, typed for your schema: - [query](https://docs.convex.dev/generated-api/server#query) - [mutation](https://docs.convex.dev/generated-api/server#mutation) If you aren't using TypeScript and code generation, you can use these untyped functions instead: - [queryGeneric](https://docs.convex.dev/api/modules/server#querygeneric) - [mutationGeneric](https://docs.convex.dev/api/modules/server#mutationgeneric) ### Example [​](https://docs.convex.dev/api/modules/server\\#example \"Direct link to Example\") Convex functions are defined by using either the `query` or `mutation` wrappers. Queries receive a `db` that implements the [GenericDatabaseReader](https://docs.convex.dev/api/interfaces/server.GenericDatabaseReader) interface. ```codeBlockLines_zEuJ import { query } from \"./_generated/server\"; export default query({ handler: async ({ db }, { arg1, arg2 }) => { // Your (read-only) code here! }, }); ``` If your function needs to write to the database, such as inserting, updating, or deleting documents, use `mutation` instead which provides a `db` that implements the [GenericDatabaseWriter](https://docs.convex.dev/api/interfaces/server.GenericDatabaseWriter) interface. ```codeBlockLines_zEuJ import { mutation } from \"./_generated/server\"; export default mutation({ handler: async ({ db }, { arg1, arg2 }) => { // Your mutation code here! }, }); ``` ## Classes [​](https://docs.convex.dev/api/modules/server\\#classes \"Direct link to Classes\") - [Crons](https://docs.convex.dev/api/classes/server.Crons) - [Expression](https://docs.convex.dev/api/classes/server.Expression) - [IndexRange](https://docs.convex.dev/api/classes/server.IndexRange) - [HttpRouter](https://docs.convex.dev/api/classes/server.HttpRouter) - [TableDefinition](https://docs.convex.dev/api/classes/server.TableDefinition) - [SchemaDefinition](https://docs.convex.dev/api/classes/server.SchemaDefinition) - [SearchFilter](https://docs.convex.dev/api/classes/server.SearchFilter) - [FilterExpression](https://docs.convex.dev/api/classes/server.FilterExpression) ## Interfaces [​](https://docs.convex.dev/api/modules/server\\#interfaces \"Direct link to Interfaces\") - [UserIdentity](https://docs.convex.dev/api/interfaces/server.UserIdentity) - [Auth](https://docs.convex.dev/api/interfaces/server.Auth) - [CronJob](https://docs.convex.dev/api/interfaces/server.CronJob) - [BaseTableReader](https://docs.convex.dev/api/interfaces/server.BaseTableReader) - [GenericDatabaseReader](https://docs.convex.dev/api/interfaces/server.GenericDatabaseReader) - [GenericDatabaseReaderWithTable](https://docs.convex.dev/api/interfaces/server.GenericDatabaseReaderWithTable) - [GenericDatabaseWriter](https://docs.convex.dev/api/interfaces/server.GenericDatabaseWriter) - [GenericDatabaseWriterWithTable](https://docs.convex.dev/api/interfaces/server.GenericDatabaseWriterWithTable) - [BaseTableWriter](https://docs.convex.dev/api/interfaces/server.BaseTableWriter) - [FilterBuilder](https://docs.convex.dev/api/interfaces/server.FilterBuilder) - [IndexRangeBuilder](https://docs.convex.dev/api/interfaces/server.IndexRangeBuilder) - [PaginationResult](https://docs.convex.dev/api/interfaces/server.PaginationResult) - [PaginationOptions](https://docs.convex.dev/api/interfaces/server.PaginationOptions) - [QueryInitializer](https://docs.convex.dev/api/interfaces/server.QueryInitializer) - [Query](https://docs.convex.dev/api/interfaces/server.Query) - [OrderedQuery](https://docs.convex.dev/api/interfaces/server.OrderedQuery) - [GenericMutationCtx](https://docs.convex.dev/api/interfaces/server.GenericMutationCtx) - [GenericQueryCtx](https://docs.convex.dev/api/interfaces/server.GenericQueryCtx) - [GenericActionCtx](https://docs.convex.dev/api/interfaces/server.GenericActionCtx) - [ValidatedFunction](https://docs.convex.dev/api/interfaces/server.ValidatedFunction) - [Scheduler](https://docs.convex.dev/api/interfaces/server.Scheduler) - [SearchIndexConfig](https://docs.convex.dev/api/interfaces/server.SearchIndexConfig) - [VectorIndexConfig](https://docs.convex.dev/api/interfaces/server.VectorIndexConfig) - [DefineSchemaOptions](https://docs.convex.dev/api/interfaces/server.DefineSchemaOptions) - [SystemDataModel](https://docs.convex.dev/api/interfaces/server.SystemDataModel) - [SearchFilterBuilder](https://docs.convex.dev/api/interfaces/server.SearchFilterBuilder) - [SearchFilterFinalizer](https://docs.convex.dev/api/interfaces/server.SearchFilterFinalizer) - [StorageReader](https://docs.convex.dev/api/interfaces/server.StorageReader) - [StorageWriter](https://docs.convex.dev/api/interfaces/server.StorageWriter) - [StorageActionWriter](https://docs.convex.dev/api/interfaces/server.StorageActionWriter) - [VectorSearchQuery](https://docs.convex.dev/api/interfaces/server.VectorSearchQuery) - [VectorFilterBuilder](https://docs.convex.dev/api/interfaces/server.VectorFilterBuilder) ## References [​](https://docs.convex.dev/api/modules/server\\#references \"Direct link to References\") ### UserIdentityAttributes [​](https://docs.convex.dev/api/modules/server\\#useridentityattributes \"Direct link to UserIdentityAttributes\") Re-exports [UserIdentityAttributes](https://docs.convex.dev/api/modules/browser#useridentityattributes) ## Type Aliases [​](https://docs.convex.dev/api/modules/server\\#type-aliases \"Direct link to Type Aliases\") ### FunctionType [​](https://docs.convex.dev/api/modules/server\\#functiontype \"Direct link to FunctionType\") Ƭ **FunctionType**: `\"query\"` \\| `\"mutation\"` \\| `\"action\"` The type of a Convex function. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in \"Direct link to Defined in\") [server/api.ts:19](https://github.com/get-convex/convex-js/blob/main/src/server/api.ts#L19) * * * ### FunctionReference [​](https://docs.convex.dev/api/modules/server\\#functionreference \"Direct link to FunctionReference\") Ƭ **FunctionReference** < `Type`, `Visibility`, `Args`, `ReturnType`, `ComponentPath` >: `Object` A reference to a registered Convex function. You can create a [FunctionReference](https://docs.convex.dev/api/modules/server#functionreference) using the generated `api` utility: ```codeBlockLines_zEuJ import { api } from \"../convex/_generated/api\"; const reference = api.myModule.myFunction; ``` If you aren't using code generation, you can create references using [anyApi](https://docs.convex.dev/api/modules/server#anyapi-1): ```codeBlockLines_zEuJ import { anyApi } from \"convex/server\"; const reference = anyApi.myModule.myFunction; ``` Function references can be used to invoke functions from the client. For example, in React you can pass references to the [useQuery](https://docs.convex.dev/api/modules/react#usequery) hook: ```codeBlockLines_zEuJ const result = useQuery(api.myModule.myFunction); ``` #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters \"Direct link to Type parameters\") | Name | Type | Description | | :-- | :-- | :-- | | `Type` | extends [`FunctionType`](https://docs.convex.dev/api/modules/server#functiontype) | The type of the function (\"query\", \"mutation\", or \"action\"). | | `Visibility` | extends [`FunctionVisibility`](https://docs.convex.dev/api/modules/server#functionvisibility) = `\"public\"` | The visibility of the function (\"public\" or \"internal\"). | | `Args` | extends [`DefaultFunctionArgs`](https://docs.convex.dev/api/modules/server#defaultfunctionargs) = `any` | The arguments to this function. This is an object mapping argument names to their types. | | `ReturnType` | `any` | The return type of this function. | | `ComponentPath` | `string` \\| `undefined` | - | #### Type declaration [​](https://docs.convex.dev/api/modules/server\\#type-declaration \"Direct link to Type declaration\") | Name | Type | | :-- | :-- | | `_type` | `Type` | | `_visibility` | `Visibility` | | `_args` | `Args` | | `_returnType` | `ReturnType` | | `_componentPath` | `ComponentPath` | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-1 \"Direct link to Defined in\") [server/api.ts:52](https://github.com/get-convex/convex-js/blob/main/src/server/api.ts#L52) * * * ### ApiFromModules [​](https://docs.convex.dev/api/modules/server\\#apifrommodules \"Direct link to ApiFromModules\") Ƭ **ApiFromModules** < `AllModules` >: [`FilterApi`](https://docs.convex.dev/api/modules/server#filterapi) < `ApiFromModulesAllowEmptyNodes` < `AllModules` >, [`FunctionReference`](https://docs.convex.dev/api/modules/server#functionreference) < `any`, `any`, `any`, `any` >> Given the types of all modules in the `convex/` directory, construct the type of `api`. `api` is a utility for constructing [FunctionReference](https://docs.convex.dev/api/modules/server#functionreference) s. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-1 \"Direct link to Type parameters\") | Name | Type | Description | | :-- | :-- | :-- | | `AllModules` | extends `Record` < `string`, `object` > | A type mapping module paths (like `\"dir/myModule\"`) to the types of the modules. | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-2 \"Direct link to Defined in\") [server/api.ts:255](https://github.com/get-convex/convex-js/blob/main/src/server/api.ts#L255) * * * ### FilterApi [​](https://docs.convex.dev/api/modules/server\\#filterapi \"Direct link to FilterApi\") Ƭ **FilterApi** < `API`, `Predicate` >: [`Expand`](https://docs.convex.dev/api/modules/server#expand) <{ \\[mod in keyof API as API\\[mod\\] extends Predicate ? mod : API\\[mod\\] extends FunctionReference ? never : FilterApi extends Record ? never : mod\\]: API\\[mod\\] extends Predicate ? API\\[mod\\] : FilterApi }> Filter a Convex deployment api object for functions which meet criteria, for example all public queries. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-2 \"Direct link to Type parameters\") | Name | | :-- | | `API` | | `Predicate` | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-3 \"Direct link to Defined in\") [server/api.ts:279](https://github.com/get-convex/convex-js/blob/main/src/server/api.ts#L279) * * * ### AnyApi [​](https://docs.convex.dev/api/modules/server\\#anyapi \"Direct link to AnyApi\") Ƭ **AnyApi**: `Record` < `string`, `Record` < `string`, `AnyModuleDirOrFunc` >> The type that Convex api objects extend. If you were writing an api from scratch it should extend this type. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-4 \"Direct link to Defined in\") [server/api.ts:393](https://github.com/get-convex/convex-js/blob/main/src/server/api.ts#L393) * * * ### PartialApi [​](https://docs.convex.dev/api/modules/server\\#partialapi \"Direct link to PartialApi\") Ƭ **PartialApi** < `API` >: { \\[mod in keyof API\\]?: API\\[mod\\] extends FunctionReference ? API\\[mod\\] : PartialApi } Recursive partial API, useful for defining a subset of an API when mocking or building custom api objects. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-3 \"Direct link to Type parameters\") | Name | | :-- | | `API` | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-5 \"Direct link to Defined in\") [server/api.ts:401](https://github.com/get-convex/convex-js/blob/main/src/server/api.ts#L401) * * * ### FunctionArgs [​](https://docs.convex.dev/api/modules/server\\#functionargs \"Direct link to FunctionArgs\") Ƭ **FunctionArgs** < `FuncRef` >: `FuncRef`\\[ `\"_args\"`\\] Given a [FunctionReference](https://docs.convex.dev/api/modules/server#functionreference), get the return type of the function. This is represented as an object mapping argument names to values. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-4 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `FuncRef` | extends `AnyFunctionReference` | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-6 \"Direct link to Defined in\") [server/api.ts:435](https://github.com/get-convex/convex-js/blob/main/src/server/api.ts#L435) * * * ### OptionalRestArgs [​](https://docs.convex.dev/api/modules/server\\#optionalrestargs \"Direct link to OptionalRestArgs\") Ƭ **OptionalRestArgs** < `FuncRef` >: `FuncRef`\\[ `\"_args\"`\\] extends `EmptyObject` ? \\[args?: EmptyObject\\] : \\[args: FuncRef\\[\"\\_args\"\\]\\] A tuple type of the (maybe optional) arguments to `FuncRef`. This type is used to make methods involving arguments type safe while allowing skipping the arguments for functions that don't require arguments. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-5 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `FuncRef` | extends `AnyFunctionReference` | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-7 \"Direct link to Defined in\") [server/api.ts:446](https://github.com/get-convex/convex-js/blob/main/src/server/api.ts#L446) * * * ### ArgsAndOptions [​](https://docs.convex.dev/api/modules/server\\#argsandoptions \"Direct link to ArgsAndOptions\") Ƭ **ArgsAndOptions** < `FuncRef`, `Options` >: `FuncRef`\\[ `\"_args\"`\\] extends `EmptyObject` ? \\[args?: EmptyObject, options?: Options\\] : \\[args: FuncRef\\[\"\\_args\"\\], options?: Options\\] A tuple type of the (maybe optional) arguments to `FuncRef`, followed by an options object of type `Options`. This type is used to make methods like `useQuery` type-safe while allowing 1. Skipping arguments for functions that don't require arguments. 2. Skipping the options object. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-6 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `FuncRef` | extends `AnyFunctionReference` | | `Options` | `Options` | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-8 \"Direct link to Defined in\") [server/api.ts:460](https://github.com/get-convex/convex-js/blob/main/src/server/api.ts#L460) * * * ### FunctionReturnType [​](https://docs.convex.dev/api/modules/server\\#functionreturntype \"Direct link to FunctionReturnType\") Ƭ **FunctionReturnType** < `FuncRef` >: `FuncRef`\\[ `\"_returnType\"`\\] Given a [FunctionReference](https://docs.convex.dev/api/modules/server#functionreference), get the return type of the function. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-7 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `FuncRef` | extends `AnyFunctionReference` | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-9 \"Direct link to Defined in\") [server/api.ts:472](https://github.com/get-convex/convex-js/blob/main/src/server/api.ts#L472) * * * ### FunctionHandle [​](https://docs.convex.dev/api/modules/server\\#functionhandle \"Direct link to FunctionHandle\") Ƭ **FunctionHandle** < `Type`, `Args`, `ReturnType` >: `string` & [`FunctionReference`](https://docs.convex.dev/api/modules/server#functionreference) < `Type`, `\"internal\"`, `Args`, `ReturnType` > A serializable reference to a Convex function. Passing a this reference to another component allows that component to call this function during the current function execution or at any later time. Function handles are used like `api.folder.function` FunctionReferences, e.g. `ctx.scheduler.runAfter(0, functionReference, args)`. A function reference is stable across code pushes but it's possible the Convex function it refers to might no longer exist. This is a feature of components, which are in beta. This API is unstable and may change in subsequent releases. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-8 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Type` | extends [`FunctionType`](https://docs.convex.dev/api/modules/server#functiontype) | | `Args` | extends [`DefaultFunctionArgs`](https://docs.convex.dev/api/modules/server#defaultfunctionargs) = `any` | | `ReturnType` | `any` | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-10 \"Direct link to Defined in\") [server/components/index.ts:35](https://github.com/get-convex/convex-js/blob/main/src/server/components/index.ts#L35) * * * ### ComponentDefinition [​](https://docs.convex.dev/api/modules/server\\#componentdefinition \"Direct link to ComponentDefinition\") Ƭ **ComponentDefinition** < `Exports` >: `Object` An object of this type should be the default export of a convex.config.ts file in a component definition directory. This is a feature of components, which are in beta. This API is unstable and may change in subsequent releases. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-9 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Exports` | extends `ComponentExports` = `any` | #### Type declaration [​](https://docs.convex.dev/api/modules/server\\#type-declaration-1 \"Direct link to Type declaration\") | Name | Type | Description | | :-- | :-- | :-- | | `use` | ( `definition`: `Definition`, `options?`: { `name?`: `string` }) =\\> `InstalledComponent` < `Definition` > | Install a component with the given definition in this component definition. Takes a component definition and an optional name. For editor tooling this method expects a [ComponentDefinition](https://docs.convex.dev/api/modules/server#componentdefinition) but at runtime the object that is imported will be a ImportedComponentDefinition | | `__exports` | `Exports` | Internal type-only property tracking exports provided. **`Deprecated`** This is a type-only property, don't use it. | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-11 \"Direct link to Defined in\") [server/components/index.ts:84](https://github.com/get-convex/convex-js/blob/main/src/server/components/index.ts#L84) * * * ### AnyComponents [​](https://docs.convex.dev/api/modules/server\\#anycomponents \"Direct link to AnyComponents\") Ƭ **AnyComponents**: `AnyChildComponents` #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-12 \"Direct link to Defined in\") [server/components/index.ts:442](https://github.com/get-convex/convex-js/blob/main/src/server/components/index.ts#L442) * * * ### GenericDocument [​](https://docs.convex.dev/api/modules/server\\#genericdocument \"Direct link to GenericDocument\") Ƭ **GenericDocument**: `Record` < `string`, [`Value`](https://docs.convex.dev/api/modules/values#value) > A document stored in Convex. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-13 \"Direct link to Defined in\") [server/data\\_model.ts:9](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L9) * * * ### GenericFieldPaths [​](https://docs.convex.dev/api/modules/server\\#genericfieldpaths \"Direct link to GenericFieldPaths\") Ƭ **GenericFieldPaths**: `string` A type describing all of the document fields in a table. These can either be field names (like \"name\") or references to fields on nested objects (like \"properties.name\"). #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-14 \"Direct link to Defined in\") [server/data\\_model.ts:18](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L18) * * * ### GenericIndexFields [​](https://docs.convex.dev/api/modules/server\\#genericindexfields \"Direct link to GenericIndexFields\") Ƭ **GenericIndexFields**: `string`\\[\\] A type describing the ordered fields in an index. These can either be field names (like \"name\") or references to fields on nested objects (like \"properties.name\"). #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-15 \"Direct link to Defined in\") [server/data\\_model.ts:29](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L29) * * * ### GenericTableIndexes [​](https://docs.convex.dev/api/modules/server\\#generictableindexes \"Direct link to GenericTableIndexes\") Ƭ **GenericTableIndexes**: `Record` < `string`, [`GenericIndexFields`](https://docs.convex.dev/api/modules/server#genericindexfields) > A type describing the indexes in a table. It's an object mapping each index name to the fields in the index. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-16 \"Direct link to Defined in\") [server/data\\_model.ts:37](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L37) * * * ### GenericSearchIndexConfig [​](https://docs.convex.dev/api/modules/server\\#genericsearchindexconfig \"Direct link to GenericSearchIndexConfig\") Ƭ **GenericSearchIndexConfig**: `Object` A type describing the configuration of a search index. #### Type declaration [​](https://docs.convex.dev/api/modules/server\\#type-declaration-2 \"Direct link to Type declaration\") | Name | Type | | :-- | :-- | | `searchField` | `string` | | `filterFields` | `string` | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-17 \"Direct link to Defined in\") [server/data\\_model.ts:43](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L43) * * * ### GenericTableSearchIndexes [​](https://docs.convex.dev/api/modules/server\\#generictablesearchindexes \"Direct link to GenericTableSearchIndexes\") Ƭ **GenericTableSearchIndexes**: `Record` < `string`, [`GenericSearchIndexConfig`](https://docs.convex.dev/api/modules/server#genericsearchindexconfig) > A type describing all of the search indexes in a table. This is an object mapping each index name to the config for the index. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-18 \"Direct link to Defined in\") [server/data\\_model.ts:54](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L54) * * * ### GenericVectorIndexConfig [​](https://docs.convex.dev/api/modules/server\\#genericvectorindexconfig \"Direct link to GenericVectorIndexConfig\") Ƭ **GenericVectorIndexConfig**: `Object` A type describing the configuration of a vector index. #### Type declaration [​](https://docs.convex.dev/api/modules/server\\#type-declaration-3 \"Direct link to Type declaration\") | Name | Type | | :-- | :-- | | `vectorField` | `string` | | `dimensions` | `number` | | `filterFields` | `string` | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-19 \"Direct link to Defined in\") [server/data\\_model.ts:63](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L63) * * * ### GenericTableVectorIndexes [​](https://docs.convex.dev/api/modules/server\\#generictablevectorindexes \"Direct link to GenericTableVectorIndexes\") Ƭ **GenericTableVectorIndexes**: `Record` < `string`, [`GenericVectorIndexConfig`](https://docs.convex.dev/api/modules/server#genericvectorindexconfig) > A type describing all of the vector indexes in a table. This is an object mapping each index name to the config for the index. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-20 \"Direct link to Defined in\") [server/data\\_model.ts:75](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L75) * * * ### FieldTypeFromFieldPath [​](https://docs.convex.dev/api/modules/server\\#fieldtypefromfieldpath \"Direct link to FieldTypeFromFieldPath\") Ƭ **FieldTypeFromFieldPath** < `Document`, `FieldPath` >: [`FieldTypeFromFieldPathInner`](https://docs.convex.dev/api/modules/server#fieldtypefromfieldpathinner) < `Document`, `FieldPath` \\> extends [`Value`](https://docs.convex.dev/api/modules/values#value) \\| `undefined` ? [`FieldTypeFromFieldPathInner`](https://docs.convex.dev/api/modules/server#fieldtypefromfieldpathinner) < `Document`, `FieldPath` \\> : [`Value`](https://docs.convex.dev/api/modules/values#value) \\| `undefined` The type of a field in a document. Note that this supports both simple fields like \"name\" and nested fields like \"properties.name\". If the field is not present in the document it is considered to be `undefined`. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-10 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Document` | extends [`GenericDocument`](https://docs.convex.dev/api/modules/server#genericdocument) | | `FieldPath` | extends `string` | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-21 \"Direct link to Defined in\") [server/data\\_model.ts:104](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L104) * * * ### FieldTypeFromFieldPathInner [​](https://docs.convex.dev/api/modules/server\\#fieldtypefromfieldpathinner \"Direct link to FieldTypeFromFieldPathInner\") Ƭ **FieldTypeFromFieldPathInner** < `Document`, `FieldPath` >: `FieldPath` extends \\`${infer First}.${infer Second}\\` ? `ValueFromUnion` < `Document`, `First`, `Record` < `never`, `never` >\\> extends [`GenericDocument`](https://docs.convex.dev/api/modules/server#genericdocument) ? [`FieldTypeFromFieldPath`](https://docs.convex.dev/api/modules/server#fieldtypefromfieldpath) < `ValueFromUnion` < `Document`, `First`, `Record` < `never`, `never` >>, `Second` \\> : `ValueFromUnion` < `Document`, `First`, `Record` < `never`, `never` >\\> extends [`GenericDocument`](https://docs.convex.dev/api/modules/server#genericdocument) \\| `undefined` ? [`FieldTypeFromFieldPath`](https://docs.convex.dev/api/modules/server#fieldtypefromfieldpath) < `ValueFromUnion` < `Document`, `First`, `Record` < `never`, `never` >>, `Second` \\> \\| `undefined` : `undefined` : `ValueFromUnion` < `Document`, `FieldPath`, `undefined` > The inner type of [FieldTypeFromFieldPath](https://docs.convex.dev/api/modules/server#fieldtypefromfieldpath). It's wrapped in a helper to coerce the type to `Value | undefined` since some versions of TypeScript fail to infer this type correctly. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-11 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Document` | extends [`GenericDocument`](https://docs.convex.dev/api/modules/server#genericdocument) | | `FieldPath` | extends `string` | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-22 \"Direct link to Defined in\") [server/data\\_model.ts:120](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L120) * * * ### GenericTableInfo [​](https://docs.convex.dev/api/modules/server\\#generictableinfo \"Direct link to GenericTableInfo\") Ƭ **GenericTableInfo**: `Object` A type describing the document type and indexes in a table. #### Type declaration [​](https://docs.convex.dev/api/modules/server\\#type-declaration-4 \"Direct link to Type declaration\") | Name | Type | | :-- | :-- | | `document` | [`GenericDocument`](https://docs.convex.dev/api/modules/server#genericdocument) | | `fieldPaths` | [`GenericFieldPaths`](https://docs.convex.dev/api/modules/server#genericfieldpaths) | | `indexes` | [`GenericTableIndexes`](https://docs.convex.dev/api/modules/server#generictableindexes) | | `searchIndexes` | [`GenericTableSearchIndexes`](https://docs.convex.dev/api/modules/server#generictablesearchindexes) | | `vectorIndexes` | [`GenericTableVectorIndexes`](https://docs.convex.dev/api/modules/server#generictablevectorindexes) | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-23 \"Direct link to Defined in\") [server/data\\_model.ts:151](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L151) * * * ### DocumentByInfo [​](https://docs.convex.dev/api/modules/server\\#documentbyinfo \"Direct link to DocumentByInfo\") Ƭ **DocumentByInfo** < `TableInfo` >: `TableInfo`\\[ `\"document\"`\\] The type of a document in a table for a given [GenericTableInfo](https://docs.convex.dev/api/modules/server#generictableinfo). #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-12 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `TableInfo` | extends [`GenericTableInfo`](https://docs.convex.dev/api/modules/server#generictableinfo) | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-24 \"Direct link to Defined in\") [server/data\\_model.ts:163](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L163) * * * ### FieldPaths [​](https://docs.convex.dev/api/modules/server\\#fieldpaths \"Direct link to FieldPaths\") Ƭ **FieldPaths** < `TableInfo` >: `TableInfo`\\[ `\"fieldPaths\"`\\] The field paths in a table for a given [GenericTableInfo](https://docs.convex.dev/api/modules/server#generictableinfo). These can either be field names (like \"name\") or references to fields on nested objects (like \"properties.name\"). #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-13 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `TableInfo` | extends [`GenericTableInfo`](https://docs.convex.dev/api/modules/server#generictableinfo) | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-25 \"Direct link to Defined in\") [server/data\\_model.ts:173](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L173) * * * ### Indexes [​](https://docs.convex.dev/api/modules/server\\#indexes \"Direct link to Indexes\") Ƭ **Indexes** < `TableInfo` >: `TableInfo`\\[ `\"indexes\"`\\] The database indexes in a table for a given [GenericTableInfo](https://docs.convex.dev/api/modules/server#generictableinfo). This will be an object mapping index names to the fields in the index. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-14 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `TableInfo` | extends [`GenericTableInfo`](https://docs.convex.dev/api/modules/server#generictableinfo) | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-26 \"Direct link to Defined in\") [server/data\\_model.ts:182](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L182) * * * ### IndexNames [​](https://docs.convex.dev/api/modules/server\\#indexnames \"Direct link to IndexNames\") Ƭ **IndexNames** < `TableInfo` >: keyof [`Indexes`](https://docs.convex.dev/api/modules/server#indexes) < `TableInfo` > The names of indexes in a table for a given [GenericTableInfo](https://docs.convex.dev/api/modules/server#generictableinfo). #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-15 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `TableInfo` | extends [`GenericTableInfo`](https://docs.convex.dev/api/modules/server#generictableinfo) | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-27 \"Direct link to Defined in\") [server/data\\_model.ts:188](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L188) * * * ### NamedIndex [​](https://docs.convex.dev/api/modules/server\\#namedindex \"Direct link to NamedIndex\") Ƭ **NamedIndex** < `TableInfo`, `IndexName` >: [`Indexes`](https://docs.convex.dev/api/modules/server#indexes) < `TableInfo` >\\[ `IndexName`\\] Extract the fields of an index from a [GenericTableInfo](https://docs.convex.dev/api/modules/server#generictableinfo) by name. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-16 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `TableInfo` | extends [`GenericTableInfo`](https://docs.convex.dev/api/modules/server#generictableinfo) | | `IndexName` | extends [`IndexNames`](https://docs.convex.dev/api/modules/server#indexnames) < `TableInfo` > | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-28 \"Direct link to Defined in\") [server/data\\_model.ts:195](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L195) * * * ### SearchIndexes [​](https://docs.convex.dev/api/modules/server\\#searchindexes \"Direct link to SearchIndexes\") Ƭ **SearchIndexes** < `TableInfo` >: `TableInfo`\\[ `\"searchIndexes\"`\\] The search indexes in a table for a given [GenericTableInfo](https://docs.convex.dev/api/modules/server#generictableinfo). This will be an object mapping index names to the search index config. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-17 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `TableInfo` | extends [`GenericTableInfo`](https://docs.convex.dev/api/modules/server#generictableinfo) | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-29 \"Direct link to Defined in\") [server/data\\_model.ts:206](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L206) * * * ### SearchIndexNames [​](https://docs.convex.dev/api/modules/server\\#searchindexnames \"Direct link to SearchIndexNames\") Ƭ **SearchIndexNames** < `TableInfo` >: keyof [`SearchIndexes`](https://docs.convex.dev/api/modules/server#searchindexes) < `TableInfo` > The names of search indexes in a table for a given [GenericTableInfo](https://docs.convex.dev/api/modules/server#generictableinfo). #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-18 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `TableInfo` | extends [`GenericTableInfo`](https://docs.convex.dev/api/modules/server#generictableinfo) | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-30 \"Direct link to Defined in\") [server/data\\_model.ts:213](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L213) * * * ### NamedSearchIndex [​](https://docs.convex.dev/api/modules/server\\#namedsearchindex \"Direct link to NamedSearchIndex\") Ƭ **NamedSearchIndex** < `TableInfo`, `IndexName` >: [`SearchIndexes`](https://docs.convex.dev/api/modules/server#searchindexes) < `TableInfo` >\\[ `IndexName`\\] Extract the config of a search index from a [GenericTableInfo](https://docs.convex.dev/api/modules/server#generictableinfo) by name. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-19 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `TableInfo` | extends [`GenericTableInfo`](https://docs.convex.dev/api/modules/server#generictableinfo) | | `IndexName` | extends [`SearchIndexNames`](https://docs.convex.dev/api/modules/server#searchindexnames) < `TableInfo` > | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-31 \"Direct link to Defined in\") [server/data\\_model.ts:220](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L220) * * * ### VectorIndexes [​](https://docs.convex.dev/api/modules/server\\#vectorindexes \"Direct link to VectorIndexes\") Ƭ **VectorIndexes** < `TableInfo` >: `TableInfo`\\[ `\"vectorIndexes\"`\\] The vector indexes in a table for a given [GenericTableInfo](https://docs.convex.dev/api/modules/server#generictableinfo). This will be an object mapping index names to the vector index config. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-20 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `TableInfo` | extends [`GenericTableInfo`](https://docs.convex.dev/api/modules/server#generictableinfo) | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-32 \"Direct link to Defined in\") [server/data\\_model.ts:231](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L231) * * * ### VectorIndexNames [​](https://docs.convex.dev/api/modules/server\\#vectorindexnames \"Direct link to VectorIndexNames\") Ƭ **VectorIndexNames** < `TableInfo` >: keyof [`VectorIndexes`](https://docs.convex.dev/api/modules/server#vectorindexes) < `TableInfo` > The names of vector indexes in a table for a given [GenericTableInfo](https://docs.convex.dev/api/modules/server#generictableinfo). #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-21 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `TableInfo` | extends [`GenericTableInfo`](https://docs.convex.dev/api/modules/server#generictableinfo) | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-33 \"Direct link to Defined in\") [server/data\\_model.ts:238](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L238) * * * ### NamedVectorIndex [​](https://docs.convex.dev/api/modules/server\\#namedvectorindex \"Direct link to NamedVectorIndex\") Ƭ **NamedVectorIndex** < `TableInfo`, `IndexName` >: [`VectorIndexes`](https://docs.convex.dev/api/modules/server#vectorindexes) < `TableInfo` >\\[ `IndexName`\\] Extract the config of a vector index from a [GenericTableInfo](https://docs.convex.dev/api/modules/server#generictableinfo) by name. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-22 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `TableInfo` | extends [`GenericTableInfo`](https://docs.convex.dev/api/modules/server#generictableinfo) | | `IndexName` | extends [`VectorIndexNames`](https://docs.convex.dev/api/modules/server#vectorindexnames) < `TableInfo` > | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-34 \"Direct link to Defined in\") [server/data\\_model.ts:245](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L245) * * * ### GenericDataModel [​](https://docs.convex.dev/api/modules/server\\#genericdatamodel \"Direct link to GenericDataModel\") Ƭ **GenericDataModel**: `Record` < `string`, [`GenericTableInfo`](https://docs.convex.dev/api/modules/server#generictableinfo) > A type describing the tables in a Convex project. This is designed to be code generated with `npx convex dev`. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-35 \"Direct link to Defined in\") [server/data\\_model.ts:258](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L258) * * * ### AnyDataModel [​](https://docs.convex.dev/api/modules/server\\#anydatamodel \"Direct link to AnyDataModel\") Ƭ **AnyDataModel**: `Object` A [GenericDataModel](https://docs.convex.dev/api/modules/server#genericdatamodel) that considers documents to be `any` and does not support indexes. This is the default before a schema is defined. #### Index signature [​](https://docs.convex.dev/api/modules/server\\#index-signature \"Direct link to Index signature\") ▪ \\[tableName: `string`\\]: { `document`: `any` ; `fieldPaths`: [`GenericFieldPaths`](https://docs.convex.dev/api/modules/server#genericfieldpaths) ; `indexes`: ; `searchIndexes`: ; `vectorIndexes`: } #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-36 \"Direct link to Defined in\") [server/data\\_model.ts:267](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L267) * * * ### TableNamesInDataModel [​](https://docs.convex.dev/api/modules/server\\#tablenamesindatamodel \"Direct link to TableNamesInDataModel\") Ƭ **TableNamesInDataModel** < `DataModel` >: keyof `DataModel` & `string` A type of all of the table names defined in a [GenericDataModel](https://docs.convex.dev/api/modules/server#genericdatamodel). #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-23 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `DataModel` | extends [`GenericDataModel`](https://docs.convex.dev/api/modules/server#genericdatamodel) | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-37 \"Direct link to Defined in\") [server/data\\_model.ts:281](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L281) * * * ### NamedTableInfo [​](https://docs.convex.dev/api/modules/server\\#namedtableinfo \"Direct link to NamedTableInfo\") Ƭ **NamedTableInfo** < `DataModel`, `TableName` >: `DataModel`\\[ `TableName`\\] Extract the `TableInfo` for a table in a [GenericDataModel](https://docs.convex.dev/api/modules/server#genericdatamodel) by table name. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-24 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `DataModel` | extends [`GenericDataModel`](https://docs.convex.dev/api/modules/server#genericdatamodel) | | `TableName` | extends keyof `DataModel` | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-38 \"Direct link to Defined in\") [server/data\\_model.ts:290](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L290) * * * ### DocumentByName [​](https://docs.convex.dev/api/modules/server\\#documentbyname \"Direct link to DocumentByName\") Ƭ **DocumentByName** < `DataModel`, `TableName` >: `DataModel`\\[ `TableName`\\]\\[ `\"document\"`\\] The type of a document in a [GenericDataModel](https://docs.convex.dev/api/modules/server#genericdatamodel) by table name. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-25 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `DataModel` | extends [`GenericDataModel`](https://docs.convex.dev/api/modules/server#genericdatamodel) | | `TableName` | extends [`TableNamesInDataModel`](https://docs.convex.dev/api/modules/server#tablenamesindatamodel) < `DataModel` > | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-39 \"Direct link to Defined in\") [server/data\\_model.ts:299](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L299) * * * ### ExpressionOrValue [​](https://docs.convex.dev/api/modules/server\\#expressionorvalue \"Direct link to ExpressionOrValue\") Ƭ **ExpressionOrValue** < `T` >: [`Expression`](https://docs.convex.dev/api/classes/server.Expression) < `T` \\> \\| `T` An [Expression](https://docs.convex.dev/api/classes/server.Expression) or a constant [Value](https://docs.convex.dev/api/modules/values#value) #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-26 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `T` | extends [`Value`](https://docs.convex.dev/api/modules/values#value) \\| `undefined` | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-40 \"Direct link to Defined in\") [server/filter\\_builder.ts:38](https://github.com/get-convex/convex-js/blob/main/src/server/filter_builder.ts#L38) * * * ### Cursor [​](https://docs.convex.dev/api/modules/server\\#cursor \"Direct link to Cursor\") Ƭ **Cursor**: `string` An opaque identifier used for paginating a database query. Cursors are returned from [paginate](https://docs.convex.dev/api/interfaces/server.OrderedQuery#paginate) and represent the point of the query where the page of results ended. To continue paginating, pass the cursor back into [paginate](https://docs.convex.dev/api/interfaces/server.OrderedQuery#paginate) in the [PaginationOptions](https://docs.convex.dev/api/interfaces/server.PaginationOptions) object to fetch another page of results. Note: Cursors can only be passed to _exactly_ the same database query that they were generated from. You may not reuse a cursor between different database queries. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-41 \"Direct link to Defined in\") [server/pagination.ts:19](https://github.com/get-convex/convex-js/blob/main/src/server/pagination.ts#L19) * * * ### GenericMutationCtxWithTable [​](https://docs.convex.dev/api/modules/server\\#genericmutationctxwithtable \"Direct link to GenericMutationCtxWithTable\") Ƭ **GenericMutationCtxWithTable** < `DataModel` >: `Omit` < [`GenericMutationCtx`](https://docs.convex.dev/api/interfaces/server.GenericMutationCtx) < `DataModel` >, `\"db\"` \\> & { `db`: [`GenericDatabaseWriterWithTable`](https://docs.convex.dev/api/interfaces/server.GenericDatabaseWriterWithTable) < `DataModel` \\> } A set of services for use within Convex mutation functions. The mutation context is passed as the first argument to any Convex mutation function run on the server. If you're using code generation, use the `MutationCtx` type in `convex/_generated/server.d.ts` which is typed for your data model. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-27 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `DataModel` | extends [`GenericDataModel`](https://docs.convex.dev/api/modules/server#genericdatamodel) | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-42 \"Direct link to Defined in\") [server/registration.ts:109](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L109) * * * ### GenericQueryCtxWithTable [​](https://docs.convex.dev/api/modules/server\\#genericqueryctxwithtable \"Direct link to GenericQueryCtxWithTable\") Ƭ **GenericQueryCtxWithTable** < `DataModel` >: `Omit` < [`GenericQueryCtx`](https://docs.convex.dev/api/interfaces/server.GenericQueryCtx) < `DataModel` >, `\"db\"` \\> & { `db`: [`GenericDatabaseReaderWithTable`](https://docs.convex.dev/api/interfaces/server.GenericDatabaseReaderWithTable) < `DataModel` \\> } A set of services for use within Convex query functions. The query context is passed as the first argument to any Convex query function run on the server. This differs from the MutationCtx because all of the services are read-only. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-28 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `DataModel` | extends [`GenericDataModel`](https://docs.convex.dev/api/modules/server#genericdatamodel) | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-43 \"Direct link to Defined in\") [server/registration.ts:167](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L167) * * * ### DefaultFunctionArgs [​](https://docs.convex.dev/api/modules/server\\#defaultfunctionargs \"Direct link to DefaultFunctionArgs\") Ƭ **DefaultFunctionArgs**: `Record` < `string`, `unknown` > The default arguments type for a Convex query, mutation, or action function. Convex functions always take an arguments object that maps the argument names to their values. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-44 \"Direct link to Defined in\") [server/registration.ts:278](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L278) * * * ### ArgsArray [​](https://docs.convex.dev/api/modules/server\\#argsarray \"Direct link to ArgsArray\") Ƭ **ArgsArray**: `OneArgArray` \\| `NoArgsArray` An array of arguments to a Convex function. Convex functions can take either a single [DefaultFunctionArgs](https://docs.convex.dev/api/modules/server#defaultfunctionargs) object or no args at all. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-45 \"Direct link to Defined in\") [server/registration.ts:301](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L301) * * * ### ArgsArrayToObject [​](https://docs.convex.dev/api/modules/server\\#argsarraytoobject \"Direct link to ArgsArrayToObject\") Ƭ **ArgsArrayToObject** < `Args` >: `Args` extends `OneArgArray` ? `ArgsObject` : `EmptyObject` Convert an [ArgsArray](https://docs.convex.dev/api/modules/server#argsarray) into a single object type. Empty arguments arrays are converted to EmptyObject. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-29 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Args` | extends [`ArgsArray`](https://docs.convex.dev/api/modules/server#argsarray) | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-46 \"Direct link to Defined in\") [server/registration.ts:316](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L316) * * * ### FunctionVisibility [​](https://docs.convex.dev/api/modules/server\\#functionvisibility \"Direct link to FunctionVisibility\") Ƭ **FunctionVisibility**: `\"public\"` \\| `\"internal\"` A type representing the visibility of a Convex function. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-47 \"Direct link to Defined in\") [server/registration.ts:324](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L324) * * * ### RegisteredMutation [​](https://docs.convex.dev/api/modules/server\\#registeredmutation \"Direct link to RegisteredMutation\") Ƭ **RegisteredMutation** < `Visibility`, `Args`, `Returns` >: ( `ctx`: [`GenericMutationCtx`](https://docs.convex.dev/api/interfaces/server.GenericMutationCtx) < `any` >, `args`: `Args`) =\\> `Returns` & `VisibilityProperties` < `Visibility` > A mutation function that is part of this app. You can create a mutation by wrapping your function in [mutationGeneric](https://docs.convex.dev/api/modules/server#mutationgeneric) or [internalMutationGeneric](https://docs.convex.dev/api/modules/server#internalmutationgeneric) and exporting it. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-30 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Visibility` | extends [`FunctionVisibility`](https://docs.convex.dev/api/modules/server#functionvisibility) | | `Args` | extends [`DefaultFunctionArgs`](https://docs.convex.dev/api/modules/server#defaultfunctionargs) | | `Returns` | `Returns` | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-48 \"Direct link to Defined in\") [server/registration.ts:347](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L347) * * * ### RegisteredQuery [​](https://docs.convex.dev/api/modules/server\\#registeredquery \"Direct link to RegisteredQuery\") Ƭ **RegisteredQuery** < `Visibility`, `Args`, `Returns` >: ( `ctx`: [`GenericQueryCtx`](https://docs.convex.dev/api/interfaces/server.GenericQueryCtx) < `any` >, `args`: `Args`) =\\> `Returns` & `VisibilityProperties` < `Visibility` > A query function that is part of this app. You can create a query by wrapping your function in [queryGeneric](https://docs.convex.dev/api/modules/server#querygeneric) or [internalQueryGeneric](https://docs.convex.dev/api/modules/server#internalquerygeneric) and exporting it. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-31 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Visibility` | extends [`FunctionVisibility`](https://docs.convex.dev/api/modules/server#functionvisibility) | | `Args` | extends [`DefaultFunctionArgs`](https://docs.convex.dev/api/modules/server#defaultfunctionargs) | | `Returns` | `Returns` | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-49 \"Direct link to Defined in\") [server/registration.ts:378](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L378) * * * ### RegisteredAction [​](https://docs.convex.dev/api/modules/server\\#registeredaction \"Direct link to RegisteredAction\") Ƭ **RegisteredAction** < `Visibility`, `Args`, `Returns` >: ( `ctx`: [`GenericActionCtx`](https://docs.convex.dev/api/interfaces/server.GenericActionCtx) < `any` >, `args`: `Args`) =\\> `Returns` & `VisibilityProperties` < `Visibility` > An action that is part of this app. You can create an action by wrapping your function in [actionGeneric](https://docs.convex.dev/api/modules/server#actiongeneric) or [internalActionGeneric](https://docs.convex.dev/api/modules/server#internalactiongeneric) and exporting it. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-32 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Visibility` | extends [`FunctionVisibility`](https://docs.convex.dev/api/modules/server#functionvisibility) | | `Args` | extends [`DefaultFunctionArgs`](https://docs.convex.dev/api/modules/server#defaultfunctionargs) | | `Returns` | `Returns` | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-50 \"Direct link to Defined in\") [server/registration.ts:409](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L409) * * * ### PublicHttpAction [​](https://docs.convex.dev/api/modules/server\\#publichttpaction \"Direct link to PublicHttpAction\") Ƭ **PublicHttpAction**: `Object` #### Call signature [​](https://docs.convex.dev/api/modules/server\\#call-signature \"Direct link to Call signature\") ▸ ( `ctx`, `request`): `Promise` < `Response` > An HTTP action that is part of this app's public API. You can create public HTTP actions by wrapping your function in [httpActionGeneric](https://docs.convex.dev/api/modules/server#httpactiongeneric) and exporting it. ##### Parameters [​](https://docs.convex.dev/api/modules/server\\#parameters \"Direct link to Parameters\") | Name | Type | | :-- | :-- | | `ctx` | [`GenericActionCtx`](https://docs.convex.dev/api/interfaces/server.GenericActionCtx) < `any` > | | `request` | `Request` | ##### Returns [​](https://docs.convex.dev/api/modules/server\\#returns \"Direct link to Returns\") `Promise` < `Response` > #### Type declaration [​](https://docs.convex.dev/api/modules/server\\#type-declaration-5 \"Direct link to Type declaration\") | Name | Type | | :-- | :-- | | `isHttp` | `true` | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-51 \"Direct link to Defined in\") [server/registration.ts:440](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L440) * * * ### UnvalidatedFunction [​](https://docs.convex.dev/api/modules/server\\#unvalidatedfunction \"Direct link to UnvalidatedFunction\") Ƭ **UnvalidatedFunction** < `Ctx`, `Args`, `Returns` >: ( `ctx`: `Ctx`, ... `args`: `Args`) =\\> `Returns` \\| { `handler`: ( `ctx`: `Ctx`, ... `args`: `Args`) =\\> `Returns` } **`Deprecated`** \\-\\- See the type definition for `MutationBuilder` or similar for the types used for defining Convex functions. The definition of a Convex query, mutation, or action function without argument validation. Convex functions always take a context object as their first argument and an (optional) args object as their second argument. This can be written as a function like: ```codeBlockLines_zEuJ import { query } from \"./_generated/server\"; export const func = query(({ db }, { arg }) => {...}); ``` or as an object like: ```codeBlockLines_zEuJ import { query } from \"./_generated/server\"; export const func = query({ handler: ({ db }, { arg }) => {...}, }); ``` See [ValidatedFunction](https://docs.convex.dev/api/interfaces/server.ValidatedFunction) to add argument validation. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-33 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Ctx` | `Ctx` | | `Args` | extends [`ArgsArray`](https://docs.convex.dev/api/modules/server#argsarray) | | `Returns` | `Returns` | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-52 \"Direct link to Defined in\") [server/registration.ts:479](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L479) * * * ### ReturnValueForOptionalValidator [​](https://docs.convex.dev/api/modules/server\\#returnvalueforoptionalvalidator \"Direct link to ReturnValueForOptionalValidator\") Ƭ **ReturnValueForOptionalValidator** < `ReturnsValidator` >: \\[ `ReturnsValidator`\\] extends \\[ [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `any`, `any` >\\] ? `ValidatorTypeToReturnType` < [`Infer`](https://docs.convex.dev/api/modules/values#infer) < `ReturnsValidator` >\\> : \\[ `ReturnsValidator`\\] extends \\[ [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators)\\] ? `ValidatorTypeToReturnType` < [`ObjectType`](https://docs.convex.dev/api/modules/values#objecttype) < `ReturnsValidator` >\\> : `any` There are multiple syntaxes for defining a Convex function: ```codeBlockLines_zEuJ - query(async (ctx, args) => {...}) - query({ handler: async (ctx, args) => {...} }) - query({ args: { a: v.string }, handler: async (ctx, args) => {...} } }) - query({ args: { a: v.string }, returns: v.string(), handler: async (ctx, args) => {...} } }) ``` In each of these, we want to correctly infer the type for the arguments and return value, preferring the type derived from a validator if it's provided. To avoid having a separate overload for each, which would show up in error messages, we use the type params -- ArgsValidator, ReturnsValidator, ReturnValue, OneOrZeroArgs. The type for ReturnValue and OneOrZeroArgs are constrained by the type or ArgsValidator and ReturnsValidator if they're present, and inferred from any explicit type annotations to the arguments or return value of the function. Below are a few utility types to get the appropriate type constraints based on an optional validator. Additional tricks: - We use Validator \\| void instead of Validator \\| undefined because the latter does not work with `strictNullChecks` since it's equivalent to just `Validator`. - We use a tuple type of length 1 to avoid distribution over the union [https://github.com/microsoft/TypeScript/issues/29368#issuecomment-453529532](https://github.com/microsoft/TypeScript/issues/29368#issuecomment-453529532) #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-34 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `ReturnsValidator` | extends [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `any`, `any` \\> \\| [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) \\| `void` | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-53 \"Direct link to Defined in\") [server/registration.ts:581](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L581) * * * ### ArgsArrayForOptionalValidator [​](https://docs.convex.dev/api/modules/server\\#argsarrayforoptionalvalidator \"Direct link to ArgsArrayForOptionalValidator\") Ƭ **ArgsArrayForOptionalValidator** < `ArgsValidator` >: \\[ `ArgsValidator`\\] extends \\[ [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `any`, `any` >\\] ? `OneArgArray` < [`Infer`](https://docs.convex.dev/api/modules/values#infer) < `ArgsValidator` >\\> : \\[ `ArgsValidator`\\] extends \\[ [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators)\\] ? `OneArgArray` < [`ObjectType`](https://docs.convex.dev/api/modules/values#objecttype) < `ArgsValidator` >\\> : [`ArgsArray`](https://docs.convex.dev/api/modules/server#argsarray) #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-35 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `ArgsValidator` | extends [`GenericValidator`](https://docs.convex.dev/api/modules/values#genericvalidator) \\| [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) \\| `void` | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-54 \"Direct link to Defined in\") [server/registration.ts:589](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L589) * * * ### DefaultArgsForOptionalValidator [​](https://docs.convex.dev/api/modules/server\\#defaultargsforoptionalvalidator \"Direct link to DefaultArgsForOptionalValidator\") Ƭ **DefaultArgsForOptionalValidator** < `ArgsValidator` >: \\[ `ArgsValidator`\\] extends \\[ [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `any`, `any` >\\] ? \\[ [`Infer`](https://docs.convex.dev/api/modules/values#infer) < `ArgsValidator` >\\] : \\[ `ArgsValidator`\\] extends \\[ [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators)\\] ? \\[ [`ObjectType`](https://docs.convex.dev/api/modules/values#objecttype) < `ArgsValidator` >\\] : `OneArgArray` #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-36 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `ArgsValidator` | extends [`GenericValidator`](https://docs.convex.dev/api/modules/values#genericvalidator) \\| [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) \\| `void` | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-55 \"Direct link to Defined in\") [server/registration.ts:597](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L597) * * * ### MutationBuilder [​](https://docs.convex.dev/api/modules/server\\#mutationbuilder \"Direct link to MutationBuilder\") Ƭ **MutationBuilder** < `DataModel`, `Visibility` >: ( `mutation`: { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: ( `ctx`: [`GenericMutationCtx`](https://docs.convex.dev/api/interfaces/server.GenericMutationCtx) < `DataModel` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue` } \\| ( `ctx`: [`GenericMutationCtx`](https://docs.convex.dev/api/interfaces/server.GenericMutationCtx) < `DataModel` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue`) =\\> [`RegisteredMutation`](https://docs.convex.dev/api/modules/server#registeredmutation) < `Visibility`, [`ArgsArrayToObject`](https://docs.convex.dev/api/modules/server#argsarraytoobject) < `OneOrZeroArgs` >, `ReturnValue` > #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-37 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `DataModel` | extends [`GenericDataModel`](https://docs.convex.dev/api/modules/server#genericdatamodel) | | `Visibility` | extends [`FunctionVisibility`](https://docs.convex.dev/api/modules/server#functionvisibility) | #### Type declaration [​](https://docs.convex.dev/api/modules/server\\#type-declaration-6 \"Direct link to Type declaration\") ▸ < `ArgsValidator`, `ReturnsValidator`, `ReturnValue`, `OneOrZeroArgs` >( `mutation`): [`RegisteredMutation`](https://docs.convex.dev/api/modules/server#registeredmutation) < `Visibility`, [`ArgsArrayToObject`](https://docs.convex.dev/api/modules/server#argsarraytoobject) < `OneOrZeroArgs` >, `ReturnValue` > Internal type helper used by Convex code generation. Used to give [mutationGeneric](https://docs.convex.dev/api/modules/server#mutationgeneric) a type specific to your data model. ##### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-38 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `ArgsValidator` | extends `void` \\| [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `\"required\"`, `any` \\> \\| [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) | | `ReturnsValidator` | extends `void` \\| [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `\"required\"`, `any` \\> \\| [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) | | `ReturnValue` | extends `any` = `any` | | `OneOrZeroArgs` | extends [`ArgsArray`](https://docs.convex.dev/api/modules/server#argsarray) \\| `OneArgArray` < [`Infer`](https://docs.convex.dev/api/modules/values#infer) < `ArgsValidator` >\\> \\| `OneArgArray` < [`Expand`](https://docs.convex.dev/api/modules/server#expand) <{ \\[Property in string \\| number \\| symbol\\]?: Exclude, undefined> } & { \\[Property in string \\| number \\| symbol\\]: Infer }>> = [`DefaultArgsForOptionalValidator`](https://docs.convex.dev/api/modules/server#defaultargsforoptionalvalidator) < `ArgsValidator` > | ##### Parameters [​](https://docs.convex.dev/api/modules/server\\#parameters-1 \"Direct link to Parameters\") | Name | Type | | :-- | :-- | | `mutation` | { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: ( `ctx`: [`GenericMutationCtx`](https://docs.convex.dev/api/interfaces/server.GenericMutationCtx) < `DataModel` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue` } \\| ( `ctx`: [`GenericMutationCtx`](https://docs.convex.dev/api/interfaces/server.GenericMutationCtx) < `DataModel` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue` | ##### Returns [​](https://docs.convex.dev/api/modules/server\\#returns-1 \"Direct link to Returns\") [`RegisteredMutation`](https://docs.convex.dev/api/modules/server#registeredmutation) < `Visibility`, [`ArgsArrayToObject`](https://docs.convex.dev/api/modules/server#argsarraytoobject) < `OneOrZeroArgs` >, `ReturnValue` > #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-56 \"Direct link to Defined in\") [server/registration.ts:611](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L611) * * * ### MutationBuilderWithTable [​](https://docs.convex.dev/api/modules/server\\#mutationbuilderwithtable \"Direct link to MutationBuilderWithTable\") Ƭ **MutationBuilderWithTable** < `DataModel`, `Visibility` >: ( `mutation`: { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: ( `ctx`: [`GenericMutationCtxWithTable`](https://docs.convex.dev/api/modules/server#genericmutationctxwithtable) < `DataModel` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue` } \\| ( `ctx`: [`GenericMutationCtxWithTable`](https://docs.convex.dev/api/modules/server#genericmutationctxwithtable) < `DataModel` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue`) =\\> [`RegisteredMutation`](https://docs.convex.dev/api/modules/server#registeredmutation) < `Visibility`, [`ArgsArrayToObject`](https://docs.convex.dev/api/modules/server#argsarraytoobject) < `OneOrZeroArgs` >, `ReturnValue` > #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-39 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `DataModel` | extends [`GenericDataModel`](https://docs.convex.dev/api/modules/server#genericdatamodel) | | `Visibility` | extends [`FunctionVisibility`](https://docs.convex.dev/api/modules/server#functionvisibility) | #### Type declaration [​](https://docs.convex.dev/api/modules/server\\#type-declaration-7 \"Direct link to Type declaration\") ▸ < `ArgsValidator`, `ReturnsValidator`, `ReturnValue`, `OneOrZeroArgs` >( `mutation`): [`RegisteredMutation`](https://docs.convex.dev/api/modules/server#registeredmutation) < `Visibility`, [`ArgsArrayToObject`](https://docs.convex.dev/api/modules/server#argsarraytoobject) < `OneOrZeroArgs` >, `ReturnValue` > Internal type helper used by Convex code generation. Used to give [mutationGeneric](https://docs.convex.dev/api/modules/server#mutationgeneric) a type specific to your data model. ##### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-40 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `ArgsValidator` | extends `void` \\| [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `\"required\"`, `any` \\> \\| [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) | | `ReturnsValidator` | extends `void` \\| [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `\"required\"`, `any` \\> \\| [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) | | `ReturnValue` | extends `any` = `any` | | `OneOrZeroArgs` | extends [`ArgsArray`](https://docs.convex.dev/api/modules/server#argsarray) \\| `OneArgArray` < [`Infer`](https://docs.convex.dev/api/modules/values#infer) < `ArgsValidator` >\\> \\| `OneArgArray` < [`Expand`](https://docs.convex.dev/api/modules/server#expand) <{ \\[Property in string \\| number \\| symbol\\]?: Exclude, undefined> } & { \\[Property in string \\| number \\| symbol\\]: Infer }>> = [`DefaultArgsForOptionalValidator`](https://docs.convex.dev/api/modules/server#defaultargsforoptionalvalidator) < `ArgsValidator` > | ##### Parameters [​](https://docs.convex.dev/api/modules/server\\#parameters-2 \"Direct link to Parameters\") | Name | Type | | :-- | :-- | | `mutation` | { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: ( `ctx`: [`GenericMutationCtxWithTable`](https://docs.convex.dev/api/modules/server#genericmutationctxwithtable) < `DataModel` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue` } \\| ( `ctx`: [`GenericMutationCtxWithTable`](https://docs.convex.dev/api/modules/server#genericmutationctxwithtable) < `DataModel` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue` | ##### Returns [​](https://docs.convex.dev/api/modules/server\\#returns-2 \"Direct link to Returns\") [`RegisteredMutation`](https://docs.convex.dev/api/modules/server#registeredmutation) < `Visibility`, [`ArgsArrayToObject`](https://docs.convex.dev/api/modules/server#argsarraytoobject) < `OneOrZeroArgs` >, `ReturnValue` > #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-57 \"Direct link to Defined in\") [server/registration.ts:704](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L704) * * * ### QueryBuilder [​](https://docs.convex.dev/api/modules/server\\#querybuilder \"Direct link to QueryBuilder\") Ƭ **QueryBuilder** < `DataModel`, `Visibility` >: ( `query`: { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: ( `ctx`: [`GenericQueryCtx`](https://docs.convex.dev/api/interfaces/server.GenericQueryCtx) < `DataModel` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue` } \\| ( `ctx`: [`GenericQueryCtx`](https://docs.convex.dev/api/interfaces/server.GenericQueryCtx) < `DataModel` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue`) =\\> [`RegisteredQuery`](https://docs.convex.dev/api/modules/server#registeredquery) < `Visibility`, [`ArgsArrayToObject`](https://docs.convex.dev/api/modules/server#argsarraytoobject) < `OneOrZeroArgs` >, `ReturnValue` > #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-41 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `DataModel` | extends [`GenericDataModel`](https://docs.convex.dev/api/modules/server#genericdatamodel) | | `Visibility` | extends [`FunctionVisibility`](https://docs.convex.dev/api/modules/server#functionvisibility) | #### Type declaration [​](https://docs.convex.dev/api/modules/server\\#type-declaration-8 \"Direct link to Type declaration\") ▸ < `ArgsValidator`, `ReturnsValidator`, `ReturnValue`, `OneOrZeroArgs` >( `query`): [`RegisteredQuery`](https://docs.convex.dev/api/modules/server#registeredquery) < `Visibility`, [`ArgsArrayToObject`](https://docs.convex.dev/api/modules/server#argsarraytoobject) < `OneOrZeroArgs` >, `ReturnValue` > Internal type helper used by Convex code generation. Used to give [queryGeneric](https://docs.convex.dev/api/modules/server#querygeneric) a type specific to your data model. ##### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-42 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `ArgsValidator` | extends `void` \\| [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `\"required\"`, `any` \\> \\| [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) | | `ReturnsValidator` | extends `void` \\| [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `\"required\"`, `any` \\> \\| [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) | | `ReturnValue` | extends `any` = `any` | | `OneOrZeroArgs` | extends [`ArgsArray`](https://docs.convex.dev/api/modules/server#argsarray) \\| `OneArgArray` < [`Infer`](https://docs.convex.dev/api/modules/values#infer) < `ArgsValidator` >\\> \\| `OneArgArray` < [`Expand`](https://docs.convex.dev/api/modules/server#expand) <{ \\[Property in string \\| number \\| symbol\\]?: Exclude, undefined> } & { \\[Property in string \\| number \\| symbol\\]: Infer }>> = [`DefaultArgsForOptionalValidator`](https://docs.convex.dev/api/modules/server#defaultargsforoptionalvalidator) < `ArgsValidator` > | ##### Parameters [​](https://docs.convex.dev/api/modules/server\\#parameters-3 \"Direct link to Parameters\") | Name | Type | | :-- | :-- | | `query` | { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: ( `ctx`: [`GenericQueryCtx`](https://docs.convex.dev/api/interfaces/server.GenericQueryCtx) < `DataModel` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue` } \\| ( `ctx`: [`GenericQueryCtx`](https://docs.convex.dev/api/interfaces/server.GenericQueryCtx) < `DataModel` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue` | ##### Returns [​](https://docs.convex.dev/api/modules/server\\#returns-3 \"Direct link to Returns\") [`RegisteredQuery`](https://docs.convex.dev/api/modules/server#registeredquery) < `Visibility`, [`ArgsArrayToObject`](https://docs.convex.dev/api/modules/server#argsarraytoobject) < `OneOrZeroArgs` >, `ReturnValue` > #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-58 \"Direct link to Defined in\") [server/registration.ts:797](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L797) * * * ### QueryBuilderWithTable [​](https://docs.convex.dev/api/modules/server\\#querybuilderwithtable \"Direct link to QueryBuilderWithTable\") Ƭ **QueryBuilderWithTable** < `DataModel`, `Visibility` >: ( `query`: { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: ( `ctx`: [`GenericQueryCtxWithTable`](https://docs.convex.dev/api/modules/server#genericqueryctxwithtable) < `DataModel` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue` } \\| ( `ctx`: [`GenericQueryCtxWithTable`](https://docs.convex.dev/api/modules/server#genericqueryctxwithtable) < `DataModel` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue`) =\\> [`RegisteredQuery`](https://docs.convex.dev/api/modules/server#registeredquery) < `Visibility`, [`ArgsArrayToObject`](https://docs.convex.dev/api/modules/server#argsarraytoobject) < `OneOrZeroArgs` >, `ReturnValue` > #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-43 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `DataModel` | extends [`GenericDataModel`](https://docs.convex.dev/api/modules/server#genericdatamodel) | | `Visibility` | extends [`FunctionVisibility`](https://docs.convex.dev/api/modules/server#functionvisibility) | #### Type declaration [​](https://docs.convex.dev/api/modules/server\\#type-declaration-9 \"Direct link to Type declaration\") ▸ < `ArgsValidator`, `ReturnsValidator`, `ReturnValue`, `OneOrZeroArgs` >( `query`): [`RegisteredQuery`](https://docs.convex.dev/api/modules/server#registeredquery) < `Visibility`, [`ArgsArrayToObject`](https://docs.convex.dev/api/modules/server#argsarraytoobject) < `OneOrZeroArgs` >, `ReturnValue` > Internal type helper used by Convex code generation. Used to give [queryGeneric](https://docs.convex.dev/api/modules/server#querygeneric) a type specific to your data model. ##### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-44 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `ArgsValidator` | extends `void` \\| [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `\"required\"`, `any` \\> \\| [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) | | `ReturnsValidator` | extends `void` \\| [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `\"required\"`, `any` \\> \\| [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) | | `ReturnValue` | extends `any` = `any` | | `OneOrZeroArgs` | extends [`ArgsArray`](https://docs.convex.dev/api/modules/server#argsarray) \\| `OneArgArray` < [`Infer`](https://docs.convex.dev/api/modules/values#infer) < `ArgsValidator` >\\> \\| `OneArgArray` < [`Expand`](https://docs.convex.dev/api/modules/server#expand) <{ \\[Property in string \\| number \\| symbol\\]?: Exclude, undefined> } & { \\[Property in string \\| number \\| symbol\\]: Infer }>> = [`DefaultArgsForOptionalValidator`](https://docs.convex.dev/api/modules/server#defaultargsforoptionalvalidator) < `ArgsValidator` > | ##### Parameters [​](https://docs.convex.dev/api/modules/server\\#parameters-4 \"Direct link to Parameters\") | Name | Type | | :-- | :-- | | `query` | { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: ( `ctx`: [`GenericQueryCtxWithTable`](https://docs.convex.dev/api/modules/server#genericqueryctxwithtable) < `DataModel` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue` } \\| ( `ctx`: [`GenericQueryCtxWithTable`](https://docs.convex.dev/api/modules/server#genericqueryctxwithtable) < `DataModel` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue` | ##### Returns [​](https://docs.convex.dev/api/modules/server\\#returns-4 \"Direct link to Returns\") [`RegisteredQuery`](https://docs.convex.dev/api/modules/server#registeredquery) < `Visibility`, [`ArgsArrayToObject`](https://docs.convex.dev/api/modules/server#argsarraytoobject) < `OneOrZeroArgs` >, `ReturnValue` > #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-59 \"Direct link to Defined in\") [server/registration.ts:886](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L886) * * * ### ActionBuilder [​](https://docs.convex.dev/api/modules/server\\#actionbuilder \"Direct link to ActionBuilder\") Ƭ **ActionBuilder** < `DataModel`, `Visibility` >: ( `func`: { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: ( `ctx`: [`GenericActionCtx`](https://docs.convex.dev/api/interfaces/server.GenericActionCtx) < `DataModel` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue` } \\| ( `ctx`: [`GenericActionCtx`](https://docs.convex.dev/api/interfaces/server.GenericActionCtx) < `DataModel` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue`) =\\> [`RegisteredAction`](https://docs.convex.dev/api/modules/server#registeredaction) < `Visibility`, [`ArgsArrayToObject`](https://docs.convex.dev/api/modules/server#argsarraytoobject) < `OneOrZeroArgs` >, `ReturnValue` > #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-45 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `DataModel` | extends [`GenericDataModel`](https://docs.convex.dev/api/modules/server#genericdatamodel) | | `Visibility` | extends [`FunctionVisibility`](https://docs.convex.dev/api/modules/server#functionvisibility) | #### Type declaration [​](https://docs.convex.dev/api/modules/server\\#type-declaration-10 \"Direct link to Type declaration\") ▸ < `ArgsValidator`, `ReturnsValidator`, `ReturnValue`, `OneOrZeroArgs` >( `func`): [`RegisteredAction`](https://docs.convex.dev/api/modules/server#registeredaction) < `Visibility`, [`ArgsArrayToObject`](https://docs.convex.dev/api/modules/server#argsarraytoobject) < `OneOrZeroArgs` >, `ReturnValue` > Internal type helper used by Convex code generation. Used to give [actionGeneric](https://docs.convex.dev/api/modules/server#actiongeneric) a type specific to your data model. ##### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-46 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `ArgsValidator` | extends `void` \\| [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `\"required\"`, `any` \\> \\| [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) | | `ReturnsValidator` | extends `void` \\| [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `\"required\"`, `any` \\> \\| [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) | | `ReturnValue` | extends `any` = `any` | | `OneOrZeroArgs` | extends [`ArgsArray`](https://docs.convex.dev/api/modules/server#argsarray) \\| `OneArgArray` < [`Infer`](https://docs.convex.dev/api/modules/values#infer) < `ArgsValidator` >\\> \\| `OneArgArray` < [`Expand`](https://docs.convex.dev/api/modules/server#expand) <{ \\[Property in string \\| number \\| symbol\\]?: Exclude, undefined> } & { \\[Property in string \\| number \\| symbol\\]: Infer }>> = [`DefaultArgsForOptionalValidator`](https://docs.convex.dev/api/modules/server#defaultargsforoptionalvalidator) < `ArgsValidator` > | ##### Parameters [​](https://docs.convex.dev/api/modules/server\\#parameters-5 \"Direct link to Parameters\") | Name | Type | | :-- | :-- | | `func` | { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: ( `ctx`: [`GenericActionCtx`](https://docs.convex.dev/api/interfaces/server.GenericActionCtx) < `DataModel` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue` } \\| ( `ctx`: [`GenericActionCtx`](https://docs.convex.dev/api/interfaces/server.GenericActionCtx) < `DataModel` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue` | ##### Returns [​](https://docs.convex.dev/api/modules/server\\#returns-5 \"Direct link to Returns\") [`RegisteredAction`](https://docs.convex.dev/api/modules/server#registeredaction) < `Visibility`, [`ArgsArrayToObject`](https://docs.convex.dev/api/modules/server#argsarraytoobject) < `OneOrZeroArgs` >, `ReturnValue` > #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-60 \"Direct link to Defined in\") [server/registration.ts:975](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L975) * * * ### HttpActionBuilder [​](https://docs.convex.dev/api/modules/server\\#httpactionbuilder \"Direct link to HttpActionBuilder\") Ƭ **HttpActionBuilder**: ( `func`: ( `ctx`: [`GenericActionCtx`](https://docs.convex.dev/api/interfaces/server.GenericActionCtx) < `any` >, `request`: `Request`) =\\> `Promise` < `Response` >) =\\> [`PublicHttpAction`](https://docs.convex.dev/api/modules/server#publichttpaction) #### Type declaration [​](https://docs.convex.dev/api/modules/server\\#type-declaration-11 \"Direct link to Type declaration\") ▸ ( `func`): [`PublicHttpAction`](https://docs.convex.dev/api/modules/server#publichttpaction) Internal type helper used by Convex code generation. Used to give [httpActionGeneric](https://docs.convex.dev/api/modules/server#httpactiongeneric) a type specific to your data model and functions. ##### Parameters [​](https://docs.convex.dev/api/modules/server\\#parameters-6 \"Direct link to Parameters\") | Name | Type | | :-- | :-- | | `func` | ( `ctx`: [`GenericActionCtx`](https://docs.convex.dev/api/interfaces/server.GenericActionCtx) < `any` >, `request`: `Request`) =\\> `Promise` < `Response` > | ##### Returns [​](https://docs.convex.dev/api/modules/server\\#returns-6 \"Direct link to Returns\") [`PublicHttpAction`](https://docs.convex.dev/api/modules/server#publichttpaction) #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-61 \"Direct link to Defined in\") [server/registration.ts:1070](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L1070) * * * ### RoutableMethod [​](https://docs.convex.dev/api/modules/server\\#routablemethod \"Direct link to RoutableMethod\") Ƭ **RoutableMethod**: typeof [`ROUTABLE_HTTP_METHODS`](https://docs.convex.dev/api/modules/server#routable_http_methods)\\[ `number`\\] A type representing the methods supported by Convex HTTP actions. HEAD is handled by Convex by running GET and stripping the body. CONNECT is not supported and will not be supported. TRACE is not supported and will not be supported. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-62 \"Direct link to Defined in\") [server/router.ts:31](https://github.com/get-convex/convex-js/blob/main/src/server/router.ts#L31) * * * ### RouteSpecWithPath [​](https://docs.convex.dev/api/modules/server\\#routespecwithpath \"Direct link to RouteSpecWithPath\") Ƭ **RouteSpecWithPath**: `Object` A type representing a route to an HTTP action using an exact request URL path match. Used by [HttpRouter](https://docs.convex.dev/api/classes/server.HttpRouter) to route requests to HTTP actions. #### Type declaration [​](https://docs.convex.dev/api/modules/server\\#type-declaration-12 \"Direct link to Type declaration\") | Name | Type | Description | | :-- | :-- | :-- | | `path` | `string` | Exact HTTP request path to route. | | `method` | [`RoutableMethod`](https://docs.convex.dev/api/modules/server#routablemethod) | HTTP method (\"GET\", \"POST\", ...) to route. | | `handler` | [`PublicHttpAction`](https://docs.convex.dev/api/modules/server#publichttpaction) | The HTTP action to execute. | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-63 \"Direct link to Defined in\") [server/router.ts:56](https://github.com/get-convex/convex-js/blob/main/src/server/router.ts#L56) * * * ### RouteSpecWithPathPrefix [​](https://docs.convex.dev/api/modules/server\\#routespecwithpathprefix \"Direct link to RouteSpecWithPathPrefix\") Ƭ **RouteSpecWithPathPrefix**: `Object` A type representing a route to an HTTP action using a request URL path prefix match. Used by [HttpRouter](https://docs.convex.dev/api/classes/server.HttpRouter) to route requests to HTTP actions. #### Type declaration [​](https://docs.convex.dev/api/modules/server\\#type-declaration-13 \"Direct link to Type declaration\") | Name | Type | Description | | :-- | :-- | :-- | | `pathPrefix` | `string` | An HTTP request path prefix to route. Requests with a path starting with this value will be routed to the HTTP action. | | `method` | [`RoutableMethod`](https://docs.convex.dev/api/modules/server#routablemethod) | HTTP method (\"GET\", \"POST\", ...) to route. | | `handler` | [`PublicHttpAction`](https://docs.convex.dev/api/modules/server#publichttpaction) | The HTTP action to execute. | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-64 \"Direct link to Defined in\") [server/router.ts:78](https://github.com/get-convex/convex-js/blob/main/src/server/router.ts#L78) * * * ### RouteSpec [​](https://docs.convex.dev/api/modules/server\\#routespec \"Direct link to RouteSpec\") Ƭ **RouteSpec**: [`RouteSpecWithPath`](https://docs.convex.dev/api/modules/server#routespecwithpath) \\| [`RouteSpecWithPathPrefix`](https://docs.convex.dev/api/modules/server#routespecwithpathprefix) A type representing a route to an HTTP action. Used by [HttpRouter](https://docs.convex.dev/api/classes/server.HttpRouter) to route requests to HTTP actions. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-65 \"Direct link to Defined in\") [server/router.ts:101](https://github.com/get-convex/convex-js/blob/main/src/server/router.ts#L101) * * * ### SchedulableFunctionReference [​](https://docs.convex.dev/api/modules/server\\#schedulablefunctionreference \"Direct link to SchedulableFunctionReference\") Ƭ **SchedulableFunctionReference**: [`FunctionReference`](https://docs.convex.dev/api/modules/server#functionreference) < `\"mutation\"` \\| `\"action\"`, `\"public\"` \\| `\"internal\"` > A [FunctionReference](https://docs.convex.dev/api/modules/server#functionreference) that can be scheduled to run in the future. Schedulable functions are mutations and actions that are public or internal. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-66 \"Direct link to Defined in\") [server/scheduler.ts:11](https://github.com/get-convex/convex-js/blob/main/src/server/scheduler.ts#L11) * * * ### GenericSchema [​](https://docs.convex.dev/api/modules/server\\#genericschema \"Direct link to GenericSchema\") Ƭ **GenericSchema**: `Record` < `string`, [`TableDefinition`](https://docs.convex.dev/api/classes/server.TableDefinition) > A type describing the schema of a Convex project. This should be constructed using [defineSchema](https://docs.convex.dev/api/modules/server#defineschema), [defineTable](https://docs.convex.dev/api/modules/server#definetable), and [v](https://docs.convex.dev/api/modules/values#v). #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-67 \"Direct link to Defined in\") [server/schema.ts:399](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L399) * * * ### DataModelFromSchemaDefinition [​](https://docs.convex.dev/api/modules/server\\#datamodelfromschemadefinition \"Direct link to DataModelFromSchemaDefinition\") Ƭ **DataModelFromSchemaDefinition** < `SchemaDef` >: `MaybeMakeLooseDataModel` <{ \\[TableName in keyof SchemaDef\\[\"tables\"\\] & string\\]: SchemaDef\\[\"tables\"\\]\\[TableName\\] extends TableDefinition ? Object : never }, `SchemaDef`\\[ `\"strictTableNameTypes\"`\\]> Internal type used in Convex code generation! Convert a [SchemaDefinition](https://docs.convex.dev/api/classes/server.SchemaDefinition) into a [GenericDataModel](https://docs.convex.dev/api/modules/server#genericdatamodel). #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-47 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `SchemaDef` | extends [`SchemaDefinition`](https://docs.convex.dev/api/classes/server.SchemaDefinition) < `any`, `boolean` > | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-68 \"Direct link to Defined in\") [server/schema.ts:530](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L530) * * * ### SystemTableNames [​](https://docs.convex.dev/api/modules/server\\#systemtablenames \"Direct link to SystemTableNames\") Ƭ **SystemTableNames**: [`TableNamesInDataModel`](https://docs.convex.dev/api/modules/server#tablenamesindatamodel) < [`SystemDataModel`](https://docs.convex.dev/api/interfaces/server.SystemDataModel) > #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-69 \"Direct link to Defined in\") [server/schema.ts:588](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L588) * * * ### StorageId [​](https://docs.convex.dev/api/modules/server\\#storageid \"Direct link to StorageId\") Ƭ **StorageId**: `string` A reference to a file in storage. This is used in the [StorageReader](https://docs.convex.dev/api/interfaces/server.StorageReader) and [StorageWriter](https://docs.convex.dev/api/interfaces/server.StorageWriter) which are accessible in Convex queries and mutations via QueryCtx and MutationCtx respectively. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-70 \"Direct link to Defined in\") [server/storage.ts:11](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L11) * * * ### FileStorageId [​](https://docs.convex.dev/api/modules/server\\#filestorageid \"Direct link to FileStorageId\") Ƭ **FileStorageId**: [`GenericId`](https://docs.convex.dev/api/modules/values#genericid) < `\"_storage\"` \\> \\| [`StorageId`](https://docs.convex.dev/api/modules/server#storageid) #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-71 \"Direct link to Defined in\") [server/storage.ts:12](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L12) * * * ### FileMetadata [​](https://docs.convex.dev/api/modules/server\\#filemetadata \"Direct link to FileMetadata\") Ƭ **FileMetadata**: `Object` Metadata for a single file as returned by [storage.getMetadata](https://docs.convex.dev/api/interfaces/server.StorageReader#getmetadata). #### Type declaration [​](https://docs.convex.dev/api/modules/server\\#type-declaration-14 \"Direct link to Type declaration\") | Name | Type | Description | | :-- | :-- | :-- | | `storageId` | [`StorageId`](https://docs.convex.dev/api/modules/server#storageid) | ID for referencing the file (eg. via [storage.getUrl](https://docs.convex.dev/api/interfaces/server.StorageReader#geturl)) | | `sha256` | `string` | Hex encoded sha256 checksum of file contents | | `size` | `number` | Size of the file in bytes | | `contentType` | `string` \\| `null` | ContentType of the file if it was provided on upload | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-72 \"Direct link to Defined in\") [server/storage.ts:18](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L18) * * * ### SystemFields [​](https://docs.convex.dev/api/modules/server\\#systemfields \"Direct link to SystemFields\") Ƭ **SystemFields**: `Object` The fields that Convex automatically adds to documents, not including `_id`. This is an object type mapping field name to field type. #### Type declaration [​](https://docs.convex.dev/api/modules/server\\#type-declaration-15 \"Direct link to Type declaration\") | Name | Type | | :-- | :-- | | `_creationTime` | `number` | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-73 \"Direct link to Defined in\") [server/system\\_fields.ts:11](https://github.com/get-convex/convex-js/blob/main/src/server/system_fields.ts#L11) * * * ### IdField [​](https://docs.convex.dev/api/modules/server\\#idfield \"Direct link to IdField\") Ƭ **IdField** < `TableName` >: `Object` The `_id` field that Convex automatically adds to documents. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-48 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `TableName` | extends `string` | #### Type declaration [​](https://docs.convex.dev/api/modules/server\\#type-declaration-16 \"Direct link to Type declaration\") | Name | Type | | :-- | :-- | | `_id` | [`GenericId`](https://docs.convex.dev/api/modules/values#genericid) < `TableName` > | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-74 \"Direct link to Defined in\") [server/system\\_fields.ts:19](https://github.com/get-convex/convex-js/blob/main/src/server/system_fields.ts#L19) * * * ### WithoutSystemFields [​](https://docs.convex.dev/api/modules/server\\#withoutsystemfields \"Direct link to WithoutSystemFields\") Ƭ **WithoutSystemFields** < `Document` >: [`Expand`](https://docs.convex.dev/api/modules/server#expand) < [`BetterOmit`](https://docs.convex.dev/api/modules/server#betteromit) < `Document`, keyof [`SystemFields`](https://docs.convex.dev/api/modules/server#systemfields) \\| `\"_id\"` >> A Convex document with the system fields like `_id` and `_creationTime` omitted. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-49 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Document` | extends [`GenericDocument`](https://docs.convex.dev/api/modules/server#genericdocument) | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-75 \"Direct link to Defined in\") [server/system\\_fields.ts:28](https://github.com/get-convex/convex-js/blob/main/src/server/system_fields.ts#L28) * * * ### WithOptionalSystemFields [​](https://docs.convex.dev/api/modules/server\\#withoptionalsystemfields \"Direct link to WithOptionalSystemFields\") Ƭ **WithOptionalSystemFields** < `Document` >: [`Expand`](https://docs.convex.dev/api/modules/server#expand) < [`WithoutSystemFields`](https://docs.convex.dev/api/modules/server#withoutsystemfields) < `Document` \\> & `Partial` < `Pick` < `Document`, keyof [`SystemFields`](https://docs.convex.dev/api/modules/server#systemfields) \\| `\"_id\"` >>> A Convex document with the system fields like `_id` and `_creationTime` optional. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-50 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Document` | extends [`GenericDocument`](https://docs.convex.dev/api/modules/server#genericdocument) | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-76 \"Direct link to Defined in\") [server/system\\_fields.ts:37](https://github.com/get-convex/convex-js/blob/main/src/server/system_fields.ts#L37) * * * ### SystemIndexes [​](https://docs.convex.dev/api/modules/server\\#systemindexes \"Direct link to SystemIndexes\") Ƭ **SystemIndexes**: `Object` The indexes that Convex automatically adds to every table. This is an object mapping index names to index field paths. #### Type declaration [​](https://docs.convex.dev/api/modules/server\\#type-declaration-17 \"Direct link to Type declaration\") | Name | Type | | :-- | :-- | | `by_id` | \\[ `\"_id\"`\\] | | `by_creation_time` | \\[ `\"_creationTime\"`\\] | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-77 \"Direct link to Defined in\") [server/system\\_fields.ts:48](https://github.com/get-convex/convex-js/blob/main/src/server/system_fields.ts#L48) * * * ### IndexTiebreakerField [​](https://docs.convex.dev/api/modules/server\\#indextiebreakerfield \"Direct link to IndexTiebreakerField\") Ƭ **IndexTiebreakerField**: `\"_creationTime\"` Convex automatically appends \"\\_creationTime\" to the end of every index to break ties if all of the other fields are identical. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-78 \"Direct link to Defined in\") [server/system\\_fields.ts:61](https://github.com/get-convex/convex-js/blob/main/src/server/system_fields.ts#L61) * * * ### VectorSearch [​](https://docs.convex.dev/api/modules/server\\#vectorsearch \"Direct link to VectorSearch\") Ƭ **VectorSearch** < `DataModel`, `TableName`, `IndexName` >: ( `tableName`: `TableName`, `indexName`: `IndexName`, `query`: [`VectorSearchQuery`](https://docs.convex.dev/api/interfaces/server.VectorSearchQuery) < [`NamedTableInfo`](https://docs.convex.dev/api/modules/server#namedtableinfo) < `DataModel`, `TableName` >, `IndexName` >) =\\> `Promise` <{ `_id`: [`GenericId`](https://docs.convex.dev/api/modules/values#genericid) < `TableName` \\> ; `_score`: `number` }\\[\\]> #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-51 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `DataModel` | extends [`GenericDataModel`](https://docs.convex.dev/api/modules/server#genericdatamodel) | | `TableName` | extends [`TableNamesInDataModel`](https://docs.convex.dev/api/modules/server#tablenamesindatamodel) < `DataModel` > | | `IndexName` | extends [`VectorIndexNames`](https://docs.convex.dev/api/modules/server#vectorindexnames) < [`NamedTableInfo`](https://docs.convex.dev/api/modules/server#namedtableinfo) < `DataModel`, `TableName` >> | #### Type declaration [​](https://docs.convex.dev/api/modules/server\\#type-declaration-18 \"Direct link to Type declaration\") ▸ ( `tableName`, `indexName`, `query`): `Promise` <{ `_id`: [`GenericId`](https://docs.convex.dev/api/modules/values#genericid) < `TableName` \\> ; `_score`: `number` }\\[\\]> ##### Parameters [​](https://docs.convex.dev/api/modules/server\\#parameters-7 \"Direct link to Parameters\") | Name | Type | | :-- | :-- | | `tableName` | `TableName` | | `indexName` | `IndexName` | | `query` | [`VectorSearchQuery`](https://docs.convex.dev/api/interfaces/server.VectorSearchQuery) < [`NamedTableInfo`](https://docs.convex.dev/api/modules/server#namedtableinfo) < `DataModel`, `TableName` >, `IndexName` > | ##### Returns [​](https://docs.convex.dev/api/modules/server\\#returns-7 \"Direct link to Returns\") `Promise` <{ `_id`: [`GenericId`](https://docs.convex.dev/api/modules/values#genericid) < `TableName` \\> ; `_score`: `number` }\\[\\]> #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-79 \"Direct link to Defined in\") [server/vector\\_search.ts:55](https://github.com/get-convex/convex-js/blob/main/src/server/vector_search.ts#L55) * * * ### Expand [​](https://docs.convex.dev/api/modules/server\\#expand \"Direct link to Expand\") Ƭ **Expand** < `ObjectType` >: `ObjectType` extends `Record` < `any`, `any` \\> ? { \\[Key in keyof ObjectType\\]: ObjectType\\[Key\\] } : `never` Hack! This type causes TypeScript to simplify how it renders object types. It is functionally the identity for object types, but in practice it can simplify expressions like `A & B`. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-52 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `ObjectType` | extends `Record` < `any`, `any` > | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-80 \"Direct link to Defined in\") [type\\_utils.ts:12](https://github.com/get-convex/convex-js/blob/main/src/type_utils.ts#L12) * * * ### BetterOmit [​](https://docs.convex.dev/api/modules/server\\#betteromit \"Direct link to BetterOmit\") Ƭ **BetterOmit** < `T`, `K` >: { \\[Property in keyof T as Property extends K ? never : Property\\]: T\\[Property\\] } An `Omit<>` type that: 1. Applies to each element of a union. 2. Preserves the index signature of the underlying type. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-53 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `T` | `T` | | `K` | extends keyof `T` | #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-81 \"Direct link to Defined in\") [type\\_utils.ts:24](https://github.com/get-convex/convex-js/blob/main/src/type_utils.ts#L24) ## Variables [​](https://docs.convex.dev/api/modules/server\\#variables \"Direct link to Variables\") ### anyApi [​](https://docs.convex.dev/api/modules/server\\#anyapi-1 \"Direct link to anyApi\") • `Const` **anyApi**: [`AnyApi`](https://docs.convex.dev/api/modules/server#anyapi) A utility for constructing [FunctionReference](https://docs.convex.dev/api/modules/server#functionreference) s in projects that are not using code generation. You can create a reference to a function like: ```codeBlockLines_zEuJ const reference = anyApi.myModule.myFunction; ``` This supports accessing any path regardless of what directories and modules are in your project. All function references are typed as AnyFunctionReference. If you're using code generation, use `api` from `convex/_generated/api` instead. It will be more type-safe and produce better auto-complete in your editor. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-82 \"Direct link to Defined in\") [server/api.ts:427](https://github.com/get-convex/convex-js/blob/main/src/server/api.ts#L427) * * * ### paginationOptsValidator [​](https://docs.convex.dev/api/modules/server\\#paginationoptsvalidator \"Direct link to paginationOptsValidator\") • `Const` **paginationOptsValidator**: [`VObject`](https://docs.convex.dev/api/classes/values.VObject) <{ `id`: `undefined` \\| `number` ; `endCursor`: `undefined` \\| `null` \\| `string` ; `maximumRowsRead`: `undefined` \\| `number` ; `maximumBytesRead`: `undefined` \\| `number` ; `numItems`: `number` ; `cursor`: `null` \\| `string` }, { `numItems`: [`VFloat64`](https://docs.convex.dev/api/classes/values.VFloat64) < `number`, `\"required\"` \\> ; `cursor`: [`VUnion`](https://docs.convex.dev/api/classes/values.VUnion) < `null` \\| `string`, \\[ [`VString`](https://docs.convex.dev/api/classes/values.VString) < `string`, `\"required\"` >, [`VNull`](https://docs.convex.dev/api/classes/values.VNull) < `null`, `\"required\"` >\\], `\"required\"`, `never` \\> ; `endCursor`: [`VUnion`](https://docs.convex.dev/api/classes/values.VUnion) < `undefined` \\| `null` \\| `string`, \\[ [`VString`](https://docs.convex.dev/api/classes/values.VString) < `string`, `\"required\"` >, [`VNull`](https://docs.convex.dev/api/classes/values.VNull) < `null`, `\"required\"` >\\], `\"optional\"`, `never` \\> ; `id`: [`VFloat64`](https://docs.convex.dev/api/classes/values.VFloat64) < `undefined` \\| `number`, `\"optional\"` \\> ; `maximumRowsRead`: [`VFloat64`](https://docs.convex.dev/api/classes/values.VFloat64) < `undefined` \\| `number`, `\"optional\"` \\> ; `maximumBytesRead`: [`VFloat64`](https://docs.convex.dev/api/classes/values.VFloat64) < `undefined` \\| `number`, `\"optional\"` \\> }, `\"required\"`, `\"id\"` \\| `\"numItems\"` \\| `\"cursor\"` \\| `\"endCursor\"` \\| `\"maximumRowsRead\"` \\| `\"maximumBytesRead\"` > A [Validator](https://docs.convex.dev/api/modules/values#validator) for [PaginationOptions](https://docs.convex.dev/api/interfaces/server.PaginationOptions). This includes the standard [PaginationOptions](https://docs.convex.dev/api/interfaces/server.PaginationOptions) properties along with an optional cache-busting `id` property used by [usePaginatedQuery](https://docs.convex.dev/api/modules/react#usepaginatedquery). #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-83 \"Direct link to Defined in\") [server/pagination.ts:131](https://github.com/get-convex/convex-js/blob/main/src/server/pagination.ts#L131) * * * ### ROUTABLE\\_HTTP\\_METHODS [​](https://docs.convex.dev/api/modules/server\\#routable_http_methods \"Direct link to ROUTABLE_HTTP_METHODS\") • `Const` **ROUTABLE\\_HTTP\\_METHODS**: readonly \\[ `\"GET\"`, `\"POST\"`, `\"PUT\"`, `\"DELETE\"`, `\"OPTIONS\"`, `\"PATCH\"`\\] A list of the methods supported by Convex HTTP actions. HEAD is handled by Convex by running GET and stripping the body. CONNECT is not supported and will not be supported. TRACE is not supported and will not be supported. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-84 \"Direct link to Defined in\") [server/router.ts:14](https://github.com/get-convex/convex-js/blob/main/src/server/router.ts#L14) ## Functions [​](https://docs.convex.dev/api/modules/server\\#functions \"Direct link to Functions\") ### getFunctionName [​](https://docs.convex.dev/api/modules/server\\#getfunctionname \"Direct link to getFunctionName\") ▸ **getFunctionName**( `functionReference`): `string` Get the name of a function from a [FunctionReference](https://docs.convex.dev/api/modules/server#functionreference). The name is a string like \"myDir/myModule:myFunction\". If the exported name of the function is `\"default\"`, the function name is omitted (e.g. \"myDir/myModule\"). #### Parameters [​](https://docs.convex.dev/api/modules/server\\#parameters-8 \"Direct link to Parameters\") | Name | Type | Description | | :-- | :-- | :-- | | `functionReference` | `AnyFunctionReference` | A [FunctionReference](https://docs.convex.dev/api/modules/server#functionreference) to get the name of. | #### Returns [​](https://docs.convex.dev/api/modules/server\\#returns-8 \"Direct link to Returns\") `string` A string of the function's name. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-85 \"Direct link to Defined in\") [server/api.ts:78](https://github.com/get-convex/convex-js/blob/main/src/server/api.ts#L78) * * * ### makeFunctionReference [​](https://docs.convex.dev/api/modules/server\\#makefunctionreference \"Direct link to makeFunctionReference\") ▸ **makeFunctionReference** < `type`, `args`, `ret` >( `name`): [`FunctionReference`](https://docs.convex.dev/api/modules/server#functionreference) < `type`, `\"public\"`, `args`, `ret` > FunctionReferences generally come from generated code, but in custom clients it may be useful to be able to build one manually. Real function references are empty objects at runtime, but the same interface can be implemented with an object for tests and clients which don't use code generation. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-54 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `type` | extends [`FunctionType`](https://docs.convex.dev/api/modules/server#functiontype) | | `args` | extends [`DefaultFunctionArgs`](https://docs.convex.dev/api/modules/server#defaultfunctionargs) = `any` | | `ret` | `any` | #### Parameters [​](https://docs.convex.dev/api/modules/server\\#parameters-9 \"Direct link to Parameters\") | Name | Type | Description | | :-- | :-- | :-- | | `name` | `string` | The identifier of the function. E.g. `path/to/file:functionName` | #### Returns [​](https://docs.convex.dev/api/modules/server\\#returns-9 \"Direct link to Returns\") [`FunctionReference`](https://docs.convex.dev/api/modules/server#functionreference) < `type`, `\"public\"`, `args`, `ret` > #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-86 \"Direct link to Defined in\") [server/api.ts:122](https://github.com/get-convex/convex-js/blob/main/src/server/api.ts#L122) * * * ### filterApi [​](https://docs.convex.dev/api/modules/server\\#filterapi-1 \"Direct link to filterApi\") ▸ **filterApi** < `API`, `Predicate` >( `api`): [`FilterApi`](https://docs.convex.dev/api/modules/server#filterapi) < `API`, `Predicate` > Given an api of type API and a FunctionReference subtype, return an api object containing only the function references that match. ```codeBlockLines_zEuJ const q = filterApi>(api) ``` #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-55 \"Direct link to Type parameters\") | Name | | :-- | | `API` | | `Predicate` | #### Parameters [​](https://docs.convex.dev/api/modules/server\\#parameters-10 \"Direct link to Parameters\") | Name | Type | | :-- | :-- | | `api` | `API` | #### Returns [​](https://docs.convex.dev/api/modules/server\\#returns-10 \"Direct link to Returns\") [`FilterApi`](https://docs.convex.dev/api/modules/server#filterapi) < `API`, `Predicate` > #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-87 \"Direct link to Defined in\") [server/api.ts:301](https://github.com/get-convex/convex-js/blob/main/src/server/api.ts#L301) * * * ### createFunctionHandle [​](https://docs.convex.dev/api/modules/server\\#createfunctionhandle \"Direct link to createFunctionHandle\") ▸ **createFunctionHandle** < `Type`, `Args`, `ReturnType` >( `functionReference`): `Promise` < [`FunctionHandle`](https://docs.convex.dev/api/modules/server#functionhandle) < `Type`, `Args`, `ReturnType` >> Create a serializable reference to a Convex function. Passing a this reference to another component allows that component to call this function during the current function execution or at any later time. Function handles are used like `api.folder.function` FunctionReferences, e.g. `ctx.scheduler.runAfter(0, functionReference, args)`. A function reference is stable across code pushes but it's possible the Convex function it refers to might no longer exist. This is a feature of components, which are in beta. This API is unstable and may change in subsequent releases. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-56 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Type` | extends [`FunctionType`](https://docs.convex.dev/api/modules/server#functiontype) | | `Args` | extends [`DefaultFunctionArgs`](https://docs.convex.dev/api/modules/server#defaultfunctionargs) | | `ReturnType` | `ReturnType` | #### Parameters [​](https://docs.convex.dev/api/modules/server\\#parameters-11 \"Direct link to Parameters\") | Name | Type | | :-- | :-- | | `functionReference` | [`FunctionReference`](https://docs.convex.dev/api/modules/server#functionreference) < `Type`, `\"public\"` \\| `\"internal\"`, `Args`, `ReturnType` > | #### Returns [​](https://docs.convex.dev/api/modules/server\\#returns-11 \"Direct link to Returns\") `Promise` < [`FunctionHandle`](https://docs.convex.dev/api/modules/server#functionhandle) < `Type`, `Args`, `ReturnType` >> #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-88 \"Direct link to Defined in\") [server/components/index.ts:54](https://github.com/get-convex/convex-js/blob/main/src/server/components/index.ts#L54) * * * ### defineComponent [​](https://docs.convex.dev/api/modules/server\\#definecomponent \"Direct link to defineComponent\") ▸ **defineComponent** < `Exports` >( `name`): [`ComponentDefinition`](https://docs.convex.dev/api/modules/server#componentdefinition) < `Exports` > Define a component, a piece of a Convex deployment with namespaced resources. The default the default export of a module like \"cool-component/convex.config.js\" is a \\`@link ComponentDefinition}, but during component definition evaluation this is its type instead. @param name Name must be alphanumeric plus underscores. Typically these are lowercase with underscores like `\"onboarding_flow_tracker\"`. This is a feature of components, which are in beta. This API is unstable and may change in subsequent releases. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-57 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Exports` | extends `ComponentExports` = `any` | #### Parameters [​](https://docs.convex.dev/api/modules/server\\#parameters-12 \"Direct link to Parameters\") | Name | Type | | :-- | :-- | | `name` | `string` | #### Returns [​](https://docs.convex.dev/api/modules/server\\#returns-12 \"Direct link to Returns\") [`ComponentDefinition`](https://docs.convex.dev/api/modules/server#componentdefinition) < `Exports` > #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-89 \"Direct link to Defined in\") [server/components/index.ts:359](https://github.com/get-convex/convex-js/blob/main/src/server/components/index.ts#L359) * * * ### defineApp [​](https://docs.convex.dev/api/modules/server\\#defineapp \"Direct link to defineApp\") ▸ **defineApp**(): `AppDefinition` Attach components, reuseable pieces of a Convex deployment, to this Convex app. This is a feature of components, which are in beta. This API is unstable and may change in subsequent releases. #### Returns [​](https://docs.convex.dev/api/modules/server\\#returns-13 \"Direct link to Returns\") `AppDefinition` #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-90 \"Direct link to Defined in\") [server/components/index.ts:385](https://github.com/get-convex/convex-js/blob/main/src/server/components/index.ts#L385) * * * ### componentsGeneric [​](https://docs.convex.dev/api/modules/server\\#componentsgeneric \"Direct link to componentsGeneric\") ▸ **componentsGeneric**(): `AnyChildComponents` #### Returns [​](https://docs.convex.dev/api/modules/server\\#returns-14 \"Direct link to Returns\") `AnyChildComponents` #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-91 \"Direct link to Defined in\") [server/components/index.ts:440](https://github.com/get-convex/convex-js/blob/main/src/server/components/index.ts#L440) * * * ### getFunctionAddress [​](https://docs.convex.dev/api/modules/server\\#getfunctionaddress \"Direct link to getFunctionAddress\") ▸ **getFunctionAddress**( `functionReference`): { `functionHandle`: `string` = functionReference; `name?`: `undefined` ; `reference?`: `undefined` = referencePath } \\| { `functionHandle?`: `undefined` = functionReference; `name`: `any` ; `reference?`: `undefined` = referencePath } \\| { `functionHandle?`: `undefined` = functionReference; `name?`: `undefined` ; `reference`: `string` = referencePath } #### Parameters [​](https://docs.convex.dev/api/modules/server\\#parameters-13 \"Direct link to Parameters\") | Name | Type | | :-- | :-- | | `functionReference` | `any` | #### Returns [​](https://docs.convex.dev/api/modules/server\\#returns-15 \"Direct link to Returns\") { `functionHandle`: `string` = functionReference; `name?`: `undefined` ; `reference?`: `undefined` = referencePath } \\| { `functionHandle?`: `undefined` = functionReference; `name`: `any` ; `reference?`: `undefined` = referencePath } \\| { `functionHandle?`: `undefined` = functionReference; `name?`: `undefined` ; `reference`: `string` = referencePath } #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-92 \"Direct link to Defined in\") [server/components/paths.ts:20](https://github.com/get-convex/convex-js/blob/main/src/server/components/paths.ts#L20) * * * ### cronJobs [​](https://docs.convex.dev/api/modules/server\\#cronjobs \"Direct link to cronJobs\") ▸ **cronJobs**(): [`Crons`](https://docs.convex.dev/api/classes/server.Crons) Create a CronJobs object to schedule recurring tasks. ```codeBlockLines_zEuJ // convex/crons.js import { cronJobs } from 'convex/server'; import { api } from \"./_generated/api\"; const crons = cronJobs(); crons.weekly( \"weekly re-engagement email\", { hourUTC: 17, // (9:30am Pacific/10:30am Daylight Savings Pacific) minuteUTC: 30, }, api.emails.send ) export default crons; ``` #### Returns [​](https://docs.convex.dev/api/modules/server\\#returns-16 \"Direct link to Returns\") [`Crons`](https://docs.convex.dev/api/classes/server.Crons) #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-93 \"Direct link to Defined in\") [server/cron.ts:180](https://github.com/get-convex/convex-js/blob/main/src/server/cron.ts#L180) * * * ### mutationGeneric [​](https://docs.convex.dev/api/modules/server\\#mutationgeneric \"Direct link to mutationGeneric\") ▸ **mutationGeneric** < `ArgsValidator`, `ReturnsValidator`, `ReturnValue`, `OneOrZeroArgs` >( `mutation`): [`RegisteredMutation`](https://docs.convex.dev/api/modules/server#registeredmutation) < `\"public\"`, [`ArgsArrayToObject`](https://docs.convex.dev/api/modules/server#argsarraytoobject) < `OneOrZeroArgs` >, `ReturnValue` > Define a mutation in this Convex app's public API. This function will be allowed to modify your Convex database and will be accessible from the client. If you're using code generation, use the `mutation` function in `convex/_generated/server.d.ts` which is typed for your data model. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-58 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `ArgsValidator` | extends `void` \\| [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `\"required\"`, `any` \\> \\| [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) | | `ReturnsValidator` | extends `void` \\| [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `\"required\"`, `any` \\> \\| [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) | | `ReturnValue` | extends `any` = `any` | | `OneOrZeroArgs` | extends [`ArgsArray`](https://docs.convex.dev/api/modules/server#argsarray) \\| `OneArgArray` < [`Infer`](https://docs.convex.dev/api/modules/values#infer) < `ArgsValidator` >\\> \\| `OneArgArray` < [`Expand`](https://docs.convex.dev/api/modules/server#expand) <{ \\[Property in string \\| number \\| symbol\\]?: Exclude, undefined> } & { \\[Property in string \\| number \\| symbol\\]: Infer }>> = [`DefaultArgsForOptionalValidator`](https://docs.convex.dev/api/modules/server#defaultargsforoptionalvalidator) < `ArgsValidator` > | #### Parameters [​](https://docs.convex.dev/api/modules/server\\#parameters-14 \"Direct link to Parameters\") | Name | Type | | :-- | :-- | | `mutation` | { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: ( `ctx`: [`GenericMutationCtx`](https://docs.convex.dev/api/interfaces/server.GenericMutationCtx) < `any` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue` } \\| ( `ctx`: [`GenericMutationCtx`](https://docs.convex.dev/api/interfaces/server.GenericMutationCtx) < `any` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue` | #### Returns [​](https://docs.convex.dev/api/modules/server\\#returns-17 \"Direct link to Returns\") [`RegisteredMutation`](https://docs.convex.dev/api/modules/server#registeredmutation) < `\"public\"`, [`ArgsArrayToObject`](https://docs.convex.dev/api/modules/server#argsarraytoobject) < `OneOrZeroArgs` >, `ReturnValue` > The wrapped mutation. Include this as an `export` to name it and make it accessible. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-94 \"Direct link to Defined in\") [server/registration.ts:615](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L615) * * * ### internalMutationGeneric [​](https://docs.convex.dev/api/modules/server\\#internalmutationgeneric \"Direct link to internalMutationGeneric\") ▸ **internalMutationGeneric** < `ArgsValidator`, `ReturnsValidator`, `ReturnValue`, `OneOrZeroArgs` >( `mutation`): [`RegisteredMutation`](https://docs.convex.dev/api/modules/server#registeredmutation) < `\"internal\"`, [`ArgsArrayToObject`](https://docs.convex.dev/api/modules/server#argsarraytoobject) < `OneOrZeroArgs` >, `ReturnValue` > Define a mutation that is only accessible from other Convex functions (but not from the client). This function will be allowed to modify your Convex database. It will not be accessible from the client. If you're using code generation, use the `internalMutation` function in `convex/_generated/server.d.ts` which is typed for your data model. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-59 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `ArgsValidator` | extends `void` \\| [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `\"required\"`, `any` \\> \\| [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) | | `ReturnsValidator` | extends `void` \\| [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `\"required\"`, `any` \\> \\| [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) | | `ReturnValue` | extends `any` = `any` | | `OneOrZeroArgs` | extends [`ArgsArray`](https://docs.convex.dev/api/modules/server#argsarray) \\| `OneArgArray` < [`Infer`](https://docs.convex.dev/api/modules/values#infer) < `ArgsValidator` >\\> \\| `OneArgArray` < [`Expand`](https://docs.convex.dev/api/modules/server#expand) <{ \\[Property in string \\| number \\| symbol\\]?: Exclude, undefined> } & { \\[Property in string \\| number \\| symbol\\]: Infer }>> = [`DefaultArgsForOptionalValidator`](https://docs.convex.dev/api/modules/server#defaultargsforoptionalvalidator) < `ArgsValidator` > | #### Parameters [​](https://docs.convex.dev/api/modules/server\\#parameters-15 \"Direct link to Parameters\") | Name | Type | | :-- | :-- | | `mutation` | { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: ( `ctx`: [`GenericMutationCtx`](https://docs.convex.dev/api/interfaces/server.GenericMutationCtx) < `any` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue` } \\| ( `ctx`: [`GenericMutationCtx`](https://docs.convex.dev/api/interfaces/server.GenericMutationCtx) < `any` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue` | #### Returns [​](https://docs.convex.dev/api/modules/server\\#returns-18 \"Direct link to Returns\") [`RegisteredMutation`](https://docs.convex.dev/api/modules/server#registeredmutation) < `\"internal\"`, [`ArgsArrayToObject`](https://docs.convex.dev/api/modules/server#argsarraytoobject) < `OneOrZeroArgs` >, `ReturnValue` > The wrapped mutation. Include this as an `export` to name it and make it accessible. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-95 \"Direct link to Defined in\") [server/registration.ts:615](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L615) * * * ### queryGeneric [​](https://docs.convex.dev/api/modules/server\\#querygeneric \"Direct link to queryGeneric\") ▸ **queryGeneric** < `ArgsValidator`, `ReturnsValidator`, `ReturnValue`, `OneOrZeroArgs` >( `query`): [`RegisteredQuery`](https://docs.convex.dev/api/modules/server#registeredquery) < `\"public\"`, [`ArgsArrayToObject`](https://docs.convex.dev/api/modules/server#argsarraytoobject) < `OneOrZeroArgs` >, `ReturnValue` > Define a query in this Convex app's public API. This function will be allowed to read your Convex database and will be accessible from the client. If you're using code generation, use the `query` function in `convex/_generated/server.d.ts` which is typed for your data model. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-60 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `ArgsValidator` | extends `void` \\| [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `\"required\"`, `any` \\> \\| [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) | | `ReturnsValidator` | extends `void` \\| [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `\"required\"`, `any` \\> \\| [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) | | `ReturnValue` | extends `any` = `any` | | `OneOrZeroArgs` | extends [`ArgsArray`](https://docs.convex.dev/api/modules/server#argsarray) \\| `OneArgArray` < [`Infer`](https://docs.convex.dev/api/modules/values#infer) < `ArgsValidator` >\\> \\| `OneArgArray` < [`Expand`](https://docs.convex.dev/api/modules/server#expand) <{ \\[Property in string \\| number \\| symbol\\]?: Exclude, undefined> } & { \\[Property in string \\| number \\| symbol\\]: Infer }>> = [`DefaultArgsForOptionalValidator`](https://docs.convex.dev/api/modules/server#defaultargsforoptionalvalidator) < `ArgsValidator` > | #### Parameters [​](https://docs.convex.dev/api/modules/server\\#parameters-16 \"Direct link to Parameters\") | Name | Type | | :-- | :-- | | `query` | { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: ( `ctx`: [`GenericQueryCtx`](https://docs.convex.dev/api/interfaces/server.GenericQueryCtx) < `any` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue` } \\| ( `ctx`: [`GenericQueryCtx`](https://docs.convex.dev/api/interfaces/server.GenericQueryCtx) < `any` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue` | #### Returns [​](https://docs.convex.dev/api/modules/server\\#returns-19 \"Direct link to Returns\") [`RegisteredQuery`](https://docs.convex.dev/api/modules/server#registeredquery) < `\"public\"`, [`ArgsArrayToObject`](https://docs.convex.dev/api/modules/server#argsarraytoobject) < `OneOrZeroArgs` >, `ReturnValue` > The wrapped query. Include this as an `export` to name it and make it accessible. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-96 \"Direct link to Defined in\") [server/registration.ts:801](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L801) * * * ### internalQueryGeneric [​](https://docs.convex.dev/api/modules/server\\#internalquerygeneric \"Direct link to internalQueryGeneric\") ▸ **internalQueryGeneric** < `ArgsValidator`, `ReturnsValidator`, `ReturnValue`, `OneOrZeroArgs` >( `query`): [`RegisteredQuery`](https://docs.convex.dev/api/modules/server#registeredquery) < `\"internal\"`, [`ArgsArrayToObject`](https://docs.convex.dev/api/modules/server#argsarraytoobject) < `OneOrZeroArgs` >, `ReturnValue` > Define a query that is only accessible from other Convex functions (but not from the client). This function will be allowed to read from your Convex database. It will not be accessible from the client. If you're using code generation, use the `internalQuery` function in `convex/_generated/server.d.ts` which is typed for your data model. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-61 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `ArgsValidator` | extends `void` \\| [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `\"required\"`, `any` \\> \\| [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) | | `ReturnsValidator` | extends `void` \\| [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `\"required\"`, `any` \\> \\| [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) | | `ReturnValue` | extends `any` = `any` | | `OneOrZeroArgs` | extends [`ArgsArray`](https://docs.convex.dev/api/modules/server#argsarray) \\| `OneArgArray` < [`Infer`](https://docs.convex.dev/api/modules/values#infer) < `ArgsValidator` >\\> \\| `OneArgArray` < [`Expand`](https://docs.convex.dev/api/modules/server#expand) <{ \\[Property in string \\| number \\| symbol\\]?: Exclude, undefined> } & { \\[Property in string \\| number \\| symbol\\]: Infer }>> = [`DefaultArgsForOptionalValidator`](https://docs.convex.dev/api/modules/server#defaultargsforoptionalvalidator) < `ArgsValidator` > | #### Parameters [​](https://docs.convex.dev/api/modules/server\\#parameters-17 \"Direct link to Parameters\") | Name | Type | | :-- | :-- | | `query` | { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: ( `ctx`: [`GenericQueryCtx`](https://docs.convex.dev/api/interfaces/server.GenericQueryCtx) < `any` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue` } \\| ( `ctx`: [`GenericQueryCtx`](https://docs.convex.dev/api/interfaces/server.GenericQueryCtx) < `any` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue` | #### Returns [​](https://docs.convex.dev/api/modules/server\\#returns-20 \"Direct link to Returns\") [`RegisteredQuery`](https://docs.convex.dev/api/modules/server#registeredquery) < `\"internal\"`, [`ArgsArrayToObject`](https://docs.convex.dev/api/modules/server#argsarraytoobject) < `OneOrZeroArgs` >, `ReturnValue` > The wrapped query. Include this as an `export` to name it and make it accessible. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-97 \"Direct link to Defined in\") [server/registration.ts:801](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L801) * * * ### actionGeneric [​](https://docs.convex.dev/api/modules/server\\#actiongeneric \"Direct link to actionGeneric\") ▸ **actionGeneric** < `ArgsValidator`, `ReturnsValidator`, `ReturnValue`, `OneOrZeroArgs` >( `func`): [`RegisteredAction`](https://docs.convex.dev/api/modules/server#registeredaction) < `\"public\"`, [`ArgsArrayToObject`](https://docs.convex.dev/api/modules/server#argsarraytoobject) < `OneOrZeroArgs` >, `ReturnValue` > Define an action in this Convex app's public API. If you're using code generation, use the `action` function in `convex/_generated/server.d.ts` which is typed for your data model. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-62 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `ArgsValidator` | extends `void` \\| [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `\"required\"`, `any` \\> \\| [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) | | `ReturnsValidator` | extends `void` \\| [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `\"required\"`, `any` \\> \\| [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) | | `ReturnValue` | extends `any` = `any` | | `OneOrZeroArgs` | extends [`ArgsArray`](https://docs.convex.dev/api/modules/server#argsarray) \\| `OneArgArray` < [`Infer`](https://docs.convex.dev/api/modules/values#infer) < `ArgsValidator` >\\> \\| `OneArgArray` < [`Expand`](https://docs.convex.dev/api/modules/server#expand) <{ \\[Property in string \\| number \\| symbol\\]?: Exclude, undefined> } & { \\[Property in string \\| number \\| symbol\\]: Infer }>> = [`DefaultArgsForOptionalValidator`](https://docs.convex.dev/api/modules/server#defaultargsforoptionalvalidator) < `ArgsValidator` > | #### Parameters [​](https://docs.convex.dev/api/modules/server\\#parameters-18 \"Direct link to Parameters\") | Name | Type | Description | | :-- | :-- | :-- | | `func` | { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: ( `ctx`: [`GenericActionCtx`](https://docs.convex.dev/api/interfaces/server.GenericActionCtx) < `any` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue` } \\| ( `ctx`: [`GenericActionCtx`](https://docs.convex.dev/api/interfaces/server.GenericActionCtx) < `any` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue` | The function. It receives a [GenericActionCtx](https://docs.convex.dev/api/interfaces/server.GenericActionCtx) as its first argument. | #### Returns [​](https://docs.convex.dev/api/modules/server\\#returns-21 \"Direct link to Returns\") [`RegisteredAction`](https://docs.convex.dev/api/modules/server#registeredaction) < `\"public\"`, [`ArgsArrayToObject`](https://docs.convex.dev/api/modules/server#argsarraytoobject) < `OneOrZeroArgs` >, `ReturnValue` > The wrapped function. Include this as an `export` to name it and make it accessible. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-98 \"Direct link to Defined in\") [server/registration.ts:979](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L979) * * * ### internalActionGeneric [​](https://docs.convex.dev/api/modules/server\\#internalactiongeneric \"Direct link to internalActionGeneric\") ▸ **internalActionGeneric** < `ArgsValidator`, `ReturnsValidator`, `ReturnValue`, `OneOrZeroArgs` >( `func`): [`RegisteredAction`](https://docs.convex.dev/api/modules/server#registeredaction) < `\"internal\"`, [`ArgsArrayToObject`](https://docs.convex.dev/api/modules/server#argsarraytoobject) < `OneOrZeroArgs` >, `ReturnValue` > Define an action that is only accessible from other Convex functions (but not from the client). If you're using code generation, use the `internalAction` function in `convex/_generated/server.d.ts` which is typed for your data model. #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-63 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `ArgsValidator` | extends `void` \\| [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `\"required\"`, `any` \\> \\| [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) | | `ReturnsValidator` | extends `void` \\| [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `\"required\"`, `any` \\> \\| [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) | | `ReturnValue` | extends `any` = `any` | | `OneOrZeroArgs` | extends [`ArgsArray`](https://docs.convex.dev/api/modules/server#argsarray) \\| `OneArgArray` < [`Infer`](https://docs.convex.dev/api/modules/values#infer) < `ArgsValidator` >\\> \\| `OneArgArray` < [`Expand`](https://docs.convex.dev/api/modules/server#expand) <{ \\[Property in string \\| number \\| symbol\\]?: Exclude, undefined> } & { \\[Property in string \\| number \\| symbol\\]: Infer }>> = [`DefaultArgsForOptionalValidator`](https://docs.convex.dev/api/modules/server#defaultargsforoptionalvalidator) < `ArgsValidator` > | #### Parameters [​](https://docs.convex.dev/api/modules/server\\#parameters-19 \"Direct link to Parameters\") | Name | Type | Description | | :-- | :-- | :-- | | `func` | { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: ( `ctx`: [`GenericActionCtx`](https://docs.convex.dev/api/interfaces/server.GenericActionCtx) < `any` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue` } \\| ( `ctx`: [`GenericActionCtx`](https://docs.convex.dev/api/interfaces/server.GenericActionCtx) < `any` >, ... `args`: `OneOrZeroArgs`) =\\> `ReturnValue` | The function. It receives a [GenericActionCtx](https://docs.convex.dev/api/interfaces/server.GenericActionCtx) as its first argument. | #### Returns [​](https://docs.convex.dev/api/modules/server\\#returns-22 \"Direct link to Returns\") [`RegisteredAction`](https://docs.convex.dev/api/modules/server#registeredaction) < `\"internal\"`, [`ArgsArrayToObject`](https://docs.convex.dev/api/modules/server#argsarraytoobject) < `OneOrZeroArgs` >, `ReturnValue` > The wrapped function. Include this as an `export` to name it and make it accessible. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-99 \"Direct link to Defined in\") [server/registration.ts:979](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L979) * * * ### httpActionGeneric [​](https://docs.convex.dev/api/modules/server\\#httpactiongeneric \"Direct link to httpActionGeneric\") ▸ **httpActionGeneric**( `func`): [`PublicHttpAction`](https://docs.convex.dev/api/modules/server#publichttpaction) Define a Convex HTTP action. #### Parameters [​](https://docs.convex.dev/api/modules/server\\#parameters-20 \"Direct link to Parameters\") | Name | Type | Description | | :-- | :-- | :-- | | `func` | ( `ctx`: [`GenericActionCtx`](https://docs.convex.dev/api/interfaces/server.GenericActionCtx) < [`GenericDataModel`](https://docs.convex.dev/api/modules/server#genericdatamodel) >, `request`: `Request`) =\\> `Promise` < `Response` > | The function. It receives an [GenericActionCtx](https://docs.convex.dev/api/interfaces/server.GenericActionCtx) as its first argument, and a `Request` object as its second. | #### Returns [​](https://docs.convex.dev/api/modules/server\\#returns-23 \"Direct link to Returns\") [`PublicHttpAction`](https://docs.convex.dev/api/modules/server#publichttpaction) The wrapped function. Route a URL path to this function in `convex/http.js`. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-100 \"Direct link to Defined in\") [server/impl/registration\\_impl.ts:454](https://github.com/get-convex/convex-js/blob/main/src/server/impl/registration_impl.ts#L454) * * * ### httpRouter [​](https://docs.convex.dev/api/modules/server\\#httprouter \"Direct link to httpRouter\") ▸ **httpRouter**(): [`HttpRouter`](https://docs.convex.dev/api/classes/server.HttpRouter) Return a new [HttpRouter](https://docs.convex.dev/api/classes/server.HttpRouter) object. #### Returns [​](https://docs.convex.dev/api/modules/server\\#returns-24 \"Direct link to Returns\") [`HttpRouter`](https://docs.convex.dev/api/classes/server.HttpRouter) #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-101 \"Direct link to Defined in\") [server/router.ts:47](https://github.com/get-convex/convex-js/blob/main/src/server/router.ts#L47) * * * ### defineTable [​](https://docs.convex.dev/api/modules/server\\#definetable \"Direct link to defineTable\") ▸ **defineTable** < `DocumentSchema` >( `documentSchema`): [`TableDefinition`](https://docs.convex.dev/api/classes/server.TableDefinition) < `DocumentSchema` > Define a table in a schema. You can either specify the schema of your documents as an object like ```codeBlockLines_zEuJ defineTable({ field: v.string() }); ``` or as a schema type like ```codeBlockLines_zEuJ defineTable( v.union( v.object({...}), v.object({...}) ) ); ``` #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-64 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `DocumentSchema` | extends [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `Record` < `string`, `any` >, `\"required\"`, `any` > | #### Parameters [​](https://docs.convex.dev/api/modules/server\\#parameters-21 \"Direct link to Parameters\") | Name | Type | Description | | :-- | :-- | :-- | | `documentSchema` | `DocumentSchema` | The type of documents stored in this table. | #### Returns [​](https://docs.convex.dev/api/modules/server\\#returns-25 \"Direct link to Returns\") [`TableDefinition`](https://docs.convex.dev/api/classes/server.TableDefinition) < `DocumentSchema` > A [TableDefinition](https://docs.convex.dev/api/classes/server.TableDefinition) for the table. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-102 \"Direct link to Defined in\") [server/schema.ts:347](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L347) ▸ **defineTable** < `DocumentSchema` >( `documentSchema`): [`TableDefinition`](https://docs.convex.dev/api/classes/server.TableDefinition) < [`VObject`](https://docs.convex.dev/api/classes/values.VObject) < [`ObjectType`](https://docs.convex.dev/api/modules/values#objecttype) < `DocumentSchema` >, `DocumentSchema` >> Define a table in a schema. You can either specify the schema of your documents as an object like ```codeBlockLines_zEuJ defineTable({ field: v.string() }); ``` or as a schema type like ```codeBlockLines_zEuJ defineTable( v.union( v.object({...}), v.object({...}) ) ); ``` #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-65 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `DocumentSchema` | extends `Record` < `string`, [`GenericValidator`](https://docs.convex.dev/api/modules/values#genericvalidator) > | #### Parameters [​](https://docs.convex.dev/api/modules/server\\#parameters-22 \"Direct link to Parameters\") | Name | Type | Description | | :-- | :-- | :-- | | `documentSchema` | `DocumentSchema` | The type of documents stored in this table. | #### Returns [​](https://docs.convex.dev/api/modules/server\\#returns-26 \"Direct link to Returns\") [`TableDefinition`](https://docs.convex.dev/api/classes/server.TableDefinition) < [`VObject`](https://docs.convex.dev/api/classes/values.VObject) < [`ObjectType`](https://docs.convex.dev/api/modules/values#objecttype) < `DocumentSchema` >, `DocumentSchema` >> A [TableDefinition](https://docs.convex.dev/api/classes/server.TableDefinition) for the table. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-103 \"Direct link to Defined in\") [server/schema.ts:375](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L375) * * * ### defineSchema [​](https://docs.convex.dev/api/modules/server\\#defineschema \"Direct link to defineSchema\") ▸ **defineSchema** < `Schema`, `StrictTableNameTypes` >( `schema`, `options?`): [`SchemaDefinition`](https://docs.convex.dev/api/classes/server.SchemaDefinition) < `Schema`, `StrictTableNameTypes` > Define the schema of this Convex project. This should be exported from a `schema.ts` file in your `convex/` directory like: ```codeBlockLines_zEuJ export default defineSchema({ ... }); ``` #### Type parameters [​](https://docs.convex.dev/api/modules/server\\#type-parameters-66 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Schema` | extends [`GenericSchema`](https://docs.convex.dev/api/modules/server#genericschema) | | `StrictTableNameTypes` | extends `boolean` = `true` | #### Parameters [​](https://docs.convex.dev/api/modules/server\\#parameters-23 \"Direct link to Parameters\") | Name | Type | Description | | :-- | :-- | :-- | | `schema` | `Schema` | A map from table name to [TableDefinition](https://docs.convex.dev/api/classes/server.TableDefinition) for all of the tables in this project. | | `options?` | [`DefineSchemaOptions`](https://docs.convex.dev/api/interfaces/server.DefineSchemaOptions) < `StrictTableNameTypes` > | Optional configuration. See [DefineSchemaOptions](https://docs.convex.dev/api/interfaces/server.DefineSchemaOptions) for a full description. | #### Returns [​](https://docs.convex.dev/api/modules/server\\#returns-27 \"Direct link to Returns\") [`SchemaDefinition`](https://docs.convex.dev/api/classes/server.SchemaDefinition) < `Schema`, `StrictTableNameTypes` > The schema. #### Defined in [​](https://docs.convex.dev/api/modules/server\\#defined-in-104 \"Direct link to Defined in\") [server/schema.ts:513](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L513) - [Usage](https://docs.convex.dev/api/modules/server#usage) - [Code Generation](https://docs.convex.dev/api/modules/server#code-generation) - [Example](https://docs.convex.dev/api/modules/server#example) - [Classes](https://docs.convex.dev/api/modules/server#classes) - [Interfaces](https://docs.convex.dev/api/modules/server#interfaces) - [References](https://docs.convex.dev/api/modules/server#references) - [UserIdentityAttributes](https://docs.convex.dev/api/modules/server#useridentityattributes) - [Type Aliases](https://docs.convex.dev/api/modules/server#type-aliases) - [FunctionType](https://docs.convex.dev/api/modules/server#functiontype) - [FunctionReference](https://docs.convex.dev/api/modules/server#functionreference) - [ApiFromModules](https://docs.convex.dev/api/modules/server#apifrommodules) - [FilterApi](https://docs.convex.dev/api/modules/server#filterapi) - [AnyApi](https://docs.convex.dev/api/modules/server#anyapi) - [PartialApi](https://docs.convex.dev/api/modules/server#partialapi) - [FunctionArgs](https://docs.convex.dev/api/modules/server#functionargs) - [OptionalRestArgs](https://docs.convex.dev/api/modules/server#optionalrestargs) - [ArgsAndOptions](https://docs.convex.dev/api/modules/server#argsandoptions) - [FunctionReturnType](https://docs.convex.dev/api/modules/server#functionreturntype) - [FunctionHandle](https://docs.convex.dev/api/modules/server#functionhandle) - [ComponentDefinition](https://docs.convex.dev/api/modules/server#componentdefinition) - [AnyComponents](https://docs.convex.dev/api/modules/server#anycomponents) - [GenericDocument](https://docs.convex.dev/api/modules/server#genericdocument) - [GenericFieldPaths](https://docs.convex.dev/api/modules/server#genericfieldpaths) - [GenericIndexFields](https://docs.convex.dev/api/modules/server#genericindexfields) - [GenericTableIndexes](https://docs.convex.dev/api/modules/server#generictableindexes) - [GenericSearchIndexConfig](https://docs.convex.dev/api/modules/server#genericsearchindexconfig) - [GenericTableSearchIndexes](https://docs.convex.dev/api/modules/server#generictablesearchindexes) - [GenericVectorIndexConfig](https://docs.convex.dev/api/modules/server#genericvectorindexconfig) - [GenericTableVectorIndexes](https://docs.convex.dev/api/modules/server#generictablevectorindexes) - [FieldTypeFromFieldPath](https://docs.convex.dev/api/modules/server#fieldtypefromfieldpath) - [FieldTypeFromFieldPathInner](https://docs.convex.dev/api/modules/server#fieldtypefromfieldpathinner) - [GenericTableInfo](https://docs.convex.dev/api/modules/server#generictableinfo) - [DocumentByInfo](https://docs.convex.dev/api/modules/server#documentbyinfo) - [FieldPaths](https://docs.convex.dev/api/modules/server#fieldpaths) - [Indexes](https://docs.convex.dev/api/modules/server#indexes) - [IndexNames](https://docs.convex.dev/api/modules/server#indexnames) - [NamedIndex](https://docs.convex.dev/api/modules/server#namedindex) - [SearchIndexes](https://docs.convex.dev/api/modules/server#searchindexes) - [SearchIndexNames](https://docs.convex.dev/api/modules/server#searchindexnames) - [NamedSearchIndex](https://docs.convex.dev/api/modules/server#namedsearchindex) - [VectorIndexes](https://docs.convex.dev/api/modules/server#vectorindexes) - [VectorIndexNames](https://docs.convex.dev/api/modules/server#vectorindexnames) - [NamedVectorIndex](https://docs.convex.dev/api/modules/server#namedvectorindex) - [GenericDataModel](https://docs.convex.dev/api/modules/server#genericdatamodel) - [AnyDataModel](https://docs.convex.dev/api/modules/server#anydatamodel) - [TableNamesInDataModel](https://docs.convex.dev/api/modules/server#tablenamesindatamodel) - [NamedTableInfo](https://docs.convex.dev/api/modules/server#namedtableinfo) - [DocumentByName](https://docs.convex.dev/api/modules/server#documentbyname) - [ExpressionOrValue](https://docs.convex.dev/api/modules/server#expressionorvalue) - [Cursor](https://docs.convex.dev/api/modules/server#cursor) - [GenericMutationCtxWithTable](https://docs.convex.dev/api/modules/server#genericmutationctxwithtable) - [GenericQueryCtxWithTable](https://docs.convex.dev/api/modules/server#genericqueryctxwithtable) - [DefaultFunctionArgs](https://docs.convex.dev/api/modules/server#defaultfunctionargs) - [ArgsArray](https://docs.convex.dev/api/modules/server#argsarray) - [ArgsArrayToObject](https://docs.convex.dev/api/modules/server#argsarraytoobject) - [FunctionVisibility](https://docs.convex.dev/api/modules/server#functionvisibility) - [RegisteredMutation](https://docs.convex.dev/api/modules/server#registeredmutation) - [RegisteredQuery](https://docs.convex.dev/api/modules/server#registeredquery) - [RegisteredAction](https://docs.convex.dev/api/modules/server#registeredaction) - [PublicHttpAction](https://docs.convex.dev/api/modules/server#publichttpaction) - [UnvalidatedFunction](https://docs.convex.dev/api/modules/server#unvalidatedfunction) - [ReturnValueForOptionalValidator](https://docs.convex.dev/api/modules/server#returnvalueforoptionalvalidator) - [ArgsArrayForOptionalValidator](https://docs.convex.dev/api/modules/server#argsarrayforoptionalvalidator) - [DefaultArgsForOptionalValidator](https://docs.convex.dev/api/modules/server#defaultargsforoptionalvalidator) - [MutationBuilder](https://docs.convex.dev/api/modules/server#mutationbuilder) - [MutationBuilderWithTable](https://docs.convex.dev/api/modules/server#mutationbuilderwithtable) - [QueryBuilder](https://docs.convex.dev/api/modules/server#querybuilder) - [QueryBuilderWithTable](https://docs.convex.dev/api/modules/server#querybuilderwithtable) - [ActionBuilder](https://docs.convex.dev/api/modules/server#actionbuilder) - [HttpActionBuilder](https://docs.convex.dev/api/modules/server#httpactionbuilder) - [RoutableMethod](https://docs.convex.dev/api/modules/server#routablemethod) - [RouteSpecWithPath](https://docs.convex.dev/api/modules/server#routespecwithpath) - [RouteSpecWithPathPrefix](https://docs.convex.dev/api/modules/server#routespecwithpathprefix) - [RouteSpec](https://docs.convex.dev/api/modules/server#routespec) - [SchedulableFunctionReference](https://docs.convex.dev/api/modules/server#schedulablefunctionreference) - [GenericSchema](https://docs.convex.dev/api/modules/server#genericschema) - [DataModelFromSchemaDefinition](https://docs.convex.dev/api/modules/server#datamodelfromschemadefinition) - [SystemTableNames](https://docs.convex.dev/api/modules/server#systemtablenames) - [StorageId](https://docs.convex.dev/api/modules/server#storageid) - [FileStorageId](https://docs.convex.dev/api/modules/server#filestorageid) - [FileMetadata](https://docs.convex.dev/api/modules/server#filemetadata) - [SystemFields](https://docs.convex.dev/api/modules/server#systemfields) - [IdField](https://docs.convex.dev/api/modules/server#idfield) - [WithoutSystemFields](https://docs.convex.dev/api/modules/server#withoutsystemfields) - [WithOptionalSystemFields](https://docs.convex.dev/api/modules/server#withoptionalsystemfields) - [SystemIndexes](https://docs.convex.dev/api/modules/server#systemindexes) - [IndexTiebreakerField](https://docs.convex.dev/api/modules/server#indextiebreakerfield) - [VectorSearch](https://docs.convex.dev/api/modules/server#vectorsearch) - [Expand](https://docs.convex.dev/api/modules/server#expand) - [BetterOmit](https://docs.convex.dev/api/modules/server#betteromit) - [Variables](https://docs.convex.dev/api/modules/server#variables) - [anyApi](https://docs.convex.dev/api/modules/server#anyapi-1) - [paginationOptsValidator](https://docs.convex.dev/api/modules/server#paginationoptsvalidator) - [ROUTABLE\\_HTTP\\_METHODS](https://docs.convex.dev/api/modules/server#routable_http_methods) - [Functions](https://docs.convex.dev/api/modules/server#functions) - [getFunctionName](https://docs.convex.dev/api/modules/server#getfunctionname) - [makeFunctionReference](https://docs.convex.dev/api/modules/server#makefunctionreference) - [filterApi](https://docs.convex.dev/api/modules/server#filterapi-1) - [createFunctionHandle](https://docs.convex.dev/api/modules/server#createfunctionhandle) - [defineComponent](https://docs.convex.dev/api/modules/server#definecomponent) - [defineApp](https://docs.convex.dev/api/modules/server#defineapp) - [componentsGeneric](https://docs.convex.dev/api/modules/server#componentsgeneric) - [getFunctionAddress](https://docs.convex.dev/api/modules/server#getfunctionaddress) - [cronJobs](https://docs.convex.dev/api/modules/server#cronjobs) - [mutationGeneric](https://docs.convex.dev/api/modules/server#mutationgeneric) - [internalMutationGeneric](https://docs.convex.dev/api/modules/server#internalmutationgeneric) - [queryGeneric](https://docs.convex.dev/api/modules/server#querygeneric) - [internalQueryGeneric](https://docs.convex.dev/api/modules/server#internalquerygeneric) - [actionGeneric](https://docs.convex.dev/api/modules/server#actiongeneric) - [internalActionGeneric](https://docs.convex.dev/api/modules/server#internalactiongeneric) - [httpActionGeneric](https://docs.convex.dev/api/modules/server#httpactiongeneric) - [httpRouter](https://docs.convex.dev/api/modules/server#httprouter) - [defineTable](https://docs.convex.dev/api/modules/server#definetable) - [defineSchema](https://docs.convex.dev/api/modules/server#defineschema) [Skip to main content](https://docs.convex.dev/quickstart/android#docusaurus_skipToContent_fallback) Learn how to query data from Convex in a Android Kotlin project. This quickstart assumes that you have Android Studio, node and npm installed. If you don’t have those tools, take time to install them first. 01. Create a new Android app in Android Studio Choose the following options in the wizard. ```codeBlockLines_zEuJ 1. Choose the \"Empty Activity\" template 2. Name it \"Convex Quickstart\" 3. Choose min SDK as 26 4. Choose Kotlin as the Gradle DSL ``` 02. Configure the AndroidManifest Add the following to your `AndroidManifest.xml`. ```codeBlockLines_zEuJ ``` 03. Configure your dependencies Add the following entries to the `:app` `build.gradle.kts` file (ignore IDE suggestion to move them to version catalog for now, if present). Ensure that you sync Gradle when all of the above is complete (Android Studio should prompt you to do so). ```codeBlockLines_zEuJ plugins { // ... existing plugins kotlin(\"plugin.serialization\") version \"1.9.0\" } dependencies { // ... existing dependencies implementation(\"dev.convex:android-convexmobile:0.4.1@aar\") { isTransitive = true } implementation(\"org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3\") } ``` 04. Install the Convex Backend Open a terminal in your Android Studio instance and install the Convex client and server library. ```codeBlockLines_zEuJ npm init -y npm install convex ``` 05. Start Convex Start a Convex dev deployment. Follow the command line instructions. ```codeBlockLines_zEuJ npx convex dev ``` 06. Create a sample data for your database Create a new `sampleData.jsonl` file with these contents. ```codeBlockLines_zEuJ {\"text\": \"Buy groceries\", \"isCompleted\": true} {\"text\": \"Go for a swim\", \"isCompleted\": true} {\"text\": \"Integrate Convex\", \"isCompleted\": false} ``` 07. Add the sample data to your database Open another terminal tab and run. ```codeBlockLines_zEuJ npx convex import --table tasks sampleData.jsonl ``` 08. Expose a database query Create a `tasks.ts` file in your `convex/` directory with the following contents. ```codeBlockLines_zEuJ import { query } from \"./_generated/server\"; export const get = query({ args: {}, handler: async (ctx) => { return await ctx.db.query(\"tasks\").collect(); }, }); ``` 09. Create a data class Add a new `data class` to your `MainActivity` to support the task data defined above. Import whatever it asks you to. ```codeBlockLines_zEuJ @Serializable data class Task(val text: String, val isCompleted: Boolean) ``` 10. Create your UI Delete the template `@Composable` functions that Android Studio created and add a new one to display data from your Convex deployment. Again, import whatever it asks you to. ```codeBlockLines_zEuJ @Composable fun Tasks(client: ConvexClient, modifier: Modifier = Modifier) { var tasks: List by remember { mutableStateOf(listOf()) } LaunchedEffect(key1 = \"launch\") { client.subscribe>(\"tasks:get\").collect { result -> result.onSuccess { remoteTasks -> tasks = remoteTasks } } } LazyColumn( modifier = modifier ) { items(tasks) { task -> Text(text = \"Text: ${task.text}, Completed?: ${task.isCompleted}\") } } } ``` 11. Connect the app to your backend 1. Get the deployment URL of your dev server with `cat .env.local | grep CONVEX_URL` 2. Update the `onCreate` method in your `MainActivity.kt` to look like ```codeBlockLines_zEuJ override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { ConvexQuickstartTheme { Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> Tasks( client = ConvexClient($YOUR_CONVEX_URL), modifier = Modifier.padding(innerPadding) ) } } } } ``` 12. Fix any missing imports Fix up any missing imports (your import declarations should look something like this): ```codeBlockLines_zEuJ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import dev.convex.android.ConvexClient import kotlinx.serialization.Serializable ``` 13. Run the app You can also try adding, updating or deleting documents in your `tasks` table at `dashboard.convex.dev` \\- the app will update with the changes in real-time. ```codeBlockLines_zEuJ From the IDE menu choose \"Run\" > \"Run 'app'\" ``` See the [complete documentation](https://docs.convex.dev/client/android). [Skip to main content](https://docs.convex.dev/functions/error-handling#docusaurus_skipToContent_fallback) On this page There are four reasons why your Convex [queries](https://docs.convex.dev/functions/query-functions) and [mutations](https://docs.convex.dev/functions/mutation-functions) may hit errors: 1. [Application Errors](https://docs.convex.dev/functions/error-handling#application-errors-expected-failures): The function code hits a logical condition that should stop further processing, and your code throws a `ConvexError` 2. Developer Errors: There is a bug in the function (like calling `db.get(null)` instead of `db.get(id)`). 3. [Read/Write Limit Errors](https://docs.convex.dev/functions/error-handling#readwrite-limit-errors): The function is retrieving or writing too much data. 4. Internal Convex Errors: There is a problem within Convex (like a network blip). Convex will automatically handle internal Convex errors. If there are problems on our end, we'll automatically retry your queries and mutations until the problem is resolved and your queries and mutations succeed. On the other hand, you must decide how to handle application, developer and read/write limit errors. When one of these errors happens, the best practices are to: 1. Show the user some appropriate UI. 2. Send the error to an exception reporting service using the [Exception Reporting Integration](https://docs.convex.dev/production/integrations/exception-reporting). 3. Log the incident using `console.*` and set up reporting with [Log Streaming](https://docs.convex.dev/production/integrations/log-streams/). This can be done in addition to the above options, and doesn't require an exception to be thrown. Additionally, you might also want to send client-side errors to a service like [Sentry](https://sentry.io/) to capture additional information for debugging and observability. ## Errors in queries [​](https://docs.convex.dev/functions/error-handling\\#errors-in-queries \"Direct link to Errors in queries\") If your query function hits an error, the error will be sent to the client and thrown from your `useQuery` call site. **The best way to handle these errors is** **with a React** **[error boundary component](https://reactjs.org/docs/error-boundaries.html).** Error boundaries allow you to catch errors thrown in their child component tree, render fallback UI, and send information about the error to your exception handling service. Adding error boundaries to your app is a great way to handle errors in Convex query functions as well as other errors in your React components. If you are using Sentry, you can use their [`Sentry.ErrorBoundary`](https://docs.sentry.io/platforms/javascript/guides/react/components/errorboundary/) component. With error boundaries, you can decide how granular you'd like your fallback UI to be. One simple option is to wrap your entire application in a single error boundary like: ```codeBlockLines_zEuJ , ``` Then any error in any of your components will be caught by the boundary and render the same fallback UI. On the other hand, if you'd like to enable some portions of your app to continue functioning even if other parts hit errors, you can instead wrap different parts of your app in separate error boundaries. Retrying Unlike other frameworks, there is no concept of \"retrying\" if your query function hits an error. Because Convex functions are [deterministic](https://docs.convex.dev/functions/query-functions#caching-reactivity), if the query function hits an error, retrying will always produce the same error. There is no point in running the query function with the same arguments again. ## Errors in mutations [​](https://docs.convex.dev/functions/error-handling\\#errors-in-mutations \"Direct link to Errors in mutations\") If a mutation hits an error, this will 1. Cause the promise returned from your mutation call to be rejected. 2. Cause your [optimistic update](https://docs.convex.dev/client/react/optimistic-updates) to be rolled back. If you have an exception service like [Sentry](https://sentry.io/) configured, it should report \"unhandled promise rejections\" like this automatically. That means that with no additional work your mutation errors should be reported. Note that errors in mutations won't be caught by your error boundaries because the error doesn't happen as part of rendering your components. If you would like to render UI specifically in response to a mutation failure, you can use `.catch` on your mutation call. For example: ```codeBlockLines_zEuJ sendMessage(newMessageText).catch((error) => { // Do something with `error` here }); ``` If you're using an `async` handled function you can also use `try...catch`: ```codeBlockLines_zEuJ try { await sendMessage(newMessageText); } catch (error) { // Do something with `error` here } ``` Reporting caught errors If you handle your mutation error, it will no longer become an unhandled promise rejection. You may need to report this error to your exception handling service manually. ## Errors in action functions [​](https://docs.convex.dev/functions/error-handling\\#errors-in-action-functions \"Direct link to Errors in action functions\") Unlike queries and mutations, [actions](https://docs.convex.dev/functions/actions) may have side-effects and therefore can't be automatically retried by Convex when errors occur. For example, say your action sends a email. If it fails part-way through, Convex has no way of knowing if the email was already sent and can't safely retry the action. It is responsibility of the caller to handle errors raised by actions and retry if appropriate. ## Differences in error reporting between dev and prod [​](https://docs.convex.dev/functions/error-handling\\#differences-in-error-reporting-between-dev-and-prod \"Direct link to Differences in error reporting between dev and prod\") Using a dev deployment any server error thrown on the client will include the original error message and a server-side stack trace to ease debugging. Using a production deployment any server error will be redacted to only include the name of the function and a generic `\"Server Error\"` message, with no stack trace. Server [application errors](https://docs.convex.dev/functions/error-handling/application-errors) will still include their custom `data`. Both development and production deployments log full errors with stack traces which can be found on the [Logs](https://docs.convex.dev/dashboard/deployments/logs) page of a given deployment. ## Application errors, expected failures [​](https://docs.convex.dev/functions/error-handling\\#application-errors-expected-failures \"Direct link to Application errors, expected failures\") If you have expected ways your functions might fail, you can either return different values or throw `ConvexError` s. See [Application Errors](https://docs.convex.dev/functions/error-handling/application-errors). ## Read/write limit errors [​](https://docs.convex.dev/functions/error-handling\\#readwrite-limit-errors \"Direct link to Read/write limit errors\") To ensure uptime and guarantee performance, Convex will catch queries and mutations that try to read or write too much data. These limits are enforced at the level of a single query or mutation function execution. The limits are: Queries and mutations error out when: - More than 16384 documents are scanned - More than 8MiB worth of data is scanned - More than 4096 queries calls to `db.get` or `db.query` are made - The function spends more than 1 second executing Javascript In addition, mutations error out when: - More than 8192 documents are written - More than 8MiB worth of data is written Documents are \"scanned\" by the database to figure out which documents should be returned from `db.query`. So for example `db.query(\"table\").take(5).collect()` will only need to scan 5 documents, but `db.query(\"table\").filter(...).first()` might scan up to as many documents as there are in `\"table\"`, to find the first one that matches the given filter. Number of calls to `db.get` and `db.query` has a limit to prevent a single query from subscribing to too many index ranges. In general, if you're running into these limits frequently, we recommend [indexing your queries](https://docs.convex.dev/database/reading-data/indexes/) to reduce the number of documents scanned, allowing you to avoid unnecessary reads. Queries that scan large swaths of your data may look innocent at first, but can easily blow up at any production scale. If your functions are close to hitting these limits they will log a warning. For information on other limits, see [here](https://docs.convex.dev/production/state/limits). ## Debugging Errors [​](https://docs.convex.dev/functions/error-handling\\#debugging-errors \"Direct link to Debugging Errors\") See [Debugging](https://docs.convex.dev/functions/debugging) and specifically [Finding relevant logs by Request ID](https://docs.convex.dev/functions/debugging#finding-relevant-logs-by-request-id). - [Errors in queries](https://docs.convex.dev/functions/error-handling#errors-in-queries) - [Errors in mutations](https://docs.convex.dev/functions/error-handling#errors-in-mutations) - [Errors in action functions](https://docs.convex.dev/functions/error-handling#errors-in-action-functions) - [Differences in error reporting between dev and prod](https://docs.convex.dev/functions/error-handling#differences-in-error-reporting-between-dev-and-prod) - [Application errors, expected failures](https://docs.convex.dev/functions/error-handling#application-errors-expected-failures) - [Read/write limit errors](https://docs.convex.dev/functions/error-handling#readwrite-limit-errors) - [Debugging Errors](https://docs.convex.dev/functions/error-handling#debugging-errors) [Skip to main content](https://docs.convex.dev/dashboard/deployments#docusaurus_skipToContent_fallback) Each project in Convex has a main production deployment, and each developer on your team can also set up their own personal development deployment. Additionally, there are [preview deployments](https://docs.convex.dev/production/hosting/preview-deployments) used to test backend changes before they're deployed to production. While on a [deployment page](https://dashboard.convex.dev/deployment), you may switch between production, your development deployment, and any preview deployments by using the dropdown menu on the top-left of the page. ![Deployment switcher](https://docs.convex.dev/assets/images/deployment_menu-b2e23e5c7d44f8defdad7685df75ef29.png) [Skip to main content](https://docs.convex.dev/quickstart/vue#docusaurus_skipToContent_fallback) Learn how to query data from Convex in a Vue app. This quickstart guide uses a [community-maintained](https://docs.convex.dev/client/vue) Vue client for Convex. 1. Create a Vue site Create a Vue site using the `npm create vue@latest my-vue-app` command. Convex will work with any set of options but to follow this quickstart most closely choose: - Yes to \"Add TypeScript?\" - No to everything else ```codeBlockLines_zEuJ npm create vue@latest my-vue-app ``` 2. Install the Convex library To get started, install the `convex` package. ```codeBlockLines_zEuJ cd my-vue-app && npm install @convex-vue/core @vueuse/core convex ``` 3. Set up a Convex dev deployment Next, run `npx convex dev`. This will prompt you to log in with GitHub, create a project, and save your production and deployment URLs. It will also create a `convex/` folder for you to write your backend API functions in. The `dev` command will then continue running to sync your functions with your dev deployment in the cloud. ```codeBlockLines_zEuJ npx convex dev ``` 4. Create sample data for your database In a new terminal window, create a `sampleData.jsonl` file with some sample data. sampleData.jsonl ```codeBlockLines_zEuJ {\"text\": \"Buy groceries\", \"isCompleted\": true} {\"text\": \"Go for a swim\", \"isCompleted\": true} {\"text\": \"Integrate Convex\", \"isCompleted\": false} ``` 5. Add the sample data to your database Now that your project is ready, add a `tasks` table with the sample data into your Convex database with the `import` command. ```codeBlockLines_zEuJ npx convex import --table tasks sampleData.jsonl ``` 6. Expose a database query Add a new file `tasks.ts` in the `convex/` folder with a query function that loads the data. Exporting a query function from this file declares an API function named after the file and the export name, `api.tasks.get`. convex/tasks.ts ```codeBlockLines_zEuJ import { query } from \"./_generated/server\"; export const get = query({ args: {}, handler: async (ctx) => { return await ctx.db.query(\"tasks\").collect(); }, }); ``` 7. Wire up the ConvexProvider In `src/main.ts` set up the Convex client there to make it available on every page of your app. src/main.ts ```codeBlockLines_zEuJ import \"./assets/main.css\"; import { createApp } from \"vue\"; import App from \"./App.vue\"; import { createConvexVue } from \"@convex-vue/core\"; const app = createApp(App); const convexVue = createConvexVue({ convexUrl: import.meta.env.VITE_CONVEX_URL, }); app.use(convexVue).mount(\"#app\"); ``` 8. Display the data in your app In `src/App.vue` use `useQuery` to subscribe your `api.tasks.get` API function. src/App.vue ```codeBlockLines_zEuJ ``` 9. Start the app Start the app, open [http://localhost:5173](http://localhost:5173/) in a browser, and see the list of tasks. ```codeBlockLines_zEuJ npm run dev ``` [Skip to main content](https://docs.convex.dev/functions/http-actions#docusaurus_skipToContent_fallback) On this page HTTP actions allow you to build an HTTP API right in Convex! HTTP actions take in a [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) and return a [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) following the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API). HTTP actions can manipulate the request and response directly, and interact with data in Convex indirectly by running [queries](https://docs.convex.dev/functions/query-functions), [mutations](https://docs.convex.dev/functions/mutation-functions), and [actions](https://docs.convex.dev/functions/actions). HTTP actions might be used for receiving webhooks from external applications or defining a public HTTP API. HTTP actions are exposed at `https://.convex.site` (e.g. `https://happy-animal-123.convex.site`). **Example:** [HTTP Actions](https://github.com/get-convex/convex-demos/tree/main/http) ## Defining HTTP actions [​](https://docs.convex.dev/functions/http-actions\\#defining-http-actions \"Direct link to Defining HTTP actions\") HTTP action handlers are defined using the [`httpAction`](https://docs.convex.dev/generated-api/server#httpaction) constructor, similar to the `action` constructor for normal actions: convex/myHttpActions.ts TS ```codeBlockLines_zEuJ import { httpAction } from \"./_generated/server\"; export const doSomething = httpAction(async () => { // implementation will be here return new Response(); }); ``` The first argument to the `handler` is an [`ActionCtx`](https://docs.convex.dev/api/interfaces/server.GenericActionCtx) object, which provides [`auth`](https://docs.convex.dev/api/interfaces/server.Auth), [`storage`](https://docs.convex.dev/api/interfaces/server.StorageActionWriter), and [`scheduler`](https://docs.convex.dev/api/interfaces/server.Scheduler), as well as `runQuery`, `runMutation`, `runAction`. The second argument contains the [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) data. HTTP actions do not support argument validation, as the parsing of arguments from the incoming Request is left entirely to you. Here's an example: convex/messages.ts TS ```codeBlockLines_zEuJ import { httpAction } from \"./_generated/server\"; import { internal } from \"./_generated/api\"; export const postMessage = httpAction(async (ctx, request) => { const { author, body } = await request.json(); await ctx.runMutation(internal.messages.sendOne, { body: `Sent via HTTP action: ${body}`, author, }); return new Response(null, { status: 200, }); }); ``` To expose the HTTP Action, export an instance of [`HttpRouter`](https://docs.convex.dev/api/classes/server.HttpRouter) from the `convex/http.ts` file. To create the instance call the `httpRouter` function. On the `HttpRouter` you can expose routes using the `route` method: convex/http.ts TS ```codeBlockLines_zEuJ import { httpRouter } from \"convex/server\"; import { postMessage, getByAuthor, getByAuthorPathSuffix } from \"./messages\"; const http = httpRouter(); http.route({ path: \"/postMessage\", method: \"POST\", handler: postMessage, }); // Define additional routes http.route({ path: \"/getMessagesByAuthor\", method: \"GET\", handler: getByAuthor, }); // Define a route using a path prefix http.route({ // Will match /getAuthorMessages/User+123 and /getAuthorMessages/User+234 etc. pathPrefix: \"/getAuthorMessages/\", method: \"GET\", handler: getByAuthorPathSuffix, }); // Convex expects the router to be the default export of `convex/http.js`. export default http; ``` You can now call this action via HTTP and interact with data stored in the Convex Database. HTTP actions are exposed on `https://.convex.site`. ```codeBlockLines_zEuJ export DEPLOYMENT_NAME=... # example: \"happy-animal-123\" curl -d '{ \"author\": \"User 123\", \"body\": \"Hello world\" }' \\ -H 'content-type: application/json' \"https://$DEPLOYMENT_NAME.convex.site/postMessage\" ``` Like other Convex functions, you can view your HTTP actions in the [Functions view](https://docs.convex.dev/dashboard/deployments/functions) of [your dashboard](https://dashboard.convex.dev/) and view logs produced by them in the [Logs view](https://docs.convex.dev/dashboard/deployments/logs). ## Limits [​](https://docs.convex.dev/functions/http-actions\\#limits \"Direct link to Limits\") HTTP actions run in the same environment as queries and mutations so also do not have access to Node.js-specific JavaScript APIs. HTTP actions can call [actions](https://docs.convex.dev/functions/actions), which can run in Node.js. Like [actions](https://docs.convex.dev/functions/actions#error-handling), HTTP actions may have side-effects and will not be automatically retried by Convex when errors occur. It is a responsibility of the caller to handle errors and retry the request if appropriate. Request and response size is limited to 20MB. HTTP actions support request and response body types of `.text()`, `.json()`, `.blob()`, and `.arrayBuffer()`. Note that you don't need to define an HTTP action to call your queries, mutations and actions over HTTP if you control the caller, since you can use use the JavaScript [`ConvexHttpClient`](https://docs.convex.dev/api/classes/browser.ConvexHttpClient) or the [Python client](https://docs.convex.dev/client/python) to call these functions directly. ## Debugging [​](https://docs.convex.dev/functions/http-actions\\#debugging \"Direct link to Debugging\") ### Step 1: Check that your HTTP actions were deployed. [​](https://docs.convex.dev/functions/http-actions\\#step-1-check-that-your-http-actions-were-deployed \"Direct link to Step 1: Check that your HTTP actions were deployed.\") Check the [functions page](https://dashboard.convex.dev/deployment/functions) in the dashboard and make sure there's an entry called `http`. If not, double check that you've defined your HTTP actions with the `httpRouter` in a file called `http.js` or `http.ts` (the name of the file must match exactly), and that `npx convex dev` has no errors. ### Step 2: Check that you can access your endpoint using curl [​](https://docs.convex.dev/functions/http-actions\\#step-2-check-that-you-can-access-your-endpoint-using-curl \"Direct link to Step 2: Check that you can access your endpoint using curl\") Get your URL from the dashboard under [Settings](https://dashboard.convex.dev/deployment/settings) \\> URL and Deploy Key. Make sure this is the URL that ends in **`.convex.site`**, and not `.convex.cloud`. E.g. `https://happy-animal-123.convex.site` Run a `curl` command to hit one of your defined endpoints, potentially defining a new endpoint specifically for testing ```codeBlockLines_zEuJ curl -X GET https://.convex.site/myEndpoint ``` Check the [logs page](https://dashboard.convex.dev/deployment/logs) in the dashboard to confirm that there's an entry for your HTTP action. ### Step 3: Check the request being made by your browser [​](https://docs.convex.dev/functions/http-actions\\#step-3-check-the-request-being-made-by-your-browser \"Direct link to Step 3: Check the request being made by your browser\") If you've determined that your HTTP actions have been deployed and are accessible via curl, but there are still issues requesting them from your app, check the exact requests being made by your browser. Open the _Network_ tab in your browser's developer tools, and trigger your HTTP requests. Check that this URL matches what you tested earlier with curl -- it ends in `.convex.site` and has the right deployment name. You should be able to see these requests in the dashboard [logs page](https://dashboard.convex.dev/deployment/logs). If you see \"CORS error\" or messages in the browser console like `Access to fetch at '...' from origin '...' has been blocked by CORS policy`, you likely need to configure CORS headers and potentially add a handler for the pre-flight `OPTIONS` request. See [this section](https://docs.convex.dev/functions/http-actions#cors) below. ## Common patterns [​](https://docs.convex.dev/functions/http-actions\\#common-patterns \"Direct link to Common patterns\") ### File Storage [​](https://docs.convex.dev/functions/http-actions\\#file-storage \"Direct link to File Storage\") HTTP actions can be used to handle uploading and fetching stored files, see [File Storage with HTTP actions](https://docs.convex.dev/file-storage#file-storage-with-http-actions). ### CORS [​](https://docs.convex.dev/functions/http-actions\\#cors \"Direct link to CORS\") To make requests to HTTP actions from a website you need to add [Cross-Origin Resource Sharing (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) headers to your HTTP actions. There are existing resources for exactly which CORS headers are required based on the use case. [This site](https://httptoolkit.com/will-it-cors/) provides an interactive walkthrough for what CORS headers to add. Here's an example of adding CORS headers to a Convex HTTP action: convex/http.ts TS ```codeBlockLines_zEuJ import { httpRouter } from \"convex/server\"; import { httpAction } from \"./_generated/server\"; import { api } from \"./_generated/api\"; import { Id } from \"./_generated/dataModel\"; const http = httpRouter(); http.route({ path: \"/sendImage\", method: \"POST\", handler: httpAction(async (ctx, request) => { // Step 1: Store the file const blob = await request.blob(); const storageId = await ctx.storage.store(blob); // Step 2: Save the storage ID to the database via a mutation const author = new URL(request.url).searchParams.get(\"author\"); await ctx.runMutation(api.messages.sendImage, { storageId, author }); // Step 3: Return a response with the correct CORS headers return new Response(null, { status: 200, // CORS headers headers: new Headers({ // e.g. https://mywebsite.com, configured on your Convex dashboard \"Access-Control-Allow-Origin\": process.env.CLIENT_ORIGIN!, Vary: \"origin\", }), }); }), }); ``` Here's an example of handling a pre-flight `OPTIONS` request: convex/http.ts TS ```codeBlockLines_zEuJ // Pre-flight request for /sendImage http.route({ path: \"/sendImage\", method: \"OPTIONS\", handler: httpAction(async (_, request) => { // Make sure the necessary headers are present // for this to be a valid pre-flight request const headers = request.headers; if ( headers.get(\"Origin\") !== null && headers.get(\"Access-Control-Request-Method\") !== null && headers.get(\"Access-Control-Request-Headers\") !== null ) { return new Response(null, { headers: new Headers({ // e.g. https://mywebsite.com, configured on your Convex dashboard \"Access-Control-Allow-Origin\": process.env.CLIENT_ORIGIN!, \"Access-Control-Allow-Methods\": \"POST\", \"Access-Control-Allow-Headers\": \"Content-Type, Digest\", \"Access-Control-Max-Age\": \"86400\", }), }); } else { return new Response(); } }), }); ``` ### Authentication [​](https://docs.convex.dev/functions/http-actions\\#authentication \"Direct link to Authentication\") You can leverage Convex's built-in [authentication](https://docs.convex.dev/auth) integration and access a user identity from [`ctx.auth.getUserIdentity()`](https://docs.convex.dev/api/interfaces/server.Auth#getuseridentity). To do this call your endpoint with an `Authorization` header including a JWT token: myPage.ts TS ```codeBlockLines_zEuJ const jwtToken = \"...\"; fetch(\"https://.convex.site/myAction\", { headers: { Authorization: `Bearer ${jwtToken}`, }, }); ``` - [Defining HTTP actions](https://docs.convex.dev/functions/http-actions#defining-http-actions) - [Limits](https://docs.convex.dev/functions/http-actions#limits) - [Debugging](https://docs.convex.dev/functions/http-actions#debugging) - [Step 1: Check that your HTTP actions were deployed.](https://docs.convex.dev/functions/http-actions#step-1-check-that-your-http-actions-were-deployed) - [Step 2: Check that you can access your endpoint using curl](https://docs.convex.dev/functions/http-actions#step-2-check-that-you-can-access-your-endpoint-using-curl) - [Step 3: Check the request being made by your browser](https://docs.convex.dev/functions/http-actions#step-3-check-the-request-being-made-by-your-browser) - [Common patterns](https://docs.convex.dev/functions/http-actions#common-patterns) - [File Storage](https://docs.convex.dev/functions/http-actions#file-storage) - [CORS](https://docs.convex.dev/functions/http-actions#cors) - [Authentication](https://docs.convex.dev/functions/http-actions#authentication) [Skip to main content](https://docs.convex.dev/generated-api#docusaurus_skipToContent_fallback) Convex uses code generation to create code that is specific to your app's data model and API. Convex generates JavaScript files ( `.js`) with TypeScript type definitions ( `.d.ts`). Code generation isn't required to use Convex, but using the generated code will give you more better autocompletion in your editor and more type safety if you're using TypeScript. To generate the code, run: ```codeBlockLines_zEuJ npx convex dev ``` This creates a `convex/_generated` directory that contains: - [`api.js` and `api.d.ts`](https://docs.convex.dev/generated-api/api) - [`dataModel.d.ts`](https://docs.convex.dev/generated-api/data-model) - [`server.js` and `server.d.ts`](https://docs.convex.dev/generated-api/server) [Skip to main content](https://docs.convex.dev/production/state/limits#docusaurus_skipToContent_fallback) On this page We’d love for you to have _unlimited_ joy building on Convex but engineering practicalities dictate a few limits. This page outlines current limits in the Convex ecosystem. Many of these limits will become more permissive over time. Please get in touch if any are prohibitive for your application. Limits are applied per team unless stated otherwise. ## Team [​](https://docs.convex.dev/production/state/limits\\#team \"Direct link to Team\") | | Starter | Professional | | --- | --- | --- | | Developers | 1-6 | 1-20
$25/member per month | | Projects | 20 | 100 | ## Database [​](https://docs.convex.dev/production/state/limits\\#database \"Direct link to Database\") | | Starter | Professional | Notes | | --- | --- | --- | --- | | Storage | 0.5 GiB | 50 GiB included
$0.20/month per additional GiB | Includes database rows and indexes but not files or backups. | | Bandwidth | 1 GiB/month | 50 GiB/month included
$0.20 per additional GiB | Document and index data transferred between Convex functions and the underlying database. | | Tables | 10,000 | 10,000 | Per deployment. | | Indexes per table | 32 | 32 | | | Fields per index | 16 | 16 | | | Index name length | 64 characters | 64 characters | | ### Restrictions [​](https://docs.convex.dev/production/state/limits\\#restrictions \"Direct link to Restrictions\") - Table and index names must be valid identifiers and cannot start with an underscore. ## Documents [​](https://docs.convex.dev/production/state/limits\\#documents \"Direct link to Documents\") Applied per document and to any nested `Object` unless stated otherwise. | | | Notes | | --- | --- | --- | | Size | 1 MiB | | | Fields | 1024 | The number of fields/keys | | Field name length | 64 characters | Nested `Object` keys can have length up to 1024 characters. | | Field nesting depth | 16 | How many times objects and arrays can be nested, e.g. `[[[[]]]]` | | Array elements | 8192 | | ### Restrictions [​](https://docs.convex.dev/production/state/limits\\#restrictions-1 \"Direct link to Restrictions\") - Field names must only contain non-control alphanumeric ASCII characters and underscores and must start with an alphabetic character or underscore. - Documents cannot contain top-level fields that start with an underscore, other than the system-provided `_id` and `_creationTime` fields. - Strings must be valid Unicode sequences with no unpaired surrogates. ## Functions [​](https://docs.convex.dev/production/state/limits\\#functions \"Direct link to Functions\") | | Starter | Professional | Notes | | --- | --- | --- | --- | | Function calls | 1,000,000/month | 25,000,000/month included
$2 per additional 1,000,000 | Explicit client calls, scheduled executions, subscription updates, and file accesses count as function calls. | | Action execution | 20 GiB-hours | 250 GiB-hours included
$0.30/GiB-hour additional | Convex runtime: 64 MiB RAM.
Node.js runtime: 512 MiB RAM. | | Code size | 32 MiB | 32 MiB | Per deployment. | | Function argument size | 8 MiB | 8 MiB | | | Function return value size | 8 MiB | 8 MiB | | | HTTP action response size | 20 MiB | 20 MiB | There is no specific limit on request size | | Length of a console.log line | 4 KiB | 4 KiB | | | [Log streaming](https://docs.convex.dev/production/integrations/log-streams/) limits | 4096 logs, flushed every 10 seconds | 4096 logs, flushed every 10 seconds | How many logs can be buffered when streaming | ## Execution time and scheduling [​](https://docs.convex.dev/production/state/limits\\#execution-time-and-scheduling \"Direct link to Execution time and scheduling\") | | | Notes | | --- | --- | --- | | Query/mutation execution time | 1 second | Limit applies only to user code and doesn’t include database operations. | | Action execution time | 10 minutes | | | Scheduled functions | 1000 | The number of other functions a single mutation can schedule. | | Total size of scheduled functions' arguments | 8 MiB | Applies only to mutations. | | Concurrent IO operations per function | 1000 | The number of IO operations a single function can perform, e.g., a database operation, or a fetch request in an action. | | Outstanding scheduled functions | 1,000,000 | | ## Transactions [​](https://docs.convex.dev/production/state/limits\\#transactions \"Direct link to Transactions\") These limits apply to each `query` or `mutation` function. | | | Notes | | --- | --- | --- | | Data read | 8 MiB | Data not returned due to a `filter` counts as scanned | | Data written | 8 MiB | | | Documents scanned | 16,384 | Documents not returned due to a `filter` count as scanned | | Documents written | 8,192 | | | Function return value size | 8 MiB | | ## Environment Variables [​](https://docs.convex.dev/production/state/limits\\#environment-variables \"Direct link to Environment Variables\") Applied per-deployment. | | | | --- | --- | | Number of variables | 100 | | Maximum name length | 40 characters | | Maximum value size | 8 KiB | ## File Storage [​](https://docs.convex.dev/production/state/limits\\#file-storage \"Direct link to File Storage\") | | Starter | Professional | Notes | | --- | --- | --- | --- | | Storage | 1 GiB | 100 GiB included
$0.03/month per additional GiB | Includes user files and backups. | | Bandwidth | 1 GiB/month | 50 GiB/month included
$0.30 per additional GiB | Includes serving user files, accessing user files inside functions, and generating and restoring backups. | ## Full text search [​](https://docs.convex.dev/production/state/limits\\#full-text-search \"Direct link to Full text search\") Full text search is in beta Full text searchis currently a [beta\\\\ feature](https://docs.convex.dev/production/state/#beta-features). If you have feedback or feature requests, [let us know on Discord](https://convex.dev/community)! | | Value | | --- | --- | | Search indexes per table | 4 | | Filters per search index | 16 | | Terms per search query | 16 | | Filters per search query | 8 | | Maximum term length | 32 B | | Maximum result set | 1024 | ## Vector search [​](https://docs.convex.dev/production/state/limits\\#vector-search \"Direct link to Vector search\") Vector search is in beta Vector searchis currently a [beta\\\\ feature](https://docs.convex.dev/production/state/#beta-features). If you have feedback or feature requests, [let us know on Discord](https://convex.dev/community)! | | Value | | --- | --- | | Vector indexes per table | 4 | | Filters per vector index | 16 | | Terms per search query | 16 | | Vectors to search by | 1 | | Dimension fields | 1 (value between 2-4096) | | Filters per search query | 64 | | Maximum term length | 32 B | | Maximum result set | 256 (defaults to 10) | If any of these limits don't work for you, [let us know](https://convex.dev/community)! Please see our [plans and pricing page](https://www.convex.dev/plans) for resource limits. After these limits are hit on a free plan, new mutations that attempt to commit more insertions or updates may fail. Paid plans have no hard resource limits - they can scale to billions of documents and TBs of storage. - [Team](https://docs.convex.dev/production/state/limits#team) - [Database](https://docs.convex.dev/production/state/limits#database) - [Restrictions](https://docs.convex.dev/production/state/limits#restrictions) - [Documents](https://docs.convex.dev/production/state/limits#documents) - [Restrictions](https://docs.convex.dev/production/state/limits#restrictions-1) - [Functions](https://docs.convex.dev/production/state/limits#functions) - [Execution time and scheduling](https://docs.convex.dev/production/state/limits#execution-time-and-scheduling) - [Transactions](https://docs.convex.dev/production/state/limits#transactions) - [Environment Variables](https://docs.convex.dev/production/state/limits#environment-variables) - [File Storage](https://docs.convex.dev/production/state/limits#file-storage) - [Full text search](https://docs.convex.dev/production/state/limits#full-text-search) - [Vector search](https://docs.convex.dev/production/state/limits#vector-search) [Skip to main content](https://docs.convex.dev/api/modules/react_auth0#docusaurus_skipToContent_fallback) On this page React login component for use with Auth0. ## Functions [​](https://docs.convex.dev/api/modules/react_auth0\\#functions \"Direct link to Functions\") ### ConvexProviderWithAuth0 [​](https://docs.convex.dev/api/modules/react_auth0\\#convexproviderwithauth0 \"Direct link to ConvexProviderWithAuth0\") ▸ **ConvexProviderWithAuth0**( `«destructured»`): `Element` A wrapper React component which provides a [ConvexReactClient](https://docs.convex.dev/api/classes/react.ConvexReactClient) authenticated with Auth0. It must be wrapped by a configured `Auth0Provider` from `@auth0/auth0-react`. See [Convex Auth0](https://docs.convex.dev/auth/auth0) on how to set up Convex with Auth0. #### Parameters [​](https://docs.convex.dev/api/modules/react_auth0\\#parameters \"Direct link to Parameters\") | Name | Type | | :-- | :-- | | `«destructured»` | `Object` | | › `children` | `ReactNode` | | › `client` | `IConvexReactClient` | #### Returns [​](https://docs.convex.dev/api/modules/react_auth0\\#returns \"Direct link to Returns\") `Element` #### Defined in [​](https://docs.convex.dev/api/modules/react_auth0\\#defined-in \"Direct link to Defined in\") [react-auth0/ConvexProviderWithAuth0.tsx:26](https://github.com/get-convex/convex-js/blob/main/src/react-auth0/ConvexProviderWithAuth0.tsx#L26) - [Functions](https://docs.convex.dev/api/modules/react_auth0#functions) - [ConvexProviderWithAuth0](https://docs.convex.dev/api/modules/react_auth0#convexproviderwithauth0) [Skip to main content](https://docs.convex.dev/search#docusaurus_skipToContent_fallback) Whether building RAG enabled chatbots or quick search in your applications, Convex provides easy apis to create powerful AI and search enabled products. [Vector Search](https://docs.convex.dev/search/vector-search) enables searching for documents based on their semantic meaning. It uses vector embeddings to calculate similarity and retrieve documents that are similar to a given query. Vector search is a key part of common AI techniques like RAG. [Full Text Search](https://docs.convex.dev/search/text-search) enables keyword and phrase search within your documents. It supports both prefix and fuzzy matching. Convex full text search is also reactive and always up to date like all Convex queries, making it easy to build reliable quick search boxes. [Convex Actions](https://docs.convex.dev/functions/actions) easily enable you to call AI apis, save data to your database, and drive your user interface. See examples of how you can use this to [build sophisticated AI applications](https://stack.convex.dev/tag/AI). Related posts from [![Stack](https://docs.convex.dev/img/stack-logo-dark.svg)![Stack](https://docs.convex.dev/img/stack-logo-light.svg)](https://stack.convex.dev/) [Skip to main content](https://docs.convex.dev/generated-api/server#docusaurus_skipToContent_fallback) On this page This code is generated These exports are not directly available in the `convex` package! Instead you must run `npx convex dev` to create `convex/_generated/server.js` and `convex/_generated/server.d.ts`. Generated utilities for implementing server-side Convex query and mutation functions. ## Functions [​](https://docs.convex.dev/generated-api/server\\#functions \"Direct link to Functions\") ### query [​](https://docs.convex.dev/generated-api/server\\#query \"Direct link to query\") ▸ **query**( `func`): [`RegisteredQuery`](https://docs.convex.dev/api/modules/server#registeredquery) Define a query in this Convex app's public API. This function will be allowed to read your Convex database and will be accessible from the client. This is an alias of [`queryGeneric`](https://docs.convex.dev/api/modules/server#querygeneric) that is typed for your app's data model. #### Parameters [​](https://docs.convex.dev/generated-api/server\\#parameters \"Direct link to Parameters\") | Name | Description | | :-- | :-- | | `func` | The query function. It receives a [QueryCtx](https://docs.convex.dev/generated-api/server#queryctx) as its first argument. | #### Returns [​](https://docs.convex.dev/generated-api/server\\#returns \"Direct link to Returns\") [`RegisteredQuery`](https://docs.convex.dev/api/modules/server#registeredquery) The wrapped query. Include this as an `export` to name it and make it accessible. * * * ### internalQuery [​](https://docs.convex.dev/generated-api/server\\#internalquery \"Direct link to internalQuery\") ▸ **internalQuery**( `func`): [`RegisteredQuery`](https://docs.convex.dev/api/modules/server#registeredquery) Define a query that is only accessible from other Convex functions (but not from the client). This function will be allowed to read from your Convex database. It will not be accessible from the client. This is an alias of [`internalQueryGeneric`](https://docs.convex.dev/api/modules/server#internalquerygeneric) that is typed for your app's data model. #### Parameters [​](https://docs.convex.dev/generated-api/server\\#parameters-1 \"Direct link to Parameters\") | Name | Description | | :-- | :-- | | `func` | The query function. It receives a [QueryCtx](https://docs.convex.dev/generated-api/server#queryctx) as its first argument. | #### Returns [​](https://docs.convex.dev/generated-api/server\\#returns-1 \"Direct link to Returns\") [`RegisteredQuery`](https://docs.convex.dev/api/modules/server#registeredquery) The wrapped query. Include this as an `export` to name it and make it accessible. * * * ### mutation [​](https://docs.convex.dev/generated-api/server\\#mutation \"Direct link to mutation\") ▸ **mutation**( `func`): [`RegisteredMutation`](https://docs.convex.dev/api/modules/server#registeredmutation) Define a mutation in this Convex app's public API. This function will be allowed to modify your Convex database and will be accessible from the client. This is an alias of [`mutationGeneric`](https://docs.convex.dev/api/modules/server#mutationgeneric) that is typed for your app's data model. #### Parameters [​](https://docs.convex.dev/generated-api/server\\#parameters-2 \"Direct link to Parameters\") | Name | Description | | :-- | :-- | | `func` | The mutation function. It receives a [MutationCtx](https://docs.convex.dev/generated-api/server#mutationctx) as its first argument. | #### Returns [​](https://docs.convex.dev/generated-api/server\\#returns-2 \"Direct link to Returns\") [`RegisteredMutation`](https://docs.convex.dev/api/modules/server#registeredmutation) The wrapped mutation. Include this as an `export` to name it and make it accessible. * * * ### internalMutation [​](https://docs.convex.dev/generated-api/server\\#internalmutation \"Direct link to internalMutation\") ▸ **internalMutation**( `func`): [`RegisteredMutation`](https://docs.convex.dev/api/modules/server#registeredmutation) Define a mutation that is only accessible from other Convex functions (but not from the client). This function will be allowed to read and write from your Convex database. It will not be accessible from the client. This is an alias of [`internalMutationGeneric`](https://docs.convex.dev/api/modules/server#internalmutationgeneric) that is typed for your app's data model. #### Parameters [​](https://docs.convex.dev/generated-api/server\\#parameters-3 \"Direct link to Parameters\") | Name | Description | | :-- | :-- | | `func` | The mutation function. It receives a [MutationCtx](https://docs.convex.dev/generated-api/server#mutationctx) as its first argument. | #### Returns [​](https://docs.convex.dev/generated-api/server\\#returns-3 \"Direct link to Returns\") [`RegisteredMutation`](https://docs.convex.dev/api/modules/server#registeredmutation) The wrapped mutation. Include this as an `export` to name it and make it accessible. * * * ### action [​](https://docs.convex.dev/generated-api/server\\#action \"Direct link to action\") ▸ **action**( `func`): [`RegisteredAction`](https://docs.convex.dev/api/modules/server#registeredaction) Define an action in this Convex app's public API. An action is a function which can execute any JavaScript code, including non-deterministic code and code with side-effects, like calling third-party services. They can be run in Convex's JavaScript environment or in Node.js using the `\"use node\"` directive. They can interact with the database indirectly by calling queries and mutations using the [`ActionCtx`](https://docs.convex.dev/generated-api/server#actionctx). This is an alias of [`actionGeneric`](https://docs.convex.dev/api/modules/server#actiongeneric) that is typed for your app's data model. #### Parameters [​](https://docs.convex.dev/generated-api/server\\#parameters-4 \"Direct link to Parameters\") | Name | Description | | :-- | :-- | | `func` | The action function. It receives an [ActionCtx](https://docs.convex.dev/generated-api/server#actionctx) as its first argument. | #### Returns [​](https://docs.convex.dev/generated-api/server\\#returns-4 \"Direct link to Returns\") [`RegisteredAction`](https://docs.convex.dev/api/modules/server#registeredaction) The wrapped function. Include this as an `export` to name it and make it accessible. * * * ### internalAction [​](https://docs.convex.dev/generated-api/server\\#internalaction \"Direct link to internalAction\") ▸ **internalAction**( `func`): [`RegisteredAction`](https://docs.convex.dev/api/modules/server#registeredaction) Define an action that is only accessible from other Convex functions (but not from the client). This is an alias of [`internalActionGeneric`](https://docs.convex.dev/api/modules/server#internalactiongeneric) that is typed for your app's data model. #### Parameters [​](https://docs.convex.dev/generated-api/server\\#parameters-5 \"Direct link to Parameters\") | Name | Description | | :-- | :-- | | `func` | The action function. It receives an [ActionCtx](https://docs.convex.dev/generated-api/server#actionctx) as its first argument. | #### Returns [​](https://docs.convex.dev/generated-api/server\\#returns-5 \"Direct link to Returns\") [`RegisteredAction`](https://docs.convex.dev/api/modules/server#registeredaction) The wrapped action. Include this as an `export` to name it and make it accessible. * * * ### httpAction [​](https://docs.convex.dev/generated-api/server\\#httpaction \"Direct link to httpAction\") ▸ **httpAction**( `func: (ctx: ActionCtx, request: Request) => Promise`): [`PublicHttpAction`](https://docs.convex.dev/api/modules/server#publichttpaction) #### Parameters [​](https://docs.convex.dev/generated-api/server\\#parameters-6 \"Direct link to Parameters\") | Name | Type | Description | | :-- | :-- | :-- | | `func` | `(ctx: ActionCtx, request: Request) => Promise` | The function. It receives an [`ActionCtx`](https://docs.convex.dev/api/modules/server#actionctx) as its first argument and a [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) as its second argument. | #### Returns [​](https://docs.convex.dev/generated-api/server\\#returns-6 \"Direct link to Returns\") [`PublicHttpAction`](https://docs.convex.dev/api/modules/server#publichttpaction) The wrapped function. Import this function from `convex/http.js` and route it to hook it up. ## Types [​](https://docs.convex.dev/generated-api/server\\#types \"Direct link to Types\") ### QueryCtx [​](https://docs.convex.dev/generated-api/server\\#queryctx \"Direct link to QueryCtx\") Ƭ **QueryCtx**: `Object` A set of services for use within Convex query functions. The query context is passed as the first argument to any Convex query function run on the server. This differs from the [MutationCtx](https://docs.convex.dev/generated-api/server#mutationctx) because all of the services are read-only. This is an alias of [`GenericQueryCtx`](https://docs.convex.dev/api/interfaces/server.GenericQueryCtx) that is typed for your app's data model. #### Type declaration [​](https://docs.convex.dev/generated-api/server\\#type-declaration \"Direct link to Type declaration\") | Name | Type | | :-- | :-- | | `db` | [`DatabaseReader`](https://docs.convex.dev/generated-api/server#databasereader) | | `auth` | [`Auth`](https://docs.convex.dev/api/interfaces/server.Auth) | | `storage` | [`StorageReader`](https://docs.convex.dev/api/interfaces/server.StorageReader) | * * * ### MutationCtx [​](https://docs.convex.dev/generated-api/server\\#mutationctx \"Direct link to MutationCtx\") Ƭ **MutationCtx**: `Object` A set of services for use within Convex mutation functions. The mutation context is passed as the first argument to any Convex mutation function run on the server. This is an alias of [`GenericMutationCtx`](https://docs.convex.dev/api/interfaces/server.GenericMutationCtx) that is typed for your app's data model. #### Type declaration [​](https://docs.convex.dev/generated-api/server\\#type-declaration-1 \"Direct link to Type declaration\") | Name | Type | | :-- | :-- | | `db` | [`DatabaseWriter`](https://docs.convex.dev/generated-api/server#databasewriter) | | `auth` | [`Auth`](https://docs.convex.dev/api/interfaces/server.Auth) | | `storage` | [`StorageWriter`](https://docs.convex.dev/api/interfaces/server.StorageWriter) | | `scheduler` | [`Scheduler`](https://docs.convex.dev/api/interfaces/server.Scheduler) | * * * ### ActionCtx [​](https://docs.convex.dev/generated-api/server\\#actionctx \"Direct link to ActionCtx\") Ƭ **ActionCtx**: `Object` A set of services for use within Convex action functions. The action context is passed as the first argument to any Convex action function run on the server. This is an alias of [`ActionCtx`](https://docs.convex.dev/api/modules/server#actionctx) that is typed for your app's data model. #### Type declaration [​](https://docs.convex.dev/generated-api/server\\#type-declaration-2 \"Direct link to Type declaration\") | Name | Type | | :-- | :-- | | `runQuery` | ( `name`: `string`, `args`?: `Record`) =\\> `Promise` | | `runMutation` | ( `name`: `string`, `args`?: `Record`) =\\> `Promise` | | `runAction` | ( `name`: `string`, `args`?: `Record`) =\\> `Promise` | | `auth` | [`Auth`](https://docs.convex.dev/api/interfaces/server.Auth) | | `scheduler` | [`Scheduler`](https://docs.convex.dev/api/interfaces/server.Scheduler) | | `storage` | [`StorageActionWriter`](https://docs.convex.dev/api/interfaces/server.StorageActionWriter) | | `vectorSearch` | ( `tableName`: `string`, `indexName`: `string`, `query`: [`VectorSearchQuery`](https://docs.convex.dev/api/interfaces/server.VectorSearchQuery)) =\\> `Promise>` | * * * ### DatabaseReader [​](https://docs.convex.dev/generated-api/server\\#databasereader \"Direct link to DatabaseReader\") An interface to read from the database within Convex query functions. This is an alias of [`GenericDatabaseReader`](https://docs.convex.dev/api/interfaces/server.GenericDatabaseReader) that is typed for your app's data model. * * * ### DatabaseWriter [​](https://docs.convex.dev/generated-api/server\\#databasewriter \"Direct link to DatabaseWriter\") An interface to read from and write to the database within Convex mutation functions. This is an alias of [`GenericDatabaseWriter`](https://docs.convex.dev/api/interfaces/server.GenericDatabaseWriter) that is typed for your app's data model. - [Functions](https://docs.convex.dev/generated-api/server#functions) - [query](https://docs.convex.dev/generated-api/server#query) - [internalQuery](https://docs.convex.dev/generated-api/server#internalquery) - [mutation](https://docs.convex.dev/generated-api/server#mutation) - [internalMutation](https://docs.convex.dev/generated-api/server#internalmutation) - [action](https://docs.convex.dev/generated-api/server#action) - [internalAction](https://docs.convex.dev/generated-api/server#internalaction) - [httpAction](https://docs.convex.dev/generated-api/server#httpaction) - [Types](https://docs.convex.dev/generated-api/server#types) - [QueryCtx](https://docs.convex.dev/generated-api/server#queryctx) - [MutationCtx](https://docs.convex.dev/generated-api/server#mutationctx) - [ActionCtx](https://docs.convex.dev/generated-api/server#actionctx) - [DatabaseReader](https://docs.convex.dev/generated-api/server#databasereader) - [DatabaseWriter](https://docs.convex.dev/generated-api/server#databasewriter) [Skip to main content](https://docs.convex.dev/quickstart/rust#docusaurus_skipToContent_fallback) Learn how to query data from Convex in a Rust app with Tokio. 1. Create a Cargo project Create a new Cargo project. ```codeBlockLines_zEuJ cargo new my_app cd my_app ``` 2. Install the Convex client and server libraries To get started, install the `convex` npm package which enables you to write your backend. And also install the `convex` Rust client library, the `tokio` runtime, and `dotenvy` for working with `.env` files. ```codeBlockLines_zEuJ npm init -y && npm install convex && cargo add convex tokio dotenvy ``` 3. Set up a Convex dev deployment Next, run `npx convex dev`. This will prompt you to log in with GitHub, create a project, and save your production and deployment URLs. It will also create a `convex/` folder for you to write your backend API functions in. The `dev` command will then continue running to sync your functions with your dev deployment in the cloud. ```codeBlockLines_zEuJ npx convex dev ``` 4. Create sample data for your database In a new terminal window, create a `sampleData.jsonl` file with some sample data. sampleData.jsonl ```codeBlockLines_zEuJ {\"text\": \"Buy groceries\", \"isCompleted\": true} {\"text\": \"Go for a swim\", \"isCompleted\": true} {\"text\": \"Integrate Convex\", \"isCompleted\": false} ``` 5. Add the sample data to your database Now that your project is ready, add a `tasks` table with the sample data into your Convex database with the `import` command. ```codeBlockLines_zEuJ npx convex import --table tasks sampleData.jsonl ``` 6. Expose a database query Add a new file `tasks.js` in the `convex/` folder with a query function that loads the data. Exporting a query function from this file declares an API function named after the file and the export name, `\"tasks:get\"`. convex/tasks.js ```codeBlockLines_zEuJ import { query } from \"./_generated/server\"; export const get = query({ handler: async ({ db }) => { return await db.query(\"tasks\").collect(); }, }); ``` 7. Connect the app to your backend In the file `src/main.rs`, create a `ConvexClient` and use it to fetch from your `\"tasks:get\"` API. src/main.rs ```codeBlockLines_zEuJ use std::{ collections::BTreeMap, env, }; use convex::ConvexClient; #[tokio::main] async fn main() { dotenvy::from_filename(\".env.local\").ok(); dotenvy::dotenv().ok(); let deployment_url = env::var(\"CONVEX_URL\").unwrap(); let mut client = ConvexClient::new(&deployment_url).await.unwrap(); let result = client.query(\"tasks:get\", BTreeMap::new()).await.unwrap(); println!(\"{result:#?}\"); } ``` 8. Run the app Run the app and see the serialized list of tasks. ```codeBlockLines_zEuJ cargo run ``` [Skip to main content](https://docs.convex.dev/production/hosting/custom#docusaurus_skipToContent_fallback) On this page ## Custom Domains [​](https://docs.convex.dev/production/hosting/custom\\#custom-domains \"Direct link to Custom Domains\") You can configure a custom domain, like `api.example.com`, to serve HTTP actions or Convex functions from your production Convex deployments. The settings for this feature are accessed through the Project Settings page on any of your projects. ![Add Custom Domain](https://docs.convex.dev/assets/images/add_custom_domain-2886f40eb3fd3ab420535fe0e9311908.png) After you enter a domain, you will be shown which records to set on your DNS provider. Some popular DNS providers that you can use to buy a domain are Cloudflare and GoDaddy. We will verify your domain in the background, and once these records are set, you will see a green checkmark. When you see that checkmark, your backend will now serve traffic from that domain. The first request may take up to a minute because Convex will have to mint a new SSL certificate. Reach out to [support@convex.dev](mailto:support@convex.dev) if you have any questions about getting set up! Custom domains require a Convex Pro plan. Custom domainsrequire a Convex Pro plan. [Learn\\\\ more](https://convex.dev/pricing) about our plans or [upgrade](https://dashboard.convex.dev/team/settings/billing). ### Hosting with a Custom Domain [​](https://docs.convex.dev/production/hosting/custom\\#hosting-with-a-custom-domain \"Direct link to Hosting with a Custom Domain\") To use a custom domain to serve your Convex functions, you'll need additional configuration in your hosting provider. The standard build command, `npx convex deploy --cmd 'npm run build'`, will automatically handle setting the `CONVEX_URL` environment variable (or similarly named) to the `.convex.cloud` URL for your production deployment, overriding any other value you have set. If you're using a custom domain, you'll want to set a different environment variable in your hosting provider to have the value of your custom domain in the production environment: ![Vercel import project](https://docs.convex.dev/assets/images/vercel_custom_domain-e18fdbfcf6c4fe0d10b1958949f74738.png) Switch the code that instantiates your Convex client to prefer this new value: ```codeBlockLines_zEuJ new ConvexReactClient( import.meta.env.VITE_CUSTOM_DOMAIN_CONVEX_URL ?? import.meta.env.VITE_CONVEX_URL, ); ``` You can confirm this works by checking the network tab in your browser's developer tools. ## Custom Hosting [​](https://docs.convex.dev/production/hosting/custom\\#custom-hosting \"Direct link to Custom Hosting\") If you're using only Convex for backend functionality you can host your web app on any static hosting provider. This guide will use [GitHub Pages](https://pages.github.com/) as an example. If you're using Next.js or other framework with server functionality you'll need to use a provider that supports it, such as [Netlify](https://docs.convex.dev/production/hosting/netlify) or [Vercel](https://docs.convex.dev/production/hosting/vercel). You can still host Next.js statically via a [static export](https://nextjs.org/docs/pages/building-your-application/deploying/static-exports). ### Configure your build [​](https://docs.convex.dev/production/hosting/custom\\#configure-your-build \"Direct link to Configure your build\") First make sure that you have a working build process. In this guide we'll set up a local build, but your hosting provider might support a remote build. For example see [Vite's Deploying to GitHub Pages guide](https://vitejs.dev/guide/static-deploy.html#github-pages) which uses GitHub actions. We'll use Vite and GitHub Pages as an example. 1. Configure `vite.config.mts`: vite.config.mts TS ```codeBlockLines_zEuJ import { defineConfig } from \"vite\"; import react from \"@vitejs/plugin-react\"; // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], build: { outDir: \"docs\", }, base: \"/some-repo-name/\", }); ``` The `build.outDir` field specifies where Vite will place the production build, and we use `docs` because that's the directory GitHub Pages allow hosting from. The `base` field specifies the URL path under which you'll serve your app, in this case we will serve on `https://.github.io/`. ### Configure your hosting provider [​](https://docs.convex.dev/production/hosting/custom\\#configure-your-hosting-provider \"Direct link to Configure your hosting provider\") With GitHub Pages, you can choose whether you want to include your build output in your main working branch or publish from a separate branch. Open your repository's GitHub page > _Settings_ \\> _Pages_. Under _Build and_ _deployment_ \\> _Source_ choose `Deploy from a branch`. Under _branch_ choose a branch (if you want to use a separate branch, push at least one commit to it first), and the `/docs` folder name. Hit _Save_. ### Build and deploy to Convex and GitHub Pages [​](https://docs.convex.dev/production/hosting/custom\\#build-and-deploy-to-convex-and-github-pages \"Direct link to Build and deploy to Convex and GitHub Pages\") To manually deploy to GitHub pages follow these steps: 1. Checkout the branch you chose to publish from 2. Run `npx convex deploy --cmd 'npm run build'` and confirm that you want to push your current backend code to your **production** deployment 3. Commit the build output changes and push to GitHub. ### How it works [​](https://docs.convex.dev/production/hosting/custom\\#how-it-works \"Direct link to How it works\") First, `npx convex deploy` runs through these steps: 1. It sets the `VITE_CONVEX_URL` (or similarly named) environment variable to your **production** Convex deployment. 2. It invokes the frontend framework build process, via `npm run build`. The build process reads the environment variable and uses it to point the built site at your **production** deployment. 3. It deploys your backend code, from the `convex` directory, to your **production** deployment. Afterwards you deploy the built frontend code to your hosting provider. In this case you used Git, but for other providers you might use a different method, such as an old-school FTP request. You can use `--cmd-url-env-var-name` to customize the variable name used by your frontend code if the `deploy` command cannot infer it, like ```codeBlockLines_zEuJ npx convex deploy --cmd-url-env-var-name CUSTOM_CONVEX_URL --cmd 'npm run build' ``` ### Authentication [​](https://docs.convex.dev/production/hosting/custom\\#authentication \"Direct link to Authentication\") You will want to configure your [authentication](https://docs.convex.dev/auth) provider (Clerk, Auth0 or other) to accept your production URL, where your frontend is served. - [Custom Domains](https://docs.convex.dev/production/hosting/custom#custom-domains) - [Hosting with a Custom Domain](https://docs.convex.dev/production/hosting/custom#hosting-with-a-custom-domain) - [Custom Hosting](https://docs.convex.dev/production/hosting/custom#custom-hosting) - [Configure your build](https://docs.convex.dev/production/hosting/custom#configure-your-build) - [Configure your hosting provider](https://docs.convex.dev/production/hosting/custom#configure-your-hosting-provider) - [Build and deploy to Convex and GitHub Pages](https://docs.convex.dev/production/hosting/custom#build-and-deploy-to-convex-and-github-pages) - [How it works](https://docs.convex.dev/production/hosting/custom#how-it-works) - [Authentication](https://docs.convex.dev/production/hosting/custom#authentication) [Skip to main content](https://docs.convex.dev/scheduling#docusaurus_skipToContent_fallback) Convex lets you easily schedule a function to run once or repeatedly in the future. This allows you to build durable workflows like sending a welcome email a day after someone joins or regularly reconciling your accounts with Stripe. Convex provides two different features for scheduling: - [Scheduled Functions](https://docs.convex.dev/scheduling/scheduled-functions) can be scheduled durably by any other function to run at a later point in time. You can schedule functions minutes, days, and even months in the future. - [Cron Jobs](https://docs.convex.dev/scheduling/cron-jobs) schedule functions to run on a recurring basis, such as daily. Related posts from [![Stack](https://docs.convex.dev/img/stack-logo-dark.svg)![Stack](https://docs.convex.dev/img/stack-logo-light.svg)](https://stack.convex.dev/) [![](https://cdn.sanity.io/images/ts10onj4/production/4c758d0a8ec559124d8f95014a7fd0ff8cec24c6-2877x1911.png?h=188)\\\\ \\\\ Automatically Retry Actions\\\\ \\\\ ![Avatar of James Cowling](https://cdn.sanity.io/images/ts10onj4/production/0d9c8f867a3ecac0ce8efe417583dbab8ce458b3-400x400.jpg)James Cowling](https://stack.convex.dev/retry-actions) [![](https://cdn.sanity.io/images/ts10onj4/production/c818fdda0370dfc1eba6ef650f2ac9af6daca4b2-2877x1911.png?h=188)\\\\ \\\\ Set up ESLint for best practices\\\\ \\\\ ![Avatar of Ian Macartney](https://cdn.sanity.io/images/ts10onj4/production/077753b63476b77fb111ba06d1bb538517033a54-3500x3500.jpg)Ian Macartney](https://stack.convex.dev/eslint-setup) [![](https://cdn.sanity.io/images/ts10onj4/production/3b04c7c457fe9a378c068b8f5e20407673266f0d-1452x956.png?h=188)\\\\ \\\\ Components for your Backend\\\\ \\\\ ![Avatar of Ian Macartney](https://cdn.sanity.io/images/ts10onj4/production/077753b63476b77fb111ba06d1bb538517033a54-3500x3500.jpg)Ian Macartney](https://stack.convex.dev/backend-components) [![](https://cdn.sanity.io/images/ts10onj4/production/5b6431ba4ee6fb2c13b631dba78eba15c83f2414-1200x852.png?h=188)\\\\ \\\\ Background Job Management\\\\ \\\\ ![Avatar of Ian Macartney](https://cdn.sanity.io/images/ts10onj4/production/077753b63476b77fb111ba06d1bb538517033a54-3500x3500.jpg)Ian Macartney](https://stack.convex.dev/background-job-management) [Skip to main content](https://docs.convex.dev/quickstart/bun#docusaurus_skipToContent_fallback) Learn how to query data from Convex in a Bun project. For instructions for subscriptions instead of point-in-time queries see [Bun notes](https://docs.convex.dev/client/javascript/bun). # Using Convex with Bun 1. Create a new Bun project Create a new directory for your Bun project. ```codeBlockLines_zEuJ mkdir my-project && cd my-project && bun init -y ``` 2. Install the Convex client and server library Install the `convex` package. ```codeBlockLines_zEuJ bun add convex ``` 3. Set up a Convex dev deployment Next, run `bunx convex dev`. This will prompt you to log in with GitHub, create a project, and save your production and deployment URLs. It will also create a `convex/` folder for you to write your backend API functions in. The `dev` command will then continue running to sync your functions with your dev deployment in the cloud. ```codeBlockLines_zEuJ bunx convex dev ``` 4. Create sample data for your database In a new terminal window, create a `sampleData.jsonl` file with some sample data. sampleData.jsonl ```codeBlockLines_zEuJ {\"text\": \"Buy groceries\", \"isCompleted\": true} {\"text\": \"Go for a swim\", \"isCompleted\": true} {\"text\": \"Integrate Convex\", \"isCompleted\": false} ``` 5. Add the sample data to your database Now that your project is ready, add a `tasks` table with the sample data into your Convex database with the `import` command. ```codeBlockLines_zEuJ bunx convex import --table tasks sampleData.jsonl ``` 6. Expose a database query Add a new file `tasks.js` in the `convex/` folder with a query function that loads the data. Exporting a query function from this file declares an API function named after the file and the export name, `api.tasks.get`. convex/tasks.js ```codeBlockLines_zEuJ import { query } from \"./_generated/server\"; export const get = query({ args: {}, handler: async (ctx) => { return await ctx.db.query(\"tasks\").collect(); }, }); ``` 7. Connect the script to your backend In a new file `index.ts`, create a `ConvexClient` using the URL of your development environment. index.ts ```codeBlockLines_zEuJ import { ConvexClient } from \"convex/browser\"; import { api } from \"./convex/_generated/api.js\"; const client = new ConvexClient(process.env[\"CONVEX_URL\"]); const unsubscribe = client.onUpdate(api.tasks.get, {}, async (tasks) => { console.log(tasks); }); await Bun.sleep(1000); unsubscribe(); await client.close(); ``` 8. Run the script Run the script from the same directory and see the list of tasks logged to the terminal. ```codeBlockLines_zEuJ bun index.ts ``` [Skip to main content](https://docs.convex.dev/file-storage#docusaurus_skipToContent_fallback) File Storage makes it easy to implement file upload in your app, store files from and send files to third-party APIs, and to serve dynamic files to your users. All file types are supported. - [Upload](https://docs.convex.dev/file-storage/upload-files) files to store them in Convex and reference them in your database documents - [Store](https://docs.convex.dev/file-storage/store-files) files generated or fetched from third-party APIs - [Serve](https://docs.convex.dev/file-storage/serve-files) files via URL - [Delete](https://docs.convex.dev/file-storage/delete-files) files stored in Convex - Access file [metadata](https://docs.convex.dev/file-storage/file-metadata) You can manage your stored files on the [dashboard](https://docs.convex.dev/dashboard#file-storage). **Examples:** [File Storage with HTTP Actions](https://github.com/get-convex/convex-demos/tree/main/file-storage-with-http), [File Storage with Queries and Mutations](https://github.com/get-convex/convex-demos/tree/main/file-storage) File storage is in beta File storageis currently a [beta\\\\ feature](https://docs.convex.dev/production/state/#beta-features). If you have feedback or feature requests, [let us know on Discord](https://convex.dev/community)! [Skip to main content](https://docs.convex.dev/database/advanced/occ#docusaurus_skipToContent_fallback) On this page In [Queries](https://docs.convex.dev/functions/query-functions), we mentioned that determinism as important in the way optimistic concurrency control (OCC) was used within Convex. In this section, we'll dive much deeper into _why_. ## Convex Financial, Inc. [​](https://docs.convex.dev/database/advanced/occ\\#convex-financial-inc \"Direct link to Convex Financial, Inc.\") Imagine that you're building a banking app, and therefore your databases stores accounts with balances. You want your users to be able to give each other money, so you write a mutation function that transfers funds from one user's account to another. One run of that transaction might read Alice's account balance, and then Bob's. You then propose to deduct $5 from Alice's account and increase Bob's balance by the same $5. Here's our pseudocode: ```codeBlockLines_zEuJ $14 <- READ Alice $11 <- READ Bob WRITE Alice $9 WRITE Bob $16 ``` This ledger balance transfer is a classic database scenario that requires a guarantee that these write operations will only apply together. It is a really bad thing if only one operation succeeds! ```codeBlockLines_zEuJ $14 <- READ Alice $11 <- READ Bob WRITE Alice $9 *crash* // $5 lost from your bank ``` You need a guarantee that this can never happen. You require transaction atomicity, and Convex provides it. The problem of data correctness is much deeper. Concurrent transactions that read and edit the same records can create _data races_. In the case of our app it's entirely possible that someone deducts Alice's balance right after we read it. Maybe she bought a Coke Zero at the airport with her debit card for $3. ```codeBlockLines_zEuJ $5 Transfer $3 Debit Card Charge ---------------------------------------------------------- $14 <- READ Alice $11 <- READ Bob $14 <- READ Alice WRITE Alice $11 WRITE Alice $9 // Free coke! WRITE Bob $16 ``` Clearly, we need to prevent these types of data races from happening. We need a way to handle these concurrent conflicts. Generally, there are two common approaches. Most traditional databases choose a _pessimistic locking_ strategy. (Pessimism in this case means the strategy assumes conflict will happen ahead of time so seeks to prevent it.) With pessimistic locking, you first need to acquire a lock on Alice's record, and then acquire a lock on Bob's record. Then you can proceed to conduct your transaction, knowing that any other transaction that needed to touch those records will wait until you are done and all your writes are committed. After decades of experience, the drawbacks of pessimistic locking are well understood and undeniable. The biggest limitation arises from real-life networks and computers being inherently unreliable. If the lock holder goes missing for whatever reason half way through its transaction, everyone else that wants to modify any of those records is waiting indefinitely. Not good! Optimistic concurrency control is, as the name states, optimistic. It assumes the transaction will succeed and doesn't worry about locking anything ahead of time. Very brash! How can it be so sure? It does this by treating the transaction as a _declarative proposal_ to write records on the basis of any read record versions (the \"read set\"). At the end of the transaction, the writes all commit if every version in the read set is still the latest version of that record. This means no concurrent conflict occurred. Now using our version read set, let's see how OCC would have prevented the soda-catastrophe above: ```codeBlockLines_zEuJ $5 Transfer $3 Debit Card Charge ---------------------------------------------------------- (v1, $14) <- READ Alice (v7, $11) <- READ Bob (v1, $14) <- READ Alice WRITE Alice $11 IF Alice.v = v1 WRITE Alice = $9, Bob = $16 IF Alice.v = v1, Bob.v = v7 // Fails! Alice is = v2 ``` This is akin to being unable to push your Git repository because you're not at HEAD. We all know in that circumstance, we need to pull, and rebase or merge, etc. ## When OCC loses, determinism wins [​](https://docs.convex.dev/database/advanced/occ\\#when-occ-loses-determinism-wins \"Direct link to When OCC loses, determinism wins\") A naive optimistic concurrency control solution would be to solve this the same way that Git does: require the user/application to resolve the conflict and determine if it is safe to retry. In Convex, however, we don't need to do that. We know the transaction is deterministic. It didn't charge money to Stripe, it didn't write a permanent value out to the filesystem. It had no effect at all other than proposing some atomic changes to Convex tables that were not applied. The determinism means that we can simply re-run the transaction; you never need to worry about temporary data races. We can run several retries if necessary until we succeed to execute the transaction without any conflicts. tip In fact, the Git analogy stays very apt. An OCC conflict means we cannot push because our HEAD is out of date, so we need to rebase our changes and try again. And determinism is what guarantees there is never a \"merge conflict\", so (unlike with Git) this rebase operation will always eventually succeed without developer intervention. ## Snapshot Isolation vs Serializability [​](https://docs.convex.dev/database/advanced/occ\\#snapshot-isolation-vs-serializability \"Direct link to Snapshot Isolation vs Serializability\") It is common for optimistic multi-version concurrency control databases to provide a guarantee of [snapshot isolation](https://en.wikipedia.org/wiki/Snapshot_isolation). This [isolation level](https://en.wikipedia.org/wiki/Isolation_(database_systems)) provides the illusion that all transactions execute on an atomic snapshot of the data but it is vulnerable to [anomalies](https://en.wikipedia.org/wiki/Snapshot_isolation#Definition) where certain combinations of concurrent transactions can yield incorrect results. The implementation of optimistic concurrency control in Convex instead provides true [serializability](https://en.wikipedia.org/wiki/Serializability) and will yield correct results regardless of what transactions are issued concurrently. ## No need to think about this [​](https://docs.convex.dev/database/advanced/occ\\#no-need-to-think-about-this \"Direct link to No need to think about this\") The beauty of this approach is that you can simply write your mutation functions as if they will _always succeed_, and always be guaranteed to be atomic. Aside from sheer curiosity about how Convex works, day to day there's no need to worry about conflicts, locking, or atomicity when you make changes to your tables and documents. The \"obvious way\" to write your mutation functions will just work. - [Convex Financial, Inc.](https://docs.convex.dev/database/advanced/occ#convex-financial-inc) - [When OCC loses, determinism wins](https://docs.convex.dev/database/advanced/occ#when-occ-loses-determinism-wins) - [Snapshot Isolation vs Serializability](https://docs.convex.dev/database/advanced/occ#snapshot-isolation-vs-serializability) - [No need to think about this](https://docs.convex.dev/database/advanced/occ#no-need-to-think-about-this) [Skip to main content](https://docs.convex.dev/production/hosting/netlify#docusaurus_skipToContent_fallback) On this page Hosting your Convex app on Netlify allows you to automatically re-deploy both your backend and your frontend whenever you push your code. ## Deploying to Netlify [​](https://docs.convex.dev/production/hosting/netlify\\#deploying-to-netlify \"Direct link to Deploying to Netlify\") This guide assumes you already have a working React app with Convex. If not follow the [Convex React Quickstart](https://docs.convex.dev/quickstart/react) first. Then: 1. Create a Netlify account If you haven't done so, create a [Netlify](https://netlify.com/) account. This is free for small projects and should take less than a minute to set up. 2. Link your project on Netlify Create a Netlify project at [https://app.netlify.com/start](https://app.netlify.com/start) and link it to the source code repository for your project on GitHub or other Git platform. ![Netlify import project](https://docs.convex.dev/assets/images/netlify_import-a65616c6c06a44eacbd8dd6a58e9ec6b.png) 3. Override the Build command Override the _Build command_ to be `npx convex deploy --cmd 'npm run build'`. If your project lives in a subdirectory of your repository you'll also need to change _Base directory_ in Netlify accordingly. ![Netlify build settings](https://docs.convex.dev/assets/images/netlify_build_settings-3003b87fdb3b152f78ef5e794fb43c4c.png) 4. Set up the CONVEX\\_DEPLOY\\_KEY environment variable On your [Convex Dashboard](https://dashboard.convex.dev/) go to your project's _Settings_ page. Click the _Generate_ button to generate a **Production** deploy key. Then click the copy button to copy the key. In Netlify, click _Add environment variables_ and _New variable_. Create an environment variable `CONVEX_DEPLOY_KEY` and paste in your deploy key. ![Netlify environment variable CONVEX_DEPLOY_KEY](https://docs.convex.dev/assets/images/netlify_prod_deploy_key-e92a5b4d1f17a3c7df3612f3574f3cdf.png) 5. Deploy your site Now click the _Deploy_ button and your work here is done! Netlify will automatically publish your site to a URL `https://.netlify.app` listed at the top of the site overview page. Every time you push to your git repository, Netlify will automatically deploy your Convex functions and publish your site changes. Using a Custom Domain? If you're using a custom domain to serve your Convex functions, you'll need additional configuration. See [Custom\\\\ Domains](https://docs.convex.dev/production/hosting/custom#hosting-with-a-custom-domain) for more information. ### How it works [​](https://docs.convex.dev/production/hosting/netlify\\#how-it-works \"Direct link to How it works\") In Netlify, we overrode the _Build Command_ to be `npx convex deploy --cmd 'npm run build'`. `npx convex deploy` will read `CONVEX_DEPLOY_KEY` from the environment and use it to set the `CONVEX_URL` (or similarly named) environment variable to point to your **production** deployment. Your frontend framework of choice invoked by `npm run build` will read the `CONVEX_URL` environment variable and point your deployed site (via `ConvexReactClient`) at your **production** deployment. Finally, `npx convex deploy` will push your Convex functions to your production deployment. Now, your production deployment has your newest functions and your app is configured to connect to it. You can use `--cmd-url-env-var-name` to customize the variable name used by your frontend code if the `deploy` command cannot infer it, like ```codeBlockLines_zEuJ npx convex deploy --cmd-url-env-var-name CUSTOM_CONVEX_URL --cmd 'npm run build' ``` ## Authentication [​](https://docs.convex.dev/production/hosting/netlify\\#authentication \"Direct link to Authentication\") You will want to configure your [authentication](https://docs.convex.dev/auth) provider (Clerk, Auth0 or other) to accept your production `.netlify.app` URL. ## Deploy Previews [​](https://docs.convex.dev/production/hosting/netlify\\#deploy-previews \"Direct link to Deploy Previews\") Netlify's Deploy Previews allow you to preview changes to your app before they're merged in. In order to preview both changes to frontend code and Convex functions, you can set up [Convex preview deployments](https://docs.convex.dev/production/hosting/preview-deployments). This will create a fresh Convex backend for each preview and leave your production and development deployments unaffected. This assumes you have already followed the steps in [Deploying to Netlify](https://docs.convex.dev/production/hosting/netlify#deploying-to-netlify) above. 1. Set up the CONVEX\\_DEPLOY\\_KEY environment variable On your [Convex Dashboard](https://dashboard.convex.dev/) go to your project's _Settings_ page. Click the _Generate Preview Deploy Key_ button to generate a **Preview** deploy key. Then click the copy button to copy the key. In Netlify, click _Site configuration_ \\> _Environment variables_. Edit your existing `CONVEX_DEPLOY_KEY` environment variable. Select _Different value for each deploy context_ and paste the key under _Deploy Previews_. ![Netlify environment variable CONVEX_DEPLOY_KEY](https://docs.convex.dev/assets/images/netlify_preview_deploy_key-51d8c3210b827a6946d8f9997987616a.png) 2. (optional) Set up default environment variables If your app depends on certain Convex environment variables, you can set up [default\\\\ environment variables](https://docs.convex.dev/production/environment-variables#project-environment-variable-defaults) for preview and development deployments in your project. ![Project Default Environment Variables](https://docs.convex.dev/assets/images/project_default_environment_variables-94be77c692d0a3c9564cb7f642b6cb64.png) 3. (optional) Run a function to set up initial data Deploy Previews run against fresh Convex backends, which do not share data with development or production Convex deployments. You can call a Convex function to set up data by adding `--preview-run 'functionName'` to the `npx convex deploy` command. This function will only be run for preview deployments, and will be ignored when deploying to production. Netlify > Site configuration > Build & deploy > Build settings > Build command ```codeBlockLines_zEuJ npx convex deploy --cmd 'npm run build' --preview-run 'functionName' ``` 4. Now test out creating a PR and generating a Deploy Preview! You can find the Convex deployment for your branch in the Convex dashboard. ![Preview Deployment in Deployment Picker](https://docs.convex.dev/assets/images/preview_deployment_deployment_picker-bc5b5e7cd3ac7e0e44ec7ed4c8b40c1c.png) ### How it works [​](https://docs.convex.dev/production/hosting/netlify\\#how-it-works-1 \"Direct link to How it works\") For Deploy Previews, `npx convex deploy` will read `CONVEX_DEPLOY_KEY` from the environment, and use it to create a Convex deployment associated with the Git branch name for the Deploy Preview. It will set the `CONVEX_URL` (or similarly named) environment variable to point to the new Convex deployment. Your frontend framework of choice invoked by `npm run build` will read the `CONVEX_URL` environment variable and point your deployed site (via `ConvexReactClient`) at the Convex preview deployment. Finally, `npx convex deploy` will push your Convex functions to the preview deployment and run the `--preview-run` function (if provided). This deployment has separate functions, data, crons and all other configuration from any other deployments. `npx convex deploy` will infer the Git branch name for Vercel, Netlify, GitHub, and GitLab environments, but the `--preview-create` option can be used to customize the name associated with the newly created deployment. Production deployments will work exactly the same as before. - [Deploying to Netlify](https://docs.convex.dev/production/hosting/netlify#deploying-to-netlify) - [How it works](https://docs.convex.dev/production/hosting/netlify#how-it-works) - [Authentication](https://docs.convex.dev/production/hosting/netlify#authentication) - [Deploy Previews](https://docs.convex.dev/production/hosting/netlify#deploy-previews) - [How it works](https://docs.convex.dev/production/hosting/netlify#how-it-works-1) [Skip to main content](https://docs.convex.dev/testing#docusaurus_skipToContent_fallback) On this page Convex makes it easy to test your app via automated tests running in JS or against a real backend, and manually in dev, preview and staging environments. ## Automated tests [​](https://docs.convex.dev/testing\\#automated-tests \"Direct link to Automated tests\") ### `convex-test` library [​](https://docs.convex.dev/testing\\#convex-test-library \"Direct link to convex-test-library\") [Use the `convex-test` library](https://docs.convex.dev/testing/convex-test) to test your functions in JS via the excellent Vitest testing framework. ### Testing against a real backend [​](https://docs.convex.dev/testing\\#testing-against-a-real-backend \"Direct link to Testing against a real backend\") Convex open source builds allow you to test all of your backend logic running on a real [local Convex backend](https://docs.convex.dev/testing/convex-backend). ### Set up testing in CI [​](https://docs.convex.dev/testing\\#set-up-testing-in-ci \"Direct link to Set up testing in CI\") It's a good idea to test your app continuously in a controlled environment. No matter which way automated method you use, it's easy to run them with [Github Actions](https://docs.convex.dev/testing/ci). ## Manual tests [​](https://docs.convex.dev/testing\\#manual-tests \"Direct link to Manual tests\") ### Running a function in dev [​](https://docs.convex.dev/testing\\#running-a-function-in-dev \"Direct link to Running a function in dev\") Manually run a function in dev to quickly see if things are working: - [Run functions from the command line](https://docs.convex.dev/cli#run-convex-functions) - [Run functions from the dashboard](https://docs.convex.dev/dashboard/deployments/functions#running-functions) ### Preview deployments [​](https://docs.convex.dev/testing\\#preview-deployments \"Direct link to Preview deployments\") [Use preview deployments](https://docs.convex.dev/production/hosting/preview-deployments) to get early feedback from your team for your in-progress features. ### Staging environment [​](https://docs.convex.dev/testing\\#staging-environment \"Direct link to Staging environment\") You can set up a separate project as a staging environment to test against. See [Deploying Your App to Production](https://docs.convex.dev/production#staging-environment). - [Automated tests](https://docs.convex.dev/testing#automated-tests) - [`convex-test` library](https://docs.convex.dev/testing#convex-test-library) - [Testing against a real backend](https://docs.convex.dev/testing#testing-against-a-real-backend) - [Set up testing in CI](https://docs.convex.dev/testing#set-up-testing-in-ci) - [Manual tests](https://docs.convex.dev/testing#manual-tests) - [Running a function in dev](https://docs.convex.dev/testing#running-a-function-in-dev) - [Preview deployments](https://docs.convex.dev/testing#preview-deployments) - [Staging environment](https://docs.convex.dev/testing#staging-environment) [Skip to main content](https://docs.convex.dev/client/open-api#docusaurus_skipToContent_fallback) On this page Convex doesn’t have explicit support for many languages including Go, Java, and C++. However, you can generate [OpenAPI](https://swagger.io/specification/) specifications from your Convex deployment to create type-safe clients for languages that aren't currently supported. Under the hood, this uses our [HTTP API](https://docs.convex.dev/http-api). This means that your queries will not be reactive/real-time. OAS generation is in beta OAS generationis currently a [beta\\\\ feature](https://docs.convex.dev/production/state/#beta-features). If you have feedback or feature requests, [let us know on Discord](https://convex.dev/community)! ## Setup [​](https://docs.convex.dev/client/open-api\\#setup \"Direct link to Setup\") 1. Install the Convex Helpers npm package Install the `convex-helpers` package, which contains a CLI command to generate an Open API specification. ```codeBlockLines_zEuJ npm install convex-helpers ``` 2. Run a command to generate an OpenAPI specification Running this command will call into your configured Convex deployment and generate an `convex-spec.yaml` file based on it. You can see additional flags by passing `--help` to the command. ```codeBlockLines_zEuJ npx convex-helpers open-api-spec ``` 3. Generate a type-safe client You can use a separate tools to generate a client from the `convex-spec.yaml` file. Some popular options are [OpenAPI Tools](https://github.com/OpenAPITools/openapi-generator) and [Swagger](https://swagger.io/tools/swagger-codegen/). ```codeBlockLines_zEuJ # convex-spec.yaml openapi: 3.0.3 info: title: Convex App - OpenAPI 3.0 version: 0.0.0 servers: - url: \"{hostUrl}\" description: Convex App API ... ``` ## Example [​](https://docs.convex.dev/client/open-api\\#example \"Direct link to Example\") Below are code snippets of what this workflow looks like in action. These snippets include two different files: - `convex/load.ts` \\- contains Convex function definitions - `convex.go` \\- contains `Go` code that uses a generated, type-safe `HTTP` client. This client was generated by installing the [OpenAPI Tools](https://github.com/OpenAPITools/openapi-generator) package and running the command `npx openapi-generator-cli generate -i convex-spec.yaml -g go -o convex_client` convex/load.ts TS ```codeBlockLines_zEuJ import { v } from \"convex/values\"; import { query } from \"./_generated/server\"; import { LinkTable } from \"./schema\"; export const loadOne = query({ args: { normalizedId: v.string(), token: v.string() }, returns: v.union( v.object({ ...LinkTable.validator.fields, _creationTime: v.number(), _id: v.id(\"links\"), }), v.null(), ), handler: async (ctx, { normalizedId, token }) => { if (token === \"\" || token !== process.env.CONVEX_AUTH_TOKEN) { throw new Error(\"Invalid authorization token\"); } return await ctx.db .query(\"links\") .withIndex(\"by_normalizedId\", (q) => q.eq(\"normalizedId\", normalizedId)) .first(); }, }); ``` convex.go ```codeBlockLines_zEuJ type Link struct { Short string // the \"foo\" part of http://go/foo Long string // the target URL or text/template pattern to run Created time.Time LastEdit time.Time // when the link was last edited Owner string // user@domain } func (c *ConvexDB) Load(short string) (*Link, error) { request := *convex.NewRequestLoadLoadOne(*convex.NewRequestLoadLoadOneArgs(short, c.token)) resp, httpRes, err := c.client.QueryAPI.ApiRunLoadLoadOnePost(context.Background()).RequestLoadLoadOne(request).Execute() validationErr := validateResponse(httpRes.StatusCode, err, resp.Status) if validationErr != nil { return nil, validationErr } linkDoc := resp.Value.Get() if linkDoc == nil { err := fs.ErrNotExist return nil, err } link := Link{ Short: linkDoc.Short, Long: linkDoc.Long, Created: time.Unix(int64(linkDoc.Created), 0), LastEdit: time.Unix(int64(linkDoc.LastEdit), 0), Owner: linkDoc.Owner, } return &link, nil ``` ## Limits [​](https://docs.convex.dev/client/open-api\\#limits \"Direct link to Limits\") - Argument and return value validators are not required, but they will enrich the types of your OpenAPI spec. Where validators aren't defined, we default to `v.any()` as the validator. - You cannot call internal functions from outside of your Convex deployment. - We currently do not support `bigints` or `bytes`. - [Setup](https://docs.convex.dev/client/open-api#setup) - [Example](https://docs.convex.dev/client/open-api#example) - [Limits](https://docs.convex.dev/client/open-api#limits) [Skip to main content](https://docs.convex.dev/quickstart/nextjs#docusaurus_skipToContent_fallback) Convex + Next.js Convex is an all-in-one backend and database that integrates quickly and easily with Next.js. Once you've gotten started, see how to set up [hosting](https://docs.convex.dev/production/hosting/) [server rendering](https://docs.convex.dev/client/react/nextjs/server-rendering), and [auth](https://docs.convex.dev/client/react/nextjs/). To get setup quickly with Convex and Next.js run **`npm create convex@latest`** **``** or follow the guide below. * * * Learn how to query data from Convex in a Next.js app using the App Router and TypeScript Alternatively see the [Pages Router](https://docs.convex.dev/client/react/nextjs-pages-router/quickstart) version of this quickstart. 01. Create a React app Create a Next.js app using the `npx create-next-app` command. Choose the default option for every prompt (hit Enter). ```codeBlockLines_zEuJ npx create-next-app@latest my-app ``` 02. Install the Convex client and server library To get started, install the `convex` package which provides a convenient interface for working with Convex from a React app. Navigate to your app and install `convex`. ```codeBlockLines_zEuJ cd my-app && npm install convex ``` 03. Set up a Convex dev deployment Next, run `npx convex dev`. This will prompt you to log in with GitHub, create a project, and save your production and deployment URLs. It will also create a `convex/` folder for you to write your backend API functions in. The `dev` command will then continue running to sync your functions with your dev deployment in the cloud. ```codeBlockLines_zEuJ npx convex dev ``` 04. Create sample data for your database In a new terminal window, create a `sampleData.jsonl` file with some sample data. sampleData.jsonl ```codeBlockLines_zEuJ {\"text\": \"Buy groceries\", \"isCompleted\": true} {\"text\": \"Go for a swim\", \"isCompleted\": true} {\"text\": \"Integrate Convex\", \"isCompleted\": false} ``` 05. Add the sample data to your database Now that your project is ready, add a `tasks` table with the sample data into your Convex database with the `import` command. ```codeBlockLines_zEuJ npx convex import --table tasks sampleData.jsonl ``` 06. Expose a database query Add a new file `tasks.ts` in the `convex/` folder with a query function that loads the data. Exporting a query function from this file declares an API function named after the file and the export name, `api.tasks.get`. convex/tasks.ts TS ```codeBlockLines_zEuJ import { query } from \"./_generated/server\"; export const get = query({ args: {}, handler: async (ctx) => { return await ctx.db.query(\"tasks\").collect(); }, }); ``` 07. Create a client component for the Convex provider Add a new file `ConvexClientProvider.tsx` in the `app/` folder. Include the `\"use client\";` directive, create a `ConvexReactClient` and a component that wraps its children in a `ConvexProvider`. app/ConvexClientProvider.tsx TS ```codeBlockLines_zEuJ \"use client\"; import { ConvexProvider, ConvexReactClient } from \"convex/react\"; import { ReactNode } from \"react\"; const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!); export function ConvexClientProvider({ children }: { children: ReactNode }) { return {children}; } ``` 08. Wire up the ConvexClientProvider In `app/layout.tsx`, wrap the children of the `body` element with the `ConvexClientProvider`. app/layout.tsx TS ```codeBlockLines_zEuJ import type { Metadata } from \"next\"; import { Geist, Geist_Mono } from \"next/font/google\"; import \"./globals.css\"; import { ConvexClientProvider } from \"./ConvexClientProvider\"; const geistSans = Geist({ variable: \"--font-geist-sans\", subsets: [\"latin\"], }); const geistMono = Geist_Mono({ variable: \"--font-geist-mono\", subsets: [\"latin\"], }); export const metadata: Metadata = { title: \"Create Next App\", description: \"Generated by create next app\", }; export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { return ( {children} ); } ``` 09. Display the data in your app In `app/page.tsx`, use the `useQuery` hook to fetch from your `api.tasks.get` API function. app/page.tsx TS ```codeBlockLines_zEuJ \"use client\"; import Image from \"next/image\"; import { useQuery } from \"convex/react\"; import { api } from \"../convex/_generated/api\"; export default function Home() { const tasks = useQuery(api.tasks.get); return (
{tasks?.map(({ _id, text }) =>
{text}
)}
); } ``` 10. Start the app Start the app, open [http://localhost:3000](http://localhost:3000/) in a browser, and see the list of tasks. ```codeBlockLines_zEuJ npm run dev ``` [Skip to main content](https://docs.convex.dev/tutorial/scale#docusaurus_skipToContent_fallback) # Convex Tutorial: Scaling your app Convex was designed from the ground up for scale. In the previous section we already talked about how keeping your actions small and most of your logic in queries and mutations are crucial to building fast scalable backends. Let's talk about a few other ways to keep your app fast and scalable. ## Indexed queries [​](https://docs.convex.dev/tutorial/scale\\#indexed-queries \"Direct link to Indexed queries\") Indexes tell the database to create a lookup structure to make it really fast to filter data. If, in our chat app we wanted to build a way to look up `messages` from just one user, we'd tell Convex to index the `user` field in the `messages` table and write the query with the `withIndex` syntax. [Learn how to use indexes](https://docs.convex.dev/database/reading-data/indexes/). ## Too many writes on the same document [​](https://docs.convex.dev/tutorial/scale\\#too-many-writes-on-the-same-document \"Direct link to Too many writes on the same document\") Let's say you decide to show a counter in your app. You may write a mutation that reads a number field, adds 1, and updates the same field in the database. At some point, this pattern may cause an [optimistic concurrency control conflict](https://docs.convex.dev/error#1). That means that the database isn't able to handle updating the document that fast. All databases have trouble with this sort of pattern. There are a [few ways to deal with this](https://docs.convex.dev/error#remediation), including building something called a sharded counter... But before you go learn advanced scaling techniques on your own, there is a better way with Convex components. ## Scaling best practices with Convex Components [​](https://docs.convex.dev/tutorial/scale\\#scaling-best-practices-with-convex-components \"Direct link to Scaling best practices with Convex Components\") In the case of the counter above, the Convex team has already built a [scalable counter](https://www.convex.dev/components/sharded-counter) Convex component for you to use. Convex components are installed in your Convex backend as an npm library. They are sandboxed, so they can't read your app's tables or call your app's functions unless explicitly provided. As you build more complicated features like AI agent [workflows](https://www.convex.dev/components/workflow), [leaderboards](https://www.convex.dev/components/aggregate), [feature flags](https://www.convex.dev/components/launchdarkly) or [rate limiters](https://www.convex.dev/components/rate-limiter), you may find that there is already a Convex component that solves this problem. [**Components directory**](https://www.convex.dev/components) ## Wrap up [​](https://docs.convex.dev/tutorial/scale\\#wrap-up \"Direct link to Wrap up\") We've covered a lot of ground in this tutorial. We started by [building a chat app](https://docs.convex.dev/tutorial/) with queries, mutations and the database that form the fundamental building blocks of the Convex sync engine. We then called an [external API](https://docs.convex.dev/tutorial/actions) from our backend, using the scheduler to coordinate the work. Finally, we learned that [Convex components](https://www.convex.dev/components) give you scaling best practices in neat packages. If you are looking for more tips, read our [best practices](https://docs.convex.dev/understanding/best-practices/) and join the [community](https://www.convex.dev/community). Convex enables you to build your MVP fast and then scale to new heights. Many great products have already done so. You're in good company. [Skip to main content](https://docs.convex.dev/client/swift#docusaurus_skipToContent_fallback) On this page The Convex Swift client library enables your iOS or macOS application to interact with your Convex backend. It allows your frontend code to: 1. Call your [queries](https://docs.convex.dev/functions/query-functions), [mutations](https://docs.convex.dev/functions/mutation-functions) and [actions](https://docs.convex.dev/functions/actions) 2. Authenticate users using [Auth0](https://docs.convex.dev/auth/auth0) The library is open source and [available on GitHub](https://github.com/get-convex/convex-swift). Follow the [Swift Quickstart](https://docs.convex.dev/quickstart/swift) to get started. ## Installation [​](https://docs.convex.dev/client/swift\\#installation \"Direct link to Installation\") For an iOS or macOS project in Xcode, you’ll need to perform the following steps to add a dependency on the `ConvexMobile` library. 1. Click on the top-level app container in the project navigator on the left 2. Click on the app name under the PROJECT heading 3. Click the _Package Dependencies_ tab 4. Click the + button ![Screenshot 2024-10-02 at 2.33.43 PM.png](https://docs.convex.dev/assets/images/swift_qs_step_2-4edae92b06d29aba638512edc3fcc267.png) 5. Paste [`https://github.com/get-convex/convex-swift`](https://github.com/get-convex/convex-swift) into the search box and press Enter 6. When the `convex-swift` package loads, click the Add Package button 7. In the _Package Products_ dialog, select your product name in the _Add to_ _Target_ dropdown 8. Click _Add Package_ ## Connecting to a backend [​](https://docs.convex.dev/client/swift\\#connecting-to-a-backend \"Direct link to Connecting to a backend\") The `ConvexClient` is used to establish and maintain a connection between your application and the Convex backend. First you need to create an instance of the client by giving it your backend deployment URL: ```codeBlockLines_zEuJ import ConvexMobile let convex = ConvexClient(deploymentUrl: \"https://.convex.cloud\") ``` You should create and use one instance of the `ConvexClient` for the lifetime of your application process. You can store the client in a global constant like shown above. An actual connection to the Convex backend won’t be initiated until you call a method on the `ConvexClient`. After that it will maintain the connection and re-establish it if it gets dropped. ## Fetching data [​](https://docs.convex.dev/client/swift\\#fetching-data \"Direct link to Fetching data\") The Swift Convex library gives you access to the Convex sync engine, which enables real-time _subscriptions_ to query results. You subscribe to queries with the `subscribe` method on `ConvexClient` which returns a [`Publisher`](https://developer.apple.com/documentation/combine). The data available via the `Publisher` will change over time as the underlying data backing the query changes. You can call methods on the `Publisher` to transform and consume the data it provides. A simple way to consume a query that returns a list of strings in a `View` is to use a combination of a `@State` containing a list and the `.task` modifier with code that loops over the query results as an `AsyncSequence`: ```codeBlockLines_zEuJ struct ColorList: View { @State private var colors: [String] = [] var body: some View { List { ForEach(colors, id: \\.self) { color in Text(color) } }.task { let latestColors = convex.subscribe(to: \"colors:get\", yielding: [String].self) .replaceError(with: []) .values for await colors in latestColors { self.colors = colors } } } } ``` Any time the data that powers the backend `\"colors:get\"` query changes, a new array of `String` values will appear in the `AsyncSequence` and the `View`'s `colors` list gets assigned the new data. The UI will then rebuild reactively to reflect the changed data. ### Query arguments [​](https://docs.convex.dev/client/swift\\#query-arguments \"Direct link to Query arguments\") You can pass arguments to `subscribe` and they will be supplied to the associated backend `query` function. The arguments must be a Dictionary keyed with strings and the values should generally be primitive types, Arrays and other Dictionaries. ```codeBlockLines_zEuJ let publisher = convex.subscribe(to: \"colors:get\", with:[\"onlyFavorites\": true], yielding:[String].self) ``` Assuming the `colors:get` query accepts an `onlyFavorites` argument, the value can be received and used to perform logic in the query function. tip Use [Decodable structs](https://docs.convex.dev/client/swift/data-types#custom-data-types) to automatically convert Convex objects to Swift structs. caution - There are important gotchas when [sending and receiving numbers](https://docs.convex.dev/client/swift/data-types#numerical-types) between Swift and Convex. - Depending on your backend functions, you may need to deal with [reserved Swift keywords](https://docs.convex.dev/client/swift/data-types#field-name-conversion). ### Subscription lifetime [​](https://docs.convex.dev/client/swift\\#subscription-lifetime \"Direct link to Subscription lifetime\") The `Publisher` returned from `subscribe` will persist as long as the associated `View` or `ObservableObject`. When either is no longer part of the UI, the underlying query subscription to Convex will be canceled. ## Editing Data [​](https://docs.convex.dev/client/swift\\#editing-data \"Direct link to Editing Data\") You can use the `mutation` method on `ConvexClient` to trigger a backend [mutation](https://docs.convex.dev/functions/mutation-functions). `mutation` is an `async` method so you'll need to call it within a `Task`. Mutations can return a value or not. Mutations can also receive arguments, just like queries. Here's an example of calling a mutation with arguments that returns a value: ```codeBlockLines_zEuJ let isColorAdded: Bool = try await convex.mutation(\"colors:put\", with: [\"color\": newColor]) ``` ### Handling errors [​](https://docs.convex.dev/client/swift\\#handling-errors \"Direct link to Handling errors\") If an error occurs during a call to `mutation`, it will throw. Typically you may want to catch [`ConvexError`](https://docs.convex.dev/functions/error-handling/application-errors) and `ServerError` and handle them however is appropriate in your application. Here’s a small example of how you might handle an error from `colors:put` if it threw a `ConvexError` with an error message if a color already existed. ```codeBlockLines_zEuJ do { try await convex.mutation(\"colors:put\", with: [\"color\": newColor]) } catch ClientError.ConvexError(let data) { errorMessage = try! JSONDecoder().decode(String.self, from: Data(data.utf8)) colorNotAdded = true } ``` See documentation on [error handling](https://docs.convex.dev/functions/error-handling/) for more details. ## Calling third-party APIs [​](https://docs.convex.dev/client/swift\\#calling-third-party-apis \"Direct link to Calling third-party APIs\") You can use the `action` method on `ConvexClient` to trigger a backend [action](https://docs.convex.dev/functions/actions). Calls to `action` can accept arguments, return values and throw exceptions just like calls to `mutation`. Even though you can call actions from your client code, it's not always the right choice. See the action docs for tips on [calling actions from clients](https://docs.convex.dev/functions/actions#calling-actions-from-clients). ## Authentication with Auth0 [​](https://docs.convex.dev/client/swift\\#authentication-with-auth0 \"Direct link to Authentication with Auth0\") You can use `ConvexClientWithAuth` in place of `ConvexClient` to configure authentication with [Auth0](https://auth0.com/). You'll need the `convex-swift-auth0` library to do that, as well as an Auth0 account and application configuration. See the [README](https://github.com/get-convex/convex-swift-auth0/blob/main/README.md) in the `convex-swift-auth0` repo for more detailed setup instructions, and the [Workout example app](https://github.com/get-convex/ios-convex-workout) which is configured for Auth0. The overall [Convex authentication docs](https://docs.convex.dev/auth) are a good resource as well. It should also be possible to integrate other similar OpenID Connect authentication providers. See the [`AuthProvider`](https://github.com/get-convex/convex-swift/blob/c47aea414c92db2ccf3a0fa4f9db8caf2029b032/Sources/ConvexMobile/ConvexMobile.swift#L188) protocol in the `convex-swift` repo for more info. ## Production and dev deployments [​](https://docs.convex.dev/client/swift\\#production-and-dev-deployments \"Direct link to Production and dev deployments\") When you're ready to move toward [production](https://docs.convex.dev/production) for your app, you can setup your Xcode build system to point different build targets to different Convex deployments. Build environment configuration is highly specialized, and it’s possible that you or your team have different conventions, but this is one way to approach the problem. 1. Create “Dev” and “Prod” folders in your project sources. 2. Add an `Env.swift` file in each one with contents like: ```codeBlockLines_zEuJ let deploymentUrl = \"https://$DEV_OR_PROD.convex.cloud\" ``` 3. Put your dev URL in `Dev/Env.swift` and your prod URL in `Prod/Env.swift`. Don’t worry if Xcode complains that `deploymentUrl` is defined multiple times. 4. Click on your top-level project in the explorer view on the left. 5. Select your build target from the **TARGETS** list. 6. Change the target’s name so it ends in “dev”. 7. Right/Ctrl-click it and duplicate it, giving it a name that ends in “prod”. 8. With the “dev” target selected, click the **Build Phases** tab. 9. Expand the **Compile Sources** section. 10. Select `Prod/Env.swift` and remove it with the - button. 11. Likewise, open the “prod” target and remove `Dev/Env.swift` from its sources. ![Screenshot 2024-10-03 at 1.34.34 PM.png](https://docs.convex.dev/assets/images/swift_env_setup-39f43c73bf9c8599957530a43582ca3d.png) Now you can refer to `deploymentUrl` wherever you create your `ConvexClient` and depending on the target that you build, it will use your dev or prod URL. ## Structuring your application [​](https://docs.convex.dev/client/swift\\#structuring-your-application \"Direct link to Structuring your application\") The examples shown in this guide are intended to be brief, and don't provide guidance on how to structure a whole application. If you want a more robust and layered approach, put your code that interacts with `ConvexClient` in a class that conforms to `ObservableObject`. Then your `View` can observe that object as a `@StateObject` and will rebuild whenever it changes. For example, if we adapt the `colors:get` example from above to a `ViewModel: ObservableObject` class, the `View` no longer plays a direct part in fetching the data - it only knows that the list of `colors` is provided by the `ViewModel`. ```codeBlockLines_zEuJ import SwiftUI class ViewModel: ObservableObject { @Published var colors: [String] = [] init() { convex.subscribe(to: \"colors:get\") .replaceError(with: []) .receive(on: DispatchQueue.main) .assign(to: &$colors) } } struct ContentView: View { @StateObject var viewModel = ViewModel() var body: some View { List { ForEach(viewModel.colors, id: \\.self) { color in Text(color) } } } } ``` Depending on your needs and the scale of your app, it might make sense to give it even more formal structure as demonstrated in something like [https://github.com/nalexn/clean-architecture-swiftui](https://github.com/nalexn/clean-architecture-swiftui). ## Under the hood [​](https://docs.convex.dev/client/swift\\#under-the-hood \"Direct link to Under the hood\") The Swift Convex library is built on top of the official [Convex Rust client](https://docs.convex.dev/client/rust). It handles maintaining a WebSocket connection with the Convex backend and implements the full Convex protocol. All method calls on `ConvexClient` are handled via a Tokio async runtime on the Rust side and are safe to call from the application's main actor. - [Installation](https://docs.convex.dev/client/swift#installation) - [Connecting to a backend](https://docs.convex.dev/client/swift#connecting-to-a-backend) - [Fetching data](https://docs.convex.dev/client/swift#fetching-data) - [Query arguments](https://docs.convex.dev/client/swift#query-arguments) - [Subscription lifetime](https://docs.convex.dev/client/swift#subscription-lifetime) - [Editing Data](https://docs.convex.dev/client/swift#editing-data) - [Handling errors](https://docs.convex.dev/client/swift#handling-errors) - [Calling third-party APIs](https://docs.convex.dev/client/swift#calling-third-party-apis) - [Authentication with Auth0](https://docs.convex.dev/client/swift#authentication-with-auth0) - [Production and dev deployments](https://docs.convex.dev/client/swift#production-and-dev-deployments) - [Structuring your application](https://docs.convex.dev/client/swift#structuring-your-application) - [Under the hood](https://docs.convex.dev/client/swift#under-the-hood) [Skip to main content](https://docs.convex.dev/search/using-cursor#docusaurus_skipToContent_fallback) [Cursor](https://cursor.com/), the AI code editor, makes it easy to write and maintain apps built with Convex. Let's walk through how to setup Cursor for the best possible results with Convex. # Add Convex to Cursor’s Docs [Cursor composer agent](https://docs.cursor.com/composer/overview#agent), the main AI coding agent built into Cursor, uses Claude as it's LLM model of choice. While Claude knows about Convex, its knowledge can be patchy or outdated. We need to give it a helping hand by using the [Cursors Docs](https://docs.cursor.com/context/@-symbols/@-docs) feature to give it the most up-to-date knowledge of Convex. From **`Cursor Settings`** > **`Features`** > **`Docs`** add new doc, use the URL \" [https://docs.convex.dev/](https://docs.convex.dev/)\" ![Chat UI]() Cursor will then index all of the Convex docs for the LLM to use. ![Chat UI](https://docs.convex.dev/assets/images/indexed_docs-90bb59330756c00540015c53da6a484c.webp) You can then reference those docs in your prompt with the `@Convex` symbol. ![Chat UI](https://docs.convex.dev/assets/images/reference_convex_docs-c791c41ddbd7663244fda1c4c59a43d9.webp) Add more Convex knowledge You can perform the above steps for [https://stack.convex.dev/](https://stack.convex.dev/) too if you would like to provide even more context to the agent. # Install and run Convex yourself Keeping Convex running is crucial because [it automatically generates](https://docs.convex.dev/cli#run-the-convex-dev-server) the client-side types. Without this, the agent can get stuck in a linting loop since it can't access the types for the queries and mutations it created. We recommended that you install ( `npm install convex`) and run convex ( `npx convex dev`) yourself in a terminal window. # Use a `convex_instructions.md` to fine-tune Convex behavior even further Despite Claude’s inbuilt knowledge of Convex plus referencing `@Convex` docs the LLM does still make silly Convex mistakes from time to time. To reduce this even more create a `convex_instructions.md` file in `/instructions` directory. Then reference it from your prompt. ![Chat UI](https://docs.convex.dev/assets/images/convex_instructions-c857878c3a3726d951cff4e80121743b.webp) To get you started see this one we have been using: [convex\\_instructions.md](https://gist.github.com/mikecann/0dc25aeae0d06a88c3da71c1e026ae47) Copy the above to your project then reference it in your prompts. You can edit it as needed. Cursor Notepads Cursor does have a beta feature called [Notepads](https://docs.cursor.com/features/beta/notepads#notepads) that may be a better way to do this in the future. # Keep your requests small and git commit frequently The best results when using agentic LLMs can be found when keeping the amount of changes you want to make small. This lets you be more specific around the context you provide the agent and it means the agent doesn't need to do a lot of searching for context. After each successful prompt or series of prompts it is a good idea to commit your changes so that its simple to rollback to that point should the next prompt cause issues. # Update and reference your `README.md` The agent needs context about the specific business goals for your project. While it can infer some details from the files it reads, this becomes more challenging as your project grows. Providing general information about your project gives the agent a helpful head start. Rather than including this information in each prompt, it's better to write a comprehensive README.md file in your project root and reference it. [Some people](https://youtu.be/2PjmPU07KNs?t=145) advocate for crafting a Product Requirements Document (PRD), this may be a good idea for more complex projects. [Skip to main content](https://docs.convex.dev/quickstart/tanstack-start#docusaurus_skipToContent_fallback) TanStack Start is in Alpha [TanStack Start](https://tanstack.com/start/latest) is a new React framework currently in beta. You can try it today but there are likely to be breaking changes before a stable release. To get setup quickly with Convex and TanStack Start run **`npm create convex@latest -- -t tanstack-start`** **``** or follow the guide below. To use Clerk with Convex and TanStack Start, see the [TanStack Start + Clerk guide](https://docs.convex.dev/client/react/tanstack-start/tanstack-start-with-clerk) * * * Learn how to query data from Convex in a TanStack Start site. 01. Create a TanStack Start site The TanStack team intends to release a CLI template starter soon, but until the official way to create a new TanStack Start site is to follow the TanStack Start [getting started](https://tanstack.com/router/latest/docs/framework/react/start/getting-started) guide. Once you've finished you'll have a directory called myApp with a minimal TanStack Start app in it. ```codeBlockLines_zEuJ . ├── app/ │ ├── routes/ │ │ ├── `index.tsx` │ │ └── `__root.tsx` │ ├── `client.tsx` │ ├── `router.tsx` │ ├── `routeTree.gen.ts` │ └── `ssr.tsx` ├── `.gitignore` ├── `app.config.ts` ├── `package.json` └── `tsconfig.json` ``` 02. Install the Convex client and server library To get started with Convex install the `convex` package and a few React Query-related packages. ```codeBlockLines_zEuJ npm install convex @convex-dev/react-query @tanstack/react-router-with-query @tanstack/react-query ``` 03. Update app/routes/\\_\\_root.tsx Add a `QueryClient` to the router context to make React Query usable anywhere in the TanStack Start site. app/routes/\\_\\_root.tsx ```codeBlockLines_zEuJ import { QueryClient } from \"@tanstack/react-query\"; import { createRootRouteWithContext } from \"@tanstack/react-router\"; import { Outlet, ScrollRestoration } from \"@tanstack/react-router\"; import { Meta, Scripts } from \"@tanstack/start\"; import * as React from \"react\"; export const Route = createRootRouteWithContext<{ queryClient: QueryClient; }>()({ head: () => ({ meta: [\\ {\\ charSet: \"utf-8\",\\ },\\ {\\ name: \"viewport\",\\ content: \"width=device-width, initial-scale=1\",\\ },\\ {\\ title: \"TanStack Start Starter\",\\ },\\ ], }), component: RootComponent, }); function RootComponent() { return ( ); } function RootDocument({ children }: { children: React.ReactNode }) { return ( {children} ); } ``` 04. Update app/router.tsx Replace the file `app/router.tsx` with these contents. This creates a `ConvexClient` and a `ConvexQueryClient` and wires in a `ConvexProvider`. app/router.tsx ```codeBlockLines_zEuJ import { createRouter as createTanStackRouter } from \"@tanstack/react-router\"; import { QueryClient } from \"@tanstack/react-query\"; import { routerWithQueryClient } from \"@tanstack/react-router-with-query\"; import { ConvexQueryClient } from \"@convex-dev/react-query\"; import { ConvexProvider } from \"convex/react\"; import { routeTree } from \"./routeTree.gen\"; export function createRouter() { const CONVEX_URL = (import.meta as any).env.VITE_CONVEX_URL!; if (!CONVEX_URL) { console.error(\"missing envar VITE_CONVEX_URL\"); } const convexQueryClient = new ConvexQueryClient(CONVEX_URL); const queryClient: QueryClient = new QueryClient({ defaultOptions: { queries: { queryKeyHashFn: convexQueryClient.hashFn(), queryFn: convexQueryClient.queryFn(), }, }, }); convexQueryClient.connect(queryClient); const router = routerWithQueryClient( createTanStackRouter({ routeTree, defaultPreload: \"intent\", context: { queryClient }, Wrap: ({ children }) => ( {children} ), }), queryClient, ); return router; } declare module \"@tanstack/react-router\" { interface Register { router: ReturnType; } } ``` 05. Set up a Convex dev deployment Next, run `npx convex dev`. This will prompt you to log in with GitHub, create a project, and save your production and deployment URLs. It will also create a `convex/` folder for you to write your backend API functions in. The `dev` command will then continue running to sync your functions with your dev deployment in the cloud. ```codeBlockLines_zEuJ npx convex dev ``` 06. Create sample data for your database In a new terminal window, create a `sampleData.jsonl` file with some sample data. sampleData.jsonl ```codeBlockLines_zEuJ {\"text\": \"Buy groceries\", \"isCompleted\": true} {\"text\": \"Go for a swim\", \"isCompleted\": true} {\"text\": \"Integrate Convex\", \"isCompleted\": false} ``` 07. Add the sample data to your database Now that your project is ready, add a `tasks` table with the sample data into your Convex database with the `import` command. ```codeBlockLines_zEuJ npx convex import --table tasks sampleData.jsonl ``` 08. Expose a database query Add a new file `tasks.ts` in the `convex/` folder with a query function that loads the data. Exporting a query function from this file declares an API function named after the file and the export name, `api.tasks.get`. convex/tasks.ts ```codeBlockLines_zEuJ import { query } from \"./_generated/server\"; export const get = query({ args: {}, handler: async (ctx) => { return await ctx.db.query(\"tasks\").collect(); }, }); ``` 09. Display the data in your app Replace the file `app/routes/index.tsx` with these contents. The `useSuspenseQuery` hook renders the API function `api.tasks.get` query result on the server initially, then it updates live in the browser. app/routes/index.tsx ```codeBlockLines_zEuJ import { convexQuery } from \"@convex-dev/react-query\"; import { useSuspenseQuery } from \"@tanstack/react-query\"; import { createFileRoute } from \"@tanstack/react-router\"; import { api } from \"../../convex/_generated/api\"; export const Route = createFileRoute(\"/\")({ component: Home, }); function Home() { const { data } = useSuspenseQuery(convexQuery(api.tasks.get, {})); return (
{data.map(({ _id, text }) => (
{text}
))}
); } ``` 10. Start the app Start the app, open [http://localhost:3000](http://localhost:3000/) in a browser, and see the list of tasks. ```codeBlockLines_zEuJ npm run dev ``` For more see the [TanStack Start with Convex](https://docs.convex.dev/client/react/tanstack-start/) client documentation page. [Skip to main content](https://docs.convex.dev/tutorial#docusaurus_skipToContent_fallback) # Convex Tutorial: A chat app Convex provides you with a fully featured backend with cloud functions, database, scheduling, and a sync engine that keeps your frontend and backend up to date in real-time. Today, in about **10 lines of code,** we'll build a backend that reads and writes to the database and automatically updates all users in a chat app. After that we'll see how to connect to external services and setup your product for success and scale. ## Start developing with Convex [​](https://docs.convex.dev/tutorial\\#start-developing-with-convex \"Direct link to Start developing with Convex\") Before you begin: You'll need Node.js 18+ and Git Ensure you have Node.js version 18 or greater installed on your computer. You can check your version of Node.js by running `node --version` in your terminal. If you don't have the appropriate version of Node.js installed, [install it from the Node.js website.](https://nodejs.org/en) In addition, this walkthrough requires Git, so verify you have it installed by running `git -v` in your terminal. If not, head over to the [Git website](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) for installation instructions. First, clone the example project repo from GitHub and install the dependencies: ```codeBlockLines_zEuJ git clone https://github.com/get-convex/convex-tutorial.git cd convex-tutorial npm install ``` This app's `dev` npm command sets up Convex and then runs the web app: ```codeBlockLines_zEuJ npm run dev ``` During setup, you'll see that Convex uses your GitHub account for authentication. Sign into Convex with GitHub and then accept the default project setup prompts. This will **automatically create your backend** and a folder called `convex/` in your project, where you'll write your backend code. **Make sure you keep this command ( `npm run dev`) running in the background** **throughout this tutorial.** It's running both the dev web server for the frontend as well as the `convex` command in the background to keep your backend in sync with your local codebase. Once your server is up and running, open [localhost:5173](http://localhost:5173/) and check it out: ![Chat UI](https://docs.convex.dev/assets/images/tut_chat_ui-9ab95f331e3132c9c61a0e2fc4eaf16c.png) If you try sending a message now, you'll see an alert telling you the mutation is not yet implemented. We'll do that in a bit, but first here's a quick summary of how Convex works. ## How Convex works [​](https://docs.convex.dev/tutorial\\#how-convex-works \"Direct link to How Convex works\") ![Overview of the sync engine](https://docs.convex.dev/assets/images/ConvexSyncEngine-3271d28868180073da72479d72a5d93e.png) **Database.** The Convex database is a document-relational database, which means you have tables with JSON like documents in them. All documents have an auto-generated `_id` that can be used to create relations between documents. You interact with the database through mutation and query functions that are written entirely in TypeScript. **Mutation functions.** Mutations are TypeScript functions that update the database. All mutation functions in Convex run as a database transaction. So either all the changes are committed, or none are. **Query functions.** Queries are TypeScript functions that can only read from the database. As we'll see in a bit, you subscribe to them from your frontend to keep your app automatically up to date. Your frontend registers to listen to query updates through the **client** **library**. The client libraries talk to Convex via WebSockets for fast realtime updates. The **sync engine** reruns query functions when any input to the function changes, including any changes to the documents in the database that the query reads. It then updates every app listening to the query. The sync engine is the combination of queries, mutations and the database. Now, let's dive into the code! ## Your first `mutation` [​](https://docs.convex.dev/tutorial\\#your-first-mutation \"Direct link to your-first-mutation\") Create a new file in your `convex/` folder called `chat.ts`. This is where you'll write your Convex backend functions for this application. **Add the following to your `convex/chat.ts` file.** ```codeBlockLines_zEuJ import { mutation } from \"./_generated/server\"; import { v } from \"convex/values\"; export const sendMessage = mutation({ args: { user: v.string(), body: v.string(), }, handler: async (ctx, args) => { console.log(\"This TypeScript function is running on the server.\"); await ctx.db.insert(\"messages\", { user: args.user, body: args.body, }); }, }); ``` Let's break this down: 1. You've added a new backend `mutation` function called `sendMessage` and exposed it as a public api. 2. The whole function automatically runs as a transaction that will roll back if an exception is thrown. 3. Since this is just a TypeScript function you can drop `console.log` lines to do simple debugging on the server. 4. `args:` ensures the function arguments are two strings named `user` and `body`, both as types and runtime values. 5. `ctx.db.insert` tells Convex to insert a new message document into the table. Now, let's connect this mutation to your web app. **Update your `src/App.tsx` file like so:** ```codeBlockLines_zEuJ // Import `useMutation` and `api` from Convex. import { useMutation } from \"convex/react\"; import { api } from \"../convex/_generated/api\"; //... export default function App() { // Replace the \"TODO: Add mutation hook here.\" with: const sendMessage = useMutation(api.chat.sendMessage); //... return (
{/* ... */}
{ e.preventDefault(); // Replace \"alert(\"Mutation not implemented yet\");\" with: await sendMessage({ user: NAME, body: newMessageText }); setNewMessageText(\"\"); }} > {/* ... */}
); } ``` There are two steps to call a mutation in your frontend: 1. `const sendMessage = useMutation(api.chat.sendMessage);` gives your frontend app a handle to the mutation function 2. `await sendMessage({ user: NAME, body: newMessageText });` calls the mutation with the proper parameters. This is a good time to **open up the Convex dashboard**. Open a new browser window and go to [https://dashboard.convex.dev](https://dashboard.convex.dev/) and find new `convex-tutorial` project. **Go to the \"Data\" screen**. So far, there is no data in your database. **Keep your chat app and dashboard windows open side by side**. Now try to send some messages from your chat app. Mutations hooked up to the Convex backend and database. You'll notice new chat messages showing up live in the `messages` table. Convex automatically created a `messages` table when you sent the first message. In Convex, [schemas](https://docs.convex.dev/database/schemas) are optional. Eventually, you'll want to enforce the structure of your tables, but for the purposes of the tutorial we'll skip this. In the dashboard you can also go to the [logs screen](https://dashboard.convex.dev/deployment/logs) and see every call to the mutation as you ran with the log line we added earlier. The logs screen is a critical part of debugging your backend in development. You've successfully created a `mutation` function, which is also a database transaction, and connected it to your UI. Now, let's make sure your app can update live the same way the dashboard is updating live. ## Your first `query` [​](https://docs.convex.dev/tutorial\\#your-first-query \"Direct link to your-first-query\") **Update your `convex/chat.ts` file like this:** ```codeBlockLines_zEuJ // Update your server import like this: import { query, mutation } from \"./_generated/server\"; // ... // Add the following function to the file: export const getMessages = query({ args: {}, handler: async (ctx) => { // Get most recent messages first const messages = await ctx.db.query(\"messages\").order(\"desc\").take(50); // Reverse the list so that it's in a chronological order. return messages.reverse(); }, }); ``` Let's break this down: 1. You've added a new backend `query` function called `getMessages` and exposed it as a public api. 2. Since this is a query function, the `ctx.db` in this function only lets you read data. 3. In the first line of the `handler` you are querying the most recent 50 messages from newest to oldest. 4. In the second line you're reversing the list using plain old TypeScript. **Now update `src/App.tsx` to read from your query:** ```codeBlockLines_zEuJ // Update your convex/react import like this: import { useQuery, useMutation } from \"convex/react\"; //... export default function App() { // Replace the `const messages = ...` line with the following const messages = useQuery(api.chat.getMessages); //... } ``` That one `useQuery` line is doing a lot of work automatically for you. It's telling the Convex client library to subscribe to your `getMessages` function. Anytime there are new messages to show the query function is automatically rerun. The result is put in `const messages` variable and React rerenders your UI component to show the latest messages. That's it. Now go back to your app and try sending messages. Your app should be showing live updates as new messages arrive: Queries hooked up and live updating to the app. Don't believe it? Try opening two chat windows side by side and send some messages: Live syncing chat app. ## What you built [​](https://docs.convex.dev/tutorial\\#what-you-built \"Direct link to What you built\") With just a few lines of code you've built a live updating chat app. 1. You created a `mutation` TypeScript function that, in a transaction, adds new chat messages to your database. 2. You created a `query` TypeScript function updates your app with the latest data. 3. You used the client library that keeps your frontend in live sync with the backend. You've learned the fundamentals of Convex and the sync engine that powers everything. ## Next up [​](https://docs.convex.dev/tutorial\\#next-up \"Direct link to Next up\") In this tutorial we just touched on the very basics. It's ok to just stop here and go explore the rest of the docs, including [efficient queries via indexes](https://docs.convex.dev/database/reading-data/indexes/) and traversing [relationships through joins](https://docs.convex.dev/database/reading-data/#join). If you're deeply curious about how Convex works, you can read this [excellent deep dive](https://stack.convex.dev/how-convex-works). But if you want to see how to call external services and build sophisticated backend workflows, jump into the [next section →](https://docs.convex.dev/tutorial/actions). [**Calling external services** \\\\ \\\\ In the previous step, you built a fully](https://docs.convex.dev/tutorial/actions) [Skip to main content](https://docs.convex.dev/api/modules/react_clerk#docusaurus_skipToContent_fallback) On this page React login component for use with Clerk. ## Functions [​](https://docs.convex.dev/api/modules/react_clerk\\#functions \"Direct link to Functions\") ### ConvexProviderWithClerk [​](https://docs.convex.dev/api/modules/react_clerk\\#convexproviderwithclerk \"Direct link to ConvexProviderWithClerk\") ▸ **ConvexProviderWithClerk**( `«destructured»`): `Element` A wrapper React component which provides a [ConvexReactClient](https://docs.convex.dev/api/classes/react.ConvexReactClient) authenticated with Clerk. It must be wrapped by a configured `ClerkProvider`, from `@clerk/clerk-react`, `@clerk/clerk-expo`, `@clerk/nextjs` or another React-based Clerk client library and have the corresponding `useAuth` hook passed in. See [Convex Clerk](https://docs.convex.dev/auth/clerk) on how to set up Convex with Clerk. #### Parameters [​](https://docs.convex.dev/api/modules/react_clerk\\#parameters \"Direct link to Parameters\") | Name | Type | | :-- | :-- | | `«destructured»` | `Object` | | › `children` | `ReactNode` | | › `client` | `IConvexReactClient` | | › `useAuth` | `UseAuth` | #### Returns [​](https://docs.convex.dev/api/modules/react_clerk\\#returns \"Direct link to Returns\") `Element` #### Defined in [​](https://docs.convex.dev/api/modules/react_clerk\\#defined-in \"Direct link to Defined in\") [react-clerk/ConvexProviderWithClerk.tsx:41](https://github.com/get-convex/convex-js/blob/main/src/react-clerk/ConvexProviderWithClerk.tsx#L41) - [Functions](https://docs.convex.dev/api/modules/react_clerk#functions) - [ConvexProviderWithClerk](https://docs.convex.dev/api/modules/react_clerk#convexproviderwithclerk) [Skip to main content](https://docs.convex.dev/client/react#docusaurus_skipToContent_fallback) On this page Convex React is the client library enabling your React application to interact with your Convex backend. It allows your frontend code to: 1. Call your [queries](https://docs.convex.dev/functions/query-functions), [mutations](https://docs.convex.dev/functions/mutation-functions) and [actions](https://docs.convex.dev/functions/actions) 2. Upload and display files from [File Storage](https://docs.convex.dev/file-storage) 3. Authenticate users using [Authentication](https://docs.convex.dev/auth) 4. Implement full text [Search](https://docs.convex.dev/search) over your data The Convex React client is open source and available on [GitHub](https://github.com/get-convex/convex-js). Follow the [React Quickstart](https://docs.convex.dev/quickstart/react) to get started with React using [Vite](https://vitejs.dev/). ## Installation [​](https://docs.convex.dev/client/react\\#installation \"Direct link to Installation\") Convex React is part of the `convex` npm package: ```codeBlockLines_zEuJ npm install convex ``` ## Connecting to a backend [​](https://docs.convex.dev/client/react\\#connecting-to-a-backend \"Direct link to Connecting to a backend\") The [`ConvexReactClient`](https://docs.convex.dev/api/classes/react.ConvexReactClient) maintains a connection to your Convex backend, and is used by the React hooks described below to call your functions. First you need to create an instance of the client by giving it your backend deployment URL. See [Configuring Deployment URL](https://docs.convex.dev/client/react/deployment-urls) on how to pass in the right value: ```codeBlockLines_zEuJ import { ConvexProvider, ConvexReactClient } from \"convex/react\"; const convex = new ConvexReactClient(\"https://.convex.cloud\"); ``` And then you make the client available to your app by passing it in to a [`ConvexProvider`](https://docs.convex.dev/api/modules/react#convexprovider) wrapping your component tree: ```codeBlockLines_zEuJ reactDOMRoot.render( , ); ``` ## Fetching data [​](https://docs.convex.dev/client/react\\#fetching-data \"Direct link to Fetching data\") Your React app fetches data using the [`useQuery`](https://docs.convex.dev/api/modules/react#usequery) React hook by calling your [queries](https://docs.convex.dev/functions/query-functions) via an [`api`](https://docs.convex.dev/generated-api/api#api) object. The `npx convex dev` command generates this api object for you in the `convex/_generated/api.js` module to provide better autocompletion in JavaScript and end-to-end type safety in [TypeScript](https://docs.convex.dev/understanding/best-practices/typescript): src/App.tsx TS ```codeBlockLines_zEuJ import { useQuery } from \"convex/react\"; import { api } from \"../convex/_generated/api\"; export function App() { const data = useQuery(api.functions.myQuery); return data ?? \"Loading...\"; } ``` The `useQuery` hook returns `undefined` while the data is first loading and afterwards the return value of your query. ### Query arguments [​](https://docs.convex.dev/client/react\\#query-arguments \"Direct link to Query arguments\") Arguments to your query follow the query name: src/App.tsx TS ```codeBlockLines_zEuJ export function App() { const a = \"Hello world\"; const b = 4; const data = useQuery(api.functions.myQuery, { a, b }); //... } ``` ### Reactivity [​](https://docs.convex.dev/client/react\\#reactivity \"Direct link to Reactivity\") The `useQuery` hook makes your app automatically reactive: when the underlying data changes in your database, your component rerenders with the new query result. The first time the hook is used it creates a subscription to your backend for a given query and any arguments you pass in. When your component unmounts, the subscription is canceled. ### Consistency [​](https://docs.convex.dev/client/react\\#consistency \"Direct link to Consistency\") Convex React ensures that your application always renders a consistent view of the query results based on a single state of the underlying database. Imagine a mutation changes some data in the database, and that 2 different `useQuery` call sites rely on this data. Your app will never render in an inconsistent state where only one of the `useQuery` call sites reflects the new data. ### Paginating queries [​](https://docs.convex.dev/client/react\\#paginating-queries \"Direct link to Paginating queries\") See [Paginating within React Components](https://docs.convex.dev/database/pagination#paginating-within-react-components). ### Skipping queries [​](https://docs.convex.dev/client/react\\#skipping-queries \"Direct link to Skipping queries\") Advanced: Loading a query conditionally With React it can be tricky to dynamically invoke a hook, because hooks cannot be placed inside conditionals or after early returns: src/App.tsx TS ```codeBlockLines_zEuJ import { useQuery } from \"convex/react\"; import { api } from \"../convex/_generated/api\"; export function App() { // the URL `param` might be null const param = new URLSearchParams(window.location.search).get(\"param\"); // ERROR! React Hook \"useQuery\" is called conditionally. React Hooks must // be called in the exact same order in every component render. const data = param !== null ? useQuery(api.functions.read, { param }) : null; //... } ``` For this reason `useQuery` can be \"disabled\" by passing in `\"skip\"` instead of its arguments: src/App.tsx TS ```codeBlockLines_zEuJ import { useQuery } from \"convex/react\"; import { api } from \"../convex/_generated/api\"; export function App() { const param = new URLSearchParams(window.location.search).get(\"param\"); const data = useQuery( api.functions.read, param !== null ? { param } : \"skip\", ); //... } ``` When `\"skip\"` is used the `useQuery` doesn't talk to your backend at all and returns `undefined`. ### One-off queries [​](https://docs.convex.dev/client/react\\#one-off-queries \"Direct link to One-off queries\") Advanced: Fetching a query from a callback Sometimes you might want to read state from the database in response to a user action, for example to validate given input, without making any changes to the database. In this case you can use a one-off [`query`](https://docs.convex.dev/api/classes/react.ConvexReactClient#query) call, similarly to calling mutations and actions. The async method `query` is exposed on the `ConvexReactClient`, which you can reference in your components via the [`useConvex()`](https://docs.convex.dev/api/modules/react#useconvex) hook. src/App.tsx TS ```codeBlockLines_zEuJ import { useConvex } from \"convex/react\"; import { api } from \"../convex/_generated/api\"; export function App() { const convex = useConvex(); return ( ); } ``` ## Editing data [​](https://docs.convex.dev/client/react\\#editing-data \"Direct link to Editing data\") Your React app edits data using the [`useMutation`](https://docs.convex.dev/api/modules/react#usemutation) React hook by calling your [mutations](https://docs.convex.dev/functions/mutation-functions). The `convex dev` command generates this api object for you in the `convex/_generated/api.js` module to provide better autocompletion in JavaScript and end-to-end type safety in [TypeScript](https://docs.convex.dev/understanding/best-practices/typescript): src/App.tsx TS ```codeBlockLines_zEuJ import { useMutation } from \"convex/react\"; import { api } from \"../convex/_generated/api\"; export function App() { const doSomething = useMutation(api.functions.doSomething); return ; } ``` The hook returns an `async` function which performs the call to the mutation. ### Mutation arguments [​](https://docs.convex.dev/client/react\\#mutation-arguments \"Direct link to Mutation arguments\") Arguments to your mutation are passed to the `async` function returned from `useMutation`: src/App.tsx TS ```codeBlockLines_zEuJ export function App() { const a = \"Hello world\"; const b = 4; const doSomething = useMutation(api.functions.doSomething); return ; } ``` ### Mutation response and error handling [​](https://docs.convex.dev/client/react\\#mutation-response-and-error-handling \"Direct link to Mutation response and error handling\") The mutation can optionally return a value or throw errors, which you can [`await`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await): src/App.tsx TS ```codeBlockLines_zEuJ export function App() { const doSomething = useMutation(api.functions.doSomething); const onClick = () => { async function callBackend() { try { const result = await doSomething(); } catch (error) { console.error(error); } console.log(result); } void callBackend(); }; return ; } ``` Or handle as a [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise): src/App.tsx TS ```codeBlockLines_zEuJ export function App() { const doSomething = useMutation(api.functions.doSomething); const onClick = () => { doSomething() .catch((error) => { console.error(error); }) .then((result) => { console.log(result); }); }; return ; } ``` Learn more about [Error Handling](https://docs.convex.dev/functions/error-handling/) in functions. ### Retries [​](https://docs.convex.dev/client/react\\#retries \"Direct link to Retries\") Convex React automatically retries mutations until they are confirmed to have been written to the database. The Convex backend ensures that despite multiple retries, every mutation call only executes once. Additionally, Convex React will warn users if they try to close their browser tab while there are outstanding mutations. This means that when you call a Convex mutation, you can be sure that the user's edits won't be lost. ### Optimistic updates [​](https://docs.convex.dev/client/react\\#optimistic-updates \"Direct link to Optimistic updates\") Convex queries are fully reactive, so all query results will be automatically updated after a mutation. Sometimes you may want to update the UI before the mutation changes propagate back to the client. To accomplish this, you can configure an _optimistic update_ to execute as part of your mutation. Optimistic updates are temporary, local changes to your query results which are used to make your app more responsive. See [Optimistic Updates](https://docs.convex.dev/client/react/optimistic-updates) on how to configure them. ## Calling third-party APIs [​](https://docs.convex.dev/client/react\\#calling-third-party-apis \"Direct link to Calling third-party APIs\") Your React app can read data, call third-party services, and write data with a single backend call using the [`useAction`](https://docs.convex.dev/api/modules/react#useaction) React hook by calling your [actions](https://docs.convex.dev/functions/actions). Like `useQuery` and `useMutation`, this hook is used with the `api` object generated for you in the `convex/_generated/api.js` module to provide better autocompletion in JavaScript and end-to-end type safety in [TypeScript](https://docs.convex.dev/understanding/best-practices/typescript): src/App.tsx TS ```codeBlockLines_zEuJ import { useAction } from \"convex/react\"; import { api } from \"../convex/_generated/api\"; export function App() { const doSomeAction = useAction(api.functions.doSomeAction); return ; } ``` The hook returns an `async` function which performs the call to the action. ### Action arguments [​](https://docs.convex.dev/client/react\\#action-arguments \"Direct link to Action arguments\") Action arguments work exactly the same as [mutation arguments](https://docs.convex.dev/client/react#mutation-arguments). ### Action response and error handling [​](https://docs.convex.dev/client/react\\#action-response-and-error-handling \"Direct link to Action response and error handling\") Action response and error handling work exactly the same as [mutation response and error handling](https://docs.convex.dev/client/react#mutation-response-and-error-handling). Actions do not support automatic retries or optimistic updates. ## Under the hood [​](https://docs.convex.dev/client/react\\#under-the-hood \"Direct link to Under the hood\") The [`ConvexReactClient`](https://docs.convex.dev/api/classes/react.ConvexReactClient) connects to your Convex deployment by creating a [`WebSocket`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket). The WebSocket provides a 2-way communication channel over TCP. This allows Convex to push new query results reactively to the client without the client needing to poll for updates. If the internet connection drops, the client will handle reconnecting and re-establishing the Convex session automatically. - [Installation](https://docs.convex.dev/client/react#installation) - [Connecting to a backend](https://docs.convex.dev/client/react#connecting-to-a-backend) - [Fetching data](https://docs.convex.dev/client/react#fetching-data) - [Query arguments](https://docs.convex.dev/client/react#query-arguments) - [Reactivity](https://docs.convex.dev/client/react#reactivity) - [Consistency](https://docs.convex.dev/client/react#consistency) - [Paginating queries](https://docs.convex.dev/client/react#paginating-queries) - [Skipping queries](https://docs.convex.dev/client/react#skipping-queries) - [One-off queries](https://docs.convex.dev/client/react#one-off-queries) - [Editing data](https://docs.convex.dev/client/react#editing-data) - [Mutation arguments](https://docs.convex.dev/client/react#mutation-arguments) - [Mutation response and error handling](https://docs.convex.dev/client/react#mutation-response-and-error-handling) - [Retries](https://docs.convex.dev/client/react#retries) - [Optimistic updates](https://docs.convex.dev/client/react#optimistic-updates) - [Calling third-party APIs](https://docs.convex.dev/client/react#calling-third-party-apis) - [Action arguments](https://docs.convex.dev/client/react#action-arguments) - [Action response and error handling](https://docs.convex.dev/client/react#action-response-and-error-handling) - [Under the hood](https://docs.convex.dev/client/react#under-the-hood) [Skip to main content](https://docs.convex.dev/api/modules/browser#docusaurus_skipToContent_fallback) On this page Tools for accessing Convex in the browser. **If you are using React, use the [react](https://docs.convex.dev/api/modules/react) module instead.** ## Usage [​](https://docs.convex.dev/api/modules/browser\\#usage \"Direct link to Usage\") Create a [ConvexHttpClient](https://docs.convex.dev/api/classes/browser.ConvexHttpClient) to connect to the Convex Cloud. ```codeBlockLines_zEuJ import { ConvexHttpClient } from \"convex/browser\"; // typically loaded from an environment variable const address = \"https://small-mouse-123.convex.cloud\"; const convex = new ConvexHttpClient(address); ``` ## Classes [​](https://docs.convex.dev/api/modules/browser\\#classes \"Direct link to Classes\") - [ConvexHttpClient](https://docs.convex.dev/api/classes/browser.ConvexHttpClient) - [ConvexClient](https://docs.convex.dev/api/classes/browser.ConvexClient) - [BaseConvexClient](https://docs.convex.dev/api/classes/browser.BaseConvexClient) ## Interfaces [​](https://docs.convex.dev/api/modules/browser\\#interfaces \"Direct link to Interfaces\") - [BaseConvexClientOptions](https://docs.convex.dev/api/interfaces/browser.BaseConvexClientOptions) - [SubscribeOptions](https://docs.convex.dev/api/interfaces/browser.SubscribeOptions) - [MutationOptions](https://docs.convex.dev/api/interfaces/browser.MutationOptions) - [OptimisticLocalStore](https://docs.convex.dev/api/interfaces/browser.OptimisticLocalStore) ## Type Aliases [​](https://docs.convex.dev/api/modules/browser\\#type-aliases \"Direct link to Type Aliases\") ### ConvexClientOptions [​](https://docs.convex.dev/api/modules/browser\\#convexclientoptions \"Direct link to ConvexClientOptions\") Ƭ **ConvexClientOptions**: [`BaseConvexClientOptions`](https://docs.convex.dev/api/interfaces/browser.BaseConvexClientOptions) & { `disabled?`: `boolean` ; `unsavedChangesWarning?`: `boolean` } #### Defined in [​](https://docs.convex.dev/api/modules/browser\\#defined-in \"Direct link to Defined in\") [browser/simple\\_client.ts:26](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L26) * * * ### ConnectionState [​](https://docs.convex.dev/api/modules/browser\\#connectionstate \"Direct link to ConnectionState\") Ƭ **ConnectionState**: `Object` State describing the client's connection with the Convex backend. #### Type declaration [​](https://docs.convex.dev/api/modules/browser\\#type-declaration \"Direct link to Type declaration\") | Name | Type | | :-- | :-- | | `hasInflightRequests` | `boolean` | | `isWebSocketConnected` | `boolean` | | `timeOfOldestInflightRequest` | `Date` \\| `null` | #### Defined in [​](https://docs.convex.dev/api/modules/browser\\#defined-in-1 \"Direct link to Defined in\") [browser/sync/client.ts:108](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L108) * * * ### FunctionResult [​](https://docs.convex.dev/api/modules/browser\\#functionresult \"Direct link to FunctionResult\") Ƭ **FunctionResult**: `FunctionSuccess` \\| `FunctionFailure` The result of running a function on the server. If the function hit an exception it will have an `errorMessage`. Otherwise it will produce a `Value`. #### Defined in [​](https://docs.convex.dev/api/modules/browser\\#defined-in-2 \"Direct link to Defined in\") [browser/sync/function\\_result.ts:11](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/function_result.ts#L11) * * * ### OptimisticUpdate [​](https://docs.convex.dev/api/modules/browser\\#optimisticupdate \"Direct link to OptimisticUpdate\") Ƭ **OptimisticUpdate** < `Args` >: ( `localQueryStore`: [`OptimisticLocalStore`](https://docs.convex.dev/api/interfaces/browser.OptimisticLocalStore), `args`: `Args`) =\\> `void` #### Type parameters [​](https://docs.convex.dev/api/modules/browser\\#type-parameters \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Args` | extends `Record` < `string`, [`Value`](https://docs.convex.dev/api/modules/values#value) > | #### Type declaration [​](https://docs.convex.dev/api/modules/browser\\#type-declaration-1 \"Direct link to Type declaration\") ▸ ( `localQueryStore`, `args`): `void` A temporary, local update to query results within this client. This update will always be executed when a mutation is synced to the Convex server and rolled back when the mutation completes. Note that optimistic updates can be called multiple times! If the client loads new data while the mutation is in progress, the update will be replayed again. ##### Parameters [​](https://docs.convex.dev/api/modules/browser\\#parameters \"Direct link to Parameters\") | Name | Type | Description | | :-- | :-- | :-- | | `localQueryStore` | [`OptimisticLocalStore`](https://docs.convex.dev/api/interfaces/browser.OptimisticLocalStore) | An interface to read and edit local query results. | | `args` | `Args` | The arguments to the mutation. | ##### Returns [​](https://docs.convex.dev/api/modules/browser\\#returns \"Direct link to Returns\") `void` #### Defined in [​](https://docs.convex.dev/api/modules/browser\\#defined-in-3 \"Direct link to Defined in\") [browser/sync/optimistic\\_updates.ts:90](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/optimistic_updates.ts#L90) * * * ### QueryJournal [​](https://docs.convex.dev/api/modules/browser\\#queryjournal \"Direct link to QueryJournal\") Ƭ **QueryJournal**: `string` \\| `null` A serialized representation of decisions made during a query's execution. A journal is produced when a query function first executes and is re-used when a query is re-executed. Currently this is used to store pagination end cursors to ensure that pages of paginated queries will always end at the same cursor. This enables gapless, reactive pagination. `null` is used to represent empty journals. #### Defined in [​](https://docs.convex.dev/api/modules/browser\\#defined-in-4 \"Direct link to Defined in\") [browser/sync/protocol.ts:112](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/protocol.ts#L112) * * * ### QueryToken [​](https://docs.convex.dev/api/modules/browser\\#querytoken \"Direct link to QueryToken\") Ƭ **QueryToken**: `string` A string representing the name and arguments of a query. This is used by the [BaseConvexClient](https://docs.convex.dev/api/classes/browser.BaseConvexClient). #### Defined in [​](https://docs.convex.dev/api/modules/browser\\#defined-in-5 \"Direct link to Defined in\") [browser/sync/udf\\_path\\_utils.ts:27](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/udf_path_utils.ts#L27) * * * ### UserIdentityAttributes [​](https://docs.convex.dev/api/modules/browser\\#useridentityattributes \"Direct link to UserIdentityAttributes\") Ƭ **UserIdentityAttributes**: `Omit` < [`UserIdentity`](https://docs.convex.dev/api/interfaces/server.UserIdentity), `\"tokenIdentifier\"` > #### Defined in [​](https://docs.convex.dev/api/modules/browser\\#defined-in-6 \"Direct link to Defined in\") [server/authentication.ts:146](https://github.com/get-convex/convex-js/blob/main/src/server/authentication.ts#L146) - [Usage](https://docs.convex.dev/api/modules/browser#usage) - [Classes](https://docs.convex.dev/api/modules/browser#classes) - [Interfaces](https://docs.convex.dev/api/modules/browser#interfaces) - [Type Aliases](https://docs.convex.dev/api/modules/browser#type-aliases) - [ConvexClientOptions](https://docs.convex.dev/api/modules/browser#convexclientoptions) - [ConnectionState](https://docs.convex.dev/api/modules/browser#connectionstate) - [FunctionResult](https://docs.convex.dev/api/modules/browser#functionresult) - [OptimisticUpdate](https://docs.convex.dev/api/modules/browser#optimisticupdate) - [QueryJournal](https://docs.convex.dev/api/modules/browser#queryjournal) - [QueryToken](https://docs.convex.dev/api/modules/browser#querytoken) - [UserIdentityAttributes](https://docs.convex.dev/api/modules/browser#useridentityattributes) [Skip to main content](https://docs.convex.dev/auth/auth0#docusaurus_skipToContent_fallback) On this page [Auth0](https://auth0.com/) is an authentication platform providing login via passwords, social identity providers, one-time email or SMS access codes, multi-factor authentication, and single sign on and basic user management. **Example:** [Convex Authentication with Auth0](https://github.com/get-convex/convex-demos/tree/main/users-and-auth) If you're using Next.js see the [Next.js setup guide](https://docs.convex.dev/client/react/nextjs). ## Get started [​](https://docs.convex.dev/auth/auth0\\#get-started \"Direct link to Get started\") This guide assumes you already have a working React app with Convex. If not follow the [Convex React Quickstart](https://docs.convex.dev/quickstart/react) first. Then: 1. Follow the Auth0 React quickstart Follow the [Auth0 React Quickstart](https://auth0.com/docs/quickstart/spa/react/interactive). Sign up for a free Auth0 account. Configure your application, using `http://localhost:3000, http://localhost:5173` for Callback and Logout URLs and Allowed Web Origins. Come back when you finish the _Install the Auth0 React SDK_ step. ![Sign up to Auth0](https://docs.convex.dev/screenshots/auth0-signup.png) 2. Create the auth config In the `convex` folder create a new file `auth.config.ts` with the server-side configuration for validating access tokens. Paste in the `domain` and `clientId` values shown in _Install the Auth0 React SDK_ step of the Auth0 quickstart or in your Auth0 application's Settings dashboard. convex/auth.config.ts TS ```codeBlockLines_zEuJ export default { providers: [\\ {\\ domain: \"your-domain.us.auth0.com\",\\ applicationID: \"yourclientid\",\\ },\\ ] }; ``` 3. Deploy your changes Run `npx convex dev` to automatically sync your configuration to your backend. ```codeBlockLines_zEuJ npx convex dev ``` 4. Configure ConvexProviderWithAuth0 Now replace your `ConvexProvider` with an `Auth0Provider` wrapping `ConvexProviderWithAuth0`. Add the `domain` and `clientId` as props to the `Auth0Provider`. Paste in the `domain` and `clientId` values shown in _Install the Auth0 React SDK_ step of the Auth0 quickstart or in your Auth0 application's Settings dashboard as props to `Auth0Provider`. src/main.tsx TS ```codeBlockLines_zEuJ import React from \"react\"; import ReactDOM from \"react-dom/client\"; import App from \"./App\"; import \"./index.css\"; import { ConvexReactClient } from \"convex/react\"; import { ConvexProviderWithAuth0 } from \"convex/react-auth0\"; import { Auth0Provider } from \"@auth0/auth0-react\"; const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL as string); ReactDOM.createRoot(document.getElementById(\"root\")!).render( , ); ``` ## Login and logout flows [​](https://docs.convex.dev/auth/auth0\\#login-and-logout-flows \"Direct link to Login and logout flows\") Now that you have everything set up, you can use the [`useAuth0()`](https://auth0.github.io/auth0-react/functions/useAuth0.html) hook to create login and logout buttons for your app. The login button will redirect the user to the Auth0 universal login page. For details see [Add Login to Your Application](https://auth0.com/docs/quickstart/spa/react/interactive#add-login-to-your-application) in the Auth0 React Quickstart. src/login.ts TS ```codeBlockLines_zEuJ import { useAuth0 } from \"@auth0/auth0-react\"; export default function LoginButton() { const { loginWithRedirect } = useAuth0(); return ; } ``` The logout button will redirect the user to the Auth0 logout endpoint. For details see [Add Logout to your Application](https://auth0.com/docs/quickstart/spa/react/interactive#add-logout-to-your-application) in the Auth0 React Quickstart. src/logout.ts TS ```codeBlockLines_zEuJ import { useAuth0 } from \"@auth0/auth0-react\"; export default function LogoutButton() { const { logout } = useAuth0(); return ( ); } ``` ## Logged-in and logged-out views [​](https://docs.convex.dev/auth/auth0\\#logged-in-and-logged-out-views \"Direct link to Logged-in and logged-out views\") Use the [`useConvexAuth()`](https://docs.convex.dev/api/modules/react#useconvexauth) hook instead of the `useAuth0` hook when you need to check whether the user is logged in or not. The `useConvex` hook makes sure that the browser has fetched the auth token needed to make authenticated requests to your Convex backend: src/App.ts TS ```codeBlockLines_zEuJ import { useConvexAuth } from \"convex/react\"; function App() { const { isLoading, isAuthenticated } = useConvexAuth(); return (
{isAuthenticated ? \"Logged in\" : \"Logged out or still loading\"}
); } ``` You can also use the `Authenticated`, `Unauthenticated` and `AuthLoading` helper components which use the `useConvexAuth` hook under the hood: src/App.ts TS ```codeBlockLines_zEuJ import { Authenticated, Unauthenticated, AuthLoading } from \"convex/react\"; function App() { return (
Logged in Logged out Still loading
); } ``` ## User information in React [​](https://docs.convex.dev/auth/auth0\\#user-information-in-react \"Direct link to User information in React\") You can access information about the authenticated user like their name from the `useAuth0` hook: src/badge.ts TS ```codeBlockLines_zEuJ import { useAuth0 } from \"@auth0/auth0-react\"; export default function Badge() { const { user } = useAuth0(); return Logged in as {user.name}; } ``` ## User information in functions [​](https://docs.convex.dev/auth/auth0\\#user-information-in-functions \"Direct link to User information in functions\") See [Auth in Functions](https://docs.convex.dev/auth/functions-auth) to learn about how to access information about the authenticated user in your queries, mutations and actions. See [Storing Users in the Convex Database](https://docs.convex.dev/auth/database-auth) to learn about how to store user information in the Convex database. ## Configuring dev and prod tenants [​](https://docs.convex.dev/auth/auth0\\#configuring-dev-and-prod-tenants \"Direct link to Configuring dev and prod tenants\") To configure a different Auth0 tenant (environment) between your Convex development and production deployments you can use environment variables configured on the Convex dashboard. ### Configuring the backend [​](https://docs.convex.dev/auth/auth0\\#configuring-the-backend \"Direct link to Configuring the backend\") First, change your `auth.config.ts` file to use environment variables: convex/auth.config.ts TS ```codeBlockLines_zEuJ export default { providers: [\\ {\\ domain: process.env.AUTH0_DOMAIN,\\ applicationID: process.env.AUTH0_CLIENT_ID,\\ },\\ ], }; ``` **Development configuration** Open the Settings for your dev deployment on the Convex [dashboard](https://dashboard.convex.dev/) and add the variables there: ![Convex dashboard dev deployment settings](https://docs.convex.dev/screenshots/auth0-convex-dashboard.png) Now switch to the new configuration by running `npx convex dev`. **Production configuration** Similarly on the Convex [dashboard](https://dashboard.convex.dev/) switch to your production deployment in the left side menu and set the values for your production Auth0 tenant there. Now switch to the new configuration by running `npx convex deploy`. ### Configuring a React client [​](https://docs.convex.dev/auth/auth0\\#configuring-a-react-client \"Direct link to Configuring a React client\") To configure your client you can use environment variables as well. The exact name of the environment variables and the way to refer to them depends on each client platform (Vite vs Next.js etc.), refer to our corresponding [Quickstart](https://docs.convex.dev/quickstarts) or the relevant documentation for the platform you're using. Change the props to `Auth0Provider` to take in environment variables: src/main.tsx TS ```codeBlockLines_zEuJ import React from \"react\"; import ReactDOM from \"react-dom/client\"; import App from \"./App\"; import \"./index.css\"; import { ConvexReactClient } from \"convex/react\"; import { ConvexProviderWithAuth0 } from \"convex/react-auth0\"; import { Auth0Provider } from \"@auth0/auth0-react\"; const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL as string); ReactDOM.createRoot(document.getElementById(\"root\")!).render( , ); ``` **Development configuration** Use the `.env.local` or `.env` file to configure your client when running locally. The name of the environment variables file depends on each client platform (Vite vs Next.js etc.), refer to our corresponding [Quickstart](https://docs.convex.dev/quickstarts) or the relevant documentation for the platform you're using: .env.local ```codeBlockLines_zEuJ VITE_AUTH0_DOMAIN=\"your-domain.us.auth0.com\" VITE_AUTH0_CLIENT_ID=\"yourclientid\" ``` **Production configuration** Set the environment variables in your production environment depending on your hosting platform. See [Hosting](https://docs.convex.dev/production/hosting/). ## Debugging authentication [​](https://docs.convex.dev/auth/auth0\\#debugging-authentication \"Direct link to Debugging authentication\") If a user goes through the Auth0 login flow successfully, and after being redirected back to your page `useConvexAuth` gives `isAuthenticated: false`, it's possible that your backend isn't correctly configured. The `auth.config.ts` file in your `convex/` directory contains a list of configured authentication providers. You must run `npx convex dev` or `npx convex deploy` after adding a new provider to sync the configuration to your backend. For more thorough debugging steps, see [Debugging Authentication](https://docs.convex.dev/auth/debug). ## Under the hood [​](https://docs.convex.dev/auth/auth0\\#under-the-hood \"Direct link to Under the hood\") The authentication flow looks like this under the hood: 1. The user clicks a login button 2. The user is redirected to a page where they log in via whatever method you configure in Auth0 3. After a successful login Auth0 redirects back to your page, or a different page which you configure via the [`authorizationParams`](https://auth0.github.io/auth0-react/interfaces/AuthorizationParams.html) prop. 4. The `Auth0Provider` now knows that the user is authenticated. 5. The `ConvexProviderWithAuth0` fetches an auth token from Auth0. 6. The `ConvexReactClient` passes this token down to your Convex backend to validate 7. Your Convex backend retrieves the public key from Auth0 to check that the token's signature is valid. 8. The `ConvexReactClient` is notified of successful authentication, and `ConvexProviderWithAuth0` now knows that the user is authenticated with Convex. `useConvexAuth` returns `isAuthenticated: true` and the `Authenticated` component renders its children. `ConvexProviderWithAuth0` takes care of refetching the token when needed to make sure the user stays authenticated with your backend. - [Get started](https://docs.convex.dev/auth/auth0#get-started) - [Login and logout flows](https://docs.convex.dev/auth/auth0#login-and-logout-flows) - [Logged-in and logged-out views](https://docs.convex.dev/auth/auth0#logged-in-and-logged-out-views) - [User information in React](https://docs.convex.dev/auth/auth0#user-information-in-react) - [User information in functions](https://docs.convex.dev/auth/auth0#user-information-in-functions) - [Configuring dev and prod tenants](https://docs.convex.dev/auth/auth0#configuring-dev-and-prod-tenants) - [Configuring the backend](https://docs.convex.dev/auth/auth0#configuring-the-backend) - [Configuring a React client](https://docs.convex.dev/auth/auth0#configuring-a-react-client) - [Debugging authentication](https://docs.convex.dev/auth/auth0#debugging-authentication) - [Under the hood](https://docs.convex.dev/auth/auth0#under-the-hood) [Skip to main content](https://docs.convex.dev/auth/clerk#docusaurus_skipToContent_fallback) On this page [Clerk](https://clerk.com/) is an authentication platform providing login via passwords, social identity providers, one-time email or SMS access codes, and multi-factor authentication and basic user management. **Example:** [TanStack Start with Convex and Clerk](https://github.com/get-convex/convex-demos/tree/main/tanstack-start-clerk) To use Clerk with Convex you'll need to complete at least steps 1 through 7 of this list. If you're using Next.js see the [Next.js setup guide](https://docs.convex.dev/client/react/nextjs/) after step 7. If you're using TanStack Start see the [TanStack Start setup guide](https://docs.convex.dev/client/react/tanstack-start/tanstack-start-with-clerk) after step 7. ## Get started [​](https://docs.convex.dev/auth/clerk\\#get-started \"Direct link to Get started\") This guide assumes you already have a working React app with Convex. If not follow the [Convex React Quickstart](https://docs.convex.dev/quickstart/react) first. Then: 01. Sign up for Clerk Sign up for a free Clerk account at [clerk.com/sign-up](https://dashboard.clerk.com/sign-up). ![Sign up to Clerk](https://docs.convex.dev/screenshots/clerk-signup.png) 02. Create an application in Clerk Choose how you want your users to sign in. ![Create a Clerk application](https://docs.convex.dev/screenshots/clerk-createapp.png) 03. Create a JWT Template In the JWT Templates section of the Clerk dashboard tap on _+ New template_ and choose **Convex** Copy the _Issuer_ URL from the Issuer input field. Hit _Apply Changes_. Note: Do NOT rename the JWT token, it must be called `convex`. ![Create a JWT template](https://docs.convex.dev/screenshots/clerk-createjwt.png) 04. Create the auth config In the `convex` folder create a new file `auth.config.ts` with the server-side configuration for validating access tokens. Paste in the _Issuer_ URL from the JWT template and set `applicationID` to `\"convex\"` (the value of the `\"aud\"` _Claims_ field). convex/auth.config.ts TS ```codeBlockLines_zEuJ export default { providers: [\\ {\\ domain: \"https://your-issuer-url.clerk.accounts.dev/\",\\ applicationID: \"convex\",\\ },\\ ] }; ``` 05. Deploy your changes Run `npx convex dev` to automatically sync your configuration to your backend. ```codeBlockLines_zEuJ npx convex dev ``` 06. Install clerk In a new terminal window, install the Clerk React library ```codeBlockLines_zEuJ npm install @clerk/clerk-react ``` 07. Get your Clerk Publishable key On the Clerk dashboard in the API Keys section copy the Publishable key ![Clerk publishable key setting](https://docs.convex.dev/assets/images/clerk-pkey-da3c2fc00a2f4fbb8e726b139f023531.png) 08. Configure ConvexProviderWithClerk Now replace your `ConvexProvider` with `ClerkProvider` wrapping `ConvexProviderWithClerk`. Pass the Clerk `useAuth` hook to the `ConvexProviderWithClerk`. Paste the Publishable key as a prop to `ClerkProvider`. src/main.tsx TS ```codeBlockLines_zEuJ import React from \"react\"; import ReactDOM from \"react-dom/client\"; import App from \"./App\"; import \"./index.css\"; import { ClerkProvider, useAuth } from \"@clerk/clerk-react\"; import { ConvexProviderWithClerk } from \"convex/react-clerk\"; import { ConvexReactClient } from \"convex/react\"; const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL as string); ReactDOM.createRoot(document.getElementById(\"root\")!).render( , ); ``` 09. Show UI based on authentication state You can control which UI is shown when the user is signed in or signed out with the provided components from `\"convex/react\"` and `\"@clerk/clerk-react\"`. To get started create a shell that will let the user sign in and sign out. Because the `Content` component is a child of `Authenticated`, within it and any of its children authentication is guaranteed and Convex queries can require it. src/App.tsx TS ```codeBlockLines_zEuJ import { SignInButton, UserButton } from \"@clerk/clerk-react\"; import { Authenticated, Unauthenticated, useQuery } from \"convex/react\"; import { api } from \"../convex/_generated/api\"; function App() { return (
); } function Content() { const messages = useQuery(api.messages.getForCurrentUser); return
Authenticated content: {messages?.length}
; } export default App; ``` 10. Use authentication state in your Convex functions If the client is authenticated, you can access the information stored in the JWT via `ctx.auth.getUserIdentity`. If the client isn't authenticated, `ctx.auth.getUserIdentity` will return `null`. **Make sure that the component calling this query is a child of `Authenticated` from** **`\"convex/react\"`**, otherwise it will throw on page load. convex/messages.ts TS ```codeBlockLines_zEuJ import { query } from \"./_generated/server\"; export const getForCurrentUser = query({ args: {}, handler: async (ctx) => { const identity = await ctx.auth.getUserIdentity(); if (identity === null) { throw new Error(\"Not authenticated\"); } return await ctx.db .query(\"messages\") .filter((q) => q.eq(q.field(\"author\"), identity.email)) .collect(); }, }); ``` ## Login and logout Flows [​](https://docs.convex.dev/auth/clerk\\#login-and-logout-flows \"Direct link to Login and logout Flows\") Now that you have everything set up, you can use the [`SignInButton`](https://clerk.com/docs/components/authentication/sign-in) component to create a login flow for your app. The login button will open the Clerk configured login dialog: src/App.tsx TS ```codeBlockLines_zEuJ import { SignInButton } from \"@clerk/clerk-react\"; function App() { return (
); } ``` To enable a logout flow you can use the [`SignOutButton`](https://clerk.com/docs/components/unstyled/sign-out-button) or the [`UserButton`](https://clerk.com/docs/components/user/user-button) which opens a dialog that includes a sign out button. ## Logged-in and logged-out views [​](https://docs.convex.dev/auth/clerk\\#logged-in-and-logged-out-views \"Direct link to Logged-in and logged-out views\") Use the [`useConvexAuth()`](https://docs.convex.dev/api/modules/react#useconvexauth) hook instead of Clerk's `useAuth` hook when you need to check whether the user is logged in or not. The `useConvexAuth` hook makes sure that the browser has fetched the auth token needed to make authenticated requests to your Convex backend, and that the Convex backend has validated it: src/App.ts TS ```codeBlockLines_zEuJ import { useConvexAuth } from \"convex/react\"; function App() { const { isLoading, isAuthenticated } = useConvexAuth(); return (
{isAuthenticated ? \"Logged in\" : \"Logged out or still loading\"}
); } ``` You can also use the `Authenticated`, `Unauthenticated` and `AuthLoading` helper components instead of the similarly named Clerk components. These components use the `useConvex` hook under the hood: src/App.ts TS ```codeBlockLines_zEuJ import { Authenticated, Unauthenticated, AuthLoading } from \"convex/react\"; function App() { return (
Logged in Logged out Still loading
); } ``` ## User information in functions [​](https://docs.convex.dev/auth/clerk\\#user-information-in-functions \"Direct link to User information in functions\") See [Auth in Functions](https://docs.convex.dev/auth/functions-auth) to learn about how to access information about the authenticated user in your queries, mutations and actions. See [Storing Users in the Convex Database](https://docs.convex.dev/auth/database-auth) to learn about how to store user information in the Convex database. ## User information in React [​](https://docs.convex.dev/auth/clerk\\#user-information-in-react \"Direct link to User information in React\") You can access information about the authenticated user like their name from Clerk's [`useUser`](https://clerk.com/docs/reference/clerk-react/useuser) hook. See the [User doc](https://clerk.com/docs/reference/clerkjs/user) for the list of available fields: src/badge.ts TS ```codeBlockLines_zEuJ import { useUser } from \"@clerk/clerk-react\"; export default function Badge() { const { user } = useUser(); return Logged in as {user.fullName}; } ``` ## Next.js, React Native Expo, Gatsby [​](https://docs.convex.dev/auth/clerk\\#nextjs-react-native-expo-gatsby \"Direct link to Next.js, React Native Expo, Gatsby\") The `ConvexProviderWithClerk` component supports all Clerk integrations based on the `@clerk/clerk-react` library. Replace the package from which you import the `ClerkProvider` component and follow any additional steps in Clerk docs. ## Configuring dev and prod instances [​](https://docs.convex.dev/auth/clerk\\#configuring-dev-and-prod-instances \"Direct link to Configuring dev and prod instances\") To configure a different Clerk instance between your Convex development and production deployments you can use environment variables configured on the Convex dashboard. ### Configuring the backend [​](https://docs.convex.dev/auth/clerk\\#configuring-the-backend \"Direct link to Configuring the backend\") First, change your `auth.config.ts` file to use an environment variable: convex/auth.config.ts TS ```codeBlockLines_zEuJ export default { providers: [\\ {\\ domain: process.env.CLERK_JWT_ISSUER_DOMAIN,\\ applicationID: \"convex\",\\ },\\ ], }; ``` **Development configuration** Open the Settings for your dev deployment on the Convex [dashboard](https://dashboard.convex.dev/) and add the variables there: ![Convex dashboard dev deployment settings](https://docs.convex.dev/screenshots/clerk-convex-dashboard.png) Now switch to the new configuration by running `npx convex dev`. **Production configuration** Similarly on the Convex [dashboard](https://dashboard.convex.dev/) switch to your production deployment in the left side menu and set the values for your production Clerk instance there. Now switch to the new configuration by running `npx convex deploy`. ### Configuring a React client [​](https://docs.convex.dev/auth/clerk\\#configuring-a-react-client \"Direct link to Configuring a React client\") To configure your client you can use environment variables as well. The exact name of the environment variables and the way to refer to them depends on each client platform (Vite vs Next.js etc.), refer to our corresponding [Quickstart](https://docs.convex.dev/quickstarts) or the relevant documentation for the platform you're using. Change the props to `ClerkProvider` to take in an environment variable: src/main.tsx TS ```codeBlockLines_zEuJ import React from \"react\"; import ReactDOM from \"react-dom/client\"; import App from \"./App\"; import \"./index.css\"; import { ClerkProvider, useAuth } from \"@clerk/clerk-react\"; import { ConvexProviderWithClerk } from \"convex/react-clerk\"; import { ConvexReactClient } from \"convex/react\"; const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL as string); ReactDOM.createRoot(document.getElementById(\"root\")!).render( , ); ``` **Development configuration** Use the `.env.local` or `.env` file to configure your client when running locally. The name of the environment variables file depends on each client platform (Vite vs Next.js etc.), refer to our corresponding [Quickstart](https://docs.convex.dev/quickstarts) or the relevant documentation for the platform you're using: .env.local ```codeBlockLines_zEuJ VITE_CLERK_PUBLISHABLE_KEY=\"pk_test_...\" ``` **Production configuration** Set the environment variable in your production environment depending on your hosting platform. See [Hosting](https://docs.convex.dev/production/hosting/). ## Debugging authentication [​](https://docs.convex.dev/auth/clerk\\#debugging-authentication \"Direct link to Debugging authentication\") If a user goes through the Clerk login flow successfully, and after being redirected back to your page `useConvexAuth` gives `isAuthenticated: false`, it's possible that your backend isn't correctly configured. The `auth.config.ts` file in your `convex/` directory contains a list of configured authentication providers. You must run `npx convex dev` or `npx convex deploy` after adding a new provider to sync the configuration to your backend. For more thorough debugging steps, see [Debugging Authentication](https://docs.convex.dev/auth/debug). ## Under the hood [​](https://docs.convex.dev/auth/clerk\\#under-the-hood \"Direct link to Under the hood\") The authentication flow looks like this under the hood: 1. The user clicks a login button 2. The user is redirected to a page where they log in via whatever method you configure in Clerk 3. After a successful login Clerk redirects back to your page, or a different page which you configure via the [`afterSignIn`](https://clerk.com/docs/authentication/sign-in#override-ur-ls) prop. 4. The `ClerkProvider` now knows that the user is authenticated. 5. The `ConvexProviderWithClerk` fetches an auth token from Clerk. 6. The `ConvexReactClient` passes this token down to your Convex backend to validate 7. Your Convex backend retrieves the public key from Clerk to check that the token's signature is valid. 8. The `ConvexReactClient` is notified of successful authentication, and `ConvexProviderWithClerk` now knows that the user is authenticated with Convex. `useConvexAuth` returns `isAuthenticated: true` and the `Authenticated` component renders its children. `ConvexProviderWithClerk` takes care of refetching the token when needed to make sure the user stays authenticated with your backend. - [Get started](https://docs.convex.dev/auth/clerk#get-started) - [Login and logout Flows](https://docs.convex.dev/auth/clerk#login-and-logout-flows) - [Logged-in and logged-out views](https://docs.convex.dev/auth/clerk#logged-in-and-logged-out-views) - [User information in functions](https://docs.convex.dev/auth/clerk#user-information-in-functions) - [User information in React](https://docs.convex.dev/auth/clerk#user-information-in-react) - [Next.js, React Native Expo, Gatsby](https://docs.convex.dev/auth/clerk#nextjs-react-native-expo-gatsby) - [Configuring dev and prod instances](https://docs.convex.dev/auth/clerk#configuring-dev-and-prod-instances) - [Configuring the backend](https://docs.convex.dev/auth/clerk#configuring-the-backend) - [Configuring a React client](https://docs.convex.dev/auth/clerk#configuring-a-react-client) - [Debugging authentication](https://docs.convex.dev/auth/clerk#debugging-authentication) - [Under the hood](https://docs.convex.dev/auth/clerk#under-the-hood) [Skip to main content](https://docs.convex.dev/functions/query-functions#docusaurus_skipToContent_fallback) On this page Queries are the bread and butter of your backend API. They fetch data from the database, check authentication or perform other business logic, and return data back to the client application. This is an example query, taking in named arguments, reading data from the database and returning a result: convex/myFunctions.ts TS ```codeBlockLines_zEuJ import { query } from \"./_generated/server\"; import { v } from \"convex/values\"; // Return the last 100 tasks in a given task list. export const getTaskList = query({ args: { taskListId: v.id(\"taskLists\") }, handler: async (ctx, args) => { const tasks = await ctx.db .query(\"tasks\") .filter((q) => q.eq(q.field(\"taskListId\"), args.taskListId)) .order(\"desc\") .take(100); return tasks; }, }); ``` Read on to understand how to build queries yourself. ## Query names [​](https://docs.convex.dev/functions/query-functions\\#query-names \"Direct link to Query names\") Queries are defined in TypeScript files inside your `convex/` directory. The path and name of the file, as well as the way the function is exported from the file, determine the name the client will use to call it: convex/myFunctions.ts TS ```codeBlockLines_zEuJ // This function will be referred to as `api.myFunctions.myQuery`. export const myQuery = …; // This function will be referred to as `api.myFunctions.sum`. export const sum = …; ``` To structure your API you can nest directories inside the `convex/` directory: convex/foo/myQueries.ts TS ```codeBlockLines_zEuJ // This function will be referred to as `api.foo.myQueries.listMessages`. export const listMessages = …; ``` Default exports receive the name `default`. convex/myFunctions.ts TS ```codeBlockLines_zEuJ // This function will be referred to as `api.myFunctions.default`. export default …; ``` The same rules apply to [mutations](https://docs.convex.dev/functions/mutation-functions) and [actions](https://docs.convex.dev/functions/actions), while [HTTP actions](https://docs.convex.dev/functions/http-actions) use a different routing approach. Client libraries in languages other than JavaScript and TypeScript use strings instead of API objects: - `api.myFunctions.myQuery` is `\"myFunctions:myQuery\"` - `api.foo.myQueries.myQuery` is `\"foo/myQueries:myQuery\"`. - `api.myFunction.default` is `\"myFunction:default\"` or `\"myFunction\"`. ## The `query` constructor [​](https://docs.convex.dev/functions/query-functions\\#the-query-constructor \"Direct link to the-query-constructor\") To actually declare a query in Convex you use the `query` constructor function. Pass it an object with a `handler` function, which returns the query result: convex/myFunctions.ts TS ```codeBlockLines_zEuJ import { query } from \"./_generated/server\"; export const myConstantString = query({ handler: () => { return \"My never changing string\"; }, }); ``` ### Query arguments [​](https://docs.convex.dev/functions/query-functions\\#query-arguments \"Direct link to Query arguments\") Queries accept named arguments. The argument values are accessible as fields of the second parameter of the handler function: convex/myFunctions.ts TS ```codeBlockLines_zEuJ import { query } from \"./_generated/server\"; export const sum = query({ handler: (_, args: { a: number; b: number }) => { return args.a + args.b; }, }); ``` Arguments and responses are automatically serialized and deserialized, and you can pass and return most value-like JavaScript data to and from your query. To both declare the types of arguments and to validate them, add an `args` object using `v` validators: convex/myFunctions.ts TS ```codeBlockLines_zEuJ import { query } from \"./_generated/server\"; import { v } from \"convex/values\"; export const sum = query({ args: { a: v.number(), b: v.number() }, handler: (_, args) => { return args.a + args.b; }, }); ``` See [argument validation](https://docs.convex.dev/functions/validation) for the full list of supported types and validators. The first parameter of the handler function contains the query context. ### Query responses [​](https://docs.convex.dev/functions/query-functions\\#query-responses \"Direct link to Query responses\") Queries can return values of any supported [Convex type](https://docs.convex.dev/functions/validation) which will be automatically serialized and deserialized. Queries can also return `undefined`, which is not a valid Convex value. When a query returns `undefined` **it is translated to `null`** on the client. ### Query context [​](https://docs.convex.dev/functions/query-functions\\#query-context \"Direct link to Query context\") The `query` constructor enables fetching data, and other Convex features by passing a [QueryCtx](https://docs.convex.dev/generated-api/server#queryctx) object to the handler function as the first parameter: convex/myFunctions.ts TS ```codeBlockLines_zEuJ import { query } from \"./_generated/server\"; import { v } from \"convex/values\"; export const myQuery = query({ args: { a: v.number(), b: v.number() }, handler: (ctx, args) => { // Do something with `ctx` }, }); ``` Which part of the query context is used depends on what your query needs to do: - To fetch from the database use the `db` field. Note that we make the handler function an `async` function so we can `await` the promise returned by `db.get()`: convex/myFunctions.ts TS ```codeBlockLines_zEuJ import { query } from \"./_generated/server\"; import { v } from \"convex/values\"; export const getTask = query({ args: { id: v.id(\"tasks\") }, handler: async (ctx, args) => { return await ctx.db.get(args.id); }, }); ``` Read more about [Reading Data](https://docs.convex.dev/database/reading-data/). - To return URLs to stored files use the `storage` field. Read more about [File Storage](https://docs.convex.dev/file-storage). - To check user authentication use the `auth` field. Read more about [Authentication](https://docs.convex.dev/auth). ## Splitting up query code via helpers [​](https://docs.convex.dev/functions/query-functions\\#splitting-up-query-code-via-helpers \"Direct link to Splitting up query code via helpers\") When you want to split up the code in your query or reuse logic across multiple Convex functions you can define and call helper TypeScript functions: convex/myFunctions.ts TS ```codeBlockLines_zEuJ import { Id } from \"./_generated/dataModel\"; import { query, QueryCtx } from \"./_generated/server\"; import { v } from \"convex/values\"; export const getTaskAndAuthor = query({ args: { id: v.id(\"tasks\") }, handler: async (ctx, args) => { const task = await ctx.db.get(args.id); if (task === null) { return null; } return { task, author: await getUserName(ctx, task.authorId ?? null) }; }, }); async function getUserName(ctx: QueryCtx, userId: Id<\"users\"> | null) { if (userId === null) { return null; } return (await ctx.db.get(userId))?.name; } ``` You can `export` helpers to use them across multiple files. They will not be callable from outside of your Convex functions. See [Type annotating server side helpers](https://docs.convex.dev/understanding/best-practices/typescript#type-annotating-server-side-helpers) for more guidance on TypeScript types. ## Using NPM packages [​](https://docs.convex.dev/functions/query-functions\\#using-npm-packages \"Direct link to Using NPM packages\") Queries can import NPM packages installed in `node_modules`. Not all NPM packages are supported, see [Runtimes](https://docs.convex.dev/functions/runtimes#default-convex-runtime) for more details. ```codeBlockLines_zEuJ npm install @faker-js/faker ``` convex/myFunctions.ts TS ```codeBlockLines_zEuJ import { query } from \"./_generated/server\"; import { faker } from \"@faker-js/faker\"; export const randomName = query({ args: {}, handler: () => { faker.seed(); return faker.person.fullName(); }, }); ``` ## Calling queries from clients [​](https://docs.convex.dev/functions/query-functions\\#calling-queries-from-clients \"Direct link to Calling queries from clients\") To call a query from [React](https://docs.convex.dev/client/react) use the [`useQuery`](https://docs.convex.dev/client/react#loading-data) hook along with the generated [`api`](https://docs.convex.dev/generated-api/api) object. src/MyApp.tsx TS ```codeBlockLines_zEuJ import { useQuery } from \"convex/react\"; import { api } from \"../convex/_generated/api\"; export function MyApp() { const data = useQuery(api.myFunctions.sum, { a: 1, b: 2 }); // do something with `data` } ``` See the [React](https://docs.convex.dev/client/react) client documentation for all the ways queries can be called. ## Caching & reactivity & consistency [​](https://docs.convex.dev/functions/query-functions\\#caching--reactivity--consistency \"Direct link to Caching & reactivity & consistency\") Queries have three awesome attributes: 1. **Caching**: Convex caches query results automatically. If many clients request the same query, with the same arguments, they will receive a cached response. 2. **Reactivity**: clients can subscribe to queries to receive new results when the underlying data changes. 3. **Consistency**: All database reads inside a single query call are performed at the same logical timestamp. Concurrent writes do not affect the query results. To have these attributes the handler function must be _deterministic_, which means that given the same arguments (including the query context) it will return the same response. For this reason queries cannot `fetch` from third party APIs. To call third party APIs, use [actions](https://docs.convex.dev/functions/actions). You might wonder whether you can use non-deterministic language functionality like `Math.random()` or `Date.now()`. The short answer is that Convex takes care of implementing these in a way that you don't have to think about the deterministic constraint. See [Runtimes](https://docs.convex.dev/functions/runtimes#default-convex-runtime) for more details on the Convex runtime. ## Limits [​](https://docs.convex.dev/functions/query-functions\\#limits \"Direct link to Limits\") Queries have a limit to the amount of data they can read at once to guarantee good performance. Check out these limits [here](https://docs.convex.dev/functions/error-handling/#database-limitations). For information on other limits, see [here](https://docs.convex.dev/functions/runtimes#default-convex-runtime). - [Query names](https://docs.convex.dev/functions/query-functions#query-names) - [The `query` constructor](https://docs.convex.dev/functions/query-functions#the-query-constructor) - [Query arguments](https://docs.convex.dev/functions/query-functions#query-arguments) - [Query responses](https://docs.convex.dev/functions/query-functions#query-responses) - [Query context](https://docs.convex.dev/functions/query-functions#query-context) - [Splitting up query code via helpers](https://docs.convex.dev/functions/query-functions#splitting-up-query-code-via-helpers) - [Using NPM packages](https://docs.convex.dev/functions/query-functions#using-npm-packages) - [Calling queries from clients](https://docs.convex.dev/functions/query-functions#calling-queries-from-clients) - [Caching & reactivity & consistency](https://docs.convex.dev/functions/query-functions#caching--reactivity--consistency) - [Limits](https://docs.convex.dev/functions/query-functions#limits) [Skip to main content](https://docs.convex.dev/api/modules/nextjs#docusaurus_skipToContent_fallback) On this page Helpers for integrating Convex into Next.js applications using server rendering. This module contains: 1. [preloadQuery](https://docs.convex.dev/api/modules/nextjs#preloadquery), for preloading data for reactive client components. 2. [fetchQuery](https://docs.convex.dev/api/modules/nextjs#fetchquery), [fetchMutation](https://docs.convex.dev/api/modules/nextjs#fetchmutation) and [fetchAction](https://docs.convex.dev/api/modules/nextjs#fetchaction) for loading and mutating Convex data from Next.js Server Components, Server Actions and Route Handlers. ## Usage [​](https://docs.convex.dev/api/modules/nextjs\\#usage \"Direct link to Usage\") All exported functions assume that a Convex deployment URL is set in the `NEXT_PUBLIC_CONVEX_URL` environment variable. `npx convex dev` will automatically set it during local development. ### Preloading data [​](https://docs.convex.dev/api/modules/nextjs\\#preloading-data \"Direct link to Preloading data\") Preload data inside a Server Component: ```codeBlockLines_zEuJ import { preloadQuery } from \"convex/nextjs\"; import { api } from \"@/convex/_generated/api\"; import ClientComponent from \"./ClientComponent\"; export async function ServerComponent() { const preloaded = await preloadQuery(api.foo.baz); return ; } ``` And pass it to a Client Component: ```codeBlockLines_zEuJ import { Preloaded, usePreloadedQuery } from \"convex/nextjs\"; import { api } from \"@/convex/_generated/api\"; export function ClientComponent(props: { preloaded: Preloaded; }) { const data = await usePreloadedQuery(props.preloaded); // render `data`... } ``` ## Type Aliases [​](https://docs.convex.dev/api/modules/nextjs\\#type-aliases \"Direct link to Type Aliases\") ### NextjsOptions [​](https://docs.convex.dev/api/modules/nextjs\\#nextjsoptions \"Direct link to NextjsOptions\") Ƭ **NextjsOptions**: `Object` Options to [preloadQuery](https://docs.convex.dev/api/modules/nextjs#preloadquery), [fetchQuery](https://docs.convex.dev/api/modules/nextjs#fetchquery), [fetchMutation](https://docs.convex.dev/api/modules/nextjs#fetchmutation) and [fetchAction](https://docs.convex.dev/api/modules/nextjs#fetchaction). #### Type declaration [​](https://docs.convex.dev/api/modules/nextjs\\#type-declaration \"Direct link to Type declaration\") | Name | Type | Description | | :-- | :-- | :-- | | `token?` | `string` | The JWT-encoded OpenID Connect authentication token to use for the function call. | | `url?` | `string` | The URL of the Convex deployment to use for the function call. Defaults to `process.env.NEXT_PUBLIC_CONVEX_URL`. | | `skipConvexDeploymentUrlCheck?` | `boolean` | Skip validating that the Convex deployment URL looks like `https://happy-animal-123.convex.cloud` or localhost. This can be useful if running a self-hosted Convex backend that uses a different URL. The default value is `false` | #### Defined in [​](https://docs.convex.dev/api/modules/nextjs\\#defined-in \"Direct link to Defined in\") [nextjs/index.ts:60](https://github.com/get-convex/convex-js/blob/main/src/nextjs/index.ts#L60) ## Functions [​](https://docs.convex.dev/api/modules/nextjs\\#functions \"Direct link to Functions\") ### preloadQuery [​](https://docs.convex.dev/api/modules/nextjs\\#preloadquery \"Direct link to preloadQuery\") ▸ **preloadQuery** < `Query` >( `query`, `...args`): `Promise` < [`Preloaded`](https://docs.convex.dev/api/modules/react#preloaded) < `Query` >> Execute a Convex query function and return a `Preloaded` payload which can be passed to [usePreloadedQuery](https://docs.convex.dev/api/modules/react#usepreloadedquery) in a Client Component. #### Type parameters [​](https://docs.convex.dev/api/modules/nextjs\\#type-parameters \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Query` | extends [`FunctionReference`](https://docs.convex.dev/api/modules/server#functionreference) < `\"query\"` > | #### Parameters [​](https://docs.convex.dev/api/modules/nextjs\\#parameters \"Direct link to Parameters\") | Name | Type | Description | | :-- | :-- | :-- | | `query` | `Query` | a [FunctionReference](https://docs.convex.dev/api/modules/server#functionreference) for the public query to run like `api.dir1.dir2.filename.func`. | | `...args` | [`ArgsAndOptions`](https://docs.convex.dev/api/modules/server#argsandoptions) < `Query`, [`NextjsOptions`](https://docs.convex.dev/api/modules/nextjs#nextjsoptions) > | The arguments object for the query. If this is omitted, the arguments will be `{}`. | #### Returns [​](https://docs.convex.dev/api/modules/nextjs\\#returns \"Direct link to Returns\") `Promise` < [`Preloaded`](https://docs.convex.dev/api/modules/react#preloaded) < `Query` >> A promise of the `Preloaded` payload. #### Defined in [​](https://docs.convex.dev/api/modules/nextjs\\#defined-in-1 \"Direct link to Defined in\") [nextjs/index.ts:99](https://github.com/get-convex/convex-js/blob/main/src/nextjs/index.ts#L99) * * * ### preloadedQueryResult [​](https://docs.convex.dev/api/modules/nextjs\\#preloadedqueryresult \"Direct link to preloadedQueryResult\") ▸ **preloadedQueryResult** < `Query` >( `preloaded`): [`FunctionReturnType`](https://docs.convex.dev/api/modules/server#functionreturntype) < `Query` > Returns the result of executing a query via [preloadQuery](https://docs.convex.dev/api/modules/nextjs#preloadquery). #### Type parameters [​](https://docs.convex.dev/api/modules/nextjs\\#type-parameters-1 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Query` | extends [`FunctionReference`](https://docs.convex.dev/api/modules/server#functionreference) < `\"query\"` > | #### Parameters [​](https://docs.convex.dev/api/modules/nextjs\\#parameters-1 \"Direct link to Parameters\") | Name | Type | Description | | :-- | :-- | :-- | | `preloaded` | [`Preloaded`](https://docs.convex.dev/api/modules/react#preloaded) < `Query` > | The `Preloaded` payload returned by [preloadQuery](https://docs.convex.dev/api/modules/nextjs#preloadquery). | #### Returns [​](https://docs.convex.dev/api/modules/nextjs\\#returns-1 \"Direct link to Returns\") [`FunctionReturnType`](https://docs.convex.dev/api/modules/server#functionreturntype) < `Query` > The query result. #### Defined in [​](https://docs.convex.dev/api/modules/nextjs\\#defined-in-2 \"Direct link to Defined in\") [nextjs/index.ts:118](https://github.com/get-convex/convex-js/blob/main/src/nextjs/index.ts#L118) * * * ### fetchQuery [​](https://docs.convex.dev/api/modules/nextjs\\#fetchquery \"Direct link to fetchQuery\") ▸ **fetchQuery** < `Query` >( `query`, `...args`): `Promise` < [`FunctionReturnType`](https://docs.convex.dev/api/modules/server#functionreturntype) < `Query` >> Execute a Convex query function. #### Type parameters [​](https://docs.convex.dev/api/modules/nextjs\\#type-parameters-2 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Query` | extends [`FunctionReference`](https://docs.convex.dev/api/modules/server#functionreference) < `\"query\"` > | #### Parameters [​](https://docs.convex.dev/api/modules/nextjs\\#parameters-2 \"Direct link to Parameters\") | Name | Type | Description | | :-- | :-- | :-- | | `query` | `Query` | a [FunctionReference](https://docs.convex.dev/api/modules/server#functionreference) for the public query to run like `api.dir1.dir2.filename.func`. | | `...args` | [`ArgsAndOptions`](https://docs.convex.dev/api/modules/server#argsandoptions) < `Query`, [`NextjsOptions`](https://docs.convex.dev/api/modules/nextjs#nextjsoptions) > | The arguments object for the query. If this is omitted, the arguments will be `{}`. | #### Returns [​](https://docs.convex.dev/api/modules/nextjs\\#returns-2 \"Direct link to Returns\") `Promise` < [`FunctionReturnType`](https://docs.convex.dev/api/modules/server#functionreturntype) < `Query` >> A promise of the query's result. #### Defined in [​](https://docs.convex.dev/api/modules/nextjs\\#defined-in-3 \"Direct link to Defined in\") [nextjs/index.ts:134](https://github.com/get-convex/convex-js/blob/main/src/nextjs/index.ts#L134) * * * ### fetchMutation [​](https://docs.convex.dev/api/modules/nextjs\\#fetchmutation \"Direct link to fetchMutation\") ▸ **fetchMutation** < `Mutation` >( `mutation`, `...args`): `Promise` < [`FunctionReturnType`](https://docs.convex.dev/api/modules/server#functionreturntype) < `Mutation` >> Execute a Convex mutation function. #### Type parameters [​](https://docs.convex.dev/api/modules/nextjs\\#type-parameters-3 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Mutation` | extends [`FunctionReference`](https://docs.convex.dev/api/modules/server#functionreference) < `\"mutation\"` > | #### Parameters [​](https://docs.convex.dev/api/modules/nextjs\\#parameters-3 \"Direct link to Parameters\") | Name | Type | Description | | :-- | :-- | :-- | | `mutation` | `Mutation` | A [FunctionReference](https://docs.convex.dev/api/modules/server#functionreference) for the public mutation to run like `api.dir1.dir2.filename.func`. | | `...args` | [`ArgsAndOptions`](https://docs.convex.dev/api/modules/server#argsandoptions) < `Mutation`, [`NextjsOptions`](https://docs.convex.dev/api/modules/nextjs#nextjsoptions) > | The arguments object for the mutation. If this is omitted, the arguments will be `{}`. | #### Returns [​](https://docs.convex.dev/api/modules/nextjs\\#returns-3 \"Direct link to Returns\") `Promise` < [`FunctionReturnType`](https://docs.convex.dev/api/modules/server#functionreturntype) < `Mutation` >> A promise of the mutation's result. #### Defined in [​](https://docs.convex.dev/api/modules/nextjs\\#defined-in-4 \"Direct link to Defined in\") [nextjs/index.ts:153](https://github.com/get-convex/convex-js/blob/main/src/nextjs/index.ts#L153) * * * ### fetchAction [​](https://docs.convex.dev/api/modules/nextjs\\#fetchaction \"Direct link to fetchAction\") ▸ **fetchAction** < `Action` >( `action`, `...args`): `Promise` < [`FunctionReturnType`](https://docs.convex.dev/api/modules/server#functionreturntype) < `Action` >> Execute a Convex action function. #### Type parameters [​](https://docs.convex.dev/api/modules/nextjs\\#type-parameters-4 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Action` | extends [`FunctionReference`](https://docs.convex.dev/api/modules/server#functionreference) < `\"action\"` > | #### Parameters [​](https://docs.convex.dev/api/modules/nextjs\\#parameters-4 \"Direct link to Parameters\") | Name | Type | Description | | :-- | :-- | :-- | | `action` | `Action` | A [FunctionReference](https://docs.convex.dev/api/modules/server#functionreference) for the public action to run like `api.dir1.dir2.filename.func`. | | `...args` | [`ArgsAndOptions`](https://docs.convex.dev/api/modules/server#argsandoptions) < `Action`, [`NextjsOptions`](https://docs.convex.dev/api/modules/nextjs#nextjsoptions) > | The arguments object for the action. If this is omitted, the arguments will be `{}`. | #### Returns [​](https://docs.convex.dev/api/modules/nextjs\\#returns-4 \"Direct link to Returns\") `Promise` < [`FunctionReturnType`](https://docs.convex.dev/api/modules/server#functionreturntype) < `Action` >> A promise of the action's result. #### Defined in [​](https://docs.convex.dev/api/modules/nextjs\\#defined-in-5 \"Direct link to Defined in\") [nextjs/index.ts:174](https://github.com/get-convex/convex-js/blob/main/src/nextjs/index.ts#L174) - [Usage](https://docs.convex.dev/api/modules/nextjs#usage) - [Preloading data](https://docs.convex.dev/api/modules/nextjs#preloading-data) - [Type Aliases](https://docs.convex.dev/api/modules/nextjs#type-aliases) - [NextjsOptions](https://docs.convex.dev/api/modules/nextjs#nextjsoptions) - [Functions](https://docs.convex.dev/api/modules/nextjs#functions) - [preloadQuery](https://docs.convex.dev/api/modules/nextjs#preloadquery) - [preloadedQueryResult](https://docs.convex.dev/api/modules/nextjs#preloadedqueryresult) - [fetchQuery](https://docs.convex.dev/api/modules/nextjs#fetchquery) - [fetchMutation](https://docs.convex.dev/api/modules/nextjs#fetchmutation) - [fetchAction](https://docs.convex.dev/api/modules/nextjs#fetchaction) [Skip to main content](https://docs.convex.dev/quickstart/react-native#docusaurus_skipToContent_fallback) Learn how to query data from Convex in a React Native app. 01. Create a React Native app Create a React Native app using the `npx create-expo-app` command. ```codeBlockLines_zEuJ npx create-expo-app my-app ``` 02. Install the Convex client and server library To get started, install the `convex` package which provides a convenient interface for working with Convex from a React app. Navigate to your app and install `convex`. ```codeBlockLines_zEuJ cd my-app && npm install convex ``` 03. Set up a Convex dev deployment Next, run `npx convex dev`. This will prompt you to log in with GitHub, create a project, and save your production and deployment URLs. It will also create a `convex/` folder for you to write your backend API functions in. The `dev` command will then continue running to sync your functions with your dev deployment in the cloud. ```codeBlockLines_zEuJ npx convex dev ``` 04. Create sample data for your database Create a `sampleData.jsonl` file with some sample data. sampleData.jsonl ```codeBlockLines_zEuJ {\"text\": \"Buy groceries\", \"isCompleted\": true} {\"text\": \"Go for a swim\", \"isCompleted\": true} {\"text\": \"Integrate Convex\", \"isCompleted\": false} ``` 05. Add the sample data to your database Now that your project is ready, add a `tasks` table with the sample data into your Convex database with the `import` command. ```codeBlockLines_zEuJ npx convex import --table tasks sampleData.jsonl ``` 06. Expose a database query Add a new file `tasks.ts` in the `convex/` folder with a query function that loads the data. Exporting a query function from this file declares an API function named after the file and the export name, `api.tasks.get`. convex/tasks.ts ```codeBlockLines_zEuJ import { query } from \"./_generated/server\"; export const get = query({ args: {}, handler: async (ctx) => { return await ctx.db.query(\"tasks\").collect(); }, }); ``` 07. Reset the Expo project If you haven't done so yet, reset the Expo project to get a fresh `app` directory. ```codeBlockLines_zEuJ npm run reset-project ``` 08. Connect the app to your backend In `_layout.tsx`, create a `ConvexReactClient` and pass it to a `ConvexProvider` wrapping your component tree. app/\\_layout.tsx ```codeBlockLines_zEuJ import { ConvexProvider, ConvexReactClient } from \"convex/react\"; import { Stack } from \"expo-router\"; const convex = new ConvexReactClient(process.env.EXPO_PUBLIC_CONVEX_URL!, { unsavedChangesWarning: false, }); export default function RootLayout() { return ( ); } ``` 09. Display the data in your app In `index.tsx` use the `useQuery` hook to fetch from your `api.tasks.get` API. app/index.tsx ```codeBlockLines_zEuJ import { api } from \"@/convex/_generated/api\"; import { useQuery } from \"convex/react\"; import { Text, View } from \"react-native\"; export default function Index() { const tasks = useQuery(api.tasks.get); return ( {tasks?.map(({ _id, text }) => {text})} ); } ``` 10. Start the app Start the app, scan the provided QR code with your phone, and see the serialized list of tasks in the center of the screen. ```codeBlockLines_zEuJ npm start ``` Are you trying to build a universal app targeting both browsers and mobile devices? Use `npm create tamagui` and apply the steps above to the `apps/expo` directory and the steps in the [Next.js Quickstart](https://docs.convex.dev/quickstart/nextjs) to the `apps/next` directory. [Skip to main content](https://docs.convex.dev/testing/convex-backend#docusaurus_skipToContent_fallback) On this page Alternatively to [`convex-test`](https://docs.convex.dev/testing/convex-test) you can test your functions using the [open-source version of the Convex backend](https://github.com/get-convex/convex-backend). ## Getting Started [​](https://docs.convex.dev/testing/convex-backend\\#getting-started \"Direct link to Getting Started\") Follow [this guide](https://stack.convex.dev/testing-with-local-oss-backend) for the instructions. Compared to `convex-test`, which uses a JS mock of the backend, running your tests against the real backend has these advantages: - Your tests will run against the same code as your Convex production (as long you keep the local backend up-to-date). - Limits on argument, data, query sizes are enforced. - You can bootstrap a large test dataset from a data import. - You can test your client code in combination with your backend logic. ## Limitations [​](https://docs.convex.dev/testing/convex-backend\\#limitations \"Direct link to Limitations\") Note that testing against the local backend also has some drawbacks: - It requires setting up the local backend, which is more involved. - No control over time and any scheduled functions will run as scheduled. - Crons will also run unless disabled via [`IS_TEST`](https://stack.convex.dev/testing-with-local-oss-backend#setting-up-a-local-backend). - No way to mock `fetch` calls. - No way to mock dependencies or parts of the codebase. - No way to control randomness (tests may not be deterministic). - No way to set environment variable values from within tests. To test your functions in JS with a mocked Convex backend, check out [convex-test](https://docs.convex.dev/testing/convex-test). ## CI [​](https://docs.convex.dev/testing/convex-backend\\#ci \"Direct link to CI\") See [Continuous Integration](https://docs.convex.dev/testing/ci) to run your tests on a shared remote machine. - [Getting Started](https://docs.convex.dev/testing/convex-backend#getting-started) - [Limitations](https://docs.convex.dev/testing/convex-backend#limitations) - [CI](https://docs.convex.dev/testing/convex-backend#ci) [Skip to main content](https://docs.convex.dev/production/environment-variables#docusaurus_skipToContent_fallback) On this page Environment variables are key-value pairs that are useful for storing values you wouldn't want to put in code or in a table, such as an API key. You can set environment variables in Convex through the dashboard, and you can access them in [functions](https://docs.convex.dev/functions) using `process.env`. ## Setting environment variables [​](https://docs.convex.dev/production/environment-variables\\#setting-environment-variables \"Direct link to Setting environment variables\") Under [Deployment Settings](https://docs.convex.dev/dashboard/deployments/deployment-settings) in the Dashboard, you can see a list of environment variables in the current deployment. ![Environment Variables Table](https://docs.convex.dev/assets/images/environment_variables_table-1d215d0d797cca385b2c94dad4e938b4.png) You can add up to 100 environment variables. Environment variable names cannot be more than 40 characters long, and they must start with a letter and only contain letters numbers, and underscores. Environment variable values cannot be larger than 8KB. You can modify environment variables using the pencil icon button: ![Edit Environment Variable](https://docs.convex.dev/assets/images/edit_environment_variable-24411104aa164c750be92ce82fce3f50.png) Environment variables can also be viewed and modified with the [command line](https://docs.convex.dev/cli#read-and-write-environment-variables). ```codeBlockLines_zEuJ npx convex env list npx convex env set API_KEY secret-api-key ``` ### Using environment variables in dev and prod deployments [​](https://docs.convex.dev/production/environment-variables\\#using-environment-variables-in-dev-and-prod-deployments \"Direct link to Using environment variables in dev and prod deployments\") Since environment variables are set per-deployment, you can use different values for the same key in dev and prod deployments. This can be useful for when you have different external accounts you'd like to use depending on the environment. For example, you might have a dev and prod SendGrid account for sending emails, and your function expects an environment variable called `SENDGRID_API_KEY` that should work in both environments. If you expect an environment variable to be always present in a function, you must add it to **all** your deployments. In this example, you would add an environment variable with the name `SENDGRID_API_KEY` to your dev and prod deployments, with a different value for dev and prod. ## Accessing environment variables [​](https://docs.convex.dev/production/environment-variables\\#accessing-environment-variables \"Direct link to Accessing environment variables\") You can access environment variables in Convex functions using `process.env.KEY`. If the variable is set it is a `string`, otherwise it is `undefined`. Here is an example of accessing an environment variable with the key `GIPHY_KEY`: ```codeBlockLines_zEuJ function giphyUrl(query) { return ( \"https://api.giphy.com/v1/gifs/translate?api_key=\" + process.env.GIPHY_KEY + \"&s=\" + encodeURIComponent(query) ); } ``` Note that you should not condition your Convex function exports on environment variables. The set of Convex functions that can be called is determined during deployment and is not reevaluated when you change an environment variable. The following code will throw an error at runtime, if the DEBUG environment variable changes between deployment and calling the function. ```codeBlockLines_zEuJ // THIS WILL NOT WORK! export const myFunc = process.env.DEBUG ? mutation(...) : internalMutation(...); ``` Similarly, environment variables used in cron definitions will only be reevaluated on deployment. ## System environment variables [​](https://docs.convex.dev/production/environment-variables\\#system-environment-variables \"Direct link to System environment variables\") The following environment variables are always available in Convex functions: - `CONVEX_CLOUD_URL` \\- Your deployment URL (eg. `https://dusty-nightingale-847.convex.cloud`) for use with Convex clients. - `CONVEX_SITE_URL` \\- Your deployment site URL (eg. `https://dusty-nightingale-847.convex.site`) for use with [HTTP Actions](https://docs.convex.dev/functions/http-actions) ## Project environment variable defaults [​](https://docs.convex.dev/production/environment-variables\\#project-environment-variable-defaults \"Direct link to Project environment variable defaults\") You can set up default environment variable values for a project for development and preview deployments in Project Settings. ![Project Default Environment Variables](https://docs.convex.dev/assets/images/project_default_environment_variables-94be77c692d0a3c9564cb7f642b6cb64.png) These default values will be used when creating a new development or preview deployment, and will have no effect on existing deployments (they are not kept in sync). The Deployment Settings will indicate when a deployment has environment variables that do not match the project defaults. ![Environment Variable Default Mismatch](https://docs.convex.dev/assets/images/environment_variable_default_diff-0d02a2a8fe3f8d48d2437e0908421368.png) - [Setting environment variables](https://docs.convex.dev/production/environment-variables#setting-environment-variables) - [Using environment variables in dev and prod deployments](https://docs.convex.dev/production/environment-variables#using-environment-variables-in-dev-and-prod-deployments) - [Accessing environment variables](https://docs.convex.dev/production/environment-variables#accessing-environment-variables) - [System environment variables](https://docs.convex.dev/production/environment-variables#system-environment-variables) - [Project environment variable defaults](https://docs.convex.dev/production/environment-variables#project-environment-variable-defaults) [Skip to main content](https://docs.convex.dev/dashboard/teams#docusaurus_skipToContent_fallback) On this page In Convex, your projects are organized by team. Teams are used to share access to your projects with other people. You may switch between teams or create a new team by clicking on the name of your team located on the top of the Convex dashboard. This will open the project selector, where you can switch teams by clicking on the team name once again. ![Team switcher](https://docs.convex.dev/assets/images/team_selector-4f2055dd3c3513c29d2232ed7365ce1b.png) You may change the name of a team or invite new members to a team by clicking on the \"Team Settings\" button located on the top of the project list page. ## General [​](https://docs.convex.dev/dashboard/teams\\#general \"Direct link to General\") The [general page](https://dashboard.convex.dev/team/settings) allows changing the team name and slug. You may also delete the team from this page. You can only delete a team after deleting all of it's projects, and removing all other team members from your team. Deleting your team will automatically cancel your Convex subscription. ![General team settings page](https://docs.convex.dev/assets/images/teams_general-be57d90397e8c7890730dfd5d52f29a3.png) ## Team Members [​](https://docs.convex.dev/dashboard/teams\\#team-members \"Direct link to Team Members\") Use the [members settings page](https://dashboard.convex.dev/team/settings/members) to invite or remove members from your team. ![Team members page](https://docs.convex.dev/assets/images/teams_members-a49899c63f9a183cb0b684f0353bc678.png) ### Roles and permissions [​](https://docs.convex.dev/dashboard/teams\\#roles-and-permissions \"Direct link to Roles and permissions\") Convex has two levels of control for managing access to your team, projects, and deployments. Team-level roles control what a user can do within the team, while project-level permissions control what a user can do within a specific project. #### Team roles [​](https://docs.convex.dev/dashboard/teams\\#team-roles \"Direct link to Team roles\") Your team members can have one of the following roles: - Admin - Developer The creator of the team is automatically assigned the Admin role. When inviting new team members, you may select a role for them. You may also change the role of a team member at any time. Developers can: - Create new projects and deployments. When a new project is created, the creator of the project is automatically granted the [Project Admin](https://docs.convex.dev/dashboard/teams#project-admins) role for that project. - View existing projects, and create development and preview deployments for these projects. Developers may read data from production deployments, but cannot write to them. - View the team's usage and billing status (such as previous and upcoming invoices) Admins can do everything developers can, as well as: - Invite new team members - Remove members from the team - Change the role of other team members - Manage the team's Convex subscription and billing details. - Change the team name and slug - Team Admins are also implicitly granted project admin access to all projects within the team. See [Project Admins](https://docs.convex.dev/dashboard/teams#project-admins) for more information. #### Project Admins [​](https://docs.convex.dev/dashboard/teams\\#project-admins \"Direct link to Project Admins\") In addition to team roles, you may also grant admin access to individual projects by granting team members the \"Project Admin\" role. If you are a Project Admin for a given project, you may: - Update the project name and slug - Update the project's default environment variables - Delete the project - Write to production deployments You may assign and remove the Project Admin role for multiple projects at the same time on the member settings page. To assign or remove the Project Admin role for multiple members at the same time, visit the [Project Settings](https://docs.convex.dev/dashboard/projects#project-settings) page instead. ## Billing [​](https://docs.convex.dev/dashboard/teams\\#billing \"Direct link to Billing\") Use the [billing page](https://dashboard.convex.dev/team/settings/billing) to upgrade your Convex subscription to a higher tier, or manage your existing subscription. On paid plans, you can also update your billing contact details, payment method, and view your invoices. [Learn more about Convex pricing](https://www.convex.dev/plans). ![Team billing page](https://docs.convex.dev/assets/images/teams_billing-52fb5e7787443bac74030153c75f3a80.png) ## Usage [​](https://docs.convex.dev/dashboard/teams\\#usage \"Direct link to Usage\") On the [usage page](https://dashboard.convex.dev/team/settings/usage) you can see all the resources consumed by your team, and how you're tracking against your plan's limits. [Learn more about Convex pricing](https://www.convex.dev/plans). ![Team usage page](https://docs.convex.dev/assets/images/teams_usage-714de6c9b025dd8a5724545347f16ff7.png) All metrics are available in daily breakdowns: ![Team usage page graphs](https://docs.convex.dev/assets/images/teams_usage_2-be702e62f3542f613dceeb4464d8a724.png) ## Audit Log [​](https://docs.convex.dev/dashboard/teams\\#audit-log \"Direct link to Audit Log\") info The Audit Log is only available for paid teams. The [audit log page](https://dashboard.convex.dev/team/settings/audit-log) shows all the actions taken by members within the team. This includes creating and managing projects and deployments, inviting and removing team members, and more. ![Team audit log page](https://docs.convex.dev/assets/images/teams_audit_log-c22793879705a616a42ab4f72274358a.png) You may also view a history of deployment-related events on the [deployment history page](https://docs.convex.dev/dashboard/deployments/history). - [General](https://docs.convex.dev/dashboard/teams#general) - [Team Members](https://docs.convex.dev/dashboard/teams#team-members) - [Roles and permissions](https://docs.convex.dev/dashboard/teams#roles-and-permissions) - [Billing](https://docs.convex.dev/dashboard/teams#billing) - [Usage](https://docs.convex.dev/dashboard/teams#usage) - [Audit Log](https://docs.convex.dev/dashboard/teams#audit-log) [Skip to main content](https://docs.convex.dev/functions/runtimes#docusaurus_skipToContent_fallback) On this page # Runtimes Convex functions can run in two runtimes: - Default [Convex runtime](https://docs.convex.dev/functions/runtimes#default-convex-runtime) - Opt-in [Node.js runtime](https://docs.convex.dev/functions/runtimes#nodejs-runtime) ## Default Convex runtime [​](https://docs.convex.dev/functions/runtimes\\#default-convex-runtime \"Direct link to 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](https://blog.cloudflare.com/cloud-computing-without-containers/) with access to most [web standard globals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects). 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](https://docs.convex.dev/database/reading-data/). Supported APIs The default runtime supports most npm libraries that work in the browser, [Deno](https://deno.com/), and [Cloudflare workers](https://developers.cloudflare.com/workers/). If your library isn't supported, you can use an action with the [Node.js runtime](https://docs.convex.dev/functions/runtimes#nodejs-runtime), or reach out in [Discord](https://convex.dev/community). We are improving support all the time. ### Network APIs [​](https://docs.convex.dev/functions/runtimes\\#network-apis \"Direct link to Network APIs\") - [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob) - [Event](https://developer.mozilla.org/en-US/docs/Web/API/Event) - [EventTarget](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget) - [fetch](https://developer.mozilla.org/en-US/docs/Web/API/fetch) — in [Actions](https://docs.convex.dev/functions/runtimes#actions) only - [File](https://developer.mozilla.org/en-US/docs/Web/API/File) - [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) - [Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers) - [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) - [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) ### Encoding APIs [​](https://docs.convex.dev/functions/runtimes\\#encoding-apis \"Direct link to Encoding APIs\") - [TextDecoder](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder) - [TextEncoder](https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder) - [atob](https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/atob) - [btoa](https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/btoa) ### Web Stream APIs [​](https://docs.convex.dev/functions/runtimes\\#web-stream-apis \"Direct link to Web Stream APIs\") - [ReadableStream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) - [ReadableStreamBYOBReader](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamBYOBReader) - [ReadableStreamDefaultReader](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultReader) - [TransformStream](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream) - [WritableStream](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream) - [WritableStreamDefaultWriter](https://developer.mozilla.org/en-US/docs/Web/API/WritableStreamDefaultWriter) ### Web Crypto APIs [​](https://docs.convex.dev/functions/runtimes\\#web-crypto-apis \"Direct link to Web Crypto APIs\") - [crypto](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) - [CryptoKey](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey) - [SubtleCrypto](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto) ### Restrictions on queries and mutations [​](https://docs.convex.dev/functions/runtimes\\#restrictions-on-queries-and-mutations \"Direct link to Restrictions on queries and mutations\") Query and mutation functions are further **restricted by the runtime to be** **[deterministic](https://en.wikipedia.org/wiki/Deterministic_algorithm)**. 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 [​](https://docs.convex.dev/functions/runtimes\\#using-randomness-and-time-in-queries-and-mutations \"Direct link to 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, ```codeBlockLines_zEuJ 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 [​](https://docs.convex.dev/functions/runtimes\\#actions \"Direct link to 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`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) 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 [​](https://docs.convex.dev/functions/runtimes\\#nodejs-runtime \"Direct link to 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](https://nodejs.org/en/about) via the `\"use node\"` directive at the top of a file that contains your action. [Learn more](https://docs.convex.dev/functions/actions#choosing-the-runtime-use-node). 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`](https://docs.convex.dev/functions/actions#action-context) or [`runMutation`](https://docs.convex.dev/functions/actions#action-context) helper to call a query or mutation. Every `.ts` and `.js` file in the convex directory [is bundled](https://docs.convex.dev/functions/bundling) either for the default Convex JavaScript runtime or Node.js, along with any code it imports. Files with the `\"use node\"` directive should not contain any Convex queries or mutations since they cannot be run in the Node.js runtime. Additionally, files without the `\"use node\"` directive should not import any files with the `\"use node\"` directive. Files that contain no Convex functions, like a `convex/utils.ts` file, also need the \"use node\" directive if they use Node.js-specific libraries. - [Default Convex runtime](https://docs.convex.dev/functions/runtimes#default-convex-runtime) - [Network APIs](https://docs.convex.dev/functions/runtimes#network-apis) - [Encoding APIs](https://docs.convex.dev/functions/runtimes#encoding-apis) - [Web Stream APIs](https://docs.convex.dev/functions/runtimes#web-stream-apis) - [Web Crypto APIs](https://docs.convex.dev/functions/runtimes#web-crypto-apis) - [Restrictions on queries and mutations](https://docs.convex.dev/functions/runtimes#restrictions-on-queries-and-mutations) - [Actions](https://docs.convex.dev/functions/runtimes#actions) - [Node.js runtime](https://docs.convex.dev/functions/runtimes#nodejs-runtime) [Skip to main content](https://docs.convex.dev/understanding/best-practices#docusaurus_skipToContent_fallback) On this page This is a list of best practices and common anti-patterns around using Convex. We recommend going through this list before broadly releasing your app to production. You may choose to try using all of these best practices from the start, or you may wait until you've gotten major parts of your app working before going through and adopting the best practices here. ## Await all Promises [​](https://docs.convex.dev/understanding/best-practices\\#await-all-promises \"Direct link to Await all Promises\") ### Why? [​](https://docs.convex.dev/understanding/best-practices\\#why \"Direct link to Why?\") Convex functions use async / await. If you don't await all your promises (e.g. `await ctx.scheduler.runAfter`, `await ctx.db.patch`), you may run into unexpected behavior (e.g. failing to schedule a function) or miss handling errors. ### How? [​](https://docs.convex.dev/understanding/best-practices\\#how \"Direct link to How?\") We recommend the [no-floating-promises](https://typescript-eslint.io/rules/no-floating-promises/) eslint rule with TypeScript. ## Avoid `.filter` on database queries [​](https://docs.convex.dev/understanding/best-practices\\#avoid-filter-on-database-queries \"Direct link to avoid-filter-on-database-queries\") ### Why? [​](https://docs.convex.dev/understanding/best-practices\\#why-1 \"Direct link to Why?\") Filtering in code instead of using the `.filter` syntax has the same performance, and is generally easier code to write. Conditions in `.withIndex` or `.withSearchIndex` are more efficient than `.filter` or filtering in code, so almost all uses of `.filter` should either be replaced with a `.withIndex` or `.withSearchIndex` condition, or written as TypeScript code. Read through the [indexes documentation](https://docs.convex.dev/database/reading-data/indexes/indexes-and-query-perf) for an overview of how to define indexes and how they work. ### Examples [​](https://docs.convex.dev/understanding/best-practices\\#examples \"Direct link to Examples\") convex/messages.ts TS ```codeBlockLines_zEuJ // ❌ const tomsMessages = ctx.db .query(\"messages\") .filter((q) => q.eq(q.field(\"author\"), \"Tom\")) .collect(); // ✅ // Option 1: Use an index const tomsMessages = await ctx.db .query(\"messages\") .withIndex(\"by_author\", (q) => q.eq(\"author\", \"Tom\")) .collect(); // Option 2: Filter in code const allMessages = await ctx.db.query(\"messages\").collect(); const tomsMessages = allMessages.filter((m) => m.author === \"Tom\"); ``` ### How? [​](https://docs.convex.dev/understanding/best-practices\\#how-1 \"Direct link to How?\") Search for `.filter` in your Convex codebase — a regex like `\\.filter\\(\\(?q` will probably find all the ones on database queries. Decide whether they should be replaced with a `.withIndex` condition — per [this section](https://docs.convex.dev/understanding/best-practices/#only-use-collect-with-a-small-number-of-results), if you are filtering over a large (1000+) or potentially unbounded number of documents, you should use an index. If not using a `.withIndex` / `.withSearchIndex` condition, consider replacing them with a filter in code for more readability and flexibility. See [this article](https://stack.convex.dev/complex-filters-in-convex) for more strategies for filtering. ### Exceptions [​](https://docs.convex.dev/understanding/best-practices\\#exceptions \"Direct link to Exceptions\") Using `.filter` on a paginated query ( `.paginate`) has advantages over filtering in code. The paginated query will return the number of documents requested, including the `.filter` condition, so filtering in code afterwards can result in a smaller page or even an empty page. Using `.withIndex` on a paginated query will still be more efficient than a `.filter`. ## Only use `.collect` with a small number of results [​](https://docs.convex.dev/understanding/best-practices\\#only-use-collect-with-a-small-number-of-results \"Direct link to only-use-collect-with-a-small-number-of-results\") ### Why? [​](https://docs.convex.dev/understanding/best-practices\\#why-2 \"Direct link to Why?\") All results returned from `.collect` count towards database bandwidth (even ones filtered out by `.filter`). It also means that if any document in the result changes, the query will re-run or the mutation will hit a conflict. If there's a chance the number of results is large (say 1000+ documents), you should use an index to filter the results further before calling `.collect`, or find some other way to avoid loading all the documents such as using pagination, denormalizing data, or changing the product feature. ### Example [​](https://docs.convex.dev/understanding/best-practices\\#example \"Direct link to Example\") **Using an index:** convex/movies.ts TS ```codeBlockLines_zEuJ // ❌ -- potentially unbounded const allMovies = await ctx.db.query(\"movies\").collect(); const moviesByDirector = allMovies.filter( (m) => m.director === \"Steven Spielberg\", ); // ✅ -- small number of results, so `collect` is fine const moviesByDirector = await ctx.db .query(\"movies\") .withIndex(\"by_director\", (q) => q.eq(\"director\", \"Steven Spielberg\")) .collect(); ``` **Using pagination:** convex/movies.ts TS ```codeBlockLines_zEuJ // ❌ -- potentially unbounded const watchedMovies = await ctx.db .query(\"watchedMovies\") .withIndex(\"by_user\", (q) => q.eq(\"user\", \"Tom\")) .collect(); // ✅ -- using pagination, showing recently watched movies first const watchedMovies = await ctx.db .query(\"watchedMovies\") .withIndex(\"by_user\", (q) => q.eq(\"user\", \"Tom\")) .order(\"desc\") .paginate(paginationOptions); ``` **Using a limit or denormalizing:** convex/movies.ts TS ```codeBlockLines_zEuJ // ❌ -- potentially unbounded const watchedMovies = await ctx.db .query(\"watchedMovies\") .withIndex(\"by_user\", (q) => q.eq(\"user\", \"Tom\")) .collect(); const numberOfWatchedMovies = watchedMovies.length; // ✅ -- Show \"99+\" instead of needing to load all documents const watchedMovies = await ctx.db .query(\"watchedMovies\") .withIndex(\"by_user\", (q) => q.eq(\"user\", \"Tom\")) .take(100); const numberOfWatchedMovies = watchedMovies.length === 100 ? \"99+\" : watchedMovies.length.toString(); // ✅ -- Denormalize the number of watched movies in a separate table const watchedMoviesCount = await ctx.db .query(\"watchedMoviesCount\") .withIndex(\"by_user\", (q) => q.eq(\"user\", \"Tom\")) .unique(); ``` ### How? [​](https://docs.convex.dev/understanding/best-practices\\#how-2 \"Direct link to How?\") Search for `.collect` in your Convex codebase (a regex like `\\.collect\\(` will probably find these). And think through whether the number of results is small. This function health page in the dashboard can also help surface these. The [aggregate component](https://www.npmjs.com/package/@convex-dev/aggregate) or [database triggers](https://stack.convex.dev/triggers) can be helpful patterns for denormalizing data. ### Exceptions [​](https://docs.convex.dev/understanding/best-practices\\#exceptions-1 \"Direct link to Exceptions\") If you're doing something that requires loading a large number of documents (e.g. performing a migration, making a summary), you may want to use an action to load them in batches via separate queries / mutations. ## Check for redundant indexes [​](https://docs.convex.dev/understanding/best-practices\\#check-for-redundant-indexes \"Direct link to Check for redundant indexes\") ### Why? [​](https://docs.convex.dev/understanding/best-practices\\#why-3 \"Direct link to Why?\") Indexes like `by_foo` and `by_foo_and_bar` are usually redundant (you only need `by_foo_and_bar`). Reducing the number of indexes saves on database storage and reduces the overhead of writing to the table. convex/teams.ts TS ```codeBlockLines_zEuJ // ❌ const allTeamMembers = await ctx.db .query(\"teamMembers\") .withIndex(\"by_team\", (q) => q.eq(\"team\", teamId)) .collect(); const currentUserId = /* get current user id from `ctx.auth` */ const currentTeamMember = await ctx.db .query(\"teamMembers\") .withIndex(\"by_team_and_user\", (q) => q.eq(\"team\", teamId).eq(\"user\", currentUserId), ) .unique(); // ✅ // Just don't include a condition on `user` when querying for results on `team` const allTeamMembers = await ctx.db .query(\"teamMembers\") .withIndex(\"by_team_and_user\", (q) => q.eq(\"team\", teamId)) .collect(); const currentUserId = /* get current user id from `ctx.auth` */ const currentTeamMember = await ctx.db .query(\"teamMembers\") .withIndex(\"by_team_and_user\", (q) => q.eq(\"team\", teamId).eq(\"user\", currentUserId), ) .unique(); ``` ### How? [​](https://docs.convex.dev/understanding/best-practices\\#how-3 \"Direct link to How?\") Look through your indexes, either in your `schema.ts` file or in the dashboard, and look for any indexes where one is a prefix of another. ### Exceptions [​](https://docs.convex.dev/understanding/best-practices\\#exceptions-2 \"Direct link to Exceptions\") `.index(\"by_foo\", [\"foo\"])` is really an index on the properties `foo` and `_creationTime`, while `.index(\"by_foo_and_bar\", [\"foo\", \"bar\"])` is an index on the properties `foo`, `bar`, and `_creationTime`. If you have queries that need to be sorted by `foo` and then `_creationTime`, then you need both indexes. For example, `.index(\"by_channel\", [\"channel\"])` on a table of messages can be used to query for the most recent messages in a channel, but `.index(\"by_channel_and_author\", [\"channel\", \"author\"])` could not be used for this since it would first sort the messages by `author`. ## Use argument validators for all public functions [​](https://docs.convex.dev/understanding/best-practices\\#use-argument-validators-for-all-public-functions \"Direct link to Use argument validators for all public functions\") ### Why? [​](https://docs.convex.dev/understanding/best-practices\\#why-4 \"Direct link to Why?\") Public functions can be called by anyone, including potentially malicious attackers trying to break your app. [Argument validators](https://docs.convex.dev/functions/validation) (as well as return value validators) help ensure you're getting the traffic you expect. ### Example [​](https://docs.convex.dev/understanding/best-practices\\#example-1 \"Direct link to Example\") convex/messages.ts TS ```codeBlockLines_zEuJ // ❌ -- could be used to update any document (not just `messages`) export const updateMessage = mutation({ handler: async (ctx, { id, update }) => { await ctx.db.patch(id, update); }, }); // ✅ -- can only be called with an ID from the messages table, and can only update // the `body` and `author` fields export const updateMessage = mutation({ args: { id: v.id(\"messages\"), update: v.object({ body: v.optional(v.string()), author: v.optional(v.string()), }), }, handler: async (ctx, { id, update }) => { await ctx.db.patch(id, update); }, }); ``` ### How? [​](https://docs.convex.dev/understanding/best-practices\\#how-4 \"Direct link to How?\") Search for `query`, `mutation`, and `action` in your Convex codebase, and ensure that all of them have argument validators (and optionally return value validators). If you have `httpAction` s, you may want to use something like `zod` to validate that the HTTP request is the shape you expect. ## Use some form of access control for all public functions [​](https://docs.convex.dev/understanding/best-practices\\#use-some-form-of-access-control-for-all-public-functions \"Direct link to Use some form of access control for all public functions\") ### Why? [​](https://docs.convex.dev/understanding/best-practices\\#why-5 \"Direct link to Why?\") Public functions can be called by anyone, including potentially malicious attackers trying to break your app. If portions of your app should only be accessible when the user is signed in, make sure all these Convex functions check that `ctx.auth.getUserIdentity()` is set. You may also have specific checks, like only loading messages that were sent to or from the current user, which you'll want to apply in every relevant public function. Favoring more granular functions like `setTeamOwner` over `updateTeam` allows more granular checks for which users can do what. Access control checks should either use `ctx.auth.getUserIdentity()` or a function argument that is unguessable (e.g. a UUID, or a Convex ID, provided that this ID is never exposed to any client but the one user). In particular, don't use a function argument which could be spoofed (e.g. email) for access control checks. ### Example [​](https://docs.convex.dev/understanding/best-practices\\#example-2 \"Direct link to Example\") convex/teams.ts TS ```codeBlockLines_zEuJ // ❌ -- no checks! anyone can update any team if they get the ID export const updateTeam = mutation({ args: { id: v.id(\"teams\"), update: v.object({ name: v.optional(v.string()), owner: v.optional(v.id(\"users\")), }), }, handler: async (ctx, { id, update }) => { await ctx.db.patch(id, update); }, }); // ❌ -- checks access, but uses `email` which could be spoofed export const updateTeam = mutation({ args: { id: v.id(\"teams\"), update: v.object({ name: v.optional(v.string()), owner: v.optional(v.id(\"users\")), }), email: v.string(), }, handler: async (ctx, { id, update, email }) => { const teamMembers = /* load team members */ if (!teamMembers.some((m) => m.email === email)) { throw new Error(\"Unauthorized\"); } await ctx.db.patch(id, update); }, }); // ✅ -- checks access, and uses `ctx.auth`, which cannot be spoofed export const updateTeam = mutation({ args: { id: v.id(\"teams\"), update: v.object({ name: v.optional(v.string()), owner: v.optional(v.id(\"users\")), }), }, handler: async (ctx, { id, update }) => { const user = await ctx.auth.getUserIdentity(); if (user === null) { throw new Error(\"Unauthorized\"); } const isTeamMember = /* check if user is a member of the team */ if (!isTeamMember) { throw new Error(\"Unauthorized\"); } await ctx.db.patch(id, update); }, }); // ✅ -- separate functions which have different access control export const setTeamOwner = mutation({ args: { id: v.id(\"teams\"), owner: v.id(\"users\"), }, handler: async (ctx, { id, owner }) => { const user = await ctx.auth.getUserIdentity(); if (user === null) { throw new Error(\"Unauthorized\"); } const isTeamOwner = /* check if user is the owner of the team */ if (!isTeamOwner) { throw new Error(\"Unauthorized\"); } await ctx.db.patch(id, { owner: owner }); }, }); export const setTeamName = mutation({ args: { id: v.id(\"teams\"), name: v.string(), }, handler: async (ctx, { id, name }) => { const user = await ctx.auth.getUserIdentity(); if (user === null) { throw new Error(\"Unauthorized\"); } const isTeamMember = /* check if user is a member of the team */ if (!isTeamMember) { throw new Error(\"Unauthorized\"); } await ctx.db.patch(id, { name: name }); }, }); ``` ### How? [​](https://docs.convex.dev/understanding/best-practices\\#how-5 \"Direct link to How?\") Search for `query`, `mutation`, `action`, and `httpAction` in your Convex codebase, and ensure that all of them have some form of access control. [Custom functions](https://github.com/get-convex/convex-helpers/blob/main/packages/convex-helpers/README.md#custom-functions) like [`authenticatedQuery`](https://stack.convex.dev/custom-functions#modifying-the-ctx-argument-to-a-server-function-for-user-auth) can be helpful. Some apps use Row Level Security (RLS) to check access to each document automatically whenever it's loaded, as described in [this article](https://stack.convex.dev/row-level-security). Alternatively, you can check access in each Convex function instead of checking access for each document. Helper functions for common checks and common operations can also be useful -- e.g. `isTeamMember`, `isTeamAdmin`, `loadTeam` (which throws if the current user does not have access to the team). ## Only schedule and `ctx.run*` internal functions [​](https://docs.convex.dev/understanding/best-practices\\#only-schedule-and-ctxrun-internal-functions \"Direct link to only-schedule-and-ctxrun-internal-functions\") ### Why? [​](https://docs.convex.dev/understanding/best-practices\\#why-6 \"Direct link to Why?\") Public functions can be called by anyone, including potentially malicious attackers trying to break your app, and should be carefully audited to ensure they can't be used maliciously. Functions that are only called within Convex can be marked as internal, and relax these checks since Convex will ensure that internal functions can only be called within Convex. ### How? [​](https://docs.convex.dev/understanding/best-practices\\#how-6 \"Direct link to How?\") Search for `ctx.runQuery`, `ctx.runMutation`, and `ctx.runAction` in your Convex codebase. Also search for `ctx.scheduler` and check the `crons.ts` file. Ensure all of these use `internal.foo.bar` functions instead of `api.foo.bar` functions. If you have code you want to share between a public Convex function and an internal Convex function, create a helper function that can be called from both. The public function will likely have additional access control checks. Alternatively, make sure that `api` from `_generated/api.ts` is never used in your Convex functions directory. ### Examples [​](https://docs.convex.dev/understanding/best-practices\\#examples-1 \"Direct link to Examples\") convex/teams.ts TS ```codeBlockLines_zEuJ // ❌ -- using `api` export const sendMessage = mutation({ args: { body: v.string(), author: v.string(), }, handler: async (ctx, { body, author }) => { // add message to the database }, }); // crons.ts crons.daily( \"send daily reminder\", { hourUTC: 17, minuteUTC: 30 }, api.messages.sendMessage, { author: \"System\", body: \"Share your daily update!\" }, ); // ✅ Using `internal` import { MutationCtx } from './_generated/server'; async function sendMessageHelper( ctx: MutationCtx, args: { body: string; author: string }, ) { // add message to the database } export const sendMessage = mutation({ args: { body: v.string(), }, handler: async (ctx, { body }) => { const user = await ctx.auth.getUserIdentity(); if (user === null) { throw new Error(\"Unauthorized\"); } await sendMessageHelper(ctx, { body, author: user.name ?? \"Anonymous\" }); }, }); export const sendInternalMessage = internalMutation({ args: { body: v.string(), // don't need to worry about `author` being spoofed since this is an internal function author: v.string(), }, handler: async (ctx, { body, author }) => { await sendMessageHelper(ctx, { body, author }); }, }); // crons.ts crons.daily( \"send daily reminder\", { hourUTC: 17, minuteUTC: 30 }, internal.messages.sendInternalMessage, { author: \"System\", body: \"Share your daily update!\" }, ); ``` ## Use helper functions to write shared code [​](https://docs.convex.dev/understanding/best-practices\\#use-helper-functions-to-write-shared-code \"Direct link to Use helper functions to write shared code\") ### Why? [​](https://docs.convex.dev/understanding/best-practices\\#why-7 \"Direct link to Why?\") Most logic should be written as plain TypeScript functions, with the `query`, `mutation`, and `action` wrapper functions being a thin wrapper around one or more helper function. Concretely, most of your code should live in a directory like `convex/model`, and your public API, which is defined with `query`, `mutation`, and `action`, should have very short functions that mostly just call into `convex/model`. Organizing your code this way makes several of the refactors mentioned in this list easier to do. See the [TypeScript page](https://docs.convex.dev/understanding/best-practices/typescript) for useful types. ### Example [​](https://docs.convex.dev/understanding/best-practices\\#example-3 \"Direct link to Example\") **❌** This example overuses `ctx.runQuery` and `ctx.runMutation`, which is discussed more in the [Avoid sequential `ctx.runMutation` / `ctx.runQuery` from actions](https://docs.convex.dev/understanding/best-practices/#avoid-sequential-ctx-runmutation-ctx-runquery-from-actions) section. convex/users.ts TS ```codeBlockLines_zEuJ export const getCurrentUser = query({ args: {}, handler: async (ctx) => { const userIdentity = await ctx.auth.getUserIdentity(); if (userIdentity === null) { throw new Error(\"Unauthorized\"); } const user = /* query ctx.db to load the user */ const userSettings = /* load other documents related to the user */ return { user, settings: userSettings }; }, }); ``` convex/conversations.ts TS ```codeBlockLines_zEuJ export const listMessages = query({ args: { conversationId: v.id(\"conversations\"), }, handler: async (ctx, { conversationId }) => { const user = await ctx.runQuery(api.users.getCurrentUser); const conversation = await ctx.db.get(conversationId); if (conversation === null || !conversation.members.includes(user._id)) { throw new Error(\"Unauthorized\"); } const messages = /* query ctx.db to load the messages */ return messages; }, }); export const summarizeConversation = action({ args: { conversationId: v.id(\"conversations\"), }, handler: async (ctx, { conversationId }) => { const messages = await ctx.runQuery(api.conversations.listMessages, { conversationId, }); const summary = /* call some external service to summarize the conversation */ await ctx.runMutation(api.conversations.addSummary, { conversationId, summary, }); }, }); ``` **✅** Most of the code here is now in the `convex/model` directory. The API for this application is in `convex/conversations.ts`, which contains very little code itself. convex/model/users.ts TS ```codeBlockLines_zEuJ import { QueryCtx } from '../_generated/server'; export async function getCurrentUser(ctx: QueryCtx) { const userIdentity = await ctx.auth.getUserIdentity(); if (userIdentity === null) { throw new Error(\"Unauthorized\"); } const user = /* query ctx.db to load the user */ const userSettings = /* load other documents related to the user */ return { user, settings: userSettings }; } ``` convex/model/conversations.ts TS ```codeBlockLines_zEuJ import { QueryCtx, MutationCtx } from '../_generated/server'; import * as Users from './users'; export async function ensureHasAccess( ctx: QueryCtx, { conversationId }: { conversationId: Id<\"conversations\"> }, ) { const user = await Users.getCurrentUser(ctx); const conversation = await ctx.db.get(conversationId); if (conversation === null || !conversation.members.includes(user._id)) { throw new Error(\"Unauthorized\"); } return conversation; } export async function listMessages( ctx: QueryCtx, { conversationId }: { conversationId: Id<\"conversations\"> }, ) { await ensureHasAccess(ctx, { conversationId }); const messages = /* query ctx.db to load the messages */ return messages; } export async function addSummary( ctx: MutationCtx, { conversationId, summary, }: { conversationId: Id<\"conversations\">; summary: string }, ) { await ensureHasAccess(ctx, { conversationId }); await ctx.db.patch(conversationId, { summary }); } export async function generateSummary( messages: Doc<\"messages\">[], conversationId: Id<\"conversations\">, ) { const summary = /* call some external service to summarize the conversation */ return summary; } ``` convex/conversations.ts TS ```codeBlockLines_zEuJ import * as Conversations from './model/conversations'; export const addSummary = internalMutation({ args: { conversationId: v.id(\"conversations\"), summary: v.string(), }, handler: async (ctx, { conversationId, summary }) => { await Conversations.addSummary(ctx, { conversationId, summary }); }, }); export const listMessages = internalQuery({ args: { conversationId: v.id(\"conversations\"), }, handler: async (ctx, { conversationId }) => { return Conversations.listMessages(ctx, { conversationId }); }, }); export const summarizeConversation = action({ args: { conversationId: v.id(\"conversations\"), }, handler: async (ctx, { conversationId }) => { const messages = await ctx.runQuery(internal.conversations.listMessages, { conversationId, }); const summary = await Conversations.generateSummary( messages, conversationId, ); await ctx.runMutation(internal.conversations.addSummary, { conversationId, summary, }); }, }); ``` ## Use `runAction` only when using a different runtime [​](https://docs.convex.dev/understanding/best-practices\\#use-runaction-only-when-using-a-different-runtime \"Direct link to use-runaction-only-when-using-a-different-runtime\") ### Why? [​](https://docs.convex.dev/understanding/best-practices\\#why-8 \"Direct link to Why?\") Calling `runAction` has more overhead than calling a plain TypeScript function. It counts as an extra function call with its own memory and CPU usage, while the parent action is doing nothing except waiting for the result. Therefore, `runAction` should almost always be replaced with calling a plain TypeScript function. However, if you want to call code that requires Node.js from a function in the Convex runtime (e.g. using a library that requires Node.js), then you can use `runAction` to call the Node.js code. ### Example [​](https://docs.convex.dev/understanding/best-practices\\#example-4 \"Direct link to Example\") convex/scrape.ts TS ```codeBlockLines_zEuJ // ❌ -- using `runAction` export const scrapeWebsite = action({ args: { siteMapUrl: v.string(), }, handler: async (ctx, { siteMapUrl }) => { const siteMap = await fetch(siteMapUrl); const pages = /* parse the site map */ await Promise.all( pages.map((page) => ctx.runAction(internal.scrape.scrapeSinglePage, { url: page }), ), ); }, }); ``` convex/model/scrape.ts TS ```codeBlockLines_zEuJ import { ActionCtx } from '../_generated/server'; // ✅ -- using a plain TypeScript function export async function scrapeSinglePage( ctx: ActionCtx, { url }: { url: string }, ) { const page = await fetch(url); const text = /* parse the page */ await ctx.runMutation(internal.scrape.addPage, { url, text }); } ``` convex/scrape.ts TS ```codeBlockLines_zEuJ import * as Scrape from './model/scrape'; export const scrapeWebsite = action({ args: { siteMapUrl: v.string(), }, handler: async (ctx, { siteMapUrl }) => { const siteMap = await fetch(siteMapUrl); const pages = /* parse the site map */ await Promise.all( pages.map((page) => Scrape.scrapeSinglePage(ctx, { url: page })), ); }, }); ``` ### How? [​](https://docs.convex.dev/understanding/best-practices\\#how-7 \"Direct link to How?\") Search for `runAction` in your Convex codebase, and see if the function it calls uses the same runtime as the parent function. If so, replace the `runAction` with a plain TypeScript function. You may want to structure your functions so the Node.js functions are in a separate directory so it's easier to spot these. ## Avoid sequential `ctx.runMutation` / `ctx.runQuery` calls from actions [​](https://docs.convex.dev/understanding/best-practices\\#avoid-sequential-ctxrunmutation--ctxrunquery-calls-from-actions \"Direct link to avoid-sequential-ctxrunmutation--ctxrunquery-calls-from-actions\") ### Why? [​](https://docs.convex.dev/understanding/best-practices\\#why-9 \"Direct link to Why?\") Each `ctx.runMutation` or `ctx.runQuery` runs in its own transaction, which means if they're called separately, they may not be consistent with each other. If instead we call a single `ctx.runQuery` or `ctx.runMutation`, we're guaranteed that the results we get are consistent. ### How? [​](https://docs.convex.dev/understanding/best-practices\\#how-8 \"Direct link to How?\") Audit your calls to `ctx.runQuery` and `ctx.runMutation` in actions. If you see multiple in a row with no other code between them, replace them with a single `ctx.runQuery` or `ctx.runMutation` that handles both things. Refactoring your code to use helper functions will make this easier. ### Example: Queries [​](https://docs.convex.dev/understanding/best-practices\\#example-queries \"Direct link to Example: Queries\") convex/teams.ts TS ```codeBlockLines_zEuJ // ❌ -- this assertion could fail if the team changed between running the two queries const team = await ctx.runQuery(internal.teams.getTeam, { teamId }); const teamOwner = await ctx.runQuery(internal.teams.getTeamOwner, { teamId }); assert(team.owner === teamOwner._id); ``` convex/teams.ts TS ```codeBlockLines_zEuJ import * as Teams from './model/teams'; import * as Users from './model/users'; export const sendBillingReminder = action({ args: { teamId: v.id(\"teams\"), }, handler: async (ctx, { teamId }) => { // ✅ -- this will always pass const teamAndOwner = await ctx.runQuery(internal.teams.getTeamAndOwner, { teamId, }); assert(teamAndOwner.team.owner === teamAndOwner.owner._id); // send a billing reminder email to the owner }, }); export const getTeamAndOwner = internalQuery({ args: { teamId: v.id(\"teams\"), }, handler: async (ctx, { teamId }) => { const team = await Teams.load(ctx, { teamId }); const owner = await Users.load(ctx, { userId: team.owner }); return { team, owner }; }, }); ``` ### Example: Loops [​](https://docs.convex.dev/understanding/best-practices\\#example-loops \"Direct link to Example: Loops\") convex/teams.ts TS ```codeBlockLines_zEuJ import * as Users from './model/users'; export const importTeams = action({ args: { teamId: v.id(\"teams\"), }, handler: async (ctx, { teamId }) => { // Fetch team members from an external API const teamMembers = await fetchTeamMemberData(teamId); // ❌ This will run a separate mutation for inserting each user, // which means you lose transaction guarantees like atomicity. for (const member of teamMembers) { await ctx.runMutation(internal.teams.insertUser, member); } }, }); export const insertUser = internalMutation({ args: { name: v.string(), email: v.string() }, handler: async (ctx, { name, email }) => { await Users.insert(ctx, { name, email }); }, }); ``` convex/teams.ts TS ```codeBlockLines_zEuJ import * as Users from './model/users'; export const importTeams = action({ args: { teamId: v.id(\"teams\"), }, handler: async (ctx, { teamId }) => { // Fetch team members from an external API const teamMembers = await fetchTeamMemberData(teamId); // ✅ This action runs a single mutation that inserts all users in the same transaction. await ctx.runMutation(internal.teams.insertUsers, teamMembers); }, }); export const insertUsers = internalMutation({ args: { users: v.array(v.object({ name: v.string(), email: v.string() })) }, handler: async (ctx, { users }) => { for (const { name, email } of users) { await Users.insert(ctx, { name, email }); } }, }); ``` ### Exceptions [​](https://docs.convex.dev/understanding/best-practices\\#exceptions-3 \"Direct link to Exceptions\") If you're intentionally trying to process more data than fits in a single transaction, like running a migration or aggregating data, then it makes sense to have multiple sequential `ctx.runMutation` / `ctx.runQuery` calls. Multiple `ctx.runQuery` / `ctx.runMutation` calls are often necessary because the action does a side effect in between them. For example, reading some data, feeding it to an external service, and then writing the result back to the database. ## Use `ctx.runQuery` and `ctx.runMutation` sparingly in queries and mutations [​](https://docs.convex.dev/understanding/best-practices\\#use-ctxrunquery-and-ctxrunmutation-sparingly-in-queries-and-mutations \"Direct link to use-ctxrunquery-and-ctxrunmutation-sparingly-in-queries-and-mutations\") ### Why? [​](https://docs.convex.dev/understanding/best-practices\\#why-10 \"Direct link to Why?\") While these queries and mutations run in the same transaction, and will give consistent results, they have extra overhead compared to plain TypeScript functions. Wanting a TypeScript helper function is much more common than needing `ctx.runQuery` or `ctx.runMutation`. ### How? [​](https://docs.convex.dev/understanding/best-practices\\#how-9 \"Direct link to How?\") Audit your calls to `ctx.runQuery` and `ctx.runMutation` in queries and mutations. Unless one of the exceptions below applies, replace them with a plain TypeScript function. ### Exceptions [​](https://docs.convex.dev/understanding/best-practices\\#exceptions-4 \"Direct link to Exceptions\") - If you're using components, these require `ctx.runQuery` or `ctx.runMutation`. - If you want partial rollback on an error, you will want `ctx.runMutation` instead of a plain TypeScript function. convex/messages.ts TS ```codeBlockLines_zEuJ export const trySendMessage = mutation({ args: { body: v.string(), author: v.string(), }, handler: async (ctx, { body, author }) => { try { await ctx.runMutation(internal.messages.sendMessage, { body, author }); } catch (e) { // Record the failure, but rollback any writes from `sendMessage` await ctx.db.insert(\"failures\", { kind: \"MessageFailed\", body, author, error: `Error: ${e}`, }); } }, }); ``` - [Await all Promises](https://docs.convex.dev/understanding/best-practices#await-all-promises) - [Avoid `.filter` on database queries](https://docs.convex.dev/understanding/best-practices#avoid-filter-on-database-queries) - [Only use `.collect` with a small number of results](https://docs.convex.dev/understanding/best-practices#only-use-collect-with-a-small-number-of-results) - [Check for redundant indexes](https://docs.convex.dev/understanding/best-practices#check-for-redundant-indexes) - [Use argument validators for all public functions](https://docs.convex.dev/understanding/best-practices#use-argument-validators-for-all-public-functions) - [Use some form of access control for all public functions](https://docs.convex.dev/understanding/best-practices#use-some-form-of-access-control-for-all-public-functions) - [Only schedule and `ctx.run*` internal functions](https://docs.convex.dev/understanding/best-practices#only-schedule-and-ctxrun-internal-functions) - [Use helper functions to write shared code](https://docs.convex.dev/understanding/best-practices#use-helper-functions-to-write-shared-code) - [Use `runAction` only when using a different runtime](https://docs.convex.dev/understanding/best-practices#use-runaction-only-when-using-a-different-runtime) - [Avoid sequential `ctx.runMutation` / `ctx.runQuery` calls from actions](https://docs.convex.dev/understanding/best-practices#avoid-sequential-ctxrunmutation--ctxrunquery-calls-from-actions) - [Use `ctx.runQuery` and `ctx.runMutation` sparingly in queries and mutations](https://docs.convex.dev/understanding/best-practices#use-ctxrunquery-and-ctxrunmutation-sparingly-in-queries-and-mutations) [Skip to main content](https://docs.convex.dev/functions/mutation-functions#docusaurus_skipToContent_fallback) On this page Mutations insert, update and remove data from the database, check authentication or perform other business logic, and optionally return a response to the client application. This is an example mutation, taking in named arguments, writing data to the database and returning a result: convex/myFunctions.ts TS ```codeBlockLines_zEuJ import { mutation } from \"./_generated/server\"; import { v } from \"convex/values\"; // Create a new task with the given text export const createTask = mutation({ args: { text: v.string() }, handler: async (ctx, args) => { const newTaskId = await ctx.db.insert(\"tasks\", { text: args.text }); return newTaskId; }, }); ``` Read on to understand how to build mutations yourself. ## Mutation names [​](https://docs.convex.dev/functions/mutation-functions\\#mutation-names \"Direct link to Mutation names\") Mutations follow the same naming rules as queries, see [Query names](https://docs.convex.dev/functions/query-functions#query-names). Queries and mutations can be defined in the same file when using named exports. ## The `mutation` constructor [​](https://docs.convex.dev/functions/mutation-functions\\#the-mutation-constructor \"Direct link to the-mutation-constructor\") To declare a mutation in Convex use the `mutation` constructor function. Pass it an object with a `handler` function, which performs the mutation: convex/myFunctions.ts TS ```codeBlockLines_zEuJ import { mutation } from \"./_generated/server\"; export const mutateSomething = mutation({ handler: () => { // implementation will be here }, }); ``` Unlike a query, a mutation can but does not have to return a value. ### Mutation arguments [​](https://docs.convex.dev/functions/mutation-functions\\#mutation-arguments \"Direct link to Mutation arguments\") Just like queries, mutations accept named arguments, and the argument values are accessible as fields of the second parameter of the `handler` function: convex/myFunctions.ts TS ```codeBlockLines_zEuJ import { mutation } from \"./_generated/server\"; export const mutateSomething = mutation({ handler: (_, args: { a: number; b: number }) => { // do something with `args.a` and `args.b` // optionally return a value return \"success\"; }, }); ``` Arguments and responses are automatically serialized and deserialized, and you can pass and return most value-like JavaScript data to and from your mutation. To both declare the types of arguments and to validate them, add an `args` object using `v` validators: convex/myFunctions.ts TS ```codeBlockLines_zEuJ import { mutation } from \"./_generated/server\"; import { v } from \"convex/values\"; export const mutateSomething = mutation({ args: { a: v.number(), b: v.number() }, handler: (_, args) => { // do something with `args.a` and `args.b` }, }); ``` See [argument validation](https://docs.convex.dev/functions/validation) for the full list of supported types and validators. The first parameter to the handler function is reserved for the mutation context. ### Mutation responses [​](https://docs.convex.dev/functions/mutation-functions\\#mutation-responses \"Direct link to Mutation responses\") Queries can return values of any supported [Convex type](https://docs.convex.dev/functions/validation) which will be automatically serialized and deserialized. Mutations can also return `undefined`, which is not a valid Convex value. When a mutation returns `undefined` **it is translated to `null`** on the client. ### Mutation context [​](https://docs.convex.dev/functions/mutation-functions\\#mutation-context \"Direct link to Mutation context\") The `mutation` constructor enables writing data to the database, and other Convex features by passing a [MutationCtx](https://docs.convex.dev/generated-api/server#mutationctx) object to the handler function as the first parameter: convex/myFunctions.ts TS ```codeBlockLines_zEuJ import { mutation } from \"./_generated/server\"; import { v } from \"convex/values\"; export const mutateSomething = mutation({ args: { a: v.number(), b: v.number() }, handler: (ctx, args) => { // Do something with `ctx` }, }); ``` Which part of the mutation context is used depends on what your mutation needs to do: - To read from and write to the database use the `db` field. Note that we make the handler function an `async` function so we can `await` the promise returned by `db.insert()`: convex/myFunctions.ts TS ```codeBlockLines_zEuJ import { mutation } from \"./_generated/server\"; import { v } from \"convex/values\"; export const addItem = mutation({ args: { text: v.string() }, handler: async (ctx, args) => { await ctx.db.insert(\"tasks\", { text: args.text }); }, }); ``` Read on about [Writing Data](https://docs.convex.dev/database/writing-data). - To generate upload URLs for storing files use the `storage` field. Read on about [File Storage](https://docs.convex.dev/file-storage). - To check user authentication use the `auth` field. Read on about [Authentication](https://docs.convex.dev/auth). - To schedule functions to run in the future, use the `scheduler` field. Read on about [Scheduled Functions](https://docs.convex.dev/scheduling/scheduled-functions). ## Splitting up mutation code via helpers [​](https://docs.convex.dev/functions/mutation-functions\\#splitting-up-mutation-code-via-helpers \"Direct link to Splitting up mutation code via helpers\") When you want to split up the code in your mutation or reuse logic across multiple Convex functions you can define and call helper TypeScript functions: convex/myFunctions.ts TS ```codeBlockLines_zEuJ import { v } from \"convex/values\"; import { mutation, MutationCtx } from \"./_generated/server\"; export const addItem = mutation({ args: { text: v.string() }, handler: async (ctx, args) => { await ctx.db.insert(\"tasks\", { text: args.text }); await trackChange(ctx, \"addItem\"); }, }); async function trackChange(ctx: MutationCtx, type: \"addItem\" | \"removeItem\") { await ctx.db.insert(\"changes\", { type }); } ``` Mutations can call helpers that take a [QueryCtx](https://docs.convex.dev/generated-api/server#queryctx) as argument, since the mutation context can do everything query context can. You can `export` helpers to use them across multiple files. They will not be callable from outside of your Convex functions. See [Type annotating server side helpers](https://docs.convex.dev/understanding/best-practices/typescript#type-annotating-server-side-helpers) for more guidance on TypeScript types. ## Using NPM packages [​](https://docs.convex.dev/functions/mutation-functions\\#using-npm-packages \"Direct link to Using NPM packages\") Mutations can import NPM packages installed in `node_modules`. Not all NPM packages are supported, see [Runtimes](https://docs.convex.dev/functions/runtimes#default-convex-runtime) for more details. ```codeBlockLines_zEuJ npm install @faker-js/faker ``` convex/myFunctions.ts TS ```codeBlockLines_zEuJ import { faker } from \"@faker-js/faker\"; import { mutation } from \"./_generated/server\"; export const randomName = mutation({ args: {}, handler: async (ctx) => { faker.seed(); await ctx.db.insert(\"tasks\", { text: \"Greet \" + faker.person.fullName() }); }, }); ``` ## Calling mutations from clients [​](https://docs.convex.dev/functions/mutation-functions\\#calling-mutations-from-clients \"Direct link to Calling mutations from clients\") To call a mutation from [React](https://docs.convex.dev/client/react) use the generated [`useMutation`](https://docs.convex.dev/client/react#editing-data) hook: To call a mutation from [React](https://docs.convex.dev/client/react) use the [`useMutation`](https://docs.convex.dev/client/react#editing-data) hook along with the generated [`api`](https://docs.convex.dev/generated-api/api) object. src/myApp.tsx TS ```codeBlockLines_zEuJ import { useMutation } from \"convex/react\"; import { api } from \"../convex/_generated/api\"; export function MyApp() { const mutateSomething = useMutation(api.myFunctions.mutateSomething); const handleClick = () => { mutateSomething({ a: 1, b: 2 }); }; // pass `handleClick` to a button // ... } ``` See the [React](https://docs.convex.dev/client/react) client documentation for all the ways queries can be called. When mutations are called from the [React](https://docs.convex.dev/client/react) or [Rust](https://docs.convex.dev/client/rust) clients, they are executed one at a time in a single, ordered queue. You don't have to worry about mutations editing the database in a different order than they were triggered. ## Transactions [​](https://docs.convex.dev/functions/mutation-functions\\#transactions \"Direct link to Transactions\") Mutations run **transactionally**. This means that: 1. All database reads inside the transaction get a consistent view of the data in the database. You don't have to worry about a concurrent update changing the data in the middle of the execution. 2. All database writes get committed together. If the mutation writes some data to the database, but later throws an error, no data is actually written to the database. For this to work, similarly to queries, mutations must be deterministic, and cannot call third party APIs. To call third party APIs, use [actions](https://docs.convex.dev/functions/actions). ## Limits [​](https://docs.convex.dev/functions/mutation-functions\\#limits \"Direct link to Limits\") Mutations have a limit to the amount of data they can read and write at once to guarantee good performance. Check out these limits [here](https://docs.convex.dev/functions/error-handling/#database-limitations). For information on other limits, see [here](https://docs.convex.dev/functions/error-handling/#database-limitations). - [Mutation names](https://docs.convex.dev/functions/mutation-functions#mutation-names) - [The `mutation` constructor](https://docs.convex.dev/functions/mutation-functions#the-mutation-constructor) - [Mutation arguments](https://docs.convex.dev/functions/mutation-functions#mutation-arguments) - [Mutation responses](https://docs.convex.dev/functions/mutation-functions#mutation-responses) - [Mutation context](https://docs.convex.dev/functions/mutation-functions#mutation-context) - [Splitting up mutation code via helpers](https://docs.convex.dev/functions/mutation-functions#splitting-up-mutation-code-via-helpers) - [Using NPM packages](https://docs.convex.dev/functions/mutation-functions#using-npm-packages) - [Calling mutations from clients](https://docs.convex.dev/functions/mutation-functions#calling-mutations-from-clients) - [Transactions](https://docs.convex.dev/functions/mutation-functions#transactions) - [Limits](https://docs.convex.dev/functions/mutation-functions#limits) [Skip to main content](https://docs.convex.dev/components#docusaurus_skipToContent_fallback) On this page Convex Components package up code and data in a sandbox that allows you to confidently and quickly add new features to your backend. Convex Components are like mini self-contained Convex backends, and installing them is always safe. They can't read your app's tables or call your app's functions unless you pass them in explicitly. You can read about the full vision in [Convex: The Software-Defined Database](https://stack.convex.dev/the-software-defined-database#introducing-convex-components) The Convex team has built a few components that add new features to your backend. You'll eventually be able to author your own components to use within your project and to share with the community, but we haven't stabilized and documented the authoring APIs yet. We've listed components built by the Convex team below. Each component is installed as its own independent library from NPM. Check out the component's README for installation and usage instructions. You can see the full directory on the [Convex website](https://convex.dev/components). The component authoring APIs are in Beta The underlying authoring APIs for components are still in flux. The Convex team authored components listed below will be kept up to date as the APIs change. ## Database [​](https://docs.convex.dev/components\\#database \"Direct link to Database\") [**Sharded Counter** \\\\ \\\\ High throughput counter](https://www.convex.dev/components/sharded-counter) [**Migrations** \\\\ \\\\ Manage live site migrations](https://www.convex.dev/components/migrations) [**Aggregate** \\\\ \\\\ Efficient sums, counts, randomization and more](https://www.convex.dev/components/aggregate) [**Geospatial (Beta)** \\\\ \\\\ Efficiently store and query points on the Earth's surface](https://www.convex.dev/components/geospatial) ## Durable Functions [​](https://docs.convex.dev/components\\#durable-functions \"Direct link to Durable Functions\") [**Runtime Crons** \\\\ \\\\ Register crons programmatically](https://www.convex.dev/components/crons) [**Workflow (Beta)** \\\\ \\\\ Simplify long running code flows](https://www.convex.dev/components/workflow) [**Action Retrier** \\\\ \\\\ Retry idempotent external calls](https://www.convex.dev/components/retrier) ## Backend [​](https://docs.convex.dev/components\\#backend \"Direct link to Backend\") [**Rate Limiter** \\\\ \\\\ Limit how often a resource is used](https://www.convex.dev/components/rate-limiter) [**Action Cache** \\\\ \\\\ Cache repeated external calls](https://www.convex.dev/components/action-cache) ## Integrations [​](https://docs.convex.dev/components\\#integrations \"Direct link to Integrations\") [**Twilio SMS** \\\\ \\\\ Send SMS and query status](https://www.convex.dev/components/twilio) [**Expo Push Notifications** \\\\ \\\\ Manage mobile push notifications](https://www.convex.dev/components/push-notifications) [**LaunchDarkly feature flags** \\\\ \\\\ Sync flags from LaunchDarkly](https://www.convex.dev/components/launchdarkly) ## Understanding Components [​](https://docs.convex.dev/components\\#understanding-components \"Direct link to Understanding Components\") Components can be thought of as a combination of concepts from frontend components, third party APIs, and both monolith and service-oriented architectures. ### Data [​](https://docs.convex.dev/components\\#data \"Direct link to Data\") Similar to frontend components, Convex Components encapsulate state and behavior and allow exposing a clean interface. However, instead of just storing state in memory, these can have internal state machines that can persist between user sessions, span users, and change in response to external inputs, such as webhooks. Components can store data in a few ways: - Database tables with their own schema validation definitions. Since Convex is realtime by default, data reads are automatically reactive, and writes commit transactionally. - File storage, independent of the main app’s file storage. - Durable functions via the built-in function scheduler. Components can reliably schedule functions to run in the future and pass along state. Typically, libraries require configuring a third party service to add stateful off-the-shelf functionality, which lack the transactional guarantees that come from storing state in the same database. ### Isolation [​](https://docs.convex.dev/components\\#isolation \"Direct link to Isolation\") Similar to regular npm libraries, Convex Components include functions, type safety, and are called from your code. However, they also provide extra guarantees. - Similar to a third-party API, components can’t read data for which you don’t provide access. This includes database tables, file storage, environment variables, scheduled functions, etc. - Similar to service-oriented architecture, functions in components are run in an isolated environment, so they can’t read or write global variables or patch system behavior. - Similar to a monolith architecture, data changes commit transactionally across calls to components, without having to reason about complicated distributed commit protocols or data inconsistencies. You’ll never have a component commit data but have the calling code roll back. - In addition, each mutation call to a component is a sub-mutation isolated from other calls, allowing you to safely catch errors thrown by components. It also allows component authors to easily reason about state changes without races, and trust that a thrown exception will always roll back the Component’s sub-mutation. [Read more](https://docs.convex.dev/components/using-components#transactions). ### Encapsulation [​](https://docs.convex.dev/components\\#encapsulation \"Direct link to Encapsulation\") Being able to reason about your code is essential to scaling a codebase. Components allow you to reason about API boundaries and abstractions. - The transactional guarantees discussed above allows authors and users of components to reason locally about data changes. - Components expose an explicit API, not direct database table access. Data invariants can be enforced in code, within the abstraction boundary. For example, the [aggregate component](https://convex.dev/components/aggregate) can internally denormalize data, the [rate limiter](https://convex.dev/components/rate-limiter) component can shard its data, and the [push notification](https://convex.dev/components/push-notifications) component can internally batch API requests, while maintaining simple interfaces. - Runtime validation ensures all data that cross a component boundary are validated: both arguments and return values. As with normal Convex functions, the validators also specify the TypeScript types, providing end-to-end typing with runtime guarantees. - [Database](https://docs.convex.dev/components#database) - [Durable Functions](https://docs.convex.dev/components#durable-functions) - [Backend](https://docs.convex.dev/components#backend) - [Integrations](https://docs.convex.dev/components#integrations) - [Understanding Components](https://docs.convex.dev/components#understanding-components) - [Data](https://docs.convex.dev/components#data) - [Isolation](https://docs.convex.dev/components#isolation) - [Encapsulation](https://docs.convex.dev/components#encapsulation) [Skip to main content](https://docs.convex.dev/quickstart/nodejs#docusaurus_skipToContent_fallback) Learn how to query data from Convex in a Node.js project. For instructions for subscriptions instead of point-in-time queries and more project configurations (TypeScript, bundlers, CJS vs ESM) see [Node.js notes](https://docs.convex.dev/client/javascript/node). 1. Create a new npm project Create a new directory for your Node.js project. ```codeBlockLines_zEuJ mkdir my-project && cd my-project && npm init -y && npm pkg set type=\"module\" ``` 2. Install the Convex client and server library Install the `convex` package which provides a convenient interface for working with Convex from JavaScript. Also install the `dotenv` library for loading `.env` files. ```codeBlockLines_zEuJ npm install convex dotenv ``` 3. Set up a Convex dev deployment Next, run `npx convex dev`. This will prompt you to log in with GitHub, create a project, and save your production and deployment URLs. It will also create a `convex/` folder for you to write your backend API functions in. The `dev` command will then continue running to sync your functions with your dev deployment in the cloud. ```codeBlockLines_zEuJ npx convex dev ``` 4. Create sample data for your database In a new terminal window, create a `sampleData.jsonl` file with some sample data. sampleData.jsonl ```codeBlockLines_zEuJ {\"text\": \"Buy groceries\", \"isCompleted\": true} {\"text\": \"Go for a swim\", \"isCompleted\": true} {\"text\": \"Integrate Convex\", \"isCompleted\": false} ``` 5. Add the sample data to your database Now that your project is ready, add a `tasks` table with the sample data into your Convex database with the `import` command. ```codeBlockLines_zEuJ npx convex import --table tasks sampleData.jsonl ``` 6. Expose a database query Add a new file `tasks.js` in the `convex/` folder with a query function that loads the data. Exporting a query function from this file declares an API function named after the file and the export name, `api.tasks.get`. convex/tasks.js ```codeBlockLines_zEuJ import { query } from \"./_generated/server\"; export const get = query({ args: {}, handler: async (ctx) => { return await ctx.db.query(\"tasks\").collect(); }, }); ``` 7. Connect the script to your backend In a new file `script.js`, create a `ConvexHttpClient` using the URL of your development environment. script.js ```codeBlockLines_zEuJ import { ConvexHttpClient } from \"convex/browser\"; import { api } from \"./convex/_generated/api.js\"; import * as dotenv from \"dotenv\"; dotenv.config({ path: \".env.local\" }); const client = new ConvexHttpClient(process.env[\"CONVEX_URL\"]); client.query(api.tasks.get).then(console.log); ``` 8. Run the script Run the script from the same directory and see the list of tasks logged to the terminal. ```codeBlockLines_zEuJ node script.js ``` [Skip to main content](https://docs.convex.dev/production/state#docusaurus_skipToContent_fallback) On this page Please [contact us](mailto:support@convex.dev) with any specific requirements or if you want to build a project on Convex that is not yet satisfied by our guarantees. ## Guarantees [​](https://docs.convex.dev/production/state\\#guarantees \"Direct link to Guarantees\") The official Convex Terms of Service, Privacy Policy and Customer Agreements are [outlined in our official terms](https://www.convex.dev/legal/tos). We do not yet have contractual agreements beyond what is listed in our official terms and the discussions within this document don't constitute an amendment to these terms. Convex is always under continual development and future releases may require code changes in order to upgrade to a new version. Code developed on Convex 1.0 or later will continue to operate as-is. If we are required to make a breaking change in future we will contact teams directly to provide substantial advance notice. All user data in Convex is encrypted at rest. Database state is replicated durably across multiple physical availability zones. Regular periodic and incremental database backups are performed and stored with 99.999999999% (11 9's) durability. We target an availability of 99.99% (4 9's) for Convex deployments although these may experience downtime for maintenance without notice. A physical outage may affect availability of a deployment but will not affect durability of the data stored in Convex. ## Limits [​](https://docs.convex.dev/production/state\\#limits \"Direct link to Limits\") For information on limits, see [here](https://docs.convex.dev/production/state/limits). ## Beta Features [​](https://docs.convex.dev/production/state\\#beta-features \"Direct link to Beta Features\") Features tagged with **beta** in these docs are still in development. They can be used in production but their APIs might change in the future, requiring additional effort when upgrading to a new version of the Convex NPM package and other Convex client libraries. ## Future Features [​](https://docs.convex.dev/production/state\\#future-features \"Direct link to Future Features\") Convex is still under very active development and here we list some of the missing functionality on our radar. We'd love to hear more about your requirements in the [Convex Discord Community](https://convex.dev/community). ### Authorization [​](https://docs.convex.dev/production/state\\#authorization \"Direct link to Authorization\") Convex currently has an [_authentication framework_](https://docs.convex.dev/auth) which verifies user identities. In the future we plan to add an _authorization_ _framework_ which will allow developers to define what data a user can access. For now, you can implement manual authorization checks within your queries and mutations, but stay tuned for a more comprehensive, fool-proof solution in the future. ### Telemetry [​](https://docs.convex.dev/production/state\\#telemetry \"Direct link to Telemetry\") Currently, the dashboard provides only basic metrics. Serious sites at scale are going to need to integrate our logs and metrics into more fully fledged observability systems that categorize them and empower things like alerting. Convex will eventually have methods to publish deployment data in formats that can be ingested by third parties. ### Analytics / OLAP [​](https://docs.convex.dev/production/state\\#analytics--olap \"Direct link to Analytics / OLAP\") Convex is designed to primarily service all your app's realtime implementation (OLTP) needs. It is less suited to be a good solution for the kinds of complex queries and huge table scans that are necessary to address the requirements of analytics (OLAP) use cases. Convex exposes [Fivetran and Airbyte connectors](https://docs.convex.dev/production/integrations/streaming-import-export) to export Convex data to external analytics systems. ### Browser support [​](https://docs.convex.dev/production/state\\#browser-support \"Direct link to Browser support\") Convex does not yet have an official browser support policy, but we strive to support most modern browsers with significant [usage](https://caniuse.com/usage-table). - [Guarantees](https://docs.convex.dev/production/state#guarantees) - [Limits](https://docs.convex.dev/production/state#limits) - [Beta Features](https://docs.convex.dev/production/state#beta-features) - [Future Features](https://docs.convex.dev/production/state#future-features) - [Authorization](https://docs.convex.dev/production/state#authorization) - [Telemetry](https://docs.convex.dev/production/state#telemetry) - [Analytics / OLAP](https://docs.convex.dev/production/state#analytics--olap) - [Browser support](https://docs.convex.dev/production/state#browser-support) [Skip to main content](https://docs.convex.dev/database/document-ids#docusaurus_skipToContent_fallback) On this page **Example:** [Relational Data Modeling](https://github.com/get-convex/convex-demos/tree/main/relational-data-modeling) Every document in convex has a globally unique string _document ID_ that is automatically generated by the system. ```codeBlockLines_zEuJ const userId = await ctx.db.insert(\"users\", { name: \"Michael Jordan\" }); ``` You can use this ID to efficiently read a single document using the `get` method: ```codeBlockLines_zEuJ const retrievedUser = await ctx.db.get(userId); ``` You can access the ID of a document in the [`_id` field](https://docs.convex.dev/database/types#system-fields): ```codeBlockLines_zEuJ const userId = retrievedUser._id; ``` Also, this same ID can be used to update that document in place: ```codeBlockLines_zEuJ await ctx.db.patch(userId, { name: \"Steph Curry\" }); ``` Convex generates an [`Id`](https://docs.convex.dev/generated-api/data-model#id) TypeScript type based on your [schema](https://docs.convex.dev/database/schemas) that is parameterized over your table names: ```codeBlockLines_zEuJ import { Id } from \"./_generated/dataModel\"; const userId: Id<\"users\"> = user._id; ``` IDs are strings at runtime, but the [`Id`](https://docs.convex.dev/generated-api/data-model#id) type can be used to distinguish IDs from other strings at compile time. ## References and relationships [​](https://docs.convex.dev/database/document-ids\\#references-and-relationships \"Direct link to References and relationships\") In Convex, you can reference a document simply by embedding its `Id` in another document: ```codeBlockLines_zEuJ await ctx.db.insert(\"books\", { title, ownerId: user._id, }); ``` You can follow references with `ctx.db.get`: ```codeBlockLines_zEuJ const user = await ctx.db.get(book.ownerId); ``` And [query for documents](https://docs.convex.dev/database/reading-data/) with a reference: ```codeBlockLines_zEuJ const myBooks = await ctx.db .query(\"books\") .filter((q) => q.eq(q.field(\"ownerId\"), user._id)) .collect(); ``` Using `Id` s as references can allow you to build a complex data model. ## Trading off deeply nested documents vs. relationships [​](https://docs.convex.dev/database/document-ids\\#trading-off-deeply-nested-documents-vs-relationships \"Direct link to Trading off deeply nested documents vs. relationships\") While it's useful that Convex supports nested objects and arrays, you should keep documents relatively small in size. In practice, we recommend limiting Arrays to no more than 5-10 elements and avoiding deeply nested Objects. Instead, leverage separate tables, documents, and references to structure your data. This will lead to better maintainability and performance as your project grows. ## Serializing IDs [​](https://docs.convex.dev/database/document-ids\\#serializing-ids \"Direct link to Serializing IDs\") IDs are strings, which can be easily inserted into URLs or stored outside of Convex. You can pass an ID string from an external source (like a URL) into a Convex function and get the corresponding object. If you're using TypeScript on the client you can cast a string to the `Id` type: src/App.tsx ```codeBlockLines_zEuJ import { useQuery } from \"convex/react\"; import { Id } from \"../convex/_generated/dataModel\"; import { api } from \"../convex/_generated/api\"; export function App() { const id = localStorage.getItem(\"myIDStorage\"); const task = useQuery(api.tasks.getTask, { taskId: id as Id<\"tasks\"> }); // ... } ``` Since this ID is coming from an external source, use an argument validator or [`ctx.db.normalizeId`](https://docs.convex.dev/api/interfaces/server.GenericDatabaseReader#normalizeid) to confirm that the ID belongs to the expected table before returning the object. convex/tasks.ts TS ```codeBlockLines_zEuJ import { query } from \"./_generated/server\"; import { v } from \"convex/values\"; export const getTask = query({ args: { taskId: v.id(\"tasks\"), }, handler: async (ctx, args) => { const task = await ctx.db.get(args.taskId); // ... }, }); ``` Related posts from [![Stack](https://docs.convex.dev/img/stack-logo-dark.svg)![Stack](https://docs.convex.dev/img/stack-logo-light.svg)](https://stack.convex.dev/) - [References and relationships](https://docs.convex.dev/database/document-ids#references-and-relationships) - [Trading off deeply nested documents vs. relationships](https://docs.convex.dev/database/document-ids#trading-off-deeply-nested-documents-vs-relationships) - [Serializing IDs](https://docs.convex.dev/database/document-ids#serializing-ids) [Skip to main content](https://docs.convex.dev/client/python#docusaurus_skipToContent_fallback) See the [Python Quickstart](https://docs.convex.dev/quickstart/python) and the [convex PyPI package\\\\ docs](https://pypi.org/project/convex/). The Python client is open source and available on [GitHub](https://github.com/get-convex/convex-py). [Skip to main content](https://docs.convex.dev/production/integrations#docusaurus_skipToContent_fallback) On this page Convex integrates with a variety of supported third party tools for log streaming and exception reporting. - [Log Streams](https://docs.convex.dev/production/integrations/log-streams) enable streaming of log events from your Convex deployment to supported destinations, such as Axiom, Datadog, or a custom webhook. - [Exception Reporting](https://docs.convex.dev/production/integrations/exception-reporting) gives visibility into errors in your Convex function executions. ## Configuring an Integration [​](https://docs.convex.dev/production/integrations\\#configuring-an-integration \"Direct link to Configuring an Integration\") To configure an integration, navigate to the [Deployment Settings](https://dashboard.convex.dev/deployment/settings) in the Dashboard, and the \"Integrations\" tab in the sidebar. This page provides a list of your configured integrations, their current health status, and other integrations available to be configured. To configure a integration, click on the card and follow the setup directions. ![Integrations Page](https://docs.convex.dev/assets/images/integrations_page-0f9edc52770c9caa6980330930e7517a.png) ## Deleting an Integration [​](https://docs.convex.dev/production/integrations\\#deleting-an-integration \"Direct link to Deleting an Integration\") To remove an integration and stop further events from being piped out to the configured destination, select the menu icon in the upper-right corner of a configured panel and select \"Delete integration\". After confirming, the integration will stop running within a few seconds. ## Feedback [​](https://docs.convex.dev/production/integrations\\#feedback \"Direct link to Feedback\") Please reach out with any questions, comments, or suggestions [on Discord](https://convex.dev/community). - [Configuring an Integration](https://docs.convex.dev/production/integrations#configuring-an-integration) - [Deleting an Integration](https://docs.convex.dev/production/integrations#deleting-an-integration) - [Feedback](https://docs.convex.dev/production/integrations#feedback) [Skip to main content](https://docs.convex.dev/database/schemas#docusaurus_skipToContent_fallback) On this page A schema is a description of 1. the tables in your Convex project 2. the type of documents within your tables While it is possible to use Convex _without_ defining a schema, adding a `schema.ts` file will ensure that the documents in your tables are the correct type. If you're using [TypeScript](https://docs.convex.dev/understanding/best-practices/typescript), adding a schema will also give you end-to-end type safety throughout your app. We recommend beginning your project without a schema for rapid prototyping and then adding a schema once you've solidified your plan. To learn more see our [Schema Philosophy](https://docs.convex.dev/database/advanced/schema-philosophy). **Example:** [TypeScript and Schemas](https://github.com/get-convex/convex-demos/tree/main/typescript) ## Writing schemas [​](https://docs.convex.dev/database/schemas\\#writing-schemas \"Direct link to Writing schemas\") Schemas are defined in a `schema.ts` file in your `convex/` directory and look like: convex/schema.ts ```codeBlockLines_zEuJ import { defineSchema, defineTable } from \"convex/server\"; import { v } from \"convex/values\"; export default defineSchema({ messages: defineTable({ body: v.string(), user: v.id(\"users\"), }), users: defineTable({ name: v.string(), tokenIdentifier: v.string(), }).index(\"by_token\", [\"tokenIdentifier\"]), }); ``` This schema (which is based on our [users and auth example](https://github.com/get-convex/convex-demos/tree/main/users-and-auth)), has 2 tables: messages and users. Each table is defined using the [`defineTable`](https://docs.convex.dev/api/modules/server#definetable) function. Within each table, the document type is defined using the validator builder, [`v`](https://docs.convex.dev/api/modules/values#v). In addition to the fields listed, Convex will also automatically add `_id` and `_creationTime` fields. To learn more, see [System Fields](https://docs.convex.dev/database/types#system-fields). Generating a Schema While writing your schema, it can be helpful to consult the [Convex Dashboard](https://docs.convex.dev/dashboard/deployments/data#generating-a-schema). The \"Generate Schema\" button in the \"Data\" view suggests a schema declaration based on the data in your tables. ### Validators [​](https://docs.convex.dev/database/schemas\\#validators \"Direct link to Validators\") The validator builder, [`v`](https://docs.convex.dev/api/modules/values#v) is used to define the type of documents in each table. It has methods for each of [Convex's types](https://docs.convex.dev/database/types): convex/schema.ts ```codeBlockLines_zEuJ import { defineSchema, defineTable } from \"convex/server\"; import { v } from \"convex/values\"; export default defineSchema({ documents: defineTable({ id: v.id(\"documents\"), string: v.string(), number: v.number(), boolean: v.boolean(), nestedObject: v.object({ property: v.string(), }), }), }); ``` It additionally allows you to define unions, optional property, string literals, and more. [Argument validation](https://docs.convex.dev/functions/validation) and schemas both use the same validator builder, `v`. #### Optional fields [​](https://docs.convex.dev/database/schemas\\#optional-fields \"Direct link to Optional fields\") You can describe optional fields by wrapping their type with `v.optional(...)`: ```codeBlockLines_zEuJ defineTable({ optionalString: v.optional(v.string()), optionalNumber: v.optional(v.number()), }); ``` This corresponds to marking fields as optional with `?` in TypeScript. #### Unions [​](https://docs.convex.dev/database/schemas\\#unions \"Direct link to Unions\") You can describe fields that could be one of multiple types using `v.union`: ```codeBlockLines_zEuJ defineTable({ stringOrNumber: v.union(v.string(), v.number()), }); ``` If your table stores multiple different types of documents, you can use `v.union` at the top level: ```codeBlockLines_zEuJ defineTable( v.union( v.object({ kind: v.literal(\"StringDocument\"), value: v.string(), }), v.object({ kind: v.literal(\"NumberDocument\"), value: v.number(), }), ), ); ``` In this schema, documents either have a `kind` of `\"StringDocument\"` and a string for their `value`: ```codeBlockLines_zEuJ { \"kind\": \"StringDocument\", \"value\": \"abc\" } ``` or they have a `kind` of `\"NumberDocument\"` and a number for their `value`: ```codeBlockLines_zEuJ { \"kind\": \"NumberDocument\", \"value\": 123 } ``` #### Literals [​](https://docs.convex.dev/database/schemas\\#literals \"Direct link to Literals\") Fields that are a constant can be expressed with `v.literal`: ```codeBlockLines_zEuJ defineTable({ oneTwoOrThree: v.union( v.literal(\"one\"), v.literal(\"two\"), v.literal(\"three\"), ), }); ``` #### Record objects [​](https://docs.convex.dev/database/schemas\\#record-objects \"Direct link to Record objects\") You can describe objects that map arbitrary keys to values with `v.record`: ```codeBlockLines_zEuJ defineTable({ simpleMapping: v.record(v.string(), v.boolean()), }); ``` You can use other types of string validators for the keys: ```codeBlockLines_zEuJ import { mutation } from \"./_generated/server\"; import { v } from \"convex/values\"; export default mutation({ args: { userIdToValue: v.record(v.id(\"users\"), v.boolean()), }, handler: async ({ db }, { userIdToValue }) => { //... }, }); ``` Notes: - This type corresponds to the [Record](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type) type in TypeScript - You cannot use string literals as a `record` key - Using `v.string()` as a `record` key validator will only allow ASCII characters #### Any [​](https://docs.convex.dev/database/schemas\\#any \"Direct link to Any\") Fields or documents that could take on any value can be represented with `v.any()`: ```codeBlockLines_zEuJ defineTable({ anyValue: v.any(), }); ``` This corresponds to the `any` type in TypeScript. ### Options [​](https://docs.convex.dev/database/schemas\\#options \"Direct link to Options\") These options are passed as part of the [options](https://docs.convex.dev/api/interfaces/server.DefineSchemaOptions) argument to [`defineSchema`](https://docs.convex.dev/api/modules/server#defineschema). #### `schemaValidation: boolean` [​](https://docs.convex.dev/database/schemas\\#schemavalidation-boolean \"Direct link to schemavalidation-boolean\") Whether Convex should validate at runtime that your documents match your schema. By default, Convex will enforce that all new and existing documents match your schema. You can disable `schemaValidation` by passing in `schemaValidation: false`: ```codeBlockLines_zEuJ defineSchema( { // Define tables here. }, { schemaValidation: false, }, ); ``` When `schemaValidation` is disabled, Convex will not validate that new or existing documents match your schema. You'll still get schema-specific TypeScript types, but there will be no validation at runtime that your documents match those types. #### `strictTableNameTypes: boolean` [​](https://docs.convex.dev/database/schemas\\#stricttablenametypes-boolean \"Direct link to stricttablenametypes-boolean\") Whether the TypeScript types should allow accessing tables not in the schema. By default, the TypeScript table name types produced by your schema are strict. That means that they will be a union of strings (ex. `\"messages\" | \"users\"`) and only support accessing tables explicitly listed in your schema. Sometimes it's useful to only define part of your schema. For example, if you are rapidly prototyping, it could be useful to try out a new table before adding it your `schema.ts` file. You can disable `strictTableNameTypes` by passing in `strictTableNameTypes: false`: ```codeBlockLines_zEuJ defineSchema( { // Define tables here. }, { strictTableNameTypes: false, }, ); ``` When `strictTableNameTypes` is disabled, the TypeScript types will allow access to tables not listed in the schema and their document type will be `any`. Regardless of the value of `strictTableNameTypes`, your schema will only validate documents in the tables listed in the schema. You can still create and modify documents in other tables in JavaScript or on the dashboard (they just won't be validated). ## Schema validation [​](https://docs.convex.dev/database/schemas\\#schema-validation \"Direct link to Schema validation\") Schemas are pushed automatically in [`npx convex dev`](https://docs.convex.dev/cli#run-the-convex-dev-server) and [`npx convex deploy`](https://docs.convex.dev/cli#deploy-convex-functions-to-production). The first push after a schema is added or modified will validate that all existing documents match the schema. If there are documents that fail validation, the push will fail. After the schema is pushed, Convex will validate that all future document inserts and updates match the schema. Schema validation is skipped if [`schemaValidation`](https://docs.convex.dev/database/schemas#schemavalidation-boolean) is set to `false`. Note that schemas only validate documents in the tables listed in the schema. You can still create and modify documents in other tables (they just won't be validated). ### Circular references [​](https://docs.convex.dev/database/schemas\\#circular-references \"Direct link to Circular references\") You might want to define a schema with circular ID references like: convex/schema.ts ```codeBlockLines_zEuJ import { defineSchema, defineTable } from \"convex/server\"; import { v } from \"convex/values\"; export default defineSchema({ users: defineTable({ preferencesId: v.id(\"preferences\"), }), preferences: defineTable({ userId: v.id(\"users\"), }), }); ``` In this schema, documents in the `users` table contain a reference to documents in `preferences` and vice versa. Because schema validation enforces your schema on every `db.insert`, `db.replace`, and `db.patch` call, creating circular references like this is not possible. The easiest way around this is to make one of the references nullable: convex/schema.ts ```codeBlockLines_zEuJ import { defineSchema, defineTable } from \"convex/server\"; import { v } from \"convex/values\"; export default defineSchema({ users: defineTable({ preferencesId: v.id(\"preferences\"), }), preferences: defineTable({ userId: v.union(v.id(\"users\"), v.null()), }), }); ``` This way you can create a preferences document first, then create a user document, then set the reference on the preferences document: convex/users.ts TS ```codeBlockLines_zEuJ import { mutation } from \"./_generated/server\"; export default mutation({ handler: async (ctx) => { const preferencesId = await ctx.db.insert(\"preferences\", {}); const userId = await ctx.db.insert(\"users\", { preferencesId }); await ctx.db.patch(preferencesId, { userId }); }, }); ``` [Let us know](https://docs.convex.dev/production/contact) if you need better support for circular references. ## TypeScript types [​](https://docs.convex.dev/database/schemas\\#typescript-types \"Direct link to TypeScript types\") Once you've defined a schema, [`npx convex dev`](https://docs.convex.dev/cli#run-the-convex-dev-server) will produce new versions of [`dataModel.d.ts`](https://docs.convex.dev/generated-api/data-model) and [`server.d.ts`](https://docs.convex.dev/generated-api/server) with types based on your schema. ### `Doc` [​](https://docs.convex.dev/database/schemas\\#doctablename \"Direct link to doctablename\") The [`Doc`](https://docs.convex.dev/generated-api/data-model#document) TypeScript type from [`dataModel.d.ts`](https://docs.convex.dev/generated-api/data-model) provides document types for all of your tables. You can use these both when writing Convex functions and in your React components: MessageView.tsx ```codeBlockLines_zEuJ import { Doc } from \"../convex/_generated/dataModel\"; function MessageView(props: { message: Doc<\"messages\"> }) { ... } ``` If you need the type for a portion of a document, use the [`Infer` type helper](https://docs.convex.dev/functions/validation#extracting-typescript-types). ### `query` and `mutation` [​](https://docs.convex.dev/database/schemas\\#query-and-mutation \"Direct link to query-and-mutation\") The [`query`](https://docs.convex.dev/generated-api/server#query) and [`mutation`](https://docs.convex.dev/generated-api/server#mutation) functions in [`server.js`](https://docs.convex.dev/generated-api/server) have the same API as before but now provide a `db` with more precise types. Functions like [`db.insert(table, document)`](https://docs.convex.dev/api/interfaces/server.GenericDatabaseWriter#insert) now understand your schema. Additionally [database queries](https://docs.convex.dev/database/reading-data/) will now return the correct document type (not `any`). Related posts from [![Stack](https://docs.convex.dev/img/stack-logo-dark.svg)![Stack](https://docs.convex.dev/img/stack-logo-light.svg)](https://stack.convex.dev/) - [Writing schemas](https://docs.convex.dev/database/schemas#writing-schemas) - [Validators](https://docs.convex.dev/database/schemas#validators) - [Optional fields](https://docs.convex.dev/database/schemas#optional-fields) - [Unions](https://docs.convex.dev/database/schemas#unions) - [Literals](https://docs.convex.dev/database/schemas#literals) - [Record objects](https://docs.convex.dev/database/schemas#record-objects) - [Any](https://docs.convex.dev/database/schemas#any) - [Options](https://docs.convex.dev/database/schemas#options) - [`schemaValidation: boolean`](https://docs.convex.dev/database/schemas#schemavalidation-boolean) - [`strictTableNameTypes: boolean`](https://docs.convex.dev/database/schemas#stricttablenametypes-boolean) - [Schema validation](https://docs.convex.dev/database/schemas#schema-validation) - [Circular references](https://docs.convex.dev/database/schemas#circular-references) - [TypeScript types](https://docs.convex.dev/database/schemas#typescript-types) - [`Doc`](https://docs.convex.dev/database/schemas#doctablename) - [`query` and `mutation`](https://docs.convex.dev/database/schemas#query-and-mutation) [Skip to main content](https://docs.convex.dev/production#docusaurus_skipToContent_fallback) Convex is built to serve live, production app traffic. Here we cover how to deploy and maintain a production version of your app. ## Project management [​](https://docs.convex.dev/production\\#project-management \"Direct link to Project management\") When you sign up for Convex, a Convex team is created for you. You can [create more teams from the dashboard](https://docs.convex.dev/dashboard/teams) and add other people to them as members. You can upgrade your team to the [Pro plan](https://www.convex.dev/plans) for additional features, higher limits and usage-based pricing. Each team can have multiple projects. When you run `npx convex dev` for the first time, a project is created for you automatically. You can also create a project from the dashboard. Every project has one shared production deployment and one development deployment per team member. This allows each team member to make and test changes independently before they are deployed to the production deployment. Usually all deployments belonging to a single project run the same code base (or a version of it), but Convex doesn't enforce this. You can also run the same code base on multiple different prod deployments belonging to different projects, see [staging](https://docs.convex.dev/production#staging-environment) below. ## Deploying to production [​](https://docs.convex.dev/production\\#deploying-to-production \"Direct link to Deploying to production\") Your Convex deployments run your backend logic and in most cases you will also develop a client that uses the backend. If your client is a web app, follow the [Hosting and Deployment](https://docs.convex.dev/production/hosting/) guide, to learn how to deploy your client and your Convex backend together. You can also deploy your backend on its own. Check out the [Project Configuration](https://docs.convex.dev/production/project-configuration) page to learn more. ## Staging environment [​](https://docs.convex.dev/production\\#staging-environment \"Direct link to Staging environment\") With Convex [preview deployments](https://docs.convex.dev/production/hosting/preview-deployments) your team can test out changes before deploying them to production. If you need a more permanent staging environment, you can use a separate Convex project, and deploy to it by setting the `CONVEX_DEPLOY_KEY` environment variable when running [`npx convex deploy`](https://docs.convex.dev/cli#deploy-convex-functions-to-production). ## Typical team development workflow [​](https://docs.convex.dev/production\\#typical-team-development-workflow \"Direct link to Typical team development workflow\") Teams developing on Convex usually follow this workflow: 1. If this is the team's first project, one team member creates a team on the dashboard. 2. One team member creates a project by running `npx convex dev`, perhaps starting with a [quickstart](https://docs.convex.dev/quickstarts) or a [template](https://www.convex.dev/templates). 3. The team member creates a Git repository from the initial code and shares it with their team (via GitHub, GitLab etc.). 4. Other team members pull the codebase, and get their own dev deployments by running `npx convex dev`. 5. All team members can make backend changes and test them out with their individual dev deployments. When a change is ready the team member opens a pull-request (or commits to a shared branch). - [Backup / Restore](https://database/backup-restore) can be used to populate a dev deployment with data from a prod deployment. - [Data import](https://docs.convex.dev/database/import-export/import) can be used to populate a dev deployment with synthetic seed data. - Members of a team with the [Pro plan](https://www.convex.dev/plans) can get separate [preview deployments](https://docs.convex.dev/production/hosting/preview-deployments) to test each other's pull-requests. 6. Deployment to production can happen [automatically](https://docs.convex.dev/production/hosting/) when changes get merged to the designated branch (say `main`). - Alternatively one of the team members can deploy to production manually by running `npx convex deploy`. ### Making safe changes [​](https://docs.convex.dev/production\\#making-safe-changes \"Direct link to Making safe changes\") Especially if your app is live you want to make sure that changes you make to your Convex codebase do not break it. Some unsafe changes are handled and caught by Convex, but others you need handle yourself. 1. **Schema must always match existing data.** Convex enforces this constraint. You cannot push a schema to a deployment with existing data that doesn't match it, unless you turn off schema enforcement. In general it safe to: 1. Add new tables to the schema. 2. Add an `optional` field to an existing table's schema, set the field on all documents in the table, and then make the field required. 3. Mark an existing field as `optional`, remove the field from all documents, and then remove the field. 4. Mark an existing field as a `union` of the existing type and a new type, modify the field on all documents to match the new type, and then change the type to the new type. 2. **Functions should be backwards compatible.** Even if your only client is a website, and you deploy it together with your backend, your users might still be running the old version of your website when your backend changes. Therefore you should make your functions backwards compatible until you are OK to break old clients. In general it is safe to: 1. Add new functions. 2. Add an `optional` named argument to an existing function. 3. Mark an existing named argument as `optional`. 4. Mark an existing named argument as a `union` of the existing type and a new type. 5. Change the behavior of the function in such a way that given the arguments from an old client its behavior will still be acceptable to the old client. 3. **Scheduled functions should be backwards compatible.** When you schedule a function to run in the future, you provide the argument values it will receive. Whenever a function runs, it always runs its currently deployed version. If you change the function between the time it was scheduled and the time it runs, you must ensure the new version will behave acceptably given the old arguments. Related posts from [![Stack](https://docs.convex.dev/img/stack-logo-dark.svg)![Stack](https://docs.convex.dev/img/stack-logo-light.svg)](https://stack.convex.dev/) [Skip to main content](https://docs.convex.dev/quickstart/svelte#docusaurus_skipToContent_fallback) Learn how to query data from Convex in a Svelte app. 01. Create a SvelteKit app Create a SvelteKit app using the `npx create svelte@latest` command. Other sets of options will work with the library as long as Svelte 5 is used but for this quickstart guide: - For \"Which Svelte app template,\" choose **\"Skeleton project.\"** - For \"Add type checking with TypeScript,\" choose **\"Yes, using TypeScript syntax.\"** - For \"Select additional options,\" enable **\"Try the Svelte 5 preview.\"** ```codeBlockLines_zEuJ npm create svelte@latest my-app ``` 02. Install the Convex client and server library To get started, install the `convex` and `convex-svelte` packages. ```codeBlockLines_zEuJ cd my-app && npm install convex convex-svelte ``` 03. Customize the convex path SvelteKit doesn't like referencing code outside of source, so customize the convex functionsDir to be under `src/`. convex.json ```codeBlockLines_zEuJ { \"functions\": \"src/convex/\" } ``` 04. Set up a Convex dev deployment Next, run `npx convex dev`. This will prompt you to log in with GitHub, create a project, and save your production and deployment URLs. It will also create a `convex/` folder for you to write your backend API functions in. The `dev` command will then continue running to sync your functions with your dev deployment in the cloud. ```codeBlockLines_zEuJ npx convex dev ``` 05. Create sample data for your database In a new terminal window, create a `sampleData.jsonl` file with some sample data. sampleData.jsonl ```codeBlockLines_zEuJ {\"text\": \"Buy groceries\", \"isCompleted\": true} {\"text\": \"Go for a swim\", \"isCompleted\": true} {\"text\": \"Integrate Convex\", \"isCompleted\": false} ``` 06. Add the sample data to your database Now that your project is ready, add a `tasks` table with the sample data into your Convex database with the `import` command. ```codeBlockLines_zEuJ npx convex import --table tasks sampleData.jsonl ``` 07. Expose a database query Add a new file `tasks.ts` in the `convex/` folder with a query function that loads the data. Exporting a query function from this file declares an API function named after the file and the export name, `api.tasks.get`. convex/tasks.ts ```codeBlockLines_zEuJ import { query } from \"./_generated/server\"; export const get = query({ args: {}, handler: async (ctx) => { const tasks = await ctx.db.query(\"tasks\").collect(); return tasks.map((task) => ({ ...task, assigner: \"tom\" })); }, }); ``` 08. Set up Convex Create a new file `src/routes/+layout.svelte` and set up the Convex client there to make it available on every page of your app. src/routes/+layout.svelte ```codeBlockLines_zEuJ {@render children()} ``` 09. Display the data in your app In `src/routes/+page.svelte` use `useQuery` to subscribe your `api.tasks.get` API function. src/routes/page.tsx ```codeBlockLines_zEuJ {#if query.isLoading} Loading... {:else if query.error} failed to load: {query.error.toString()} {:else}
    {#each query.data as task}
  • {task.isCompleted ? '☑' : '☐'} {task.text} assigned by {task.assigner}
  • {/each}
{/if} ``` 10. Start the app Start the app, open [http://localhost:5173](http://localhost:5173/) in a browser, and see the list of tasks. ```codeBlockLines_zEuJ npm run dev ``` [Skip to main content](https://docs.convex.dev/production/hosting#docusaurus_skipToContent_fallback) The easiest way to publish your full-stack web app is to use a hosting provider like [Vercel](https://vercel.com/) or [Netlify](https://netlify.com/). Both Vercel and Netlify integrate with Git to deploy code whenever a new revision is pushed. To host your app: 1. Commit all files and push to your favorite Git hosting provider such as [GitHub](https://github.com/), [GitLab](https://gitlab.com/) or [Bitbucket](https://bitbucket.org/). 2. Follow the appropriate guide below. If you aren't using Netlify or Vercel, you can follow the Custom Hosting guide. - [Vercel](https://docs.convex.dev/production/hosting/vercel) - [Netlify](https://docs.convex.dev/production/hosting/netlify) - [Custom Hosting](https://docs.convex.dev/production/hosting/custom) [Skip to main content](https://docs.convex.dev/scheduling/cron-jobs#docusaurus_skipToContent_fallback) On this page Convex allows you to schedule functions to run on a recurring basis. For example, cron jobs can be used to clean up data at a regular interval, send a reminder email at the same time every month, or schedule a backup every Saturday. **Example:** [Cron Jobs](https://github.com/get-convex/convex-demos/tree/main/cron-jobs) ## Defining your cron jobs [​](https://docs.convex.dev/scheduling/cron-jobs\\#defining-your-cron-jobs \"Direct link to Defining your cron jobs\") Cron jobs are defined in a `crons.ts` file in your `convex/` directory and look like: convex/crons.ts TS ```codeBlockLines_zEuJ import { cronJobs } from \"convex/server\"; import { internal } from \"./_generated/api\"; const crons = cronJobs(); crons.interval( \"clear messages table\", { minutes: 1 }, // every minute internal.messages.clearAll, ); crons.monthly( \"payment reminder\", { day: 1, hourUTC: 16, minuteUTC: 0 }, // Every month on the first day at 8:00am PST internal.payments.sendPaymentEmail, { email: \"my_email@gmail.com\" }, // argument to sendPaymentEmail ); // An alternative way to create the same schedule as above with cron syntax crons.cron( \"payment reminder duplicate\", \"0 16 1 * *\", internal.payments.sendPaymentEmail, { email: \"my_email@gmail.com\" }, // argument to sendPaymentEmail ); export default crons; ``` The first argument is a unique identifier for the cron job. The second argument is the schedule at which the function should run, see [Supported schedules](https://docs.convex.dev/scheduling/cron-jobs#supported-schedules) below. The third argument is the name of the public function or [internal function](https://docs.convex.dev/functions/internal-functions), either a [mutation](https://docs.convex.dev/functions/mutation-functions) or an [action](https://docs.convex.dev/functions/actions). ## Supported schedules [​](https://docs.convex.dev/scheduling/cron-jobs\\#supported-schedules \"Direct link to Supported schedules\") - [`crons.interval()`](https://docs.convex.dev/api/classes/server.Crons#interval) runs a function every specified number of `seconds`, `minutes`, or `hours`. The first run occurs when the cron job is first deployed to Convex. Unlike traditional crons, this option allows you to have seconds-level granularity. - [`crons.cron()`](https://docs.convex.dev/api/classes/server.Crons#cron) the traditional way of specifying cron jobs by a string with five fields separated by spaces (e.g. `\"* * * * *\"`). Times in cron syntax are in the UTC timezone. [Crontab Guru](https://crontab.guru/) is a helpful resource for understanding and creating schedules in this format. - [`crons.hourly()`](https://docs.convex.dev/api/classes/server.Crons#cron), [`crons.daily()`](https://docs.convex.dev/api/classes/server.Crons#daily), [`crons.weekly()`](https://docs.convex.dev/api/classes/server.Crons#weekly), [`crons.monthly()`](https://docs.convex.dev/api/classes/server.Crons#monthly) provide an alternative syntax for common cron schedules with explicitly named arguments. ## Viewing your cron jobs [​](https://docs.convex.dev/scheduling/cron-jobs\\#viewing-your-cron-jobs \"Direct link to Viewing your cron jobs\") You can view all your cron jobs in the [Convex dashboard cron jobs view](https://docs.convex.dev/dashboard/deployments/schedules#cron-jobs-ui). You can view added, updated, and deleted cron jobs in the logs and history view. Results of previously executed runs of the cron jobs are also available in the logs view. ## Error handling [​](https://docs.convex.dev/scheduling/cron-jobs\\#error-handling \"Direct link to Error handling\") Mutations and actions have the same guarantees that are described in [Error handling](https://docs.convex.dev/scheduling/scheduled-functions#error-handling) for scheduled functions. At most one run of each cron job can be executing at any moment. If the function scheduled by the cron job takes too long to run, following runs of the cron job may be skipped to avoid execution from falling behind. Skipping a scheduled run of a cron job due to the previous run still executing logs a message visible in the logs view of the dashboard. - [Defining your cron jobs](https://docs.convex.dev/scheduling/cron-jobs#defining-your-cron-jobs) - [Supported schedules](https://docs.convex.dev/scheduling/cron-jobs#supported-schedules) - [Viewing your cron jobs](https://docs.convex.dev/scheduling/cron-jobs#viewing-your-cron-jobs) - [Error handling](https://docs.convex.dev/scheduling/cron-jobs#error-handling) [Skip to main content](https://docs.convex.dev/search/vector-search#docusaurus_skipToContent_fallback) On this page Vector search allows you to find Convex documents similar to a provided vector. Typically, vectors will be embeddings which are numerical representations of text, images, or audio. Embeddings and vector search enable you to provide useful context to LLMs for AI powered applications, recommendations for similar content and more. Vector search is consistent and fully up-to-date. You can write a vector and immediately read it from a vector search. Unlike [full text search](https://docs.convex.dev/search), however, vector search is only available in [Convex actions](https://docs.convex.dev/functions/actions). **Example:** [Vector Search App](https://github.com/get-convex/convex-demos/tree/main/vector-search) To use vector search you need to: 1. Define a vector index. 2. Run a vector search from within an [action](https://docs.convex.dev/functions/actions). ## Defining vector indexes [​](https://docs.convex.dev/search/vector-search\\#defining-vector-indexes \"Direct link to Defining vector indexes\") Like [database indexes](https://docs.convex.dev/database/reading-data/indexes/), vector indexes are a data structure that is built in advance to enable efficient querying. Vector indexes are defined as part of your Convex [schema](https://docs.convex.dev/database/schemas). To add a vector index onto a table, use the [`vectorIndex`](https://docs.convex.dev/api/classes/server.TableDefinition#vectorindex) method on your table's schema. Every vector index has a unique name and a definition with: 1. `vectorField` string - The name of the field indexed for vector search. 2. `dimensions` number - The fixed size of the vectors index. If you're using embeddings, this dimension should match the size of your embeddings (e.g. `1536` for OpenAI). 3. \\[Optional\\] `filterFields` array - The names of additional fields that are indexed for fast filtering within your vector index. For example, if you want an index that can search for similar foods within a given cuisine, your table definition could look like: convex/schema.ts ```codeBlockLines_zEuJ foods: defineTable({ description: v.string(), cuisine: v.string(), embedding: v.array(v.float64()), }).vectorIndex(\"by_embedding\", { vectorField: \"embedding\", dimensions: 1536, filterFields: [\"cuisine\"], }), ``` You can specify vector and filter fields on nested documents by using a dot-separated path like `properties.name`. ## Running vector searches [​](https://docs.convex.dev/search/vector-search\\#running-vector-searches \"Direct link to Running vector searches\") Unlike database queries or full text search, vector searches can only be performed in a [Convex action](https://docs.convex.dev/functions/actions). They generally involve three steps: 1. Generate a vector from provided input (e.g. using OpenAI) 2. Use [`ctx.vectorSearch`](https://docs.convex.dev/api/interfaces/server.GenericActionCtx#vectorsearch) to fetch the IDs of similar documents 3. Load the desired information for the documents Here's an example of the first two steps for searching for similar French foods based on a description: convex/foods.ts TS ```codeBlockLines_zEuJ import { v } from \"convex/values\"; import { action } from \"./_generated/server\"; export const similarFoods = action({ args: { descriptionQuery: v.string(), }, handler: async (ctx, args) => { // 1. Generate an embedding from you favorite third party API: const embedding = await embed(args.descriptionQuery); // 2. Then search for similar foods! const results = await ctx.vectorSearch(\"foods\", \"by_embedding\", { vector: embedding, limit: 16, filter: (q) => q.eq(\"cuisine\", \"French\"), }); // ... }, }); ``` An example of the first step can be found [here](https://github.com/get-convex/convex-demos/blob/main/vector-search/convex/foods.ts#L18) in the vector search demo app. Focusing on the second step, the `vectorSearch` API takes in the table name, the index name, and finally a [`VectorSearchQuery`](https://docs.convex.dev/api/interfaces/server.VectorSearchQuery) object describing the search. This object has the following fields: 1. `vector` array - An array of numbers (e.g. embedding) to use in the search. - The search will return the document IDs of the documents with the most similar stored vectors. - It must have the same length as the `dimensions` of the index. 2. \\[Optional\\] `limit` number - The number of results to get back. If specified, this value must be between 1 and 256. 3. \\[Optional\\] `filter` - An expression that restricts the set of results based on the `filterFields` in the `vectorIndex` in your schema. See [Filter expressions](https://docs.convex.dev/search/vector-search#filter-expressions) for details. It returns an `Array` of objects containing exactly two fields: 1. `_id` - The [Document ID](https://docs.convex.dev/database/document-ids) for the matching document in the table 2. `_score` - An indicator of how similar the result is to the vector you were searching for, ranging from -1 (least similar) to 1 (most similar) Neither the underlying document nor the vector are included in `results`, so once you have the list of results, you will want to load the desired information about the results. There are a few strategies for loading this information documented in the [Advanced Patterns](https://docs.convex.dev/search/vector-search#advanced-patterns) section. For now, let's load the documents and return them from the action. To do so, we'll pass the list of results to a Convex query and run it inside of our action, returning the result: convex/foods.ts TS ```codeBlockLines_zEuJ export const fetchResults = internalQuery({ args: { ids: v.array(v.id(\"foods\")) }, handler: async (ctx, args) => { const results = []; for (const id of args.ids) { const doc = await ctx.db.get(id); if (doc === null) { continue; } results.push(doc); } return results; }, }); ``` convex/foods.ts TS ```codeBlockLines_zEuJ export const similarFoods = action({ args: { descriptionQuery: v.string(), }, handler: async (ctx, args) => { // 1. Generate an embedding from you favorite third party API: const embedding = await embed(args.descriptionQuery); // 2. Then search for similar foods! const results = await ctx.vectorSearch(\"foods\", \"by_embedding\", { vector: embedding, limit: 16, filter: (q) => q.eq(\"cuisine\", \"French\"), }); // 3. Fetch the results const foods: Array> = await ctx.runQuery( internal.foods.fetchResults, { ids: results.map((result) => result._id) }, ); return foods; }, }); ``` ### Filter expressions [​](https://docs.convex.dev/search/vector-search\\#filter-expressions \"Direct link to Filter expressions\") As mentioned above, vector searches support efficiently filtering results by additional fields on your document using either exact equality on a single field, or an `OR` of expressions. For example, here's a filter for foods with cuisine exactly equal to \"French\": ```codeBlockLines_zEuJ filter: (q) => q.eq(\"cuisine\", \"French\"), ``` You can also filter documents by a single field that contains several different values using an `or` expression. Here's a filter for French or Indonesian dishes: ```codeBlockLines_zEuJ filter: (q) => q.or(q.eq(\"cuisine\", \"French\"), q.eq(\"cuisine\", \"Indonesian\")), ``` For indexes with multiple filter fields, you can also use `.or()` filters on different fields. Here's a filter for dishes whose cuisine is French or whose main ingredient is butter: ```codeBlockLines_zEuJ filter: (q) => q.or(q.eq(\"cuisine\", \"French\"), q.eq(\"mainIngredient\", \"butter\")), ``` **Both `cuisine` and `mainIngredient` would need to be included in the** **`filterFields` in the `.vectorIndex` definition.** ### Other filtering [​](https://docs.convex.dev/search/vector-search\\#other-filtering \"Direct link to Other filtering\") Results can be filtered based on how similar they are to the provided vector using the `_score` field in your action: ```codeBlockLines_zEuJ const results = await ctx.vectorSearch(\"foods\", \"by_embedding\", { vector: embedding, }); const filteredResults = results.filter((result) => result._score >= 0.9); ``` Additional filtering can always be done by passing the vector search results to a query or mutation function that loads the documents and performs filtering using any of the fields on the document. **For performance, always put as many of your filters as possible into** **`.vectorSearch`.** ### Ordering [​](https://docs.convex.dev/search/vector-search\\#ordering \"Direct link to Ordering\") Vector queries always return results in relevance order. Currently Convex searches vectors using an [approximate nearest neighbor search](https://en.wikipedia.org/wiki/Nearest_neighbor_search#Approximate_nearest_neighbor) based on [cosine similarity](https://en.wikipedia.org/wiki/Cosine_similarity). Support for more similarity metrics [will come in the future](https://docs.convex.dev/search/vector-search#coming-soon). If multiple documents have the same score, ties are broken by the document ID. ## Advanced patterns [​](https://docs.convex.dev/search/vector-search\\#advanced-patterns \"Direct link to Advanced patterns\") ### Using a separate table to store vectors [​](https://docs.convex.dev/search/vector-search\\#using-a-separate-table-to-store-vectors \"Direct link to Using a separate table to store vectors\") There are two main options for setting up a vector index: 1. Storing vectors in the same table as other metadata 2. Storing vectors in a separate table, with a reference The examples above show the first option, which is simpler and works well for reading small amounts of documents. The second option is more complex, but better supports reading or returning large amounts of documents. Since vectors are typically large and not useful beyond performing vector searches, it's nice to avoid loading them from the database when reading other data (e.g. `db.get()`) or returning them from functions by storing them in a separate table. A table definition for movies, and a vector index supporting search for similar movies filtering by genre would look like this: convex/schema.ts ```codeBlockLines_zEuJ movieEmbeddings: defineTable({ embedding: v.array(v.float64()), genre: v.string(), }).vectorIndex(\"by_embedding\", { vectorField: \"embedding\", dimensions: 1536, filterFields: [\"genre\"], }), movies: defineTable({ title: v.string(), genre: v.string(), description: v.string(), votes: v.number(), embeddingId: v.optional(v.id(\"movieEmbeddings\")), }).index(\"by_embedding\", [\"embeddingId\"]), ``` Generating an embedding and running a vector search are the same as using a single table. Loading the relevant documents given the vector search result is different since we have an ID for `movieEmbeddings` but want to load a `movies` document. We can do this using the `by_embedding` database index on the `movies` table: convex/movies.ts TS ```codeBlockLines_zEuJ export const fetchMovies = query({ args: { ids: v.array(v.id(\"movieEmbeddings\")), }, handler: async (ctx, args) => { const results = []; for (const id of args.ids) { const doc = await ctx.db .query(\"movies\") .withIndex(\"by_embedding\", (q) => q.eq(\"embeddingId\", id)) .unique(); if (doc === null) { continue; } results.push(doc); } return results; }, }); ``` ### Fetching results and adding new documents [​](https://docs.convex.dev/search/vector-search\\#fetching-results-and-adding-new-documents \"Direct link to Fetching results and adding new documents\") Returning information from a vector search involves an action (since vector search is only available in actions) and a query or mutation to load the data. The example above used a query to load data and return it from an action. Since this is an action, the data returned is not reactive. An alternative would be to return the results of the vector search in the action, and have a separate query that reactively loads the data. The search results will not update reactively, but the data about each result would be reactive. The [Vector Search Demo App](https://github.com/get-convex/convex-demos/tree/main/vector-search) uses this strategy to show similar movies with a reactive \"Votes\" count. ## Limits [​](https://docs.convex.dev/search/vector-search\\#limits \"Direct link to Limits\") Convex supports millions of vectors today. This is an ongoing project and we will continue to scale this offering out with the rest of Convex. Vector indexes must have: - Exactly 1 vector index field. - The field must be of type `v.array(v.float64())` (or a union in which one of the possible types is `v.array(v.float64())`) - Exactly 1 dimension field with a value between 2 and 4096. - Up to 16 filter fields. Vector indexes count towards the [limit of 32 indexes per table](https://docs.convex.dev/database/reading-data/indexes/#limits). In addition you can have up to 4 vector indexes per table. Vector searches can have: - Exactly 1 vector to search by in the `vector` field - Up to 64 filter expressions - Up to 256 requested results (defaulting to 10). If your action performs a vector search then passes the results to a query or mutation function, you may find that one or more results from the vector search have been deleted or mutated. Because vector search is only available in actions, you cannot perform additional transactional queries or mutations based on the results. If this is important for your use case, please [let us know on Discord](https://convex.dev/community)! Only documents that contain a vector of the size and in the field specified by a vector index will be included in the index and returned by the vector search. For information on limits, see [here](https://docs.convex.dev/production/state/limits). ## Future development [​](https://docs.convex.dev/search/vector-search\\#future-development \"Direct link to Future development\") We're always open to customer feedback and requests. Some ideas we've considered for improving vector search in Convex include: - More sophisticated filters and filter syntax - Filtering by score in the `vectorSearch` API - Better support for generating embeddings If any of these features is important for your app, [let us know on Discord](https://convex.dev/community)! - [Defining vector indexes](https://docs.convex.dev/search/vector-search#defining-vector-indexes) - [Running vector searches](https://docs.convex.dev/search/vector-search#running-vector-searches) - [Filter expressions](https://docs.convex.dev/search/vector-search#filter-expressions) - [Other filtering](https://docs.convex.dev/search/vector-search#other-filtering) - [Ordering](https://docs.convex.dev/search/vector-search#ordering) - [Advanced patterns](https://docs.convex.dev/search/vector-search#advanced-patterns) - [Using a separate table to store vectors](https://docs.convex.dev/search/vector-search#using-a-separate-table-to-store-vectors) - [Fetching results and adding new documents](https://docs.convex.dev/search/vector-search#fetching-results-and-adding-new-documents) - [Limits](https://docs.convex.dev/search/vector-search#limits) - [Future development](https://docs.convex.dev/search/vector-search#future-development) [Skip to main content](https://docs.convex.dev/functions/debugging#docusaurus_skipToContent_fallback) On this page Debugging is the process of figuring out why your code isn't behaving as you expect. ## Debugging during development [​](https://docs.convex.dev/functions/debugging\\#debugging-during-development \"Direct link to Debugging during development\") During development the built-in `console` API allows you to understand what's going on inside your functions: convex/myFunctions.ts TS ```codeBlockLines_zEuJ import { mutation } from \"./_generated/server\"; import { v } from \"convex/values\"; export const mutateSomething = mutation({ args: { a: v.number(), b: v.number() }, handler: (_, args) => { console.log(\"Received args\", args); // ... }, }); ``` The following methods are available in the [default Convex runtime](https://docs.convex.dev/functions/runtimes#default-convex-runtime): - Logging values, with a specified severity level: - `console.log` - `console.info` - `console.warn` - `console.error` - `console.debug` - Logging with a stack trace: - [`console.trace`](https://developer.mozilla.org/en-US/docs/Web/API/console/trace_static) - Measuring execution time: - [`console.time`](https://developer.mozilla.org/en-US/docs/Web/API/console/time_static) - [`console.timeLog`](https://developer.mozilla.org/en-US/docs/Web/API/console/timelog_static) - [`console.timeEnd`](https://developer.mozilla.org/en-US/docs/Web/API/console/timeend_static) The Convex backend also automatically logs all successful function executions and all errors thrown by your functions. You can view these logs: 1. When using the [`ConvexReactClient`](https://docs.convex.dev/client/react), in your browser developer tools console pane. The logs are sent from your dev deployment to your client, and the client logs them to the browser. Production deployments [**do not** send logs to the client](https://docs.convex.dev/functions/error-handling/#differences-in-error-reporting-between-dev-and-prod). 2. In your Convex dashboard on the [Logs page](https://docs.convex.dev/dashboard/deployments/logs). 3. In your terminal by running [`npx convex logs`](https://docs.convex.dev/cli#tail-deployment-logs) or `npx convex dev --tail-logs`. ### Using a debugger [​](https://docs.convex.dev/functions/debugging\\#using-a-debugger \"Direct link to Using a debugger\") You can exercise your functions from tests, in which case you can add `debugger;` statements and step through your code. See [Testing](https://docs.convex.dev/testing/convex-test#debugging-tests). ## Debugging in production [​](https://docs.convex.dev/functions/debugging\\#debugging-in-production \"Direct link to Debugging in production\") When debugging an issue in production your options are: 1. Leverage existing logging 2. Add more logging and deploy a new version of your backend to production Convex backend currently only preserves a limited number of logs, and logs can be erased at any time when the Convex team performs internal maintenance and upgrades. You should therefore set up [log streaming and error reporting](https://docs.convex.dev/production/integrations/) integrations to enable your team easy access to historical logs and additional information logged by your client. ## Finding relevant logs by Request ID [​](https://docs.convex.dev/functions/debugging\\#finding-relevant-logs-by-request-id \"Direct link to Finding relevant logs by Request ID\") To find the appropriate logs for an error you or your users experience, Convex includes a Request ID in all exception messages in both dev and prod in this format: `[Request ID: ]`. You can copy and paste a Request ID into your Convex dashboard to view the logs for functions started by that request. See the [Dashboard logs page](https://docs.convex.dev/dashboard/deployments/logs#filter-logs) for details. - [Debugging during development](https://docs.convex.dev/functions/debugging#debugging-during-development) - [Using a debugger](https://docs.convex.dev/functions/debugging#using-a-debugger) - [Debugging in production](https://docs.convex.dev/functions/debugging#debugging-in-production) - [Finding relevant logs by Request ID](https://docs.convex.dev/functions/debugging#finding-relevant-logs-by-request-id) [Skip to main content](https://docs.convex.dev/client/react/nextjs#docusaurus_skipToContent_fallback) On this page [Next.js](https://nextjs.org/) is a React web development framework. When used with Convex, Next.js provides: - File-system based routing - Fast refresh in development - Font and image optimization and more! This page covers the App Router variant of Next.js. Alternatively see the [Pages Router](https://docs.convex.dev/client/react/nextjs-pages-router/nextjs-pages-router) version of this page. ## Getting started [​](https://docs.convex.dev/client/react/nextjs\\#getting-started \"Direct link to Getting started\") Follow the [Next.js Quickstart](https://docs.convex.dev/quickstart/nextjs) to add Convex to a new or existing Next.js project. ## Adding authentication [​](https://docs.convex.dev/client/react/nextjs\\#adding-authentication \"Direct link to Adding authentication\") ### Client-side only [​](https://docs.convex.dev/client/react/nextjs\\#client-side-only \"Direct link to Client-side only\") The simplest way to add user authentication to your Next.js app is to follow our React-based authentication guides for [Clerk](https://docs.convex.dev/auth/clerk) or [Auth0](https://docs.convex.dev/auth/auth0), inside your `app/ConvexClientProvider.tsx` file. For example this is what the file would look like for Auth0: app/ConvexClientProvider.tsx TS ```codeBlockLines_zEuJ \"use client\"; import { Auth0Provider } from \"@auth0/auth0-react\"; import { ConvexReactClient } from \"convex/react\"; import { ConvexProviderWithAuth0 } from \"convex/react-auth0\"; import { ReactNode } from \"react\"; const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!); export function ConvexClientProvider({ children }: { children: ReactNode }) { return ( {children} ); } ``` Custom loading and logged out views can be built with the helper `Authenticated`, `Unauthenticated` and `AuthLoading` components from `convex/react`, see the [Convex Next.js demo](https://github.com/get-convex/convex-demos/tree/main/nextjs-pages-router/pages/_app.tsx) for an example. If only some routes of your app require login, the same helpers can be used directly in page components that do require login instead of being shared between all pages from `app/ConvexClientProvider.tsx`. Share a single [ConvexReactClient](https://docs.convex.dev/api/classes/react.ConvexReactClient) instance between pages to avoid needing to reconnect to Convex on client-side page navigation. ### Server and client side [​](https://docs.convex.dev/client/react/nextjs\\#server-and-client-side \"Direct link to Server and client side\") To access user information or load Convex data requiring `ctx.auth` from Server Components, Server Actions, or Route Handlers you need to use the Next.js specific SDKs provided by Clerk and Auth0. Additional `.env.local` configuration is needed for these hybrid SDKs. #### Clerk [​](https://docs.convex.dev/client/react/nextjs\\#clerk \"Direct link to Clerk\") For an example of using Convex and with Next.js 15, run **`npm create convex@latest -- -t nextjs-clerk`** **``** Otherwise, follow the [Clerk Next.js quickstart](https://clerk.com/docs/quickstarts/nextjs), a guide from Clerk that includes steps for adding `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` and `CLERK_SECRET_KEY` to the .env.local file. In Next.js 15, the `` component imported from the `@clerk/nextjs` v6 package functions as both a client and a server context provider so you probably won't need the `ClerkProvider` from `@clerk/clerk-react`. #### Auth0 [​](https://docs.convex.dev/client/react/nextjs\\#auth0 \"Direct link to Auth0\") See the [Auth0 Next.js](https://auth0.com/docs/quickstart/webapp/nextjs/01-login) guide. #### Other providers [​](https://docs.convex.dev/client/react/nextjs\\#other-providers \"Direct link to Other providers\") Convex uses JWT identity tokens on the client for live query subscriptions and running mutations and actions, and on the Next.js backend for running queries, mutations, and actions in server components and API routes. Obtain the appropriate OpenID Identity JWT in both locations and you should be able to use any auth provider. See [Custom Auth](https://docs.convex.dev/auth/advanced/custom-auth) for more. ## Server rendering (SSR) [​](https://docs.convex.dev/client/react/nextjs\\#server-rendering-ssr \"Direct link to Server rendering (SSR)\") Next.js automatically renders both Client and Server Components on the server during the initial page load. To keep your UI [automatically reactive](https://docs.convex.dev/functions/query-functions#caching-reactivity) to changes in your Convex database it needs to use Client Components. The `ConvexReactClient` will maintain a connection to your deployment and will get updates as data changes and that must happen on the client. See the dedicated [Server Rendering](https://docs.convex.dev/functions/query-functions#caching-reactivity) page for more details about preloading data for Client Components, fetching data and authentication in Server Components, and implementing Route Handlers. - [Getting started](https://docs.convex.dev/client/react/nextjs#getting-started) - [Adding authentication](https://docs.convex.dev/client/react/nextjs#adding-authentication) - [Client-side only](https://docs.convex.dev/client/react/nextjs#client-side-only) - [Server and client side](https://docs.convex.dev/client/react/nextjs#server-and-client-side) - [Server rendering (SSR)](https://docs.convex.dev/client/react/nextjs#server-rendering-ssr) [Skip to main content](https://docs.convex.dev/auth/database-auth#docusaurus_skipToContent_fallback) On this page _If you're using [Convex Auth](https://docs.convex.dev/auth/convex-auth) the user information_ _is already stored in your database. There's nothing else you need to implement._ You might want to store user information directly in your Convex database, for the following reasons: - Your functions need information about other users, not just about the currently logged-in user - Your functions need access to information other than the fields available in the [Open ID Connect JWT](https://docs.convex.dev/auth/functions-auth) There are two ways you can choose from for storing user information in your database (but only the second one allows storing information not contained in the JWT): 1. Have your app's [client call a mutation](https://docs.convex.dev/auth/database-auth#call-a-mutation-from-the-client) that stores the information from the JWT available on [`ctx.auth`](https://docs.convex.dev/api/interfaces/server.Auth) 2. [Implement a webhook](https://docs.convex.dev/auth/database-auth#set-up-webhooks) and have your identity provider call it whenever user information changes ## Call a mutation from the client [​](https://docs.convex.dev/auth/database-auth\\#call-a-mutation-from-the-client \"Direct link to Call a mutation from the client\") **Example:** [Convex Authentication with Clerk](https://github.com/get-convex/convex-demos/tree/main/users-and-clerk) ### (optional) Users table schema [​](https://docs.convex.dev/auth/database-auth\\#optional-users-table-schema \"Direct link to (optional) Users table schema\") You can define a `\"users\"` table, optionally with an [index](https://docs.convex.dev/database/reading-data/indexes/) for efficient looking up the users in the database. In the examples below we will use the `tokenIdentifier` from the `ctx.auth.getUserIdentity()` to identify the user, but you could use the `subject` field (which is usually set to the unique user ID from your auth provider) or even `email`, if your authentication provider provides email verification and you have it enabled. Which field you use will determine how multiple providers interact, and how hard it will be to migrate to a different provider. convex/schema.ts ```codeBlockLines_zEuJ users: defineTable({ name: v.string(), tokenIdentifier: v.string(), }).index(\"by_token\", [\"tokenIdentifier\"]), ``` ### Mutation for storing current user [​](https://docs.convex.dev/auth/database-auth\\#mutation-for-storing-current-user \"Direct link to Mutation for storing current user\") This is an example of a mutation that stores the user's `name` and `tokenIdentifier`: convex/users.ts TS ```codeBlockLines_zEuJ import { mutation } from \"./_generated/server\"; export const store = mutation({ args: {}, handler: async (ctx) => { const identity = await ctx.auth.getUserIdentity(); if (!identity) { throw new Error(\"Called storeUser without authentication present\"); } // Check if we've already stored this identity before. // Note: If you don't want to define an index right away, you can use // ctx.db.query(\"users\") // .filter(q => q.eq(q.field(\"tokenIdentifier\"), identity.tokenIdentifier)) // .unique(); const user = await ctx.db .query(\"users\") .withIndex(\"by_token\", (q) => q.eq(\"tokenIdentifier\", identity.tokenIdentifier), ) .unique(); if (user !== null) { // If we've seen this identity before but the name has changed, patch the value. if (user.name !== identity.name) { await ctx.db.patch(user._id, { name: identity.name }); } return user._id; } // If it's a new identity, create a new `User`. return await ctx.db.insert(\"users\", { name: identity.name ?? \"Anonymous\", tokenIdentifier: identity.tokenIdentifier, }); }, }); ``` ### Calling the store user mutation from React [​](https://docs.convex.dev/auth/database-auth\\#calling-the-store-user-mutation-from-react \"Direct link to Calling the store user mutation from React\") You can call this mutation when the user logs in from a `useEffect` hook. After the mutation succeeds you can update local state to reflect that the user has been stored. This helper hook that does the job: src/useStoreUserEffect.ts TS ```codeBlockLines_zEuJ import { useUser } from \"@clerk/clerk-react\"; import { useConvexAuth } from \"convex/react\"; import { useEffect, useState } from \"react\"; import { useMutation } from \"convex/react\"; import { api } from \"../convex/_generated/api\"; import { Id } from \"../convex/_generated/dataModel\"; export function useStoreUserEffect() { const { isLoading, isAuthenticated } = useConvexAuth(); const { user } = useUser(); // When this state is set we know the server // has stored the user. const [userId, setUserId] = useState | null>(null); const storeUser = useMutation(api.users.store); // Call the `storeUser` mutation function to store // the current user in the `users` table and return the `Id` value. useEffect(() => { // If the user is not logged in don't do anything if (!isAuthenticated) { return; } // Store the user in the database. // Recall that `storeUser` gets the user information via the `auth` // object on the server. You don't need to pass anything manually here. async function createUser() { const id = await storeUser(); setUserId(id); } createUser(); return () => setUserId(null); // Make sure the effect reruns if the user logs in with // a different identity }, [isAuthenticated, storeUser, user?.id]); // Combine the local state with the state from context return { isLoading: isLoading || (isAuthenticated && userId === null), isAuthenticated: isAuthenticated && userId !== null, }; } ``` You can use this hook in your top-level component. If your queries need the user document to be present, make sure that you only render the components that call them after the user has been stored: src/App.tsx TS ```codeBlockLines_zEuJ import { SignInButton, UserButton } from \"@clerk/clerk-react\"; import { useQuery } from \"convex/react\"; import { api } from \"../convex/_generated/api\"; import { useStoreUserEffect } from \"./useStoreUserEffect.js\"; function App() { const { isLoading, isAuthenticated } = useStoreUserEffect(); return (
{isLoading ? ( <>Loading... ) : !isAuthenticated ? ( ) : ( <> )}
); } function Content() { const messages = useQuery(api.messages.getForCurrentUser); return
Authenticated content: {messages?.length}
; } export default App; ``` In this way the `useStoreUserEffect` hook replaces the `useConvexAuth` hook. ### Using the current user's document ID [​](https://docs.convex.dev/auth/database-auth\\#using-the-current-users-document-id \"Direct link to Using the current user's document ID\") Similarly to the store user mutation, you can retrieve the current user's ID, or throw an error if the user hasn't been stored. Now that you have users stored as documents in your Convex database, you can use their IDs as foreign keys in other documents: convex/messages.ts TS ```codeBlockLines_zEuJ import { v } from \"convex/values\"; import { mutation } from \"./_generated/server\"; export const send = mutation({ args: { body: v.string() }, handler: async (ctx, args) => { const identity = await ctx.auth.getUserIdentity(); if (!identity) { throw new Error(\"Unauthenticated call to mutation\"); } const user = await ctx.db .query(\"users\") .withIndex(\"by_token\", (q) => q.eq(\"tokenIdentifier\", identity.tokenIdentifier), ) .unique(); if (!user) { throw new Error(\"Unauthenticated call to mutation\"); } await ctx.db.insert(\"messages\", { body: args.body, user: user._id }); }, }); // do something with `user`... } }); ``` ### Loading users by their ID [​](https://docs.convex.dev/auth/database-auth\\#loading-users-by-their-id \"Direct link to Loading users by their ID\") The information about other users can be retrieved via their IDs: convex/messages.ts TS ```codeBlockLines_zEuJ import { query } from \"./_generated/server\"; export const list = query({ args: {}, handler: async (ctx) => { const messages = await ctx.db.query(\"messages\").collect(); return Promise.all( messages.map(async (message) => { // For each message in this channel, fetch the `User` who wrote it and // insert their name into the `author` field. const user = await ctx.db.get(message.user); return { author: user?.name ?? \"Anonymous\", ...message, }; }), ); }, }); ``` ## Set up webhooks [​](https://docs.convex.dev/auth/database-auth\\#set-up-webhooks \"Direct link to Set up webhooks\") This guide will use Clerk, but Auth0 can be set up similarly via [Auth0 Actions](https://auth0.com/docs/customize/actions/actions-overview). With this implementation Clerk will call your Convex backend via an HTTP endpoint any time a user signs up, updates or deletes their account. **Example:** [Convex Authentication with Clerk and Webhooks](https://github.com/get-convex/convex-demos/tree/main/users-and-clerk-webhooks) ### Configure the webhook endpoint in Clerk [​](https://docs.convex.dev/auth/database-auth\\#configure-the-webhook-endpoint-in-clerk \"Direct link to Configure the webhook endpoint in Clerk\") On your Clerk dashboard, go to _Webhooks_, click on _\\+ Add Endpoint_. Set _Endpoint URL_ to `https://.convex.site/clerk-users-webhook` (note the domain ends in **`.site`**, not `.cloud`). You can see your deployment name in the `.env.local` file in your project directory, or on your Convex dashboard as part of the [Deployment URL](https://docs.convex.dev/dashboard/deployments/deployment-settings). For example, the endpoint URL could be: `https://happy-horse-123.convex.site/clerk-users-webhook`. In _Message Filtering_, select **user** for all user events (scroll down or use the search input). Click on _Create_. After the endpoint is saved, copy the _Signing Secret_ (on the right side of the UI), it should start with `whsec_`. Set it as the value of the `CLERK_WEBHOOK_SECRET` environment variable in your Convex [dashboard](https://dashboard.convex.dev/). ### (optional) Users table schema [​](https://docs.convex.dev/auth/database-auth\\#optional-users-table-schema-1 \"Direct link to (optional) Users table schema\") You can define a `\"users\"` table, optionally with an [index](https://docs.convex.dev/database/reading-data/indexes/) for efficient looking up the users in the database. In the examples below we will use the `subject` from the `ctx.auth.getUserIdentity()` to identify the user, which should be set to the Clerk user ID. convex/schema.ts ```codeBlockLines_zEuJ users: defineTable({ name: v.string(), // this the Clerk ID, stored in the subject JWT field externalId: v.string(), }).index(\"byExternalId\", [\"externalId\"]), ``` ### Mutations for upserting and deleting users [​](https://docs.convex.dev/auth/database-auth\\#mutations-for-upserting-and-deleting-users \"Direct link to Mutations for upserting and deleting users\") This is an example of mutations that handle the updates received via the webhook: convex/users.ts TS ```codeBlockLines_zEuJ import { internalMutation, query, QueryCtx } from \"./_generated/server\"; import { UserJSON } from \"@clerk/backend\"; import { v, Validator } from \"convex/values\"; export const current = query({ args: {}, handler: async (ctx) => { return await getCurrentUser(ctx); }, }); export const upsertFromClerk = internalMutation({ args: { data: v.any() as Validator }, // no runtime validation, trust Clerk async handler(ctx, { data }) { const userAttributes = { name: `${data.first_name} ${data.last_name}`, externalId: data.id, }; const user = await userByExternalId(ctx, data.id); if (user === null) { await ctx.db.insert(\"users\", userAttributes); } else { await ctx.db.patch(user._id, userAttributes); } }, }); export const deleteFromClerk = internalMutation({ args: { clerkUserId: v.string() }, async handler(ctx, { clerkUserId }) { const user = await userByExternalId(ctx, clerkUserId); if (user !== null) { await ctx.db.delete(user._id); } else { console.warn( `Can't delete user, there is none for Clerk user ID: ${clerkUserId}`, ); } }, }); export async function getCurrentUserOrThrow(ctx: QueryCtx) { const userRecord = await getCurrentUser(ctx); if (!userRecord) throw new Error(\"Can't get current user\"); return userRecord; } export async function getCurrentUser(ctx: QueryCtx) { const identity = await ctx.auth.getUserIdentity(); if (identity === null) { return null; } return await userByExternalId(ctx, identity.subject); } async function userByExternalId(ctx: QueryCtx, externalId: string) { return await ctx.db .query(\"users\") .withIndex(\"byExternalId\", (q) => q.eq(\"externalId\", externalId)) .unique(); } ``` There are also a few helpers in this file: - `current` exposes the user information to the client, which will helps the client determine whether the webhook already succeeded - `upsertFromClerk` will be called when a user signs up or when they update their account - `deleteFromClerk` will be called when a user deletes their account via Clerk UI from your app - `getCurrentUserOrThrow` retrieves the currently logged-in user or throws an error - `getCurrentUser` retrieves the currently logged-in user or returns null - `userByExternalId` retrieves a user given the Clerk ID, and is used only for retrieving the current user or when updating an existing user via the webhook ### Webhook endpoint implementation [​](https://docs.convex.dev/auth/database-auth\\#webhook-endpoint-implementation \"Direct link to Webhook endpoint implementation\") This how the actual HTTP endpoint can be implemented: convex/http.ts TS ```codeBlockLines_zEuJ import { httpRouter } from \"convex/server\"; import { httpAction } from \"./_generated/server\"; import { internal } from \"./_generated/api\"; import type { WebhookEvent } from \"@clerk/backend\"; import { Webhook } from \"svix\"; const http = httpRouter(); http.route({ path: \"/clerk-users-webhook\", method: \"POST\", handler: httpAction(async (ctx, request) => { const event = await validateRequest(request); if (!event) { return new Response(\"Error occured\", { status: 400 }); } switch (event.type) { case \"user.created\": // intentional fallthrough case \"user.updated\": await ctx.runMutation(internal.users.upsertFromClerk, { data: event.data, }); break; case \"user.deleted\": { const clerkUserId = event.data.id!; await ctx.runMutation(internal.users.deleteFromClerk, { clerkUserId }); break; } default: console.log(\"Ignored Clerk webhook event\", event.type); } return new Response(null, { status: 200 }); }), }); async function validateRequest(req: Request): Promise { const payloadString = await req.text(); const svixHeaders = { \"svix-id\": req.headers.get(\"svix-id\")!, \"svix-timestamp\": req.headers.get(\"svix-timestamp\")!, \"svix-signature\": req.headers.get(\"svix-signature\")!, }; const wh = new Webhook(process.env.CLERK_WEBHOOK_SECRET!); try { return wh.verify(payloadString, svixHeaders) as unknown as WebhookEvent; } catch (error) { console.error(\"Error verifying webhook event\", error); return null; } } export default http; ``` If you deploy your code now and sign in, you should see the user being created in your Convex database. ### Using the current user's document [​](https://docs.convex.dev/auth/database-auth\\#using-the-current-users-document \"Direct link to Using the current user's document\") You can use the helpers defined before to retrieve the current user's document. Now that you have users stored as documents in your Convex database, you can use their IDs as foreign keys in other documents: convex/messages.ts TS ```codeBlockLines_zEuJ import { v } from \"convex/values\"; import { mutation } from \"./_generated/server\"; import { getCurrentUserOrThrow } from \"./users\"; export const send = mutation({ args: { body: v.string() }, handler: async (ctx, args) => { const user = await getCurrentUserOrThrow(ctx); await ctx.db.insert(\"messages\", { body: args.body, userId: user._id }); }, }); ``` ### Loading users by their ID [​](https://docs.convex.dev/auth/database-auth\\#loading-users-by-their-id-1 \"Direct link to Loading users by their ID\") The information about other users can be retrieved via their IDs: convex/messages.ts TS ```codeBlockLines_zEuJ export const list = query({ args: {}, handler: async (ctx) => { const messages = await ctx.db.query(\"messages\").collect(); return Promise.all( messages.map(async (message) => { // For each message in this channel, fetch the `User` who wrote it and // insert their name into the `author` field. const user = await ctx.db.get(message.user); return { author: user?.name ?? \"Anonymous\", ...message, }; }), ); }, }); ``` ### Waiting for current user to be stored [​](https://docs.convex.dev/auth/database-auth\\#waiting-for-current-user-to-be-stored \"Direct link to Waiting for current user to be stored\") If you want to use the current user's document in a query, make sure that the user has already been stored. You can do this by explicitly checking for this condition before rendering the components that call the query, or before redirecting to the authenticated portion of your app. For example you can define a hook that determines the current authentication state of the client, taking into account whether the current user has been stored: src/useCurrentUser.ts TS ```codeBlockLines_zEuJ import { useConvexAuth, useQuery } from \"convex/react\"; import { api } from \"../convex/_generated/api\"; export function useCurrentUser() { const { isLoading, isAuthenticated } = useConvexAuth(); const user = useQuery(api.users.current); // Combine the authentication state with the user existence check return { isLoading: isLoading || (isAuthenticated && user === null), isAuthenticated: isAuthenticated && user !== null, }; } ``` And then you can use it to render the appropriate components: src/App.tsx TS ```codeBlockLines_zEuJ import { useCurrentUser } from \"./useCurrentUser\"; export default function App() { const { isLoading, isAuthenticated } = useCurrentUser(); return (
{isLoading ? ( <>Loading... ) : isAuthenticated ? ( ) : ( )}
); } ``` - [Call a mutation from the client](https://docs.convex.dev/auth/database-auth#call-a-mutation-from-the-client) - [(optional) Users table schema](https://docs.convex.dev/auth/database-auth#optional-users-table-schema) - [Mutation for storing current user](https://docs.convex.dev/auth/database-auth#mutation-for-storing-current-user) - [Calling the store user mutation from React](https://docs.convex.dev/auth/database-auth#calling-the-store-user-mutation-from-react) - [Using the current user's document ID](https://docs.convex.dev/auth/database-auth#using-the-current-users-document-id) - [Loading users by their ID](https://docs.convex.dev/auth/database-auth#loading-users-by-their-id) - [Set up webhooks](https://docs.convex.dev/auth/database-auth#set-up-webhooks) - [Configure the webhook endpoint in Clerk](https://docs.convex.dev/auth/database-auth#configure-the-webhook-endpoint-in-clerk) - [(optional) Users table schema](https://docs.convex.dev/auth/database-auth#optional-users-table-schema-1) - [Mutations for upserting and deleting users](https://docs.convex.dev/auth/database-auth#mutations-for-upserting-and-deleting-users) - [Webhook endpoint implementation](https://docs.convex.dev/auth/database-auth#webhook-endpoint-implementation) - [Using the current user's document](https://docs.convex.dev/auth/database-auth#using-the-current-users-document) - [Loading users by their ID](https://docs.convex.dev/auth/database-auth#loading-users-by-their-id-1) - [Waiting for current user to be stored](https://docs.convex.dev/auth/database-auth#waiting-for-current-user-to-be-stored) [Skip to main content](https://docs.convex.dev/database/writing-data#docusaurus_skipToContent_fallback) On this page [Mutations](https://docs.convex.dev/functions/mutation-functions) can insert, update, and remove data from database tables. ## Inserting new documents [​](https://docs.convex.dev/database/writing-data\\#inserting-new-documents \"Direct link to Inserting new documents\") You can create new documents in the database with the [`db.insert`](https://docs.convex.dev/api/interfaces/server.GenericDatabaseWriter#insert) method: convex/tasks.ts TS ```codeBlockLines_zEuJ import { mutation } from \"./_generated/server\"; import { v } from \"convex/values\"; export const createTask = mutation({ args: { text: v.string() }, handler: async (ctx, args) => { const taskId = await ctx.db.insert(\"tasks\", { text: args.text }); // do something with `taskId` }, }); ``` The second argument to `db.insert` is a JavaScript object with data for the new document. The same types of values that can be passed into and returned from [queries](https://docs.convex.dev/functions/query-functions) and [mutations](https://docs.convex.dev/functions/mutation-functions) can be written into the database. See [Data Types](https://docs.convex.dev/database/types) for the full list of supported types. The `insert` method returns a globally unique ID for the newly inserted document. ## Updating existing documents [​](https://docs.convex.dev/database/writing-data\\#updating-existing-documents \"Direct link to Updating existing documents\") Given an existing document ID the document can be updated using the following methods: 1. The [`db.patch`](https://docs.convex.dev/api/interfaces/server.GenericDatabaseWriter#patch) method will patch an existing document, shallow merging it with the given partial document. New fields are added. Existing fields are overwritten. Fields set to `undefined` are removed. convex/tasks.ts TS ```codeBlockLines_zEuJ import { mutation } from \"./_generated/server\"; import { v } from \"convex/values\"; export const updateTask = mutation({ args: { id: v.id(\"tasks\") }, handler: async (ctx, args) => { const { id } = args; console.log(await ctx.db.get(id)); // { text: \"foo\", status: { done: true }, _id: ... } // Add `tag` and overwrite `status`: await ctx.db.patch(id, { tag: \"bar\", status: { archived: true } }); console.log(await ctx.db.get(id)); // { text: \"foo\", tag: \"bar\", status: { archived: true }, _id: ... } // Unset `tag` by setting it to `undefined` await ctx.db.patch(id, { tag: undefined }); console.log(await ctx.db.get(id)); // { text: \"foo\", status: { archived: true }, _id: ... } }, }); ``` 2. The [`db.replace`](https://docs.convex.dev/api/interfaces/server.GenericDatabaseWriter#replace) method will replace the existing document entirely, potentially removing existing fields: convex/tasks.ts TS ```codeBlockLines_zEuJ import { mutation } from \"./_generated/server\"; import { v } from \"convex/values\"; export const replaceTask = mutation({ args: { id: v.id(\"tasks\") }, handler: async (ctx, args) => { const { id } = args; console.log(await ctx.db.get(id)); // { text: \"foo\", _id: ... } // Replace the whole document await ctx.db.replace(id, { invalid: true }); console.log(await ctx.db.get(id)); // { invalid: true, _id: ... } }, }); ``` ## Deleting documents [​](https://docs.convex.dev/database/writing-data\\#deleting-documents \"Direct link to Deleting documents\") Given an existing document ID the document can be removed from the table with the [`db.delete`](https://docs.convex.dev/api/interfaces/server.GenericDatabaseWriter#delete) method. convex/tasks.ts TS ```codeBlockLines_zEuJ import { mutation } from \"./_generated/server\"; import { v } from \"convex/values\"; export const deleteTask = mutation({ args: { id: v.id(\"tasks\") }, handler: async (ctx, args) => { await ctx.db.delete(args.id); }, }); ``` ## Write performance and limits [​](https://docs.convex.dev/database/writing-data\\#write-performance-and-limits \"Direct link to Write performance and limits\") To prevent accidental writes of large amounts of records, queries and mutations enforce limits detailed [here](https://docs.convex.dev/production/state/limits#transactions). - [Inserting new documents](https://docs.convex.dev/database/writing-data#inserting-new-documents) - [Updating existing documents](https://docs.convex.dev/database/writing-data#updating-existing-documents) - [Deleting documents](https://docs.convex.dev/database/writing-data#deleting-documents) - [Write performance and limits](https://docs.convex.dev/database/writing-data#write-performance-and-limits) [Skip to main content](https://docs.convex.dev/api/modules/react#docusaurus_skipToContent_fallback) On this page Tools to integrate Convex into React applications. This module contains: 1. [ConvexReactClient](https://docs.convex.dev/api/classes/react.ConvexReactClient), a client for using Convex in React. 2. [ConvexProvider](https://docs.convex.dev/api/modules/react#convexprovider), a component that stores this client in React context. 3. [Authenticated](https://docs.convex.dev/api/modules/react#authenticated), [Unauthenticated](https://docs.convex.dev/api/modules/react#unauthenticated) and [AuthLoading](https://docs.convex.dev/api/modules/react#authloading) helper auth components. 4. Hooks [useQuery](https://docs.convex.dev/api/modules/react#usequery), [useMutation](https://docs.convex.dev/api/modules/react#usemutation), [useAction](https://docs.convex.dev/api/modules/react#useaction) and more for accessing this client from your React components. ## Usage [​](https://docs.convex.dev/api/modules/react\\#usage \"Direct link to Usage\") ### Creating the client [​](https://docs.convex.dev/api/modules/react\\#creating-the-client \"Direct link to Creating the client\") ```codeBlockLines_zEuJ import { ConvexReactClient } from \"convex/react\"; // typically loaded from an environment variable const address = \"https://small-mouse-123.convex.cloud\" const convex = new ConvexReactClient(address); ``` ### Storing the client in React Context [​](https://docs.convex.dev/api/modules/react\\#storing-the-client-in-react-context \"Direct link to Storing the client in React Context\") ```codeBlockLines_zEuJ import { ConvexProvider } from \"convex/react\"; ``` ### Using the auth helpers [​](https://docs.convex.dev/api/modules/react\\#using-the-auth-helpers \"Direct link to Using the auth helpers\") ```codeBlockLines_zEuJ import { Authenticated, Unauthenticated, AuthLoading } from \"convex/react\"; Logged in Logged out Still loading ``` ### Using React hooks [​](https://docs.convex.dev/api/modules/react\\#using-react-hooks \"Direct link to Using React hooks\") ```codeBlockLines_zEuJ import { useQuery, useMutation } from \"convex/react\"; import { api } from \"../convex/_generated/api\"; function App() { const counter = useQuery(api.getCounter.default); const increment = useMutation(api.incrementCounter.default); // Your component here! } ``` ## Classes [​](https://docs.convex.dev/api/modules/react\\#classes \"Direct link to Classes\") - [ConvexReactClient](https://docs.convex.dev/api/classes/react.ConvexReactClient) ## Interfaces [​](https://docs.convex.dev/api/modules/react\\#interfaces \"Direct link to Interfaces\") - [ReactMutation](https://docs.convex.dev/api/interfaces/react.ReactMutation) - [ReactAction](https://docs.convex.dev/api/interfaces/react.ReactAction) - [Watch](https://docs.convex.dev/api/interfaces/react.Watch) - [WatchQueryOptions](https://docs.convex.dev/api/interfaces/react.WatchQueryOptions) - [MutationOptions](https://docs.convex.dev/api/interfaces/react.MutationOptions) - [ConvexReactClientOptions](https://docs.convex.dev/api/interfaces/react.ConvexReactClientOptions) ## Type Aliases [​](https://docs.convex.dev/api/modules/react\\#type-aliases \"Direct link to Type Aliases\") ### AuthTokenFetcher [​](https://docs.convex.dev/api/modules/react\\#authtokenfetcher \"Direct link to AuthTokenFetcher\") Ƭ **AuthTokenFetcher**: ( `args`: { `forceRefreshToken`: `boolean` }) =\\> `Promise` < `string` \\| `null` \\| `undefined` > #### Type declaration [​](https://docs.convex.dev/api/modules/react\\#type-declaration \"Direct link to Type declaration\") ▸ ( `args`): `Promise` < `string` \\| `null` \\| `undefined` > An async function returning the JWT-encoded OpenID Connect Identity Token if available. `forceRefreshToken` is `true` if the server rejected a previously returned token, and the client should try to fetch a new one. See [setAuth](https://docs.convex.dev/api/classes/react.ConvexReactClient#setauth). ##### Parameters [​](https://docs.convex.dev/api/modules/react\\#parameters \"Direct link to Parameters\") | Name | Type | | :-- | :-- | | `args` | `Object` | | `args.forceRefreshToken` | `boolean` | ##### Returns [​](https://docs.convex.dev/api/modules/react\\#returns \"Direct link to Returns\") `Promise` < `string` \\| `null` \\| `undefined` > #### Defined in [​](https://docs.convex.dev/api/modules/react\\#defined-in \"Direct link to Defined in\") [browser/sync/authentication\\_manager.ts:21](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/authentication_manager.ts#L21) * * * ### ConvexAuthState [​](https://docs.convex.dev/api/modules/react\\#convexauthstate \"Direct link to ConvexAuthState\") Ƭ **ConvexAuthState**: `Object` Type representing the state of an auth integration with Convex. #### Type declaration [​](https://docs.convex.dev/api/modules/react\\#type-declaration-1 \"Direct link to Type declaration\") | Name | Type | | :-- | :-- | | `isLoading` | `boolean` | | `isAuthenticated` | `boolean` | #### Defined in [​](https://docs.convex.dev/api/modules/react\\#defined-in-1 \"Direct link to Defined in\") [react/ConvexAuthState.tsx:26](https://github.com/get-convex/convex-js/blob/main/src/react/ConvexAuthState.tsx#L26) * * * ### OptionalRestArgsOrSkip [​](https://docs.convex.dev/api/modules/react\\#optionalrestargsorskip \"Direct link to OptionalRestArgsOrSkip\") Ƭ **OptionalRestArgsOrSkip** < `FuncRef` >: `FuncRef`\\[ `\"_args\"`\\] extends `EmptyObject` ? \\[args?: EmptyObject \\| \"skip\"\\] : \\[args: FuncRef\\[\"\\_args\"\\] \\| \"skip\"\\] #### Type parameters [​](https://docs.convex.dev/api/modules/react\\#type-parameters \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `FuncRef` | extends [`FunctionReference`](https://docs.convex.dev/api/modules/server#functionreference) < `any` > | #### Defined in [​](https://docs.convex.dev/api/modules/react\\#defined-in-2 \"Direct link to Defined in\") [react/client.ts:575](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L575) * * * ### Preloaded [​](https://docs.convex.dev/api/modules/react\\#preloaded \"Direct link to Preloaded\") Ƭ **Preloaded** < `Query` >: `Object` The preloaded query payload, which should be passed to a client component and passed to [usePreloadedQuery](https://docs.convex.dev/api/modules/react#usepreloadedquery). #### Type parameters [​](https://docs.convex.dev/api/modules/react\\#type-parameters-1 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Query` | extends [`FunctionReference`](https://docs.convex.dev/api/modules/server#functionreference) < `\"query\"` > | #### Type declaration [​](https://docs.convex.dev/api/modules/react\\#type-declaration-2 \"Direct link to Type declaration\") | Name | Type | | :-- | :-- | | `__type` | `Query` | | `_name` | `string` | | `_argsJSON` | `string` | | `_valueJSON` | `string` | #### Defined in [​](https://docs.convex.dev/api/modules/react\\#defined-in-3 \"Direct link to Defined in\") [react/hydration.tsx:12](https://github.com/get-convex/convex-js/blob/main/src/react/hydration.tsx#L12) * * * ### PaginatedQueryReference [​](https://docs.convex.dev/api/modules/react\\#paginatedqueryreference \"Direct link to PaginatedQueryReference\") Ƭ **PaginatedQueryReference**: [`FunctionReference`](https://docs.convex.dev/api/modules/server#functionreference) < `\"query\"`, `\"public\"`, { `paginationOpts`: [`PaginationOptions`](https://docs.convex.dev/api/interfaces/server.PaginationOptions) }, [`PaginationResult`](https://docs.convex.dev/api/interfaces/server.PaginationResult) < `any` >> A [FunctionReference](https://docs.convex.dev/api/modules/server#functionreference) that is usable with [usePaginatedQuery](https://docs.convex.dev/api/modules/react#usepaginatedquery). This function reference must: - Refer to a public query - Have an argument named \"paginationOpts\" of type [PaginationOptions](https://docs.convex.dev/api/interfaces/server.PaginationOptions) - Have a return type of [PaginationResult](https://docs.convex.dev/api/interfaces/server.PaginationResult). #### Defined in [​](https://docs.convex.dev/api/modules/react\\#defined-in-4 \"Direct link to Defined in\") [react/use\\_paginated\\_query.ts:30](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L30) * * * ### UsePaginatedQueryResult [​](https://docs.convex.dev/api/modules/react\\#usepaginatedqueryresult \"Direct link to UsePaginatedQueryResult\") Ƭ **UsePaginatedQueryResult** < `Item` >: { `results`: `Item`\\[\\] ; `loadMore`: ( `numItems`: `number`) =\\> `void` } & { `status`: `\"LoadingFirstPage\"` ; `isLoading`: `true` } \\| { `status`: `\"CanLoadMore\"` ; `isLoading`: `false` } \\| { `status`: `\"LoadingMore\"` ; `isLoading`: `true` } \\| { `status`: `\"Exhausted\"` ; `isLoading`: `false` } The result of calling the [usePaginatedQuery](https://docs.convex.dev/api/modules/react#usepaginatedquery) hook. This includes: - `results` \\- An array of the currently loaded results. - `isLoading` \\- Whether the hook is currently loading results. - `status` \\- The status of the pagination. The possible statuses are: - \"LoadingFirstPage\": The hook is loading the first page of results. - \"CanLoadMore\": This query may have more items to fetch. Call `loadMore` to fetch another page. - \"LoadingMore\": We're currently loading another page of results. - \"Exhausted\": We've paginated to the end of the list. - `loadMore(n)` A callback to fetch more results. This will only fetch more results if the status is \"CanLoadMore\". #### Type parameters [​](https://docs.convex.dev/api/modules/react\\#type-parameters-2 \"Direct link to Type parameters\") | Name | | :-- | | `Item` | #### Defined in [​](https://docs.convex.dev/api/modules/react\\#defined-in-5 \"Direct link to Defined in\") [react/use\\_paginated\\_query.ts:440](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L440) * * * ### PaginationStatus [​](https://docs.convex.dev/api/modules/react\\#paginationstatus \"Direct link to PaginationStatus\") Ƭ **PaginationStatus**: [`UsePaginatedQueryResult`](https://docs.convex.dev/api/modules/react#usepaginatedqueryresult) < `any` >\\[ `\"status\"`\\] The possible pagination statuses in [UsePaginatedQueryResult](https://docs.convex.dev/api/modules/react#usepaginatedqueryresult). This is a union of string literal types. #### Defined in [​](https://docs.convex.dev/api/modules/react\\#defined-in-6 \"Direct link to Defined in\") [react/use\\_paginated\\_query.ts:468](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L468) * * * ### PaginatedQueryArgs [​](https://docs.convex.dev/api/modules/react\\#paginatedqueryargs \"Direct link to PaginatedQueryArgs\") Ƭ **PaginatedQueryArgs** < `Query` >: [`Expand`](https://docs.convex.dev/api/modules/server#expand) < [`BetterOmit`](https://docs.convex.dev/api/modules/server#betteromit) < [`FunctionArgs`](https://docs.convex.dev/api/modules/server#functionargs) < `Query` >, `\"paginationOpts\"` >> Given a [PaginatedQueryReference](https://docs.convex.dev/api/modules/react#paginatedqueryreference), get the type of the arguments object for the query, excluding the `paginationOpts` argument. #### Type parameters [​](https://docs.convex.dev/api/modules/react\\#type-parameters-3 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Query` | extends [`PaginatedQueryReference`](https://docs.convex.dev/api/modules/react#paginatedqueryreference) | #### Defined in [​](https://docs.convex.dev/api/modules/react\\#defined-in-7 \"Direct link to Defined in\") [react/use\\_paginated\\_query.ts:476](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L476) * * * ### PaginatedQueryItem [​](https://docs.convex.dev/api/modules/react\\#paginatedqueryitem \"Direct link to PaginatedQueryItem\") Ƭ **PaginatedQueryItem** < `Query` >: [`FunctionReturnType`](https://docs.convex.dev/api/modules/server#functionreturntype) < `Query` >\\[ `\"page\"`\\]\\[ `number`\\] Given a [PaginatedQueryReference](https://docs.convex.dev/api/modules/react#paginatedqueryreference), get the type of the item being paginated over. #### Type parameters [​](https://docs.convex.dev/api/modules/react\\#type-parameters-4 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Query` | extends [`PaginatedQueryReference`](https://docs.convex.dev/api/modules/react#paginatedqueryreference) | #### Defined in [​](https://docs.convex.dev/api/modules/react\\#defined-in-8 \"Direct link to Defined in\") [react/use\\_paginated\\_query.ts:485](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L485) * * * ### UsePaginatedQueryReturnType [​](https://docs.convex.dev/api/modules/react\\#usepaginatedqueryreturntype \"Direct link to UsePaginatedQueryReturnType\") Ƭ **UsePaginatedQueryReturnType** < `Query` >: [`UsePaginatedQueryResult`](https://docs.convex.dev/api/modules/react#usepaginatedqueryresult) < [`PaginatedQueryItem`](https://docs.convex.dev/api/modules/react#paginatedqueryitem) < `Query` >> The return type of [usePaginatedQuery](https://docs.convex.dev/api/modules/react#usepaginatedquery). #### Type parameters [​](https://docs.convex.dev/api/modules/react\\#type-parameters-5 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Query` | extends [`PaginatedQueryReference`](https://docs.convex.dev/api/modules/react#paginatedqueryreference) | #### Defined in [​](https://docs.convex.dev/api/modules/react\\#defined-in-9 \"Direct link to Defined in\") [react/use\\_paginated\\_query.ts:493](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L493) * * * ### RequestForQueries [​](https://docs.convex.dev/api/modules/react\\#requestforqueries \"Direct link to RequestForQueries\") Ƭ **RequestForQueries**: `Record` < `string`, { `query`: [`FunctionReference`](https://docs.convex.dev/api/modules/server#functionreference) < `\"query\"` \\> ; `args`: `Record` < `string`, [`Value`](https://docs.convex.dev/api/modules/values#value) \\> }> An object representing a request to load multiple queries. The keys of this object are identifiers and the values are objects containing the query function and the arguments to pass to it. This is used as an argument to [useQueries](https://docs.convex.dev/api/modules/react#usequeries). #### Defined in [​](https://docs.convex.dev/api/modules/react\\#defined-in-10 \"Direct link to Defined in\") [react/use\\_queries.ts:126](https://github.com/get-convex/convex-js/blob/main/src/react/use_queries.ts#L126) ## Functions [​](https://docs.convex.dev/api/modules/react\\#functions \"Direct link to Functions\") ### useConvexAuth [​](https://docs.convex.dev/api/modules/react\\#useconvexauth \"Direct link to useConvexAuth\") ▸ **useConvexAuth**(): `Object` Get the [ConvexAuthState](https://docs.convex.dev/api/modules/react#convexauthstate) within a React component. This relies on a Convex auth integration provider being above in the React component tree. #### Returns [​](https://docs.convex.dev/api/modules/react\\#returns-1 \"Direct link to Returns\") `Object` The current [ConvexAuthState](https://docs.convex.dev/api/modules/react#convexauthstate). | Name | Type | | :-- | :-- | | `isLoading` | `boolean` | | `isAuthenticated` | `boolean` | #### Defined in [​](https://docs.convex.dev/api/modules/react\\#defined-in-11 \"Direct link to Defined in\") [react/ConvexAuthState.tsx:43](https://github.com/get-convex/convex-js/blob/main/src/react/ConvexAuthState.tsx#L43) * * * ### ConvexProviderWithAuth [​](https://docs.convex.dev/api/modules/react\\#convexproviderwithauth \"Direct link to ConvexProviderWithAuth\") ▸ **ConvexProviderWithAuth**( `«destructured»`): `Element` A replacement for [ConvexProvider](https://docs.convex.dev/api/modules/react#convexprovider) which additionally provides [ConvexAuthState](https://docs.convex.dev/api/modules/react#convexauthstate) to descendants of this component. Use this to integrate any auth provider with Convex. The `useAuth` prop should be a React hook that returns the provider's authentication state and a function to fetch a JWT access token. If the `useAuth` prop function updates causing a rerender then auth state wil transition to loading and the `fetchAccessToken()` function called again. See [Custom Auth Integration](https://docs.convex.dev/auth/advanced/custom-auth) for more information. #### Parameters [​](https://docs.convex.dev/api/modules/react\\#parameters-1 \"Direct link to Parameters\") | Name | Type | | :-- | :-- | | `«destructured»` | `Object` | | › `children?` | `ReactNode` | | › `client` | `IConvexReactClient` | | › `useAuth` | () =\\> { `isLoading`: `boolean` ; `isAuthenticated`: `boolean` ; `fetchAccessToken`: ( `args`: { `forceRefreshToken`: `boolean` }) =\\> `Promise` < `null` \\| `string` \\> } | #### Returns [​](https://docs.convex.dev/api/modules/react\\#returns-2 \"Direct link to Returns\") `Element` #### Defined in [​](https://docs.convex.dev/api/modules/react\\#defined-in-12 \"Direct link to Defined in\") [react/ConvexAuthState.tsx:75](https://github.com/get-convex/convex-js/blob/main/src/react/ConvexAuthState.tsx#L75) * * * ### Authenticated [​](https://docs.convex.dev/api/modules/react\\#authenticated \"Direct link to Authenticated\") ▸ **Authenticated**( `«destructured»`): `null` \\| `Element` Renders children if the client is authenticated. #### Parameters [​](https://docs.convex.dev/api/modules/react\\#parameters-2 \"Direct link to Parameters\") | Name | Type | | :-- | :-- | | `«destructured»` | `Object` | | › `children` | `ReactNode` | #### Returns [​](https://docs.convex.dev/api/modules/react\\#returns-3 \"Direct link to Returns\") `null` \\| `Element` #### Defined in [​](https://docs.convex.dev/api/modules/react\\#defined-in-13 \"Direct link to Defined in\") [react/auth\\_helpers.tsx:10](https://github.com/get-convex/convex-js/blob/main/src/react/auth_helpers.tsx#L10) * * * ### Unauthenticated [​](https://docs.convex.dev/api/modules/react\\#unauthenticated \"Direct link to Unauthenticated\") ▸ **Unauthenticated**( `«destructured»`): `null` \\| `Element` Renders children if the client is using authentication but is not authenticated. #### Parameters [​](https://docs.convex.dev/api/modules/react\\#parameters-3 \"Direct link to Parameters\") | Name | Type | | :-- | :-- | | `«destructured»` | `Object` | | › `children` | `ReactNode` | #### Returns [​](https://docs.convex.dev/api/modules/react\\#returns-4 \"Direct link to Returns\") `null` \\| `Element` #### Defined in [​](https://docs.convex.dev/api/modules/react\\#defined-in-14 \"Direct link to Defined in\") [react/auth\\_helpers.tsx:23](https://github.com/get-convex/convex-js/blob/main/src/react/auth_helpers.tsx#L23) * * * ### AuthLoading [​](https://docs.convex.dev/api/modules/react\\#authloading \"Direct link to AuthLoading\") ▸ **AuthLoading**( `«destructured»`): `null` \\| `Element` Renders children if the client isn't using authentication or is in the process of authenticating. #### Parameters [​](https://docs.convex.dev/api/modules/react\\#parameters-4 \"Direct link to Parameters\") | Name | Type | | :-- | :-- | | `«destructured»` | `Object` | | › `children` | `ReactNode` | #### Returns [​](https://docs.convex.dev/api/modules/react\\#returns-5 \"Direct link to Returns\") `null` \\| `Element` #### Defined in [​](https://docs.convex.dev/api/modules/react\\#defined-in-15 \"Direct link to Defined in\") [react/auth\\_helpers.tsx:37](https://github.com/get-convex/convex-js/blob/main/src/react/auth_helpers.tsx#L37) * * * ### useConvex [​](https://docs.convex.dev/api/modules/react\\#useconvex \"Direct link to useConvex\") ▸ **useConvex**(): [`ConvexReactClient`](https://docs.convex.dev/api/classes/react.ConvexReactClient) Get the [ConvexReactClient](https://docs.convex.dev/api/classes/react.ConvexReactClient) within a React component. This relies on the [ConvexProvider](https://docs.convex.dev/api/modules/react#convexprovider) being above in the React component tree. #### Returns [​](https://docs.convex.dev/api/modules/react\\#returns-6 \"Direct link to Returns\") [`ConvexReactClient`](https://docs.convex.dev/api/classes/react.ConvexReactClient) The active [ConvexReactClient](https://docs.convex.dev/api/classes/react.ConvexReactClient) object, or `undefined`. #### Defined in [​](https://docs.convex.dev/api/modules/react\\#defined-in-16 \"Direct link to Defined in\") [react/client.ts:550](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L550) * * * ### ConvexProvider [​](https://docs.convex.dev/api/modules/react\\#convexprovider \"Direct link to ConvexProvider\") ▸ **ConvexProvider**( `props`, `deprecatedLegacyContext?`): `null` \\| `ReactElement` < `any`, `any` > Provides an active Convex [ConvexReactClient](https://docs.convex.dev/api/classes/react.ConvexReactClient) to descendants of this component. Wrap your app in this component to use Convex hooks `useQuery`, `useMutation`, and `useConvex`. #### Parameters [​](https://docs.convex.dev/api/modules/react\\#parameters-5 \"Direct link to Parameters\") | Name | Type | Description | | :-- | :-- | :-- | | `props` | `Object` | an object with a `client` property that refers to a [ConvexReactClient](https://docs.convex.dev/api/classes/react.ConvexReactClient). | | `props.client` | [`ConvexReactClient`](https://docs.convex.dev/api/classes/react.ConvexReactClient) | - | | `props.children?` | `ReactNode` | - | | `deprecatedLegacyContext?` | `any` | **`Deprecated`** **`See`** [React Docs](https://legacy.reactjs.org/docs/legacy-context.html#referencing-context-in-lifecycle-methods) | #### Returns [​](https://docs.convex.dev/api/modules/react\\#returns-7 \"Direct link to Returns\") `null` \\| `ReactElement` < `any`, `any` > #### Defined in [​](https://docs.convex.dev/api/modules/react\\#defined-in-17 \"Direct link to Defined in\") ../../common/temp/node\\_modules/.pnpm/@ [types+react@18.3.18](mailto:types+react@18.3.18)/node\\_modules/@types/react/ts5.0/index.d.ts:1128 * * * ### useQuery [​](https://docs.convex.dev/api/modules/react\\#usequery \"Direct link to useQuery\") ▸ **useQuery** < `Query` >( `query`, `...args`): `Query`\\[ `\"_returnType\"`\\] \\| `undefined` Load a reactive query within a React component. This React hook contains internal state that will cause a rerender whenever the query result changes. Throws an error if not used under [ConvexProvider](https://docs.convex.dev/api/modules/react#convexprovider). #### Type parameters [​](https://docs.convex.dev/api/modules/react\\#type-parameters-6 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Query` | extends [`FunctionReference`](https://docs.convex.dev/api/modules/server#functionreference) < `\"query\"` > | #### Parameters [​](https://docs.convex.dev/api/modules/react\\#parameters-6 \"Direct link to Parameters\") | Name | Type | Description | | :-- | :-- | :-- | | `query` | `Query` | a [FunctionReference](https://docs.convex.dev/api/modules/server#functionreference) for the public query to run like `api.dir1.dir2.filename.func`. | | `...args` | [`OptionalRestArgsOrSkip`](https://docs.convex.dev/api/modules/react#optionalrestargsorskip) < `Query` > | The arguments to the query function or the string \"skip\" if the query should not be loaded. | #### Returns [​](https://docs.convex.dev/api/modules/react\\#returns-8 \"Direct link to Returns\") `Query`\\[ `\"_returnType\"`\\] \\| `undefined` the result of the query. If the query is loading returns `undefined`. #### Defined in [​](https://docs.convex.dev/api/modules/react\\#defined-in-18 \"Direct link to Defined in\") [react/client.ts:596](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L596) * * * ### useMutation [​](https://docs.convex.dev/api/modules/react\\#usemutation \"Direct link to useMutation\") ▸ **useMutation** < `Mutation` >( `mutation`): [`ReactMutation`](https://docs.convex.dev/api/interfaces/react.ReactMutation) < `Mutation` > Construct a new [ReactMutation](https://docs.convex.dev/api/interfaces/react.ReactMutation). Mutation objects can be called like functions to request execution of the corresponding Convex function, or further configured with [optimistic updates](https://docs.convex.dev/using/optimistic-updates). The value returned by this hook is stable across renders, so it can be used by React dependency arrays and memoization logic relying on object identity without causing rerenders. Throws an error if not used under [ConvexProvider](https://docs.convex.dev/api/modules/react#convexprovider). #### Type parameters [​](https://docs.convex.dev/api/modules/react\\#type-parameters-7 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Mutation` | extends [`FunctionReference`](https://docs.convex.dev/api/modules/server#functionreference) < `\"mutation\"` > | #### Parameters [​](https://docs.convex.dev/api/modules/react\\#parameters-7 \"Direct link to Parameters\") | Name | Type | Description | | :-- | :-- | :-- | | `mutation` | `Mutation` | A [FunctionReference](https://docs.convex.dev/api/modules/server#functionreference) for the public mutation to run like `api.dir1.dir2.filename.func`. | #### Returns [​](https://docs.convex.dev/api/modules/react\\#returns-9 \"Direct link to Returns\") [`ReactMutation`](https://docs.convex.dev/api/interfaces/react.ReactMutation) < `Mutation` > The [ReactMutation](https://docs.convex.dev/api/interfaces/react.ReactMutation) object with that name. #### Defined in [​](https://docs.convex.dev/api/modules/react\\#defined-in-19 \"Direct link to Defined in\") [react/client.ts:648](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L648) * * * ### useAction [​](https://docs.convex.dev/api/modules/react\\#useaction \"Direct link to useAction\") ▸ **useAction** < `Action` >( `action`): [`ReactAction`](https://docs.convex.dev/api/interfaces/react.ReactAction) < `Action` > Construct a new [ReactAction](https://docs.convex.dev/api/interfaces/react.ReactAction). Action objects can be called like functions to request execution of the corresponding Convex function. The value returned by this hook is stable across renders, so it can be used by React dependency arrays and memoization logic relying on object identity without causing rerenders. Throws an error if not used under [ConvexProvider](https://docs.convex.dev/api/modules/react#convexprovider). #### Type parameters [​](https://docs.convex.dev/api/modules/react\\#type-parameters-8 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Action` | extends [`FunctionReference`](https://docs.convex.dev/api/modules/server#functionreference) < `\"action\"` > | #### Parameters [​](https://docs.convex.dev/api/modules/react\\#parameters-8 \"Direct link to Parameters\") | Name | Type | Description | | :-- | :-- | :-- | | `action` | `Action` | A [FunctionReference](https://docs.convex.dev/api/modules/server#functionreference) for the public action to run like `api.dir1.dir2.filename.func`. | #### Returns [​](https://docs.convex.dev/api/modules/react\\#returns-10 \"Direct link to Returns\") [`ReactAction`](https://docs.convex.dev/api/interfaces/react.ReactAction) < `Action` > The [ReactAction](https://docs.convex.dev/api/interfaces/react.ReactAction) object with that name. #### Defined in [​](https://docs.convex.dev/api/modules/react\\#defined-in-20 \"Direct link to Defined in\") [react/client.ts:689](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L689) * * * ### usePreloadedQuery [​](https://docs.convex.dev/api/modules/react\\#usepreloadedquery \"Direct link to usePreloadedQuery\") ▸ **usePreloadedQuery** < `Query` >( `preloadedQuery`): `Query`\\[ `\"_returnType\"`\\] Load a reactive query within a React component using a `Preloaded` payload from a Server Component returned by [preloadQuery](https://docs.convex.dev/api/modules/nextjs#preloadquery). This React hook contains internal state that will cause a rerender whenever the query result changes. Throws an error if not used under [ConvexProvider](https://docs.convex.dev/api/modules/react#convexprovider). #### Type parameters [​](https://docs.convex.dev/api/modules/react\\#type-parameters-9 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Query` | extends [`FunctionReference`](https://docs.convex.dev/api/modules/server#functionreference) < `\"query\"` > | #### Parameters [​](https://docs.convex.dev/api/modules/react\\#parameters-9 \"Direct link to Parameters\") | Name | Type | Description | | :-- | :-- | :-- | | `preloadedQuery` | [`Preloaded`](https://docs.convex.dev/api/modules/react#preloaded) < `Query` > | The `Preloaded` query payload from a Server Component. | #### Returns [​](https://docs.convex.dev/api/modules/react\\#returns-11 \"Direct link to Returns\") `Query`\\[ `\"_returnType\"`\\] the result of the query. Initially returns the result fetched by the Server Component. Subsequently returns the result fetched by the client. #### Defined in [​](https://docs.convex.dev/api/modules/react\\#defined-in-21 \"Direct link to Defined in\") [react/hydration.tsx:34](https://github.com/get-convex/convex-js/blob/main/src/react/hydration.tsx#L34) * * * ### usePaginatedQuery [​](https://docs.convex.dev/api/modules/react\\#usepaginatedquery \"Direct link to usePaginatedQuery\") ▸ **usePaginatedQuery** < `Query` >( `query`, `args`, `options`): [`UsePaginatedQueryReturnType`](https://docs.convex.dev/api/modules/react#usepaginatedqueryreturntype) < `Query` > Load data reactively from a paginated query to a create a growing list. This can be used to power \"infinite scroll\" UIs. This hook must be used with public query references that match [PaginatedQueryReference](https://docs.convex.dev/api/modules/react#paginatedqueryreference). `usePaginatedQuery` concatenates all the pages of results into a single list and manages the continuation cursors when requesting more items. Example usage: ```codeBlockLines_zEuJ const { results, status, isLoading, loadMore } = usePaginatedQuery( api.messages.list, { channel: \"#general\" }, { initialNumItems: 5 } ); ``` If the query reference or arguments change, the pagination state will be reset to the first page. Similarly, if any of the pages result in an InvalidCursor error or an error associated with too much data, the pagination state will also reset to the first page. To learn more about pagination, see [Paginated Queries](https://docs.convex.dev/database/pagination). #### Type parameters [​](https://docs.convex.dev/api/modules/react\\#type-parameters-10 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Query` | extends [`PaginatedQueryReference`](https://docs.convex.dev/api/modules/react#paginatedqueryreference) | #### Parameters [​](https://docs.convex.dev/api/modules/react\\#parameters-10 \"Direct link to Parameters\") | Name | Type | Description | | :-- | :-- | :-- | | `query` | `Query` | A FunctionReference to the public query function to run. | | `args` | `\"skip\"` \\| [`Expand`](https://docs.convex.dev/api/modules/server#expand) < [`BetterOmit`](https://docs.convex.dev/api/modules/server#betteromit) < [`FunctionArgs`](https://docs.convex.dev/api/modules/server#functionargs) < `Query` >, `\"paginationOpts\"` >> | The arguments object for the query function, excluding the `paginationOpts` property. That property is injected by this hook. | | `options` | `Object` | An object specifying the `initialNumItems` to be loaded in the first page. | | `options.initialNumItems` | `number` | - | #### Returns [​](https://docs.convex.dev/api/modules/react\\#returns-12 \"Direct link to Returns\") [`UsePaginatedQueryReturnType`](https://docs.convex.dev/api/modules/react#usepaginatedqueryreturntype) < `Query` > A [UsePaginatedQueryResult](https://docs.convex.dev/api/modules/react#usepaginatedqueryresult) that includes the currently loaded items, the status of the pagination, and a `loadMore` function. #### Defined in [​](https://docs.convex.dev/api/modules/react\\#defined-in-22 \"Direct link to Defined in\") [react/use\\_paginated\\_query.ts:161](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L161) * * * ### resetPaginationId [​](https://docs.convex.dev/api/modules/react\\#resetpaginationid \"Direct link to resetPaginationId\") ▸ **resetPaginationId**(): `void` Reset pagination id for tests only, so tests know what it is. #### Returns [​](https://docs.convex.dev/api/modules/react\\#returns-13 \"Direct link to Returns\") `void` #### Defined in [​](https://docs.convex.dev/api/modules/react\\#defined-in-23 \"Direct link to Defined in\") [react/use\\_paginated\\_query.ts:419](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L419) * * * ### optimisticallyUpdateValueInPaginatedQuery [​](https://docs.convex.dev/api/modules/react\\#optimisticallyupdatevalueinpaginatedquery \"Direct link to optimisticallyUpdateValueInPaginatedQuery\") ▸ **optimisticallyUpdateValueInPaginatedQuery** < `Query` >( `localStore`, `query`, `args`, `updateValue`): `void` Optimistically update the values in a paginated list. This optimistic update is designed to be used to update data loaded with [usePaginatedQuery](https://docs.convex.dev/api/modules/react#usepaginatedquery). It updates the list by applying `updateValue` to each element of the list across all of the loaded pages. This will only apply to queries with a matching names and arguments. Example usage: ```codeBlockLines_zEuJ const myMutation = useMutation(api.myModule.myMutation) .withOptimisticUpdate((localStore, mutationArg) => { // Optimistically update the document with ID `mutationArg` // to have an additional property. optimisticallyUpdateValueInPaginatedQuery( localStore, api.myModule.paginatedQuery {}, currentValue => { if (mutationArg === currentValue._id) { return { ...currentValue, \"newProperty\": \"newValue\", }; } return currentValue; } ); }); ``` #### Type parameters [​](https://docs.convex.dev/api/modules/react\\#type-parameters-11 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Query` | extends [`PaginatedQueryReference`](https://docs.convex.dev/api/modules/react#paginatedqueryreference) | #### Parameters [​](https://docs.convex.dev/api/modules/react\\#parameters-11 \"Direct link to Parameters\") | Name | Type | Description | | :-- | :-- | :-- | | `localStore` | [`OptimisticLocalStore`](https://docs.convex.dev/api/interfaces/browser.OptimisticLocalStore) | An [OptimisticLocalStore](https://docs.convex.dev/api/interfaces/browser.OptimisticLocalStore) to update. | | `query` | `Query` | A [FunctionReference](https://docs.convex.dev/api/modules/server#functionreference) for the paginated query to update. | | `args` | [`Expand`](https://docs.convex.dev/api/modules/server#expand) < [`BetterOmit`](https://docs.convex.dev/api/modules/server#betteromit) < [`FunctionArgs`](https://docs.convex.dev/api/modules/server#functionargs) < `Query` >, `\"paginationOpts\"` >> | The arguments object to the query function, excluding the `paginationOpts` property. | | `updateValue` | ( `currentValue`: [`PaginatedQueryItem`](https://docs.convex.dev/api/modules/react#paginatedqueryitem) < `Query` >) =\\> [`PaginatedQueryItem`](https://docs.convex.dev/api/modules/react#paginatedqueryitem) < `Query` > | A function to produce the new values. | #### Returns [​](https://docs.convex.dev/api/modules/react\\#returns-14 \"Direct link to Returns\") `void` #### Defined in [​](https://docs.convex.dev/api/modules/react\\#defined-in-24 \"Direct link to Defined in\") [react/use\\_paginated\\_query.ts:539](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L539) * * * ### useQueries [​](https://docs.convex.dev/api/modules/react\\#usequeries \"Direct link to useQueries\") ▸ **useQueries**( `queries`): `Record` < `string`, `any` \\| `undefined` \\| `Error` > Load a variable number of reactive Convex queries. `useQueries` is similar to [useQuery](https://docs.convex.dev/api/modules/react#usequery) but it allows loading multiple queries which can be useful for loading a dynamic number of queries without violating the rules of React hooks. This hook accepts an object whose keys are identifiers for each query and the values are objects of `{ query: FunctionReference, args: Record }`. The `query` is a FunctionReference for the Convex query function to load, and the `args` are the arguments to that function. The hook returns an object that maps each identifier to the result of the query, `undefined` if the query is still loading, or an instance of `Error` if the query threw an exception. For example if you loaded a query like: ```codeBlockLines_zEuJ const results = useQueries({ messagesInGeneral: { query: \"listMessages\", args: { channel: \"#general\" } } }); ``` then the result would look like: ```codeBlockLines_zEuJ { messagesInGeneral: [{\\ channel: \"#general\",\\ body: \"hello\"\\ _id: ...,\\ _creationTime: ...\\ }] } ``` This React hook contains internal state that will cause a rerender whenever any of the query results change. Throws an error if not used under [ConvexProvider](https://docs.convex.dev/api/modules/react#convexprovider). #### Parameters [​](https://docs.convex.dev/api/modules/react\\#parameters-12 \"Direct link to Parameters\") | Name | Type | Description | | :-- | :-- | :-- | | `queries` | [`RequestForQueries`](https://docs.convex.dev/api/modules/react#requestforqueries) | An object mapping identifiers to objects of `{query: string, args: Record }` describing which query functions to fetch. | #### Returns [​](https://docs.convex.dev/api/modules/react\\#returns-15 \"Direct link to Returns\") `Record` < `string`, `any` \\| `undefined` \\| `Error` > An object with the same keys as the input. The values are the result of the query function, `undefined` if it's still loading, or an `Error` if it threw an exception. #### Defined in [​](https://docs.convex.dev/api/modules/react\\#defined-in-25 \"Direct link to Defined in\") [react/use\\_queries.ts:60](https://github.com/get-convex/convex-js/blob/main/src/react/use_queries.ts#L60) - [Usage](https://docs.convex.dev/api/modules/react#usage) - [Creating the client](https://docs.convex.dev/api/modules/react#creating-the-client) - [Storing the client in React Context](https://docs.convex.dev/api/modules/react#storing-the-client-in-react-context) - [Using the auth helpers](https://docs.convex.dev/api/modules/react#using-the-auth-helpers) - [Using React hooks](https://docs.convex.dev/api/modules/react#using-react-hooks) - [Classes](https://docs.convex.dev/api/modules/react#classes) - [Interfaces](https://docs.convex.dev/api/modules/react#interfaces) - [Type Aliases](https://docs.convex.dev/api/modules/react#type-aliases) - [AuthTokenFetcher](https://docs.convex.dev/api/modules/react#authtokenfetcher) - [ConvexAuthState](https://docs.convex.dev/api/modules/react#convexauthstate) - [OptionalRestArgsOrSkip](https://docs.convex.dev/api/modules/react#optionalrestargsorskip) - [Preloaded](https://docs.convex.dev/api/modules/react#preloaded) - [PaginatedQueryReference](https://docs.convex.dev/api/modules/react#paginatedqueryreference) - [UsePaginatedQueryResult](https://docs.convex.dev/api/modules/react#usepaginatedqueryresult) - [PaginationStatus](https://docs.convex.dev/api/modules/react#paginationstatus) - [PaginatedQueryArgs](https://docs.convex.dev/api/modules/react#paginatedqueryargs) - [PaginatedQueryItem](https://docs.convex.dev/api/modules/react#paginatedqueryitem) - [UsePaginatedQueryReturnType](https://docs.convex.dev/api/modules/react#usepaginatedqueryreturntype) - [RequestForQueries](https://docs.convex.dev/api/modules/react#requestforqueries) - [Functions](https://docs.convex.dev/api/modules/react#functions) - [useConvexAuth](https://docs.convex.dev/api/modules/react#useconvexauth) - [ConvexProviderWithAuth](https://docs.convex.dev/api/modules/react#convexproviderwithauth) - [Authenticated](https://docs.convex.dev/api/modules/react#authenticated) - [Unauthenticated](https://docs.convex.dev/api/modules/react#unauthenticated) - [AuthLoading](https://docs.convex.dev/api/modules/react#authloading) - [useConvex](https://docs.convex.dev/api/modules/react#useconvex) - [ConvexProvider](https://docs.convex.dev/api/modules/react#convexprovider) - [useQuery](https://docs.convex.dev/api/modules/react#usequery) - [useMutation](https://docs.convex.dev/api/modules/react#usemutation) - [useAction](https://docs.convex.dev/api/modules/react#useaction) - [usePreloadedQuery](https://docs.convex.dev/api/modules/react#usepreloadedquery) - [usePaginatedQuery](https://docs.convex.dev/api/modules/react#usepaginatedquery) - [resetPaginationId](https://docs.convex.dev/api/modules/react#resetpaginationid) - [optimisticallyUpdateValueInPaginatedQuery](https://docs.convex.dev/api/modules/react#optimisticallyupdatevalueinpaginatedquery) - [useQueries](https://docs.convex.dev/api/modules/react#usequeries) [Skip to main content](https://docs.convex.dev/tutorial/actions#docusaurus_skipToContent_fallback) # Convex Tutorial: Calling external services In the [previous step](https://docs.convex.dev/tutorial/), you built a fully self-contained chat app. Data in, data out. In order to power the automatic reactivity we just saw while providing strong database transactions, query and mutation functions in Convex are not allowed to make `fetch` calls to the outside world. Real apps aren't this simple. They often need to talk to the rest of the internet directly from the backend. Convex lets you do this too via **action** functions. Action functions let the sync engine access the external world by scheduling out work that can then write data back via mutations. Let's make our chat app a bit smarter by letting anyone in the chat get the Wikipedia summary of a topic using the Wikipedia API. ## Your first `action` [​](https://docs.convex.dev/tutorial/actions\\#your-first-action \"Direct link to your-first-action\") **Add the following action to your `convex/chat.ts` file.** ```codeBlockLines_zEuJ // Update your server import like this: import { query, mutation, internalAction } from \"./_generated/server\"; //... export const getWikipediaSummary = internalAction({ args: { topic: v.string() }, handler: async (ctx, args) => { const response = await fetch( \"https://en.wikipedia.org/w/api.php?format=json&action=query&prop=extracts&exintro&explaintext&redirects=1&titles=\" + args.topic, ); return getSummaryFromJSON(await response.json()); }, }); function getSummaryFromJSON(data: any) { const firstPageId = Object.keys(data.query.pages)[0]; return data.query.pages[firstPageId].extract; } ``` Let's walk through it: 1. First, we created a new Convex action function called `getWikipediaSummary`. We used `internalAction` because we want this function to be private to the Convex backend and not exposed as a public API. This function does a simple fetch to the Wikipedia API with our topic. 2. Next, we have a helper TypeScript function called `getSummaryFromJSON` to pull out the summary text from the JSON response. 3. The `getWikipediaSummary` function calls our helper function like any other TypeScript function. This is great and all, but how do I use it? To quickly test this function in the Convex dashboard, go to [https://dashboard.convex.dev](https://dashboard.convex.dev/deployment/functions) and navigate to your project. Click on the Functions in the left nav, and then click on the `getWikipediaSummary` function. Click \"Run Function\". The function runner UI will pop up. Try making a few searches. Running a few Wikipedia queries ## Hooking it up to your app [​](https://docs.convex.dev/tutorial/actions\\#hooking-it-up-to-your-app \"Direct link to Hooking it up to your app\") It's awesome that we can call Wikipedia, but we still need to show up in our chat. So, let's hook it all up. **Update your existing `sendMessage` mutation like this:** ```codeBlockLines_zEuJ // Import the api reference import { api, internal } from \"./_generated/api\"; //... export const sendMessage = mutation({ args: { user: v.string(), body: v.string(), }, handler: async (ctx, args) => { console.log(\"This TypeScript function is running on the server.\"); await ctx.db.insert(\"messages\", { user: args.user, body: args.body, }); // Add the following lines: if (args.body.startsWith(\"/wiki\")) { // Get the string after the first space const topic = args.body.slice(args.body.indexOf(\" \") + 1); await ctx.scheduler.runAfter(0, internal.chat.getWikipediaSummary, { topic, }); } }, }); ``` Wait a second! What's with this `ctx.scheduler` stuff? Convex comes with a powerful durable function scheduler. It's a fundamental part of the sync engine, and it's the way you coordinate asynchronous functions in Convex. In the case of mutations, it's the only way to call an action to fetch from the outside world. The really cool part is, if for some reason your mutation throws an exception, then nothing is scheduled. This is because mutations are transactions, and scheduling is just a write in the database to tell Convex to run this function at a future time. Ok so, we can schedule our action, but we still need to write the summary back to the chat. **Let's go back and update our `getWikipediaSummary` action:** ```codeBlockLines_zEuJ export const getWikipediaSummary = internalAction({ args: { topic: v.string() }, handler: async (ctx, args) => { const response = await fetch( \"https://en.wikipedia.org/w/api.php?format=json&action=query&prop=extracts&exintro&explaintext&redirects=1&titles=\" + args.topic, ); // Replace the `return ...` with the following. const summary = getSummaryFromJSON(await response.json()); await ctx.scheduler.runAfter(0, api.chat.sendMessage, { user: \"Wikipedia\", body: summary, }); }, }); ``` Just like scheduling the action, we're now scheduling our `sendMessage` mutation to send the result of our Wikipedia lookup to our chat. Go ahead, now play with your app! Chat with Wikipedia ## The scheduler, actions, and the sync engine [​](https://docs.convex.dev/tutorial/actions\\#the-scheduler-actions-and-the-sync-engine \"Direct link to The scheduler, actions, and the sync engine\") ![Sync engine with actions](https://docs.convex.dev/assets/images/ConvexSyncAction-29b050dc3377673c0d3d21cc60efd709.png) Queries and mutations are the only ways to interact with the database and the scheduler enables building sophisticated workflows with actions in between. [Actions](https://docs.convex.dev/functions/actions) are normal serverless functions like AWS Lambda and Google Cloud Run. They help model flows like calling AI APIs and using the Vector Store. They serve as an escape hatch. They deal with the reality of the messy outside world with few guarantees. Actions are not part of the sync engine. To talk to the database they have to talk through query and mutation functions. This restriction lets Convex enforce transactional guarantees in the database and keep the sync engine fast and nimble. The best way to structure your application for scale is to minimize the work that happens in an action. Only the part that needs the [non-determinism](https://en.wikipedia.org/wiki/Deterministic_algorithm), like making the external `fetch` call should use them. Keeping them as small as possible is the most scalable way to build Convex apps, enabling the highest throughput. The scheduler allows your app to keep most of its important logic in queries and mutations and structure your code as workflows in and out of actions. ## What you built [​](https://docs.convex.dev/tutorial/actions\\#what-you-built \"Direct link to What you built\") In this section of the tutorial, you built an action to talk to the outside world and used the scheduler to trigger this work. You learned that keeping our actions small and keeping most of our work in queries and mutations are fundamental to building scalable Convex backends. ## Next up [​](https://docs.convex.dev/tutorial/actions\\#next-up \"Direct link to Next up\") You've now learned the most important concepts in Convex. As a full-featured backend, Convex is capable of many things such as [authentication](https://docs.convex.dev/auth), [file storage](https://docs.convex.dev/file-storage) and [search](https://docs.convex.dev/search). You can add those features as needed by following the documentation. We touched a little bit on setting your app up for success. As your application scales, you will run into new challenges. Let's learn how to deal with some of these challenges in the [next section →](https://docs.convex.dev/tutorial/scale). [**Scaling your app** \\\\ \\\\ Convex was designed from the ground up for scale. In the previous section we](https://docs.convex.dev/tutorial/scale) [Skip to main content](https://docs.convex.dev/quickstart/swift#docusaurus_skipToContent_fallback) Learn how to query data from Convex in an application targeting iOS and MacOS devices built with Swift and SwiftUI. This quickstart assumes that you have a Mac with Xcode, node and npm installed. If you don’t have those tools, take time to install them first. 01. Create a new iOS app in Xcode 1. Click _Create New Project_ 2. Select iOS App and click _Next_ 3. Name your project something like “ConvexQuickstart” 4. Ensure Language is set to Swift and User Interface is SwiftUI 5. Click _Next_ ![Create new iOS project](https://docs.convex.dev/screenshots/swift_qs_step_1.png) 02. Configure dependencies 1. Click on the top-level ConvexQuickstart app container in the project navigator on the left 2. Click on ConvexQuickstart under the PROJECT heading 3. Click the Package Dependencies tab 4. Click the + button (See Screenshot) 5. Paste ```codeBlockLines_zEuJ https://github.com/get-convex/convex-swift ``` into the search box and press enter 6. When the `convex-swift` package loads, click the _Add Package_ button 7. In the _Package Products_ dialog, select ConvexQuickstart in the _Add to Target_ dropdown 8. Click the Add Package button ![Add Convex dependency to package](https://docs.convex.dev/screenshots/swift_qs_step_2.png) 04. Install the Convex backend Open a terminal and `cd` to the directory for the Xcode project you created. Run the following commands to install the Convex client and server library. ```codeBlockLines_zEuJ npm init -y npm install convex ``` 05. Start Convex Start a Convex dev deployment. Follow the command line instructions to create a new project. ```codeBlockLines_zEuJ npx convex dev ``` 06. Create sample data for your database Create a new `sampleData.jsonl` file in your Swift project directory with these contents ```codeBlockLines_zEuJ {\"text\": \"Buy groceries\", \"isCompleted\": true} {\"text\": \"Go for a swim\", \"isCompleted\": true} {\"text\": \"Integrate Convex\", \"isCompleted\": false} ``` 07. Add the sample data to a table called \\`tasks\\` in your database Open another terminal tab by pressing ⌘+T which should open in your Swift project directory and run ```codeBlockLines_zEuJ npx convex import --table tasks sampleData.jsonl ``` 08. Expose a database query Create a `tasks.ts` file in the `convex/` directory within your Swift project with the following contents ```codeBlockLines_zEuJ import { query } from \"./_generated/server\"; export const get = query({ args: {}, handler: async (ctx) => { return await ctx.db.query(\"tasks\").collect(); }, }); ``` 09. Create a Swift struct Back in Xcode, create a `struct` at the bottom of the `ContentView` file to match the sample data ```codeBlockLines_zEuJ // We're using the name Todo instead of Task to avoid clashing with // Swift's builtin Task type. struct Todo: Decodable { let _id: String let text: String let isCompleted: Bool } ``` 10. Connect the app to your backend 1. Get the deployment URL of your dev server with `cat .env.local | grep CONVEX_URL` 2. Create a `ConvexClient` instance near the top of the file, just above the `ContentView` struct ```codeBlockLines_zEuJ import SwiftUI import ConvexMobile let convex = ConvexClient(deploymentUrl: \"YOUR_CONVEX_URL\") struct ContentView: View { ... ``` 11. Create your UI Replace the default `ContentView` with the following code that will refresh the list of todo items whenever the backend data changes. ```codeBlockLines_zEuJ struct ContentView: View { @State private var todos: [Todo] = [] var body: some View { List { ForEach(todos, id: \\._id) { todo in Text(todo.text) } }.task { for await todos: [Todo] in convex.subscribe(to: \"tasks:get\") .replaceError(with: []).values { self.todos = todos } }.padding() } } ``` 12. Run the app 1. Press ⌘+R or click _Product → Run_ 2. You can also try adding, updating or deleting documents in your `tasks` table at `dashboard.convex.dev` \\- the app will update with the changes in real-time. ![App preview](https://docs.convex.dev/screenshots/swift_qs_final.png) [Skip to main content](https://docs.convex.dev/http-api#docusaurus_skipToContent_fallback) On this page # HTTP APIs HTTP APIs include: - [Functions API](https://docs.convex.dev/http-api#functions-api) - [Streaming export API](https://docs.convex.dev/http-api#streaming-export-api) - [Streaming import API](https://docs.convex.dev/http-api#streaming-import-api) ## Convex value format [​](https://docs.convex.dev/http-api\\#convex-value-format \"Direct link to Convex value format\") Each of the HTTP APIs take a `format` query param that describes how documents are formatted. Currently the only supported value is `json`. See our [types page](https://docs.convex.dev/database/types#convex-values) for details. Note that for simplicity, the `json` format does not support all Convex data types as input, and uses overlapping representation for several data types in output. We plan to add a new format with support for all Convex data types in the future. ## API authentication [​](https://docs.convex.dev/http-api\\#api-authentication \"Direct link to API authentication\") The Functions API can be optionally authenticated as a user via a bearer token in a `Authorization` header. The value is `Bearer ` where the key is a token from your auth provider. See the [under the hood](https://docs.convex.dev/auth/clerk#under-the-hood) portion of the Clerk docs for details on how this works with Clerk. Streaming export and streaming import requests require deployment admin authorization via the HTTP header `Authorization`. The value is `Convex ` where the access key comes from \"Deploy key\" on the Convex dashboard and gives full read and write access to your Convex data. ## Functions API [​](https://docs.convex.dev/http-api\\#functions-api \"Direct link to Functions API\") ### POST `/api/query`, `/api/mutation`, `/api/action` [​](https://docs.convex.dev/http-api\\#post-apiquery-apimutation-apiaction \"Direct link to post-apiquery-apimutation-apiaction\") These HTTP endpoints allow you to call Convex functions and get the result as a value. You can find your backend deployment URL on the dashboard [Settings](https://docs.convex.dev/dashboard/deployments/deployment-settings) page, then the API URL will be `/api/query` etc., for example: - Shell - NodeJS - Python ```codeBlockLines_zEuJ curl https://acoustic-panther-728.convex.cloud/api/query \\ -d '{\"path\": \"messages:list\", \"args\": {}, \"format\": \"json\"}' \\ -X POST -H \"Content-Type: application/json\" ``` ```codeBlockLines_zEuJ const url = \"https://acoustic-panther-728.convex.cloud/api/query\"; const request = { path: \"messages:list\", args: {}, format: \"json\" }; const response = fetch(url, { method: \"POST\", headers: { \"Content-Type\": \"application/json\", }, body: JSON.stringify(request), }); ``` ```codeBlockLines_zEuJ import requests url = \"https://acoustic-panther-728.convex.cloud/api/query\" headers = {\"accept\": \"application/json\"} body = {\"path\": \"messages:list\", \"args\": {}, \"format\": \"json\"} response = requests.post(url, headers=headers, json=body) ``` **JSON Body parameters** | Name | Type | Required | Description | | --- | --- | --- | --- | | path | string | y | Path to the Convex function formatted as a string as defined [here](https://docs.convex.dev/functions/query-functions#query-names). | | args | object | y | Named argument object to pass to the Convex function. | | format | string | n | Output format for values. Valid values: \\[ `json`\\] | **Result JSON on success** | Field Name | Type | Description | | --- | --- | --- | | status | string | \"success\" | | value | object | Result of the Convex function in the requested format. | | logLines | list\\[string\\] | Log lines printed out during the function execution. | **Result JSON on error** | Field Name | Type | Description | | --- | --- | --- | | status | string | \"error\" | | errorMessage | string | The error message. | | errorData | object | Error data within an [application error](https://docs.convex.dev/functions/error-handling/application-errors) if it was thrown. | | logLines | list\\[string\\] | Log lines printed out during the function execution. | ### POST `/api/run/{functionIdentifier}` [​](https://docs.convex.dev/http-api\\#post-apirunfunctionidentifier \"Direct link to post-apirunfunctionidentifier\") This HTTP endpoint allows you to call arbitrary Convex function types with the path in the request URL and get the result as a value. The function identifier is formatted as a string as defined [here](https://docs.convex.dev/functions/query-functions#query-names) with a `/` replacing the `:`. You can find your backend deployment URL on the dashboard [Settings](https://docs.convex.dev/dashboard/deployments/deployment-settings) page, then the API URL will be `/api/run/{functionIdentifier}` etc., for example: - Shell - NodeJS - Python ```codeBlockLines_zEuJ curl https://acoustic-panther-728.convex.cloud/api/run/messages/list \\ -d '{\"args\": {}, \"format\": \"json\"}' \\ -X POST -H \"Content-Type: application/json\" ``` ```codeBlockLines_zEuJ const url = \"https://acoustic-panther-728.convex.cloud/api/run/messages/list\"; const request = { args: {}, format: \"json\" }; const response = fetch(url, { method: \"POST\", headers: { \"Content-Type\": \"application/json\", }, body: JSON.stringify(request), }); ``` ```codeBlockLines_zEuJ import requests url = \"https://acoustic-panther-728.convex.cloud/api/run/messages/list\" headers = {\"accept\": \"application/json\"} body = {\"args\": {}, \"format\": \"json\"} response = requests.get(url, headers=headers, body=json) ``` **JSON Body parameters** | Name | Type | Required | Description | | --- | --- | --- | --- | | args | object | y | Named argument object to pass to the Convex function. | | format | string | n | Output format for values. Defaults to `json`. Valid values: \\[ `json`\\] | **Result JSON on success** | Field Name | Type | Description | | --- | --- | --- | | status | string | \"success\" | | value | object | Result of the Convex function in the requested format. | | logLines | list\\[string\\] | Log lines printed out during the function execution. | **Result JSON on error** | Field Name | Type | Description | | --- | --- | --- | | status | string | \"error\" | | errorMessage | string | The error message. | | errorData | object | Error data within an [application error](https://docs.convex.dev/functions/error-handling/application-errors) if it was thrown. | | logLines | list\\[string\\] | Log lines printed out during the function execution. | ## Streaming export API [​](https://docs.convex.dev/http-api\\#streaming-export-api \"Direct link to Streaming export API\") Convex supports streaming export. Convex provides connector implementations for [Fivetran and Airbyte](https://docs.convex.dev/production/integrations/streaming-import-export). Those connectors use the following APIs. Sign up for a [Professional plan](https://www.convex.dev/plans) for streaming export support. You can also read the [documentation on streaming export](https://docs.convex.dev/production/integrations/streaming-import-export). Streaming Export HTTP APIs are in beta Streaming Export HTTP APIsare currently a [beta\\\\ feature](https://docs.convex.dev/production/state/#beta-features). If you have feedback or feature requests, [let us know on Discord](https://convex.dev/community)! ### GET `/api/json_schemas` [​](https://docs.convex.dev/http-api\\#get-apijson_schemas \"Direct link to get-apijson_schemas\") The JSON Schemas endpoint lists tables, and for each table describes how documents will be encoded, given as [JSON Schema](https://json-schema.org/). This endpoint returns `$description` tags throughout the schema to describe unintuitive encodings and give extra information like the table referenced by `Id` fields. **Query parameters** | Name | Type | Required | Description | | --- | --- | --- | --- | | deltaSchema | boolean | n | If set, include metadata fields returned by document\\_deltas and list\\_snapshot ( `_ts`, `_deleted`, and `_table`) | | format | string | n | Output format for values. Valid values: \\[ `json`\\] | ### GET `/api/list_snapshot` [​](https://docs.convex.dev/http-api\\#get-apilist_snapshot \"Direct link to get-apilist_snapshot\") The `list_snapshot` endpoint walks a consistent snapshot of documents. It may take one or more calls to `list_snapshot` to walk a full snapshot. **Query parameters** | Name | Type | Required | Description | | --- | --- | --- | --- | | snapshot | int | n | Database timestamp at which to continue the snapshot. The timestamp must not be older than 30 days. If omitted, select the latest timestamp. | | cursor | string | n | An opaque cursor representing the progress in paginating through the snapshot. If omitted, start from the first page of the snapshot. | | tableName | string | n | If provided, filters the snapshot to a table. If omitted, provide snapshot across all tables. | | format | string | n | Output format for values. Valid values: \\[ `json`\\] | **Result JSON** | Field Name | Type | Description | | --- | --- | --- | | values | List\\[ConvexValue\\] | List of convex values in the requested format. Each value includes extra fields `_ts` and `_table`. | | hasMore | boolean | True if there are more pages to the snapshot. | | snapshot | int | A value that represents the database timestamp at which the snapshot was taken. | | cursor | string | An opaque cursor representing the end of the progress on the given page. Pass this to subsequent calls. | Expected API usage (pseudocode): ```codeBlockLines_zEuJ def list_full_snapshot() snapshot_values = [] snapshot = None cursor = None while True: result = api.list_snapshot(cursor, snapshot) snapshot_values.extend(result.values) (cursor, snapshot) = (result.cursor, result.snapshot) if !result.hasMore: break return (snapshot_values, result.snapshot) ``` ### GET `/api/document_deltas` [​](https://docs.convex.dev/http-api\\#get-apidocument_deltas \"Direct link to get-apidocument_deltas\") The `document_deltas` endpoint walks the change log of documents to find new, updated, and deleted documents in the order of their mutations. This order is given by a `_ts` field on the returned documents. Deletions are represented as JSON objects with fields `_id`, `_ts`, and `_deleted: true`. **Query parameters** | Name | Type | Required | Description | | --- | --- | --- | --- | | cursor | int | y | Database timestamp after which to continue streaming document deltas. Initial value is the `snapshot` field returned from list\\_snapshot. | | tableName | string | n | If provided, filters the document deltas to a table. If omitted, provide deltas across all tables. | | format | string | n | Output format for values. Valid values: \\[ `json`\\] | **Result JSON** | Field Name | Type | Description | | --- | --- | --- | | values | List\\[ConvexValue\\] | List of convex values in the requested format. Each value includes extra fields for `_ts`, and `_table`. Deletions include a field `_deleted`. | | hasMore | boolean | True if there are more pages to the snapshot. | | cursor | int | A value that represents the database timestamp at the end of the page. Pass to subsequent calls to document\\_deltas. | Expected API usage (pseudocode): ```codeBlockLines_zEuJ def delta_sync(delta_cursor): delta_values = [] while True: result = api.document_deltas(cursor) delta_values.extend(result.values) cursor = result.cursor if !hasMore: break return (delta_values, delta_cursor) (snapshot_values, delta_cursor) = list_full_snapshot() (delta_values, delta_cursor) = delta_sync(delta_cursor) # Save delta_cursor for the next sync ``` ## Streaming import API [​](https://docs.convex.dev/http-api\\#streaming-import-api \"Direct link to Streaming import API\") Convex supports streaming import. Convex provides a connector implementation for [Airbyte](https://docs.convex.dev/production/integrations/streaming-import-export). Those connectors use the following APIs. Streaming import support is automatically enabled for all Convex projects. ### Headers [​](https://docs.convex.dev/http-api\\#headers \"Direct link to Headers\") Streaming import endpoints accept a `Convex-Client: streaming-import-` header, where the version follows [Semver](https://semver.org/) guidelines. If this header is not specified, Convex will default to the latest version. We recommend using the header to ensure the consumer of this API does not break as the API changes. ### GET `/api/streaming_import/primary_key_indexes_ready` [​](https://docs.convex.dev/http-api\\#get-apistreaming_importprimary_key_indexes_ready \"Direct link to get-apistreaming_importprimary_key_indexes_ready\") The `primary_key_indexes_ready` endpoint takes a list of table names and returns true if the primary key indexes (created by `add_primary_key_indexes`) on all those tables are ready. If the tables are newly created, the indexes should be ready immediately; however if there are existing documents in the tables, it may take some time to backfill the primary key indexes. The response looks like: ```codeBlockLines_zEuJ { \"indexesReady\": true } ``` ### PUT `/api/streaming_import/add_primary_key_indexes` [​](https://docs.convex.dev/http-api\\#put-apistreaming_importadd_primary_key_indexes \"Direct link to put-apistreaming_importadd_primary_key_indexes\") The `add_primary_key_indexes` endpoint takes a JSON body containing the primary keys for tables and creates indexes on the primary keys to be backfilled. Note that they are not immediately ready to query - the `primary_key_indexes_ready` endpoint needs to be polled until it returns True before calling `import_airbyte_records` with records that require primary key indexes. Also note that Convex queries will not have access to these added indexes. These are solely for use in `import_airbyte_records`. The body takes the form of a map of index names to list of field paths to index. Each field path is represented by a list of fields that can represent nested field paths. ```codeBlockLines_zEuJ { \"indexes\": { \"\": [[\"\"], [\"\", \"\"]] } } ``` Expected API Usage: 1. Add indexes for primary keys by making a request to `add_primary_key_indexes`. 2. Poll `primary_key_indexes_ready` until the response is true. 3. Query using the added indexes. ### PUT `api/streaming_import/clear_tables` [​](https://docs.convex.dev/http-api\\#put-apistreaming_importclear_tables \"Direct link to put-apistreaming_importclear_tables\") The `clear_tables` endpoint deletes all documents from the specified tables. Note that this may require multiple transactions. If there is an intermediate error only some documents may be deleted. The JSON body to use this API request contains a list of table names: ```codeBlockLines_zEuJ { \"tableNames\": [\"\", \"\"] } ``` ### POST `api/streaming_import/replace_tables` [​](https://docs.convex.dev/http-api\\#post-apistreaming_importreplace_tables \"Direct link to post-apistreaming_importreplace_tables\") This endpoint is no longer supported. Use `api/streaming_import/clear_tables` instead. The `replace_tables` endpoint renames tables with temporary names to their final names, deleting any existing tables with the final names. The JSON body to use this API request contains a list of table names: ```codeBlockLines_zEuJ { \"tableNames\": { \"\": \"\", \"\": \"\" } } ``` ### POST `api/streaming_import/import_airbyte_records` [​](https://docs.convex.dev/http-api\\#post-apistreaming_importimport_airbyte_records \"Direct link to post-apistreaming_importimport_airbyte_records\") The `import_airbyte_records` endpoint enables streaming ingress into a Convex deployment and is designed to be called from an Airbyte destination connector. It takes a map of streams and a list of messages in the JSON body. Each stream has a name and JSON schema that will correspond to a Convex table. Streams where records should be deduplicated include a primary key as well, which is represented as a list of lists of strings that are field paths. Records for streams without a primary key are appended to tables; records for streams with a primary key replace an existing record where the primary key value matches or are appended if there is no match. If you are using primary keys, you must call the `add_primary_key_indexes` endpoint first and wait for them to backfill by polling `primary_key_indexes_ready`. Each message contains a stream name and a JSON document that will be inserted (or replaced, in the case of deduplicated sync) into the table with the corresponding stream name. Table names are same as the stream names. Airbyte records become Convex documents. ```codeBlockLines_zEuJ { \"tables\": { \"\": { \"primaryKey\": [[\"\"], [\"\", \"\"]], \"jsonSchema\": // see https://json-schema.org/ for examples } }, \"messages\": [{\\ \"tableName\": \"\",\\ \"data\": {} // JSON object conforming to the `json_schema` for that stream\\ }] } ``` Similar to `clear_tables`, it is possible to execute a partial import using `import_airbyte_records` if there is a failure after a transaction has committed. Expected API Usage: 1. \\[Optional\\] Add any indexes if using primary keys and [deduplicated sync](https://docs.airbyte.com/understanding-airbyte/connections/incremental-deduped-history/) (see `add_primary_key_indexes` above). 2. \\[Optional\\] Delete all documents in specified tables using `clear_tables` if using [overwrite sync](https://docs.airbyte.com/understanding-airbyte/connections/full-refresh-overwrite). 3. Make a request to `import_airbyte_records` with new records to sync and stream information. - [Convex value format](https://docs.convex.dev/http-api#convex-value-format) - [API authentication](https://docs.convex.dev/http-api#api-authentication) - [Functions API](https://docs.convex.dev/http-api#functions-api) - [POST `/api/query`, `/api/mutation`, `/api/action`](https://docs.convex.dev/http-api#post-apiquery-apimutation-apiaction) - [POST `/api/run/{functionIdentifier}`](https://docs.convex.dev/http-api#post-apirunfunctionidentifier) - [Streaming export API](https://docs.convex.dev/http-api#streaming-export-api) - [GET `/api/json_schemas`](https://docs.convex.dev/http-api#get-apijson_schemas) - [GET `/api/list_snapshot`](https://docs.convex.dev/http-api#get-apilist_snapshot) - [GET `/api/document_deltas`](https://docs.convex.dev/http-api#get-apidocument_deltas) - [Streaming import API](https://docs.convex.dev/http-api#streaming-import-api) - [Headers](https://docs.convex.dev/http-api#headers) - [GET `/api/streaming_import/primary_key_indexes_ready`](https://docs.convex.dev/http-api#get-apistreaming_importprimary_key_indexes_ready) - [PUT `/api/streaming_import/add_primary_key_indexes`](https://docs.convex.dev/http-api#put-apistreaming_importadd_primary_key_indexes) - [PUT `api/streaming_import/clear_tables`](https://docs.convex.dev/http-api#put-apistreaming_importclear_tables) - [POST `api/streaming_import/replace_tables`](https://docs.convex.dev/http-api#post-apistreaming_importreplace_tables) - [POST `api/streaming_import/import_airbyte_records`](https://docs.convex.dev/http-api#post-apistreaming_importimport_airbyte_records) [Skip to main content](https://docs.convex.dev/client/svelte#docusaurus_skipToContent_fallback) Convex is a great fit for reactive UI frameworks like Svelte. The [convex-svelte npm package](https://www.npmjs.com/package/convex-svelte) enhances the [ConvexClient](https://docs.convex.dev/api/classes/browser.ConvexClient) with declarative subscriptions in Svelte 5. See the [Svelte Quickstart](https://docs.convex.dev/quickstart/svelte) to get started. The Svelte client is open source and available on [GitHub](https://github.com/get-convex/convex-svelte). [Skip to main content](https://docs.convex.dev/functions/bundling#docusaurus_skipToContent_fallback) On this page Bundling is the process of gathering, optimizing and transpiling the JS/TS source code of [functions](https://docs.convex.dev/functions) and their dependencies. During development and when deploying, the code is transformed to a format that Convex [runtimes](https://docs.convex.dev/functions/runtimes) can directly and efficiently execute. Convex currently bundles all dependencies automatically, but for the Node.js runtime you can disable bundling certain packages via the [external packages](https://docs.convex.dev/functions/bundling#external-packages) config. ## Bundling for Convex [​](https://docs.convex.dev/functions/bundling\\#bundling-for-convex \"Direct link to Bundling for Convex\") When you push code either via `npx convex dev` or `npx convex deploy`, the Convex CLI uses [esbuild](https://esbuild.github.io/) to traverse your `convex/` folder and bundle your functions and all of their used dependencies into a source code bundle. This bundle is then sent to the server. Thanks to bundling you can write your code using both modern ECMAScript Modules (ESM) or the older CommonJS (CJS) syntax. ESM vs. CJS ESM - Is the standard for browser Javascript - Uses static imports via the `import` and `export` **keywords** (not functions) at the global scope - Also supports dynamic imports via the asynchronous `import` function CJS - Was previously the standard module system for Node.js - Relies on dynamic imports via the `require` and asynchronous `import` functions for fetching external modules - Uses the `module.exports` object for exports ## Bundling limitations [​](https://docs.convex.dev/functions/bundling\\#bundling-limitations \"Direct link to Bundling limitations\") The nature of bundling comes with a few limitations. ### Code size limits [​](https://docs.convex.dev/functions/bundling\\#code-size-limits \"Direct link to Code size limits\") The total size of your bundled function code in your `convex/` folder is **limited to 32MiB (~33.55MB)**. Other platform limits can be found [here](https://docs.convex.dev/production/state/limits). While this limit in itself is quite high for just source code, certain dependencies can quickly make your bundle size cross over this limit, particularly if they are not effectively [tree-shakeable](https://webpack.js.org/guides/tree-shaking/) (such as [aws-sdk](https://www.npmjs.com/package/aws-sdk) or [snowflake-sdk](https://www.npmjs.com/package/snowflake-sdk)) You can follow these steps to debug bundle size: 1. Make sure you're using the most recent version of convex ```codeBlockLines_zEuJ npm install convex@latest ``` 2. Generate the bundle Note that this will not push code, and just generated a bundle for debugging purposes. ```codeBlockLines_zEuJ npx convex dev --once --debug-bundle-path /tmp/myBundle ``` 3. Visualize the bundle Use [source-map-explorer](https://github.com/danvk/source-map-explorer/tree/master) to visualize your bundle. ```codeBlockLines_zEuJ npx source-map-explorer /tmp/myBundle/**/*.js ``` Code bundled for the Convex runtime will be in the `isolate` directory while code bundled for node actions will be in the `node` directory. Large node dependencies can be eliminated from the bundle by marking them as [external packages](https://docs.convex.dev/functions/bundling#external-packages). ### Dynamic dependencies [​](https://docs.convex.dev/functions/bundling\\#dynamic-dependencies \"Direct link to Dynamic dependencies\") Some libraries rely on dynamic imports (via `import`/ `require` calls) to avoid always including their dependencies. These imports are not supported by the [default Convex runtime](https://docs.convex.dev/functions/runtimes#default-convex-runtime) and will throw an error at runtime. Additionally, some libraries rely on local files, which cannot be bundled by esbuild. If bundling is used, irrespective of the choice of runtime, these imports will always fail in Convex. Examples of libraries with dynamic dependencies Consider the following examples of packages relying on dynamic dependencies: - [langchain](https://www.npmjs.com/package/langchain) relying on the presence of peer dependencies that it can dynamically import. These dependencies are not statically `import` ed so will not be bundled by `esbuild`. - [sharp](https://www.npmjs.com/package/sharp) relying on the presence of `libvips` binaries for image-processing operations - [pdf-parse](https://www.npmjs.com/package/pdf-parse) relies on being dynamically imported with `require()` in order to detect if it is being run in test mode. Bundling can eliminate these `require()` calls, making `pdf-parse` assume it is running in test mode. - [tiktoken](https://www.npmjs.com/package/tiktoken) relying on local WASM files ## External packages [​](https://docs.convex.dev/functions/bundling\\#external-packages \"Direct link to External packages\") As a workaround for the bundling limitations above, Convex provides an escape hatch: **external packages**. This feature is currently exclusive to Convex's [Node.js runtime](https://docs.convex.dev/functions/runtimes#nodejs-runtime). External packages use [`esbuild`'s facility for marking a dependency as external](https://esbuild.github.io/api/#external). This tells `esbuild` to not bundle the external dependency at all and to leave the import as a dynamic runtime import using `require()` or `import()`. Thus, your Convex modules will rely on the underlying system having that dependency made available at execution-time. External Packages are in beta External Packagesare currently a [beta\\\\ feature](https://docs.convex.dev/production/state/#beta-features). If you have feedback or feature requests, [let us know on Discord](https://convex.dev/community)! ### Package installation on the server [​](https://docs.convex.dev/functions/bundling\\#package-installation-on-the-server \"Direct link to Package installation on the server\") Packages marked as external are installed from [npm](https://www.npmjs.com/) the first time you push code that uses them. The version installed matches the version installed in the `node_modules` folder on your local machine. While this comes with a latency penalty the first time you push external packages, your packages are cached and this install step only ever needs to rerun if your external packages change. Once cached, pushes can actually be faster due to smaller source code bundles being sent to the server during pushes! ### Specifying external packages [​](https://docs.convex.dev/functions/bundling\\#specifying-external-packages \"Direct link to Specifying external packages\") Create a [`convex.json`](https://docs.convex.dev/production/project-configuration#convex.json) file in the same directory as your `package.json` if it does not exist already. Set the `node.externalPackages` field to `[\"*\"]` to mark all dependencies used within your Node actions as external: ```codeBlockLines_zEuJ { \"node\": { \"externalPackages\": [\"*\"] } } ``` Alternatively, you can explicitly specify which packages to mark as external: ```codeBlockLines_zEuJ { \"node\": { \"externalPackages\": [\"aws-sdk\", \"sharp\"] } } ``` The package identifiers should match the string used in `import`/ `require` in your [Node.js action](https://docs.convex.dev/functions/actions#choosing-the-runtime-use-node). ### Troubleshooting external packages [​](https://docs.convex.dev/functions/bundling\\#troubleshooting-external-packages \"Direct link to Troubleshooting external packages\") #### Incorrect package versions [​](https://docs.convex.dev/functions/bundling\\#incorrect-package-versions \"Direct link to Incorrect package versions\") The Convex CLI searches for external packages within your local `node_modules` directory. Thus, changing version of a package in the `package.json` will not affect the version used on the server until you've updated the package version installed in your local `node_modules` folder (e.g. running `npm install`). #### Import errors [​](https://docs.convex.dev/functions/bundling\\#import-errors \"Direct link to Import errors\") Marking a dependency as external may result in errors like this: > The requested module \"some-module\" is a CommonJs module, which may not support > all module.exports as named exports. CommonJs modules can always be imported > via the default export This requires rewriting any imports for this module as follows: ```codeBlockLines_zEuJ // ❌ old import { Foo } from \"some-module\"; // ✅ new import SomeModule from \"some-module\"; const { Foo } = SomeModule; ``` ### Limitations [​](https://docs.convex.dev/functions/bundling\\#limitations \"Direct link to Limitations\") The total size of your source code bundle and external packages cannot exceed the following: - 45MB zipped - 240MB unzipped Packages that are known not to work at this time: - [Puppeteer](https://www.npmjs.com/package/puppeteer) \\- browser binary installation exceeds the size limit - [@ffmpeg.wasm](https://www.npmjs.com/package/@ffmpeg/ffmpeg) \\- since 0.12.0, [no longer supports Node environments](https://ffmpegwasm.netlify.app/docs/faq#why-ffmpegwasm-doesnt-support-nodejs) If there is a package that you would like working in your Convex functions, [let us know](https://convex.dev/community). - [Bundling for Convex](https://docs.convex.dev/functions/bundling#bundling-for-convex) - [Bundling limitations](https://docs.convex.dev/functions/bundling#bundling-limitations) - [Code size limits](https://docs.convex.dev/functions/bundling#code-size-limits) - [Dynamic dependencies](https://docs.convex.dev/functions/bundling#dynamic-dependencies) - [External packages](https://docs.convex.dev/functions/bundling#external-packages) - [Package installation on the server](https://docs.convex.dev/functions/bundling#package-installation-on-the-server) - [Specifying external packages](https://docs.convex.dev/functions/bundling#specifying-external-packages) - [Troubleshooting external packages](https://docs.convex.dev/functions/bundling#troubleshooting-external-packages) - [Limitations](https://docs.convex.dev/functions/bundling#limitations) [Skip to main content](https://docs.convex.dev/functions/internal-functions#docusaurus_skipToContent_fallback) On this page Internal functions can only be called by other [functions](https://docs.convex.dev/functions) and cannot be called directly from a [Convex client](https://docs.convex.dev/client/react). By default your Convex functions are public and accessible to clients. Public functions may be called by malicious users in ways that cause surprising results. Internal functions help you mitigate this risk. We recommend using internal functions any time you're writing logic that should not be called from a client. While internal functions help mitigate risk by reducing the public surface area of your application, you can still validate internal invariants using [argument validation](https://docs.convex.dev/functions/validation) and/or [authentication](https://docs.convex.dev/auth/functions-auth). ## Use cases for internal functions [​](https://docs.convex.dev/functions/internal-functions\\#use-cases-for-internal-functions \"Direct link to Use cases for internal functions\") Leverage internal functions by: - Calling them from [actions](https://docs.convex.dev/functions/actions#action-context) via `runQuery` and `runMutation` - Calling them from [HTTP actions](https://docs.convex.dev/functions/http-actions) via `runQuery`, `runMutation`, and `runAction` - [Scheduling](https://docs.convex.dev/scheduling/scheduled-functions) them from other functions to run in the future - Scheduling them to run periodically from [cron jobs](https://docs.convex.dev/scheduling/cron-jobs) - Running them using the [Dashboard](https://docs.convex.dev/dashboard/deployments/functions#running-functions) - Running them from the [CLI](https://docs.convex.dev/cli#run-convex-functions) ## Defining internal functions [​](https://docs.convex.dev/functions/internal-functions\\#defining-internal-functions \"Direct link to Defining internal functions\") An internal function is defined using `internalQuery`, `internalMutation`, or `internalAction`. For example: convex/plans.ts TS ```codeBlockLines_zEuJ import { internalMutation } from \"./_generated/server\"; import { v } from \"convex/values\"; export const markPlanAsProfessional = internalMutation({ args: { planId: v.id(\"plans\") }, handler: async (ctx, args) => { await ctx.db.patch(args.planId, { planType: \"professional\" }); }, }); ``` If you need to pass complicated objects to internal functions you might prefer to not use argument validation. Note though that if you're using `internalQuery` or `internalMutation` it's a better idea to pass around document IDs instead of documents, to ensure the query or mutation is working with the up-to-date state of the database. Internal function without argument validation convex/plans.ts TS ```codeBlockLines_zEuJ import { internalAction } from \"./_generated/server\"; import { Doc } from \"./_generated/dataModel\"; export const markPlanAsProfessional = internalAction({ handler: async (actionCtx, args) => { // perform an action, perhaps calling a third-party API }, }); ``` ## Calling internal functions [​](https://docs.convex.dev/functions/internal-functions\\#calling-internal-functions \"Direct link to Calling internal functions\") Internal functions can be called from actions and scheduled from actions and mutation using the [`internal`](https://docs.convex.dev/generated-api/api#internal) object. For example, consider this public `upgrade` action that calls the internal `plans.markPlanAsProfessional` mutation we defined above: convex/changes.ts TS ```codeBlockLines_zEuJ import { action } from \"./_generated/server\"; import { internal } from \"./_generated/api\"; import { v } from \"convex/values\"; export const upgrade = action({ args: { planId: v.id(\"plans\"), }, handler: async (ctx, args) => { // Call out to payment provider (e.g. Stripe) to charge customer const response = await fetch(\"https://...\"); if (response.ok) { // Mark the plan as \"professional\" in the Convex DB await ctx.runMutation(internal.plans.markPlanAsProfessional, { planId: args.planId, }); } }, }); ``` In this example a user should not be able to directly call `internal.plans.markPlanAsProfessional` without going through the `upgrade` action — if they did, then they would get a free upgrade. You can define public and internal functions in the same file. - [Use cases for internal functions](https://docs.convex.dev/functions/internal-functions#use-cases-for-internal-functions) - [Defining internal functions](https://docs.convex.dev/functions/internal-functions#defining-internal-functions) - [Calling internal functions](https://docs.convex.dev/functions/internal-functions#calling-internal-functions) [Skip to main content](https://docs.convex.dev/client/tanstack-query#docusaurus_skipToContent_fallback) On this page [TanStack Query](https://tanstack.com/query/latest) is an excellent, popular library for managing requests to a server. The [`@convex-dev/react-query`](https://www.npmjs.com/package/@convex-dev/react-query) library provides [Query Option](https://tanstack.com/query/latest/docs/framework/react/guides/query-options) functions for use with TanStack Query. Not all features of the standard [Convex React client](https://docs.convex.dev/client/react) are available through the TanStack Query APIs but you can use the two alongside each other, dropping into the standard Convex React hooks as necessary. The TanStack Query adapter is in beta The TanStack Query adapteris currently a [beta\\\\ feature](https://docs.convex.dev/production/state/#beta-features). If you have feedback or feature requests, [let us know on Discord](https://convex.dev/community)! This makes subscribing to a Convex query function using the TanStack Query `useQuery` hook look like this: ```codeBlockLines_zEuJ const { data, isPending, error } = useQuery(convexQuery(api.messages.list, {})); ``` Instead of the typical polling pattern for API endpoints used with TanStack Query, the code above receives updates for this `api.messages.list` query from the Convex server reactively. New results for all relevant subscriptions are pushed to the client where they update at the same time so data is never stale and there's no need to manually invalidate queries. Support for other frameworks Currently only [React\\\\ Query](https://tanstack.com/query/latest/docs/framework/react/overview) is supported via [`@convex-dev/react-query`](https://www.npmjs.com/package/@convex-dev/react-query). [Let us know](https://convex.dev/community) if you would find support for vue-query, svelte-query, solid-query, or angular-query helpful. ## Setup [​](https://docs.convex.dev/client/tanstack-query\\#setup \"Direct link to Setup\") To get live updates in TanStack Query create a `ConvexQueryClient` and connect it to the TanStack Query [QueryClient](https://tanstack.com/query/latest/docs/reference/QueryClient). After installing the adapter library with ```codeBlockLines_zEuJ npm i @convex-dev/react-query ``` wire up Convex to TanStack Query like this: src/main.tsx ```codeBlockLines_zEuJ import { ConvexQueryClient } from \"@convex-dev/react-query\"; import { QueryClient, QueryClientProvider } from \"@tanstack/react-query\"; import { ConvexProvider, ConvexReactClient } from \"convex/react\"; import ReactDOM from \"react-dom/client\"; import App from \"./App\"; import \"./index.css\"; const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL); const convexQueryClient = new ConvexQueryClient(convex); const queryClient = new QueryClient({ defaultOptions: { queries: { queryKeyHashFn: convexQueryClient.hashFn(), queryFn: convexQueryClient.queryFn(), }, }, }); convexQueryClient.connect(queryClient); ReactDOM.createRoot(document.getElementById(\"root\")!).render( , ); ``` Note that when your create your React tree you should both: - wrap your app in the TanStack Query [`QueryClientProvider`](https://tanstack.com/query/latest/docs/framework/react/reference/QueryClientProvider) so you can use [TanStack Query hooks](https://tanstack.com/query/latest/docs/framework/react/reference/useQuery) and - wrap your app in the [`ConvexProvider`](https://docs.convex.dev/api/modules/react#convexprovider) so you can also use normal [Convex React](https://docs.convex.dev/client/react) hooks ## Queries [​](https://docs.convex.dev/client/tanstack-query\\#queries \"Direct link to Queries\") A live-updating subscription to a Convex [query](https://docs.convex.dev/functions/query-functions) is as simple as calling TanStack [`useQuery`](https://tanstack.com/query/latest/docs/framework/react/reference/useQuery) with `convexQuery`: ```codeBlockLines_zEuJ import { useQuery } from \"@tanstack/react-query\"; import { convexQuery } from \"@convex-dev/react-query\"; import { api } from \"../convex/_generated/api\"; export function App() { const { data, isPending, error } = useQuery( convexQuery(api.functions.myQuery, { id: 123 }), ); return isPending ? \"Loading...\" : data; } ``` You can spread the object returned by `convexQuery` into an object specifying additional [arguments of `useQuery`](https://tanstack.com/query/latest/docs/framework/react/reference/useQuery). ```codeBlockLines_zEuJ const { data, isPending, error } = useQuery({ ...convexQuery(api.functions.myQuery, { id: 123 }), initialData: [], // use an empty list if no data is available yet gcTime: 10000, // stay subscribed for 10 seconds after this component unmounts }); ``` ## Mutations [​](https://docs.convex.dev/client/tanstack-query\\#mutations \"Direct link to Mutations\") Your app can call Convex [mutations](https://docs.convex.dev/functions/mutation-functions) by using the TanStack [`useMutation`](https://tanstack.com/query/latest/docs/framework/react/reference/useMutation) hook, and setting the `mutationFn` property to the result of calling `useConvexMutation`: ```codeBlockLines_zEuJ import { useMutation } from \"@tanstack/react-query\"; import { useConvexMutation } from \"@convex-dev/react-query\"; import { api } from \"../convex/_generated/api\"; export function App() { const { mutate, isPending } = useMutation({ mutationFn: useConvexMutation(api.functions.doSomething), }); return ; } ``` `useConvexMutation` is just a re-export of the [`useMutation`](https://docs.convex.dev/client/react#editing-data) hook from [Convex React](https://docs.convex.dev/client/react). ## Differences from using `fetch` with TanStack Query [​](https://docs.convex.dev/client/tanstack-query\\#differences-from-using-fetch-with-tanstack-query \"Direct link to differences-from-using-fetch-with-tanstack-query\") Convex provides stronger guarantees than other methods of fetching data with React Query, so some options and return value properties are no longer necessary. Subscriptions to Convex queries will remain active after the last component using `useQuery` for a given function unmounts for `gcTime` milliseconds. This value is 5 minutes by default; if this results in unwanted function activity use a smaller value. Data provided by Convex is never stale, so the `isStale` property of the return value of `useQuery` will always be false. `retry`-related options are ignored, since Convex provides its own retry mechanism over its WebSocket protocol. `refetch`-related options are similarly ignored since Convex queries are always up to date. - [Setup](https://docs.convex.dev/client/tanstack-query#setup) - [Queries](https://docs.convex.dev/client/tanstack-query#queries) - [Mutations](https://docs.convex.dev/client/tanstack-query#mutations) - [Differences from using `fetch` with TanStack Query](https://docs.convex.dev/client/tanstack-query#differences-from-using-fetch-with-tanstack-query) [Skip to main content](https://docs.convex.dev/api/modules/values#docusaurus_skipToContent_fallback) On this page Utilities for working with values stored in Convex. You can see the full set of supported types at [Types](https://docs.convex.dev/using/types). ## Namespaces [​](https://docs.convex.dev/api/modules/values\\#namespaces \"Direct link to Namespaces\") - [Base64](https://docs.convex.dev/api/namespaces/values.Base64) ## Classes [​](https://docs.convex.dev/api/modules/values\\#classes \"Direct link to Classes\") - [ConvexError](https://docs.convex.dev/api/classes/values.ConvexError) - [VId](https://docs.convex.dev/api/classes/values.VId) - [VFloat64](https://docs.convex.dev/api/classes/values.VFloat64) - [VInt64](https://docs.convex.dev/api/classes/values.VInt64) - [VBoolean](https://docs.convex.dev/api/classes/values.VBoolean) - [VBytes](https://docs.convex.dev/api/classes/values.VBytes) - [VString](https://docs.convex.dev/api/classes/values.VString) - [VNull](https://docs.convex.dev/api/classes/values.VNull) - [VAny](https://docs.convex.dev/api/classes/values.VAny) - [VObject](https://docs.convex.dev/api/classes/values.VObject) - [VLiteral](https://docs.convex.dev/api/classes/values.VLiteral) - [VArray](https://docs.convex.dev/api/classes/values.VArray) - [VRecord](https://docs.convex.dev/api/classes/values.VRecord) - [VUnion](https://docs.convex.dev/api/classes/values.VUnion) ## Type Aliases [​](https://docs.convex.dev/api/modules/values\\#type-aliases \"Direct link to Type Aliases\") ### GenericValidator [​](https://docs.convex.dev/api/modules/values\\#genericvalidator \"Direct link to GenericValidator\") Ƭ **GenericValidator**: [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `any`, `any` > The type that all validators must extend. #### Defined in [​](https://docs.convex.dev/api/modules/values\\#defined-in \"Direct link to Defined in\") [values/validator.ts:27](https://github.com/get-convex/convex-js/blob/main/src/values/validator.ts#L27) * * * ### AsObjectValidator [​](https://docs.convex.dev/api/modules/values\\#asobjectvalidator \"Direct link to AsObjectValidator\") Ƭ **AsObjectValidator** < `V` >: `V` extends [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `any`, `any` \\> ? `V` : `V` extends [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) ? [`Validator`](https://docs.convex.dev/api/modules/values#validator) < [`ObjectType`](https://docs.convex.dev/api/modules/values#objecttype) < `V` >\\> : `never` Coerce an object with validators as properties to a validator. If a validator is passed, return it. #### Type parameters [​](https://docs.convex.dev/api/modules/values\\#type-parameters \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `V` | extends [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `any`, `any` \\> \\| [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) | #### Defined in [​](https://docs.convex.dev/api/modules/values\\#defined-in-1 \"Direct link to Defined in\") [values/validator.ts:61](https://github.com/get-convex/convex-js/blob/main/src/values/validator.ts#L61) * * * ### PropertyValidators [​](https://docs.convex.dev/api/modules/values\\#propertyvalidators \"Direct link to PropertyValidators\") Ƭ **PropertyValidators**: `Record` < `string`, [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, [`OptionalProperty`](https://docs.convex.dev/api/modules/values#optionalproperty), `any` >> Validators for each property of an object. This is represented as an object mapping the property name to its [Validator](https://docs.convex.dev/api/modules/values#validator). #### Defined in [​](https://docs.convex.dev/api/modules/values\\#defined-in-2 \"Direct link to Defined in\") [values/validator.ts:235](https://github.com/get-convex/convex-js/blob/main/src/values/validator.ts#L235) * * * ### ObjectType [​](https://docs.convex.dev/api/modules/values\\#objecttype \"Direct link to ObjectType\") Ƭ **ObjectType** < `Fields` >: [`Expand`](https://docs.convex.dev/api/modules/server#expand) <{ \\[Property in OptionalKeys\\]?: Exclude, undefined> } & { \\[Property in RequiredKeys\\]: Infer }> Compute the type of an object from [PropertyValidators](https://docs.convex.dev/api/modules/values#propertyvalidators). #### Type parameters [​](https://docs.convex.dev/api/modules/values\\#type-parameters-1 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Fields` | extends [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) | #### Defined in [​](https://docs.convex.dev/api/modules/values\\#defined-in-3 \"Direct link to Defined in\") [values/validator.ts:245](https://github.com/get-convex/convex-js/blob/main/src/values/validator.ts#L245) * * * ### Infer [​](https://docs.convex.dev/api/modules/values\\#infer \"Direct link to Infer\") Ƭ **Infer** < `T` >: `T`\\[ `\"type\"`\\] Extract a TypeScript type from a validator. Example usage: ```codeBlockLines_zEuJ const objectSchema = v.object({ property: v.string(), }); type MyObject = Infer; // { property: string } ``` **`Type Param`** The type of a [Validator](https://docs.convex.dev/api/modules/values#validator) constructed with [v](https://docs.convex.dev/api/modules/values#v). #### Type parameters [​](https://docs.convex.dev/api/modules/values\\#type-parameters-2 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `T` | extends [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, [`OptionalProperty`](https://docs.convex.dev/api/modules/values#optionalproperty), `any` > | #### Defined in [​](https://docs.convex.dev/api/modules/values\\#defined-in-4 \"Direct link to Defined in\") [values/validator.ts:287](https://github.com/get-convex/convex-js/blob/main/src/values/validator.ts#L287) * * * ### VOptional [​](https://docs.convex.dev/api/modules/values\\#voptional \"Direct link to VOptional\") Ƭ **VOptional** < `T` >: `T` extends [`VId`](https://docs.convex.dev/api/classes/values.VId) ? [`VId`](https://docs.convex.dev/api/classes/values.VId) < `Type` \\| `undefined`, `\"optional\"` \\> : `T` extends [`VString`](https://docs.convex.dev/api/classes/values.VString) ? [`VString`](https://docs.convex.dev/api/classes/values.VString) < `Type` \\| `undefined`, `\"optional\"` \\> : `T` extends [`VFloat64`](https://docs.convex.dev/api/classes/values.VFloat64) ? [`VFloat64`](https://docs.convex.dev/api/classes/values.VFloat64) < `Type` \\| `undefined`, `\"optional\"` \\> : `T` extends [`VInt64`](https://docs.convex.dev/api/classes/values.VInt64) ? [`VInt64`](https://docs.convex.dev/api/classes/values.VInt64) < `Type` \\| `undefined`, `\"optional\"` \\> : `T` extends [`VBoolean`](https://docs.convex.dev/api/classes/values.VBoolean) ? [`VBoolean`](https://docs.convex.dev/api/classes/values.VBoolean) < `Type` \\| `undefined`, `\"optional\"` \\> : `T` extends [`VNull`](https://docs.convex.dev/api/classes/values.VNull) ? [`VNull`](https://docs.convex.dev/api/classes/values.VNull) < `Type` \\| `undefined`, `\"optional\"` \\> : `T` extends [`VAny`](https://docs.convex.dev/api/classes/values.VAny) ? [`VAny`](https://docs.convex.dev/api/classes/values.VAny) < `Type` \\| `undefined`, `\"optional\"` \\> : `T` extends [`VLiteral`](https://docs.convex.dev/api/classes/values.VLiteral) ? [`VLiteral`](https://docs.convex.dev/api/classes/values.VLiteral) < `Type` \\| `undefined`, `\"optional\"` \\> : `T` extends [`VBytes`](https://docs.convex.dev/api/classes/values.VBytes) ? [`VBytes`](https://docs.convex.dev/api/classes/values.VBytes) < `Type` \\| `undefined`, `\"optional\"` \\> : `T` extends [`VObject`](https://docs.convex.dev/api/classes/values.VObject) ? [`VObject`](https://docs.convex.dev/api/classes/values.VObject) < `Type` \\| `undefined`, `Fields`, `\"optional\"`, `FieldPaths` \\> : `T` extends [`VArray`](https://docs.convex.dev/api/classes/values.VArray) ? [`VArray`](https://docs.convex.dev/api/classes/values.VArray) < `Type` \\| `undefined`, `Element`, `\"optional\"` \\> : `T` extends [`VRecord`](https://docs.convex.dev/api/classes/values.VRecord) ? [`VRecord`](https://docs.convex.dev/api/classes/values.VRecord) < `Type` \\| `undefined`, `Key`, `Value`, `\"optional\"`, `FieldPaths` \\> : `T` extends [`VUnion`](https://docs.convex.dev/api/classes/values.VUnion) ? [`VUnion`](https://docs.convex.dev/api/classes/values.VUnion) < `Type` \\| `undefined`, `Members`, `\"optional\"`, `FieldPaths` \\> : `never` #### Type parameters [​](https://docs.convex.dev/api/modules/values\\#type-parameters-3 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `T` | extends [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, [`OptionalProperty`](https://docs.convex.dev/api/modules/values#optionalproperty), `any` > | #### Defined in [​](https://docs.convex.dev/api/modules/values\\#defined-in-5 \"Direct link to Defined in\") [values/validators.ts:522](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L522) * * * ### OptionalProperty [​](https://docs.convex.dev/api/modules/values\\#optionalproperty \"Direct link to OptionalProperty\") Ƭ **OptionalProperty**: `\"optional\"` \\| `\"required\"` Type representing whether a property in an object is optional or required. #### Defined in [​](https://docs.convex.dev/api/modules/values\\#defined-in-6 \"Direct link to Defined in\") [values/validators.ts:555](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L555) * * * ### Validator [​](https://docs.convex.dev/api/modules/values\\#validator \"Direct link to Validator\") Ƭ **Validator** < `Type`, `IsOptional`, `FieldPaths` >: [`VId`](https://docs.convex.dev/api/classes/values.VId) < `Type`, `IsOptional` \\> \\| [`VString`](https://docs.convex.dev/api/classes/values.VString) < `Type`, `IsOptional` \\> \\| [`VFloat64`](https://docs.convex.dev/api/classes/values.VFloat64) < `Type`, `IsOptional` \\> \\| [`VInt64`](https://docs.convex.dev/api/classes/values.VInt64) < `Type`, `IsOptional` \\> \\| [`VBoolean`](https://docs.convex.dev/api/classes/values.VBoolean) < `Type`, `IsOptional` \\> \\| [`VNull`](https://docs.convex.dev/api/classes/values.VNull) < `Type`, `IsOptional` \\> \\| [`VAny`](https://docs.convex.dev/api/classes/values.VAny) < `Type`, `IsOptional` \\> \\| [`VLiteral`](https://docs.convex.dev/api/classes/values.VLiteral) < `Type`, `IsOptional` \\> \\| [`VBytes`](https://docs.convex.dev/api/classes/values.VBytes) < `Type`, `IsOptional` \\> \\| [`VObject`](https://docs.convex.dev/api/classes/values.VObject) < `Type`, `Record` < `string`, [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, [`OptionalProperty`](https://docs.convex.dev/api/modules/values#optionalproperty), `any` >>, `IsOptional`, `FieldPaths` \\> \\| [`VArray`](https://docs.convex.dev/api/classes/values.VArray) < `Type`, [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `\"required\"`, `any` >, `IsOptional` \\> \\| [`VRecord`](https://docs.convex.dev/api/classes/values.VRecord) < `Type`, [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `string`, `\"required\"`, `any` >, [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `\"required\"`, `any` >, `IsOptional`, `FieldPaths` \\> \\| [`VUnion`](https://docs.convex.dev/api/classes/values.VUnion) < `Type`, [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `\"required\"`, `any` >\\[\\], `IsOptional`, `FieldPaths` > A validator for a Convex value. This should be constructed using the validator builder, [v](https://docs.convex.dev/api/modules/values#v). A validator encapsulates: - The TypeScript type of this value. - Whether this field should be optional if it's included in an object. - The TypeScript type for the set of index field paths that can be used to build indexes on this value. - A JSON representation of the validator. Specific types of validators contain additional information: for example an `ArrayValidator` contains an `element` property with the validator used to validate each element of the list. Use the shared 'kind' property to identity the type of validator. More validators can be added in future releases so an exhaustive switch statement on validator `kind` should be expected to break in future releases of Convex. #### Type parameters [​](https://docs.convex.dev/api/modules/values\\#type-parameters-4 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `Type` | `Type` | | `IsOptional` | extends [`OptionalProperty`](https://docs.convex.dev/api/modules/values#optionalproperty) = `\"required\"` | | `FieldPaths` | extends `string` = `never` | #### Defined in [​](https://docs.convex.dev/api/modules/values\\#defined-in-7 \"Direct link to Defined in\") [values/validators.ts:580](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L580) * * * ### ObjectFieldType [​](https://docs.convex.dev/api/modules/values\\#objectfieldtype \"Direct link to ObjectFieldType\") Ƭ **ObjectFieldType**: `Object` #### Type declaration [​](https://docs.convex.dev/api/modules/values\\#type-declaration \"Direct link to Type declaration\") | Name | Type | | :-- | :-- | | `fieldType` | [`ValidatorJSON`](https://docs.convex.dev/api/modules/values#validatorjson) | | `optional` | `boolean` | #### Defined in [​](https://docs.convex.dev/api/modules/values\\#defined-in-8 \"Direct link to Defined in\") [values/validators.ts:621](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L621) * * * ### ValidatorJSON [​](https://docs.convex.dev/api/modules/values\\#validatorjson \"Direct link to ValidatorJSON\") Ƭ **ValidatorJSON**: { `type`: `\"null\"` } \\| { `type`: `\"number\"` } \\| { `type`: `\"bigint\"` } \\| { `type`: `\"boolean\"` } \\| { `type`: `\"string\"` } \\| { `type`: `\"bytes\"` } \\| { `type`: `\"any\"` } \\| { `type`: `\"literal\"` ; `value`: [`JSONValue`](https://docs.convex.dev/api/modules/values#jsonvalue) } \\| { `type`: `\"id\"` ; `tableName`: `string` } \\| { `type`: `\"array\"` ; `value`: [`ValidatorJSON`](https://docs.convex.dev/api/modules/values#validatorjson) } \\| { `type`: `\"record\"` ; `keys`: `RecordKeyValidatorJSON` ; `values`: `RecordValueValidatorJSON` } \\| { `type`: `\"object\"` ; `value`: `Record` < `string`, [`ObjectFieldType`](https://docs.convex.dev/api/modules/values#objectfieldtype) \\> } \\| { `type`: `\"union\"` ; `value`: [`ValidatorJSON`](https://docs.convex.dev/api/modules/values#validatorjson)\\[\\] } #### Defined in [​](https://docs.convex.dev/api/modules/values\\#defined-in-9 \"Direct link to Defined in\") [values/validators.ts:623](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L623) * * * ### JSONValue [​](https://docs.convex.dev/api/modules/values\\#jsonvalue \"Direct link to JSONValue\") Ƭ **JSONValue**: `null` \\| `boolean` \\| `number` \\| `string` \\| [`JSONValue`](https://docs.convex.dev/api/modules/values#jsonvalue)\\[\\] \\| { `[key: string]`: [`JSONValue`](https://docs.convex.dev/api/modules/values#jsonvalue); } The type of JavaScript values serializable to JSON. #### Defined in [​](https://docs.convex.dev/api/modules/values\\#defined-in-10 \"Direct link to Defined in\") [values/value.ts:24](https://github.com/get-convex/convex-js/blob/main/src/values/value.ts#L24) * * * ### GenericId [​](https://docs.convex.dev/api/modules/values\\#genericid \"Direct link to GenericId\") Ƭ **GenericId** < `TableName` >: `string` & { `__tableName`: `TableName` } An identifier for a document in Convex. Convex documents are uniquely identified by their `Id`, which is accessible on the `_id` field. To learn more, see [Document IDs](https://docs.convex.dev/database/document-ids). Documents can be loaded using `db.get(id)` in query and mutation functions. IDs are base 32 encoded strings which are URL safe. IDs are just strings at runtime, but this type can be used to distinguish them from other strings at compile time. If you're using code generation, use the `Id` type generated for your data model in `convex/_generated/dataModel.d.ts`. #### Type parameters [​](https://docs.convex.dev/api/modules/values\\#type-parameters-5 \"Direct link to Type parameters\") | Name | Type | Description | | :-- | :-- | :-- | | `TableName` | extends `string` | A string literal type of the table name (like \"users\"). | #### Defined in [​](https://docs.convex.dev/api/modules/values\\#defined-in-11 \"Direct link to Defined in\") [values/value.ts:52](https://github.com/get-convex/convex-js/blob/main/src/values/value.ts#L52) * * * ### Value [​](https://docs.convex.dev/api/modules/values\\#value \"Direct link to Value\") Ƭ **Value**: `null` \\| `bigint` \\| `number` \\| `boolean` \\| `string` \\| `ArrayBuffer` \\| [`Value`](https://docs.convex.dev/api/modules/values#value)\\[\\] \\| { `[key: string]`: `undefined` \\| [`Value`](https://docs.convex.dev/api/modules/values#value); } A value supported by Convex. Values can be: - stored inside of documents. - used as arguments and return types to queries and mutation functions. You can see the full set of supported types at [Types](https://docs.convex.dev/using/types). #### Defined in [​](https://docs.convex.dev/api/modules/values\\#defined-in-12 \"Direct link to Defined in\") [values/value.ts:66](https://github.com/get-convex/convex-js/blob/main/src/values/value.ts#L66) * * * ### NumericValue [​](https://docs.convex.dev/api/modules/values\\#numericvalue \"Direct link to NumericValue\") Ƭ **NumericValue**: `bigint` \\| `number` The types of [Value](https://docs.convex.dev/api/modules/values#value) that can be used to represent numbers. #### Defined in [​](https://docs.convex.dev/api/modules/values\\#defined-in-13 \"Direct link to Defined in\") [values/value.ts:81](https://github.com/get-convex/convex-js/blob/main/src/values/value.ts#L81) ## Variables [​](https://docs.convex.dev/api/modules/values\\#variables \"Direct link to Variables\") ### v [​](https://docs.convex.dev/api/modules/values\\#v \"Direct link to v\") • `Const` **v**: `Object` The validator builder. This builder allows you to build validators for Convex values. Validators can be used in [schema definitions](https://docs.convex.dev/database/schemas) and as input validators for Convex functions. #### Type declaration [​](https://docs.convex.dev/api/modules/values\\#type-declaration-1 \"Direct link to Type declaration\") | Name | Type | | :-- | :-- | | `id` | ( `tableName`: `TableName`) =\\> [`VId`](https://docs.convex.dev/api/classes/values.VId) < [`GenericId`](https://docs.convex.dev/api/modules/values#genericid) < `TableName` >, `\"required\"` > | | `null` | () =\\> [`VNull`](https://docs.convex.dev/api/classes/values.VNull) < `null`, `\"required\"` > | | `number` | () =\\> [`VFloat64`](https://docs.convex.dev/api/classes/values.VFloat64) < `number`, `\"required\"` > | | `float64` | () =\\> [`VFloat64`](https://docs.convex.dev/api/classes/values.VFloat64) < `number`, `\"required\"` > | | `bigint` | () =\\> [`VInt64`](https://docs.convex.dev/api/classes/values.VInt64) < `bigint`, `\"required\"` > | | `int64` | () =\\> [`VInt64`](https://docs.convex.dev/api/classes/values.VInt64) < `bigint`, `\"required\"` > | | `boolean` | () =\\> [`VBoolean`](https://docs.convex.dev/api/classes/values.VBoolean) < `boolean`, `\"required\"` > | | `string` | () =\\> [`VString`](https://docs.convex.dev/api/classes/values.VString) < `string`, `\"required\"` > | | `bytes` | () =\\> [`VBytes`](https://docs.convex.dev/api/classes/values.VBytes) < `ArrayBuffer`, `\"required\"` > | | `literal` | ( `literal`: `T`) =\\> [`VLiteral`](https://docs.convex.dev/api/classes/values.VLiteral) < `T`, `\"required\"` > | | `array` | ( `element`: `T`) =\\> [`VArray`](https://docs.convex.dev/api/classes/values.VArray) < `T`\\[ `\"type\"`\\]\\[\\], `T`, `\"required\"` > | | `object` | ( `fields`: `T`) =\\> [`VObject`](https://docs.convex.dev/api/classes/values.VObject) < [`Expand`](https://docs.convex.dev/api/modules/server#expand) <{ \\[Property in string \\| number \\| symbol\\]?: Exclude, undefined> } & { \\[Property in string \\| number \\| symbol\\]: Infer }>, `T`, `\"required\"`, { \\[Property in string \\| number \\| symbol\\]: Property \\| \\`${Property & string}.${T\\[Property\\]\\[\"fieldPaths\"\\]}\\` }\\[keyof `T`\\] & `string` > | | `record` | ( `keys`: `Key`, `values`: `Value`) =\\> [`VRecord`](https://docs.convex.dev/api/classes/values.VRecord) < `Record` < [`Infer`](https://docs.convex.dev/api/modules/values#infer) < `Key` >, `Value`\\[ `\"type\"`\\]>, `Key`, `Value`, `\"required\"`, `string` > | | `union` | (... `members`: `T`) =\\> [`VUnion`](https://docs.convex.dev/api/classes/values.VUnion) < `T`\\[ `number`\\]\\[ `\"type\"`\\], `T`, `\"required\"`, `T`\\[ `number`\\]\\[ `\"fieldPaths\"`\\]> | | `any` | () =\\> [`VAny`](https://docs.convex.dev/api/classes/values.VAny) < `any`, `\"required\"`, `string` > | | `optional` | ( `value`: `T`) =\\> [`VOptional`](https://docs.convex.dev/api/modules/values#voptional) < `T` > | #### Defined in [​](https://docs.convex.dev/api/modules/values\\#defined-in-14 \"Direct link to Defined in\") [values/validator.ts:80](https://github.com/get-convex/convex-js/blob/main/src/values/validator.ts#L80) ## Functions [​](https://docs.convex.dev/api/modules/values\\#functions \"Direct link to Functions\") ### asObjectValidator [​](https://docs.convex.dev/api/modules/values\\#asobjectvalidator-1 \"Direct link to asObjectValidator\") ▸ **asObjectValidator** < `V` >( `obj`): `V` extends [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `any`, `any` \\> ? `V` : `V` extends [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) ? [`Validator`](https://docs.convex.dev/api/modules/values#validator) < [`ObjectType`](https://docs.convex.dev/api/modules/values#objecttype) < `V` >\\> : `never` Coerce an object with validators as properties to a validator. If a validator is passed, return it. #### Type parameters [​](https://docs.convex.dev/api/modules/values\\#type-parameters-6 \"Direct link to Type parameters\") | Name | Type | | :-- | :-- | | `V` | extends [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `any`, `any` \\> \\| [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) | #### Parameters [​](https://docs.convex.dev/api/modules/values\\#parameters \"Direct link to Parameters\") | Name | Type | | :-- | :-- | | `obj` | `V` | #### Returns [​](https://docs.convex.dev/api/modules/values\\#returns \"Direct link to Returns\") `V` extends [`Validator`](https://docs.convex.dev/api/modules/values#validator) < `any`, `any`, `any` \\> ? `V` : `V` extends [`PropertyValidators`](https://docs.convex.dev/api/modules/values#propertyvalidators) ? [`Validator`](https://docs.convex.dev/api/modules/values#validator) < [`ObjectType`](https://docs.convex.dev/api/modules/values#objecttype) < `V` >\\> : `never` #### Defined in [​](https://docs.convex.dev/api/modules/values\\#defined-in-15 \"Direct link to Defined in\") [values/validator.ts:39](https://github.com/get-convex/convex-js/blob/main/src/values/validator.ts#L39) * * * ### jsonToConvex [​](https://docs.convex.dev/api/modules/values\\#jsontoconvex \"Direct link to jsonToConvex\") ▸ **jsonToConvex**( `value`): [`Value`](https://docs.convex.dev/api/modules/values#value) Parse a Convex value from its JSON representation. This function will deserialize serialized Int64s to `BigInt` s, Bytes to `ArrayBuffer` s etc. To learn more about Convex values, see [Types](https://docs.convex.dev/using/types). #### Parameters [​](https://docs.convex.dev/api/modules/values\\#parameters-1 \"Direct link to Parameters\") | Name | Type | Description | | :-- | :-- | :-- | | `value` | [`JSONValue`](https://docs.convex.dev/api/modules/values#jsonvalue) | The JSON representation of a Convex value previously created with [convexToJson](https://docs.convex.dev/api/modules/values#convextojson). | #### Returns [​](https://docs.convex.dev/api/modules/values\\#returns-1 \"Direct link to Returns\") [`Value`](https://docs.convex.dev/api/modules/values#value) The JavaScript representation of the Convex value. #### Defined in [​](https://docs.convex.dev/api/modules/values\\#defined-in-16 \"Direct link to Defined in\") [values/value.ts:187](https://github.com/get-convex/convex-js/blob/main/src/values/value.ts#L187) * * * ### convexToJson [​](https://docs.convex.dev/api/modules/values\\#convextojson \"Direct link to convexToJson\") ▸ **convexToJson**( `value`): [`JSONValue`](https://docs.convex.dev/api/modules/values#jsonvalue) Convert a Convex value to its JSON representation. Use [jsonToConvex](https://docs.convex.dev/api/modules/values#jsontoconvex) to recreate the original value. To learn more about Convex values, see [Types](https://docs.convex.dev/using/types). #### Parameters [​](https://docs.convex.dev/api/modules/values\\#parameters-2 \"Direct link to Parameters\") | Name | Type | Description | | :-- | :-- | :-- | | `value` | [`Value`](https://docs.convex.dev/api/modules/values#value) | A Convex value to convert into JSON. | #### Returns [​](https://docs.convex.dev/api/modules/values\\#returns-2 \"Direct link to Returns\") [`JSONValue`](https://docs.convex.dev/api/modules/values#jsonvalue) The JSON representation of `value`. #### Defined in [​](https://docs.convex.dev/api/modules/values\\#defined-in-17 \"Direct link to Defined in\") [values/value.ts:416](https://github.com/get-convex/convex-js/blob/main/src/values/value.ts#L416) - [Namespaces](https://docs.convex.dev/api/modules/values#namespaces) - [Classes](https://docs.convex.dev/api/modules/values#classes) - [Type Aliases](https://docs.convex.dev/api/modules/values#type-aliases) - [GenericValidator](https://docs.convex.dev/api/modules/values#genericvalidator) - [AsObjectValidator](https://docs.convex.dev/api/modules/values#asobjectvalidator) - [PropertyValidators](https://docs.convex.dev/api/modules/values#propertyvalidators) - [ObjectType](https://docs.convex.dev/api/modules/values#objecttype) - [Infer](https://docs.convex.dev/api/modules/values#infer) - [VOptional](https://docs.convex.dev/api/modules/values#voptional) - [OptionalProperty](https://docs.convex.dev/api/modules/values#optionalproperty) - [Validator](https://docs.convex.dev/api/modules/values#validator) - [ObjectFieldType](https://docs.convex.dev/api/modules/values#objectfieldtype) - [ValidatorJSON](https://docs.convex.dev/api/modules/values#validatorjson) - [JSONValue](https://docs.convex.dev/api/modules/values#jsonvalue) - [GenericId](https://docs.convex.dev/api/modules/values#genericid) - [Value](https://docs.convex.dev/api/modules/values#value) - [NumericValue](https://docs.convex.dev/api/modules/values#numericvalue) - [Variables](https://docs.convex.dev/api/modules/values#variables) - [v](https://docs.convex.dev/api/modules/values#v) - [Functions](https://docs.convex.dev/api/modules/values#functions) - [asObjectValidator](https://docs.convex.dev/api/modules/values#asobjectvalidator-1) - [jsonToConvex](https://docs.convex.dev/api/modules/values#jsontoconvex) - [convexToJson](https://docs.convex.dev/api/modules/values#convextojson) [Skip to main content](https://docs.convex.dev/testing/convex-test#docusaurus_skipToContent_fallback) On this page The `convex-test` library provides a mock implementation of the Convex backend in JavaScript. It enables fast automated testing of the logic in your [functions](https://docs.convex.dev/functions). **Example:** The library includes a [test suite](https://github.com/get-convex/convex-test/tree/main/convex) which you can browse to see examples of using it. ## Get Started [​](https://docs.convex.dev/testing/convex-test\\#get-started \"Direct link to Get Started\") 1. Install test dependencies Install [Vitest](https://vitest.dev/) and the [`convex-test`](https://www.npmjs.com/package/convex-test) library. ```codeBlockLines_zEuJ npm install --save-dev convex-test vitest @edge-runtime/vm ``` 2. Setup NPM scripts Add these scripts to your `package.json` package.json ```codeBlockLines_zEuJ \"scripts\": { \"test\": \"vitest\", \"test:once\": \"vitest run\", \"test:debug\": \"vitest --inspect-brk --no-file-parallelism\", \"test:coverage\": \"vitest run --coverage --coverage.reporter=text\", } ``` 3. Configure Vitest Add `vitest.config.mts` file to configure the test environment to better match the Convex runtime, and to inline the test library for better dependency tracking. vitest.config.mts TS ```codeBlockLines_zEuJ import { defineConfig } from \"vitest/config\"; export default defineConfig({ test: { environment: \"edge-runtime\", server: { deps: { inline: [\"convex-test\"] } }, }, }); ``` 4. Add a test file In your `convex` folder add a file ending in `.test.ts` The example test calls the `api.messages.send` mutation twice and then asserts that the `api.messages.list` query returns the expected results. convex/messages.test.ts TS ```codeBlockLines_zEuJ import { convexTest } from \"convex-test\"; import { expect, test } from \"vitest\"; import { api } from \"./_generated/api\"; import schema from \"./schema\"; test(\"sending messages\", async () => { const t = convexTest(schema); await t.mutation(api.messages.send, { body: \"Hi!\", author: \"Sarah\" }); await t.mutation(api.messages.send, { body: \"Hey!\", author: \"Tom\" }); const messages = await t.query(api.messages.list); expect(messages).toMatchObject([\\ { body: \"Hi!\", author: \"Sarah\" },\\ { body: \"Hey!\", author: \"Tom\" }\\ ]); }); ``` 5. Run tests Start the tests with `npm run test`. When you change the test file or your functions the tests will rerun automatically. ```codeBlockLines_zEuJ npm run test ``` If you're not familiar with Vitest or Jest read the [Vitest Getting Started docs](https://vitest.dev/guide) first. ## `convexTest` [​](https://docs.convex.dev/testing/convex-test\\#convextest \"Direct link to convextest\") The library exports a `convexTest` function which should be called at the start of each of your tests. The function returns an object which is by convention stored in the `t` variable and which provides methods for exercising your Convex functions. If your project uses a [schema](https://docs.convex.dev/database/schemas) you should pass it to the `convexTest` function: convex/myFunctions.test.ts TS ```codeBlockLines_zEuJ import { convexTest } from \"convex-test\"; import { test } from \"vitest\"; import schema from \"./schema\"; test(\"some behavior\", async () => { const t = convexTest(schema); // use `t`... }); ``` Passing in the schema is required for the tests to correctly implement schema validation and for correct typing of [`t.run`](https://docs.convex.dev/testing/convex-test#setting-up-and-inspecting-data-and-storage-with-trun). If you don't have a schema, call `convexTest()` with no argument. ## Calling functions with `t.query`, `t.mutation` and `t.action` [​](https://docs.convex.dev/testing/convex-test\\#calling-functions-with-tquery-tmutation-and-taction \"Direct link to calling-functions-with-tquery-tmutation-and-taction\") Your test can call public and internal Convex [functions](https://docs.convex.dev/functions) in your project: convex/myFunctions.test.ts TS ```codeBlockLines_zEuJ import { convexTest } from \"convex-test\"; import { test } from \"vitest\"; import { api, internal } from \"./_generated/api\"; test(\"functions\", async () => { const t = convexTest(); const x = await t.query(api.myFunctions.myQuery, { a: 1, b: 2 }); const y = await t.query(internal.myFunctions.internalQuery, { a: 1, b: 2 }); const z = await t.mutation(api.myFunctions.mutateSomething, { a: 1, b: 2 }); const w = await t.mutation(internal.myFunctions.mutateSomething, { a: 1 }); const u = await t.action(api.myFunctions.doSomething, { a: 1, b: 2 }); const v = await t.action(internal.myFunctions.internalAction, { a: 1, b: 2 }); }); ``` ## Setting up and inspecting data and storage with `t.run` [​](https://docs.convex.dev/testing/convex-test\\#setting-up-and-inspecting-data-and-storage-with-trun \"Direct link to setting-up-and-inspecting-data-and-storage-with-trun\") Sometimes you might want to directly [write](https://docs.convex.dev/database/writing-data) to the mock database or [file storage](https://docs.convex.dev/file-storage) from your test, without needing a declared function in your project. You can use the `t.run` method which takes a handler that is given a `ctx` that allows reading from and writing to the mock backend: convex/tasks.test.ts TS ```codeBlockLines_zEuJ import { convexTest } from \"convex-test\"; import { expect, test } from \"vitest\"; test(\"functions\", async () => { const t = convexTest(); const firstTask = await t.run(async (ctx) => { await ctx.db.insert(\"tasks\", { text: \"Eat breakfast\" }); return await ctx.db.query(\"tasks\").first(); }); expect(firstTask).toMatchObject({ text: \"Eat breakfast\" }); }); ``` ## Testing HTTP actions with `t.fetch` [​](https://docs.convex.dev/testing/convex-test\\#testing-http-actions-with-tfetch \"Direct link to testing-http-actions-with-tfetch\") Your test can call [HTTP actions](https://docs.convex.dev/functions/http-actions) registered by your router: convex/http.test.ts TS ```codeBlockLines_zEuJ import { convexTest } from \"convex-test\"; import { test } from \"vitest\"; test(\"functions\", async () => { const t = convexTest(); const response = await t.fetch(\"/some/path\", { method: \"POST\" }); }); ``` Mocking the global `fetch` function doesn't affect `t.fetch`, but you can use `t.fetch` in a `fetch` mock to route to your HTTP actions. ## Testing scheduled functions [​](https://docs.convex.dev/testing/convex-test\\#testing-scheduled-functions \"Direct link to Testing scheduled functions\") One advantage of using a mock implementation running purely in JavaScript is that you can control time in the Vitest test environment. To test implementations relying on [scheduled functions](https://docs.convex.dev/scheduling/scheduled-functions) use [Vitest's fake timers](https://vitest.dev/guide/mocking.html#timers) in combination with `t.finishInProgressScheduledFunctions`: convex/scheduling.test.ts TS ```codeBlockLines_zEuJ import { convexTest } from \"convex-test\"; import { expect, test, vi } from \"vitest\"; import { api } from \"./_generated/api\"; import schema from \"./schema\"; test(\"mutation scheduling action\", async () => { // Enable fake timers vi.useFakeTimers(); const t = convexTest(schema); // Call a function that schedules a mutation or action const scheduledFunctionId = await t.mutation( api.scheduler.mutationSchedulingAction, { delayMs: 10000 }, ); // Advance the mocked time vi.advanceTimersByTime(5000); // Advance the mocked time past the scheduled time of the function vi.advanceTimersByTime(6000); // Or run all currently pending timers vi.runAllTimers(); // At this point the scheduled function will be `inProgress`, // now wait for it to finish await t.finishInProgressScheduledFunctions(); // Assert that the scheduled function succeeded or failed const scheduledFunctionStatus = t.run(async (ctx) => { return await ctx.db.get(scheduledFunctionId); }); expect(scheduledFunctionStatus).toMatchObject({ state: { kind: \"success\" } }); // Reset to normal `setTimeout` etc. implementation vi.useRealTimers(); }); ``` If you have a chain of several scheduled functions, for example a mutation that schedules an action that schedules another action, you can use `t.finishAllScheduledFunctions` to wait for all scheduled functions, including recursively scheduled functions, to finish: convex/chainedScheduling.test.ts TS ```codeBlockLines_zEuJ import { convexTest } from \"convex-test\"; import { expect, test, vi } from \"vitest\"; import { api } from \"./_generated/api\"; import schema from \"./schema\"; test(\"mutation scheduling action scheduling action\", async () => { // Enable fake timers vi.useFakeTimers(); const t = convexTest(schema); // Call a function that schedules a mutation or action await t.mutation(api.scheduler.mutationSchedulingActionSchedulingAction); // Wait for all scheduled functions, repeatedly // advancing time and waiting for currently in-progress // functions to finish await t.finishAllScheduledFunctions(vi.runAllTimers); // Assert the resulting state after all scheduled functions finished const createdTask = t.run(async (ctx) => { return await ctx.db.query(\"tasks\").first(); }); expect(createdTask).toMatchObject({ author: \"AI\" }); // Reset to normal `setTimeout` etc. implementation vi.useRealTimers(); }); ``` Check out more examples in [this file](https://github.com/get-convex/convex-test/blob/main/convex/scheduler.test.ts). ## Testing authentication with `t.withIdentity` [​](https://docs.convex.dev/testing/convex-test\\#testing-authentication-with-twithidentity \"Direct link to testing-authentication-with-twithidentity\") To test functions which depend on the current [authenticated](https://docs.convex.dev/auth) user identity you can create a version of the `t` accessor with given [user identity attributes](https://docs.convex.dev/api/interfaces/server.UserIdentity). If you don't provide them, `issuer`, `subject` and `tokenIdentifier` will be generated automatically: convex/tasks.test.ts TS ```codeBlockLines_zEuJ import { convexTest } from \"convex-test\"; import { expect, test } from \"vitest\"; import { api } from \"./_generated/api\"; import schema from \"./schema\"; test(\"authenticated functions\", async () => { const t = convexTest(schema); const asSarah = t.withIdentity({ name: \"Sarah\" }); await asSarah.mutation(api.tasks.create, { text: \"Add tests\" }); const sarahsTasks = await asSarah.query(api.tasks.list); expect(sarahsTasks).toMatchObject([{ text: \"Add tests\" }]); const asLee = t.withIdentity({ name: \"Lee\" }); const leesTasks = await asLee.query(api.tasks.list); expect(leesTasks).toEqual([]); }); ``` ## Mocking `fetch` calls [​](https://docs.convex.dev/testing/convex-test\\#mocking-fetch-calls \"Direct link to mocking-fetch-calls\") You can use Vitest's [vi.stubGlobal](https://vitest.dev/guide/mocking.html#globals) method: convex/ai.test.ts TS ```codeBlockLines_zEuJ import { expect, test, vi } from \"vitest\"; import { convexTest } from \"../index\"; import { api } from \"./_generated/api\"; import schema from \"./schema\"; test(\"ai\", async () => { const t = convexTest(schema); vi.stubGlobal( \"fetch\", vi.fn(async () => ({ text: async () => \"I am the overlord\" }) as Response), ); const reply = await t.action(api.messages.sendAIMessage, { prompt: \"hello\" }); expect(reply).toEqual(\"I am the overlord\"); vi.unstubAllGlobals(); }); ``` ## Asserting results [​](https://docs.convex.dev/testing/convex-test\\#asserting-results \"Direct link to Asserting results\") See Vitest's [Expect](https://vitest.dev/api/expect.html) reference. [`toMatchObject()`](https://vitest.dev/api/expect.html#tomatchobject) is particularly helpful when asserting the shape of results without needing to list every object field. ### Asserting errors [​](https://docs.convex.dev/testing/convex-test\\#asserting-errors \"Direct link to Asserting errors\") To assert that a function throws, use [`.rejects.toThrowError()`](https://vitest.dev/api/expect.html#tothrowerror): convex/messages.test.ts TS ```codeBlockLines_zEuJ import { convexTest } from \"convex-test\"; import { expect, test } from \"vitest\"; import { api } from \"./_generated/api\"; import schema from \"./schema\"; test(\"messages validation\", async () => { const t = convexTest(schema); expect(async () => { await t.mutation(api.messages.send, { body: \"\", author: \"James\" }); }).rejects.toThrowError(\"Empty message body is not allowed\"); }); ``` ## Measuring test coverage [​](https://docs.convex.dev/testing/convex-test\\#measuring-test-coverage \"Direct link to Measuring test coverage\") You can get a printout of the code coverage provided by your tests. Besides answering the question \"how much of my code is covered by tests\" it is also helpful to check that your test is actually exercising the code that you want it to exercise. Run `npm run test:coverage` `` . It will ask you to install a required dependency the first time you run it. ![example coverage printout](https://docs.convex.dev/screenshots/testing_coverage.png) ## Debugging tests [​](https://docs.convex.dev/testing/convex-test\\#debugging-tests \"Direct link to Debugging tests\") You can attach a debugger to the running tests. Read the Vitest [Debugging docs](https://vitest.dev/guide/debugging.html) and then use `npm run test:debug` `` . ## Multiple environments [​](https://docs.convex.dev/testing/convex-test\\#multiple-environments \"Direct link to Multiple environments\") If you want to use Vitest to test both your Convex functions and your React frontend, you might want to use multiple Vitest environments depending on the test file location via [environmentMatchGlobs](https://vitest.dev/guide/debugging.html): vitest.config.mts TS ```codeBlockLines_zEuJ import { defineConfig } from \"vitest/config\"; export default defineConfig({ test: { environmentMatchGlobs: [\\ // all tests in convex/ will run in edge-runtime\\ [\"convex/**\", \"edge-runtime\"],\\ // all other tests use jsdom\\ [\"**\", \"jsdom\"],\\ ], server: { deps: { inline: [\"convex-test\"] } }, }, }); ``` ## Custom `convex/` folder name or location [​](https://docs.convex.dev/testing/convex-test\\#multiple-environments \"Direct link to Multiple environments\") If your project has a [different name or location configured](https://vitest.dev/config/#environmentmatchglobs) for the `convex/` folder in `convex.json`, you need to call [`import.meta.glob`](https://vitejs.dev/guide/features#glob-import) and pass the result as the second argument to `convexTest`. The argument to `import.meta.glob` must be a glob pattern matching all the files containing your Convex functions. The paths are relative to the test file in which `import.meta.glob` is called. It's best to do this in one place in your custom functions folder: src/convex/test.setup.ts TS ```codeBlockLines_zEuJ /// export const modules = import.meta.glob(\"./**/!(*.*.*)*.*s\"); ``` This example glob pattern includes all files with a single extension ending in `s` (like `js` or `ts`) in the `src/convex` folder and any of its children. Use the result in your tests: src/convex/messages.test.ts TS ```codeBlockLines_zEuJ import { convexTest } from \"convex-test\"; import { test } from \"vitest\"; import schema from \"./schema\"; import { modules } from \"./test.setup\"; test(\"some behavior\", async () => { const t = convexTest(schema, modules); // use `t`... }); ``` ## Limitations [​](https://docs.convex.dev/testing/convex-test\\#limitations \"Direct link to Limitations\") Since `convex-test` is only a mock implementation, it doesn't have many of the behaviors of the real Convex backend. Still, it should be helpful for testing the logic in your functions, and catching regressions caused by changes to your code. Some of the ways the mock differs: - Error messages content. You should not write product logic that relies on the content of error messages thrown by the real backend, as they are always subject to change. - Limits. The mock doesn't enforce size and time [limits](https://docs.convex.dev/production/state/limits). - ID format. Your code should not depend on the document or storage ID format. - Runtime built-ins. Most of your functions are written for the [Convex default runtime](https://docs.convex.dev/functions/runtimes), while Vitest uses a mock of Vercel's Edge Runtime, which is similar but might differ from the Convex runtime. You should always test new code manually to make sure it doesn't use built-ins not available in the Convex runtime. - Some features have only simplified semantics, namely: - [Text search](https://docs.convex.dev/search) returns all documents that include a word for which at least one word in the searched string is a prefix. It does not implement fuzzy searching and doesn't sort the results by relevance. - [Vector search](https://docs.convex.dev/search/vector-search) returns results sorted by cosine similarity, but doesn't use an efficient vector index in its implementation. - There is no support for [cron jobs](https://docs.convex.dev/scheduling/cron-jobs), you should trigger your functions manually from the test. To test your functions running on a real Convex backend, check out [Testing Local Backend](https://docs.convex.dev/testing/convex-backend). ## CI [​](https://docs.convex.dev/testing/convex-test\\#ci \"Direct link to CI\") See [Continuous Integration](https://docs.convex.dev/testing/ci) to run your tests on a shared remote machine. - [Get Started](https://docs.convex.dev/testing/convex-test#get-started) - [`convexTest`](https://docs.convex.dev/testing/convex-test#convextest) - [Calling functions with `t.query`, `t.mutation` and `t.action`](https://docs.convex.dev/testing/convex-test#calling-functions-with-tquery-tmutation-and-taction) - [Setting up and inspecting data and storage with `t.run`](https://docs.convex.dev/testing/convex-test#setting-up-and-inspecting-data-and-storage-with-trun) - [Testing HTTP actions with `t.fetch`](https://docs.convex.dev/testing/convex-test#testing-http-actions-with-tfetch) - [Testing scheduled functions](https://docs.convex.dev/testing/convex-test#testing-scheduled-functions) - [Testing authentication with `t.withIdentity`](https://docs.convex.dev/testing/convex-test#testing-authentication-with-twithidentity) - [Mocking `fetch` calls](https://docs.convex.dev/testing/convex-test#mocking-fetch-calls) - [Asserting results](https://docs.convex.dev/testing/convex-test#asserting-results) - [Asserting errors](https://docs.convex.dev/testing/convex-test#asserting-errors) - [Measuring test coverage](https://docs.convex.dev/testing/convex-test#measuring-test-coverage) - [Debugging tests](https://docs.convex.dev/testing/convex-test#debugging-tests) - [Multiple environments](https://docs.convex.dev/testing/convex-test#multiple-environments) - [Custom `convex/` folder name or location](https://docs.convex.dev/testing/convex-test#custom-convex-folder-name-or-location) - [Limitations](https://docs.convex.dev/testing/convex-test#limitations) - [CI](https://docs.convex.dev/testing/convex-test#ci) [Skip to main content](https://docs.convex.dev/client/javascript/bun#docusaurus_skipToContent_fallback) On this page [Bun](https://bun.sh/) can be used to run scripts and servers that use Convex clients and can even run the Convex CLI. Convex supports point-in-time queries, mutations and actions (see [HTTP client](https://docs.convex.dev/api/classes/browser.ConvexHttpClient)) and those plus query subscriptions (see [ConvexClient](https://docs.convex.dev/api/classes/browser.ConvexClient)) in Bun. ```codeBlockLines_zEuJ import { ConvexHttpClient, ConvexClient } from \"convex/browser\"; import { api } from \"./convex/_generated/api.js\"; // HTTP client const httpClient = new ConvexHttpClient(process.env.CONVEX_URL); httpClient.query(api.messages.list).then((messages) => { console.log(messages); }); // Subscription client const client = new ConvexClient(process.env.CONVEX_URL); const unsubscribe = client.onUpdate(api.messages.list, {}, (messages) => console.log(messages), ); await Bun.sleep(1000); client.mutate(api.messages.send, {}, { body: \"hello!\", author: \"me\" }); await Bun.sleep(1000); ``` ## Using Convex with Bun without codegen [​](https://docs.convex.dev/client/javascript/bun\\#using-convex-with-bun-without-codegen \"Direct link to Using Convex with Bun without codegen\") You can always use the `anyApi` object or strings if you don't have the Convex functions and api file handy. An api reference like `api.folder.file.exportName` becomes `anyApi.folder.file.exportName` or `\"folder/file:exportName\"`. - [Using Convex with Bun without codegen](https://docs.convex.dev/client/javascript/bun#using-convex-with-bun-without-codegen) [Skip to main content](https://docs.convex.dev/auth/convex-auth#docusaurus_skipToContent_fallback) On this page [Convex Auth](https://labs.convex.dev/auth) is a library for implementing authentication directly within your Convex backend. This allows you to authenticate users without needing an authentication service or even a hosting server. Convex Auth currently supports client-side React web apps served from a CDN and React Native mobile apps. **Example:** [Live Demo](https://labs.convex.dev/auth-example) ( [Source](https://github.com/get-convex/convex-auth-example)) Convex Auth is in beta Convex Authis currently a [beta\\\\ feature](https://docs.convex.dev/production/state/#beta-features). If you have feedback or feature requests, [let us know on Discord](https://convex.dev/community)! Support for [authentication in Next.js](https://labs.convex.dev/auth/authz/nextjs) server components, API routes, middleware, SSR etc. is under active development. If you'd like to help test this experimental support please [let us know how it goes in Discord](https://convex.dev/community). ## Get Started [​](https://docs.convex.dev/auth/convex-auth\\#get-started \"Direct link to Get Started\") To start a new project from scratch with Convex and Convex Auth, run: ```codeBlockLines_zEuJ npm create convex@latest ``` and choose `React (Vite)` and `Convex Auth`. * * * To add Convex Auth to an existing project, follow the full [setup guide](https://labs.convex.dev/auth/setup). ## Overview [​](https://docs.convex.dev/auth/convex-auth\\#overview \"Direct link to Overview\") Convex Auth enables you to implement the following authentication methods: 1. Magic Links & OTPs - send a link or code via email 2. OAuth - sign in with Github / Google / Apple etc. 3. Passwords - including password reset flow and optional email verification The library doesn't come with UI components, but you can copy code from the docs and example repo to quickly build a UI in React. Learn more in the [Convex Auth docs](https://labs.convex.dev/auth). - [Get Started](https://docs.convex.dev/auth/convex-auth#get-started) - [Overview](https://docs.convex.dev/auth/convex-auth#overview)