# Convex Documentation > For general information about Convex, read [https://www.convex.dev/llms.txt](https://www.convex.dev/llms.txt). ## understanding - [Convex Overview](/understanding.md): Introduction to Convex - the reactive database with TypeScript queries - [Best Practices](/understanding/best-practices.md): Essential best practices for building scalable Convex applications including database queries, function organization, validation, and security. - [TypeScript](/understanding/best-practices/typescript.md): Move faster with end-to-end type safety - [Dev workflow](/understanding/workflow.md): Development workflow from project creation to production deployment - [The Zen of Convex](/understanding/zen.md): Convex best practices and design philosophy ## quickstart - [Android Kotlin Quickstart](/quickstart/android.md): Add Convex to an Android Kotlin project - [Using Convex with Bun](/quickstart/bun.md): Add Convex to a Bun project - [Next.js Quickstart](/quickstart/nextjs.md): Add Convex to a Next.js project - [Node.js Quickstart](/quickstart/nodejs.md): Add Convex to a Node.js project - [Nuxt Quickstart](/quickstart/nuxt.md): Add Convex to a Nuxt project - [Python Quickstart](/quickstart/python.md): Add Convex to a Python project - [React Quickstart](/quickstart/react.md): Add Convex to a React project - [React Native Quickstart](/quickstart/react-native.md): Add Convex to a React Native Expo project - [Remix Quickstart](/quickstart/remix.md): Add Convex to a Remix project - [Rust Quickstart](/quickstart/rust.md): Add Convex to a Rust project - [Script Tag Quickstart](/quickstart/script-tag.md): Add Convex to any website - [Svelte Quickstart](/quickstart/svelte.md): Add Convex to a Svelte project - [iOS Swift Quickstart](/quickstart/swift.md): Add Convex to an iOS Swift project - [TanStack Start Quickstart](/quickstart/tanstack-start.md): Add Convex to a TanStack Start project - [Vue Quickstart](/quickstart/vue.md): Add Convex to a Vue project ## functions - [Functions](/functions.md): Write functions to define your server behavior - [Actions](/functions/actions.md): Call third-party services and external APIs from Convex - [Bundling](/functions/bundling.md): How Convex bundles and optimizes your function code - [Debugging](/functions/debugging.md): Debug Convex functions during development and production - [Error Handling](/functions/error-handling.md): Handle errors in Convex queries, mutations, and actions - [Application Errors](/functions/error-handling/application-errors.md): Handle expected failures in Convex functions - [HTTP Actions](/functions/http-actions.md): Build HTTP APIs directly in Convex - [Internal Functions](/functions/internal-functions.md): Functions that can only be called by other Convex functions - [Mutations](/functions/mutation-functions.md): Insert, update, and remove data from the database - [Queries](/functions/query-functions.md): Fetch data from the database with caching and reactivity - [Runtimes](/functions/runtimes.md): Learn the differences between the Convex and Node.js runtimes for functions - [Argument and Return Value Validation](/functions/validation.md): Validate function arguments and return values for security ## database - [Database](/database.md): Store JSON-like documents with a relational data model - [OCC and Atomicity](/database/advanced/occ.md): Optimistic concurrency control and transaction atomicity in Convex - [Schema Philosophy](/database/advanced/schema-philosophy.md): Convex schema design philosophy and best practices - [System Tables](/database/advanced/system-tables.md): Access metadata for Convex built-in features through system tables including scheduled functions and file storage information. - [Backups](/database/backup-restore.md): Backup and restore your Convex data and files - [Document IDs](/database/document-ids.md): Create complex, relational data models using IDs - [Data Import & Export](/database/import-export.md): Import data from existing sources and export data to external systems - [Data Export](/database/import-export/export.md): Export your data out of Convex - [Data Import](/database/import-export/import.md): Import data into Convex - [Paginated Queries](/database/pagination.md): Load paginated queries - [Reading Data](/database/reading-data.md): Query and read data from Convex database tables - [Filtering](/database/reading-data/filters.md): Filter documents in Convex queries - [Indexes](/database/reading-data/indexes.md): Speed up queries with database indexes - [Introduction to Indexes and Query Performance](/database/reading-data/indexes/indexes-and-query-perf.md): Learn the effects of indexes on query performance - [Schemas](/database/schemas.md): Schema validation keeps your Convex data neat and tidy. It also gives you end-to-end TypeScript type safety! - [Data Types](/database/types.md): Supported data types in Convex documents - [Writing Data](/database/writing-data.md): Insert, update, and delete data in Convex database tables ## realtime - [Realtime](/realtime.md): Building realtime apps with Convex ## auth - [Authentication](/auth.md): Add authentication to your Convex app. - [Custom OIDC Provider](/auth/advanced/custom-auth.md): Integrate Convex with any OpenID Connect identity provider using custom authentication configuration and ConvexProviderWithAuth. - [Custom JWT Provider](/auth/advanced/custom-jwt.md): Configure Convex to work with custom JWT providers that don't implement full OIDC protocol, including setup and client-side integration. - [Convex & Auth0](/auth/auth0.md): Integrate Auth0 authentication with Convex - [Convex & WorkOS AuthKit](/auth/authkit.md): Integrate WorkOS AuthKit authentication with Convex - [Automatic AuthKit Configuration](/auth/authkit/auto-provision.md): WorkOS AuthKit authentication with Convex - [Convex & Clerk](/auth/clerk.md): Integrate Clerk authentication with Convex - [Convex Auth](/auth/convex-auth.md): Built-in authentication for Convex applications - [Storing Users in the Convex Database](/auth/database-auth.md): Store user information in your Convex database - [Debugging Authentication](/auth/debug.md): Troubleshoot authentication issues in Convex - [Auth in Functions](/auth/functions-auth.md): Access user authentication in Convex functions ## scheduling - [Scheduling](/scheduling.md): Schedule functions to run once or repeatedly with scheduled functions and cron jobs - [Cron Jobs](/scheduling/cron-jobs.md): Schedule recurring functions in Convex - [Scheduled Functions](/scheduling/scheduled-functions.md): Schedule functions to run in the future ## file-storage - [File Storage](/file-storage.md): Store and serve files of any type - [Deleting Files](/file-storage/delete-files.md): Delete files stored in Convex - [Accessing File Metadata](/file-storage/file-metadata.md): Access file metadata stored in Convex - [Serving Files](/file-storage/serve-files.md): Serve files stored in Convex to users - [Storing Generated Files](/file-storage/store-files.md): Store files generated in Convex actions - [Uploading and Storing Files](/file-storage/upload-files.md): Upload files to Convex storage ## search - [AI & Search](/search.md): Run search queries over your Convex documents - [Full Text Search](/search/text-search.md): Run search queries over your Convex documents - [Vector Search](/search/vector-search.md): Run vector search queries on embeddings ## components - [Components](/components.md): Self contained building blocks of your app - [Authoring Components](/components/authoring.md): Creating new components - [Understanding Components](/components/understanding.md): Understanding components - [Using Components](/components/using.md): Using existing components ## ai - [AI Code Generation](/ai.md): How to use AI code generation effectively with Convex - [Convex MCP Server](/ai/convex-mcp-server.md): Convex MCP server - [Using Cursor with Convex](/ai/using-cursor.md): Tips and best practices for using Cursor with Convex - [Using GitHub Copilot with Convex](/ai/using-github-copilot.md): Tips and best practices for using GitHub Copilot with Convex - [Using Windsurf with Convex](/ai/using-windsurf.md): Tips and best practices for using Windsurf with Convex ## agents - [AI Agents](/agents.md): Building AI Agents with Convex - [Agent Definition and Usage](/agents/agent-usage.md): Configuring and using the Agent class - [LLM Context](/agents/context.md): Customizing the context provided to the Agent's LLM - [Debugging](/agents/debugging.md): Debugging the Agent component - [Files and Images in Agent messages](/agents/files.md): Working with images and files in the Agent component - [Getting Started with Agent](/agents/getting-started.md): Setting up the agent component - [Human Agents](/agents/human-agents.md): Saving messages from a human as an agent - [Messages](/agents/messages.md): Sending and receiving messages with an agent - [Playground](/agents/playground.md): A simple way to test, debug, and develop with the agent - [RAG (Retrieval-Augmented Generation) with the Agent component](/agents/rag.md): Examples of how to use RAG with the Convex Agent component - [Rate Limiting](/agents/rate-limiting.md): Control the rate of requests to your AI agent - [Streaming](/agents/streaming.md): Streaming messages with an agent - [Threads](/agents/threads.md): Group messages together in a conversation history - [Tools](/agents/tools.md): Using tool calls with the Agent component - [Usage Tracking](/agents/usage-tracking.md): Tracking token usage of the Agent component - [Workflows](/agents/workflows.md): Defining long-lived workflows for the Agent component ## testing - [Testing](/testing.md): Testing your backend - [Continuous Integration](/testing/ci.md): Set up continuous integration testing for Convex applications - [Testing Local Backend](/testing/convex-backend.md): Test functions using the local open-source Convex backend - [convex-test](/testing/convex-test.md): Mock Convex backend for fast automated testing of functions ## production - [Deploying Your App to Production](/production.md): Tips for building safe and reliable production apps - [Contact Us](/production/contact.md): Get support, provide feedback, stay updated with Convex releases, and report security vulnerabilities through our community channels. - [Environment Variables](/production/environment-variables.md): Store and access environment variables in Convex - [Hosting and Deployment](/production/hosting.md): Share your Convex backend and web app with the world - [Custom Domains & Hosting](/production/hosting/custom.md): Serve requests from any domains and host your frontend on any static hosting provider, such as GitHub. - [Using Convex with Netlify](/production/hosting/netlify.md): Host your frontend on Netlify and your backend on Convex - [Preview Deployments](/production/hosting/preview-deployments.md): Use Convex with your hosting provider's preview deployments - [Using Convex with Vercel](/production/hosting/vercel.md): Host your frontend on Vercel and your backend on Convex - [Integrations](/production/integrations.md): Integrate Convex with third party services - [Exception Reporting](/production/integrations/exception-reporting.md): Configure exception reporting integrations for your Convex deployment - [Log Streams](/production/integrations/log-streams.md): Configure logging integrations for your Convex deployment - [(Legacy) Event schema](/production/integrations/log-streams/legacy-event-schema.md): Log streams configured before May 23, 2024 will use the legacy format - [Streaming Data in and out of Convex](/production/integrations/streaming-import-export.md): Streaming Data in and out of Convex - [Multiple Repositories](/production/multiple-repos.md): Use Convex in multiple repositories - [Pausing a Deployment](/production/pause-deployment.md): Temporarily disable a deployment without deleting data - [Project Configuration](/production/project-configuration.md): Configure your Convex project for development and production deployment using convex.json, environment variables, and deployment settings. - [Status and Guarantees](/production/state.md): Learn about Convex's production guarantees, availability targets, data durability, security features, and upcoming platform enhancements. - [Limits](/production/state/limits.md): We’d love for you to have unlimited joy building on Convex but engineering ## self-hosting - [Self Hosting](/self-hosting.md): Self Hosting Convex Projects ## cli - [CLI](/cli.md): Command-line interface for managing Convex projects and functions - [Agent Mode](/cli/agent-mode.md): Configure anonymous development mode for cloud-based coding agents - [Deploy keys](/cli/deploy-key-types.md): Use deploy keys for authentication in production build environments - [Local Deployments for Development](/cli/local-deployments.md): Develop with Convex using deployments running locally on your machine ## client - [Android Kotlin](/client/android.md): Android Kotlin client library for mobile applications using Convex - [Kotlin and Convex type conversion](/client/android/data-types.md): Customizing and converting types between the Kotlin app and Convex - [Convex JavaScript Clients](/client/javascript.md): JavaScript clients for Node.js and browser applications using Convex - [Bun](/client/javascript/bun.md): Use Convex clients with the Bun JavaScript runtime - [Node.js](/client/javascript/node.md): Use Convex HTTP and subscription clients in Node.js applications - [Script Tag](/client/javascript/script-tag.md): Use Convex directly in HTML with script tags, no build tools required - [Next.js](/client/nextjs/app-router.md): How Convex works in a Next.js app - [Next.js Server Rendering](/client/nextjs/app-router/server-rendering.md): Implement server-side rendering with Convex in Next.js App Router using preloadQuery, fetchQuery, and server actions for improved performance. - [Next.js Pages Router](/client/nextjs/pages-router.md): Complete guide to using Convex with Next.js Pages Router including client-side authentication, API routes, and server-side rendering. - [Next.js Pages Quickstart](/client/nextjs/pages-router/quickstart.md): Get started with Convex in Next.js Pages Router by building a reactive task list app with queries, mutations, and real-time updates. - [OpenAPI & Other Languages](/client/open-api.md): Convex doesn’t have explicit support for many languages including Go, Java, and - [Python](/client/python.md): Python client library for building applications with Convex - [Convex React](/client/react.md): React client library for interacting with your Convex backend - [Convex React Native](/client/react-native.md): How Convex works in a React Native app - [Configuring Deployment URL](/client/react/deployment-urls.md): Configuring your project to run with Convex - [Optimistic Updates](/client/react/optimistic-updates.md): Make your React app more responsive with optimistic UI updates - [Rust](/client/rust.md): Rust client library for building applications with Convex - [Svelte](/client/svelte.md): Reactive Svelte client library for Convex applications - [iOS & macOS Swift](/client/swift.md): Swift client library for iOS and macOS applications using Convex - [Swift and Convex type conversion](/client/swift/data-types.md): Customizing and converting types between the Swift app and Convex - [Convex with TanStack Query](/client/tanstack/tanstack-query.md): Integrate Convex with TanStack Query for advanced data fetching patterns - [TanStack Start](/client/tanstack/tanstack-start.md): How Convex works with TanStack Start - [TanStack Start with Clerk](/client/tanstack/tanstack-start/clerk.md): Learn how to integrate Clerk authentication with Convex in TanStack Start applications using ID tokens and ConvexProviderWithClerk. - [Vue](/client/vue.md): Community-maintained Vue integration for Convex applications - [Nuxt](/client/vue/nuxt.md): Nuxt is a powerful web framework powered by Vue. ## dashboard - [Dashboard](/dashboard.md): Learn how to use the Convex dashboard - [Deployments](/dashboard/deployments.md): Understand Convex deployments including production, development, and preview deployments, and how to switch between them in the dashboard. - [Data](/dashboard/deployments/data.md): View, edit, and manage database tables and documents in the dashboard - [Settings](/dashboard/deployments/deployment-settings.md): Configure your Convex deployment settings including URLs, environment variables, authentication, backups, integrations, and deployment management. - [File Storage](/dashboard/deployments/file-storage.md): Upload, download, and manage files stored in your Convex deployment - [Functions](/dashboard/deployments/functions.md): Run, test, and monitor Convex functions with metrics and performance data - [Health](/dashboard/deployments/health.md): Monitor your Convex deployment health including failure rates, cache performance, scheduler status, and deployment insights for optimization. - [History](/dashboard/deployments/history.md): View an audit log of configuration-related events in your Convex deployment including function deployments, index changes, and environment variable updates. - [Logs](/dashboard/deployments/logs.md): View real-time function logs and deployment activity in your dashboard - [Schedules](/dashboard/deployments/schedules.md): Monitor and manage scheduled functions and cron jobs in your deployment - [Projects](/dashboard/projects.md): Create and manage Convex projects, settings, and deployments - [Teams](/dashboard/teams.md): Manage team settings, members, billing, and access control in Convex ## error - [Errors and Warnings](/error.md): Understand specific errors thrown by Convex ## eslint - [ESLint rules](/eslint.md): ESLint rules for Convex ## tutorial - [Convex Tutorial: A chat app](/tutorial.md): Build a real-time chat application with Convex using queries, mutations, and the sync engine for automatic updates across all connected clients. - [Convex Tutorial: Calling external services](/tutorial/actions.md): Extend your chat app by calling external APIs using Convex actions and the scheduler to integrate Wikipedia summaries into your application. - [Convex Tutorial: Scaling your app](/tutorial/scale.md): Learn how to scale your Convex application using indexes, handling write conflicts, and leveraging Convex Components for best practices. ## api - [Convex](/api.md): TypeScript backend SDK, client libraries, and CLI for Convex. - [Class: BaseConvexClient](/api/classes/browser.BaseConvexClient.md): browser.BaseConvexClient - [Class: ConvexClient](/api/classes/browser.ConvexClient.md): browser.ConvexClient - [Class: ConvexHttpClient](/api/classes/browser.ConvexHttpClient.md): browser.ConvexHttpClient - [Class: ConvexReactClient](/api/classes/react.ConvexReactClient.md): react.ConvexReactClient - [Class: Crons](/api/classes/server.Crons.md): server.Crons - [Class: Expression](/api/classes/server.Expression.md): server.Expression - [Class: FilterExpression](/api/classes/server.FilterExpression.md): server.FilterExpression - [Class: HttpRouter](/api/classes/server.HttpRouter.md): server.HttpRouter - [Class: IndexRange](/api/classes/server.IndexRange.md): server.IndexRange - [Class: SchemaDefinition](/api/classes/server.SchemaDefinition.md): server.SchemaDefinition - [Class: SearchFilter](/api/classes/server.SearchFilter.md): server.SearchFilter - [Class: TableDefinition](/api/classes/server.TableDefinition.md): server.TableDefinition - [Class: ConvexError](/api/classes/values.ConvexError.md): values.ConvexError - [Class: VAny](/api/classes/values.VAny.md): values.VAny - [Class: VArray](/api/classes/values.VArray.md): values.VArray - [Class: VBoolean](/api/classes/values.VBoolean.md): values.VBoolean - [Class: VBytes](/api/classes/values.VBytes.md): values.VBytes - [Class: VFloat64](/api/classes/values.VFloat64.md): values.VFloat64 - [Class: VId](/api/classes/values.VId.md): values.VId - [Class: VInt64](/api/classes/values.VInt64.md): values.VInt64 - [Class: VLiteral](/api/classes/values.VLiteral.md): values.VLiteral - [Class: VNull](/api/classes/values.VNull.md): values.VNull - [Class: VObject](/api/classes/values.VObject.md): values.VObject - [Class: VRecord](/api/classes/values.VRecord.md): values.VRecord - [Class: VString](/api/classes/values.VString.md): values.VString - [Class: VUnion](/api/classes/values.VUnion.md): values.VUnion - [Interface: BaseConvexClientOptions](/api/interfaces/browser.BaseConvexClientOptions.md): browser.BaseConvexClientOptions - [Interface: MutationOptions](/api/interfaces/browser.MutationOptions.md): browser.MutationOptions - [Interface: OptimisticLocalStore](/api/interfaces/browser.OptimisticLocalStore.md): browser.OptimisticLocalStore - [Interface: SubscribeOptions](/api/interfaces/browser.SubscribeOptions.md): browser.SubscribeOptions - [Interface: ConvexReactClientOptions](/api/interfaces/react.ConvexReactClientOptions.md): react.ConvexReactClientOptions - [Interface: MutationOptions](/api/interfaces/react.MutationOptions.md): react.MutationOptions - [Interface: ReactAction](/api/interfaces/react.ReactAction.md): react.ReactAction - [Interface: ReactMutation](/api/interfaces/react.ReactMutation.md): react.ReactMutation - [Interface: Watch](/api/interfaces/react.Watch.md): react.Watch - [Interface: WatchQueryOptions](/api/interfaces/react.WatchQueryOptions.md): react.WatchQueryOptions - [Interface: Auth](/api/interfaces/server.Auth.md): server.Auth - [Interface: BaseTableReader](/api/interfaces/server.BaseTableReader.md): server.BaseTableReader - [Interface: BaseTableWriter](/api/interfaces/server.BaseTableWriter.md): server.BaseTableWriter - [Interface: CronJob](/api/interfaces/server.CronJob.md): server.CronJob - [Interface: DefineSchemaOptions](/api/interfaces/server.DefineSchemaOptions.md): server.DefineSchemaOptions - [Interface: FilterBuilder](/api/interfaces/server.FilterBuilder.md): server.FilterBuilder - [Interface: GenericActionCtx](/api/interfaces/server.GenericActionCtx.md): server.GenericActionCtx - [Interface: GenericDatabaseReader](/api/interfaces/server.GenericDatabaseReader.md): server.GenericDatabaseReader - [Interface: GenericDatabaseReaderWithTable](/api/interfaces/server.GenericDatabaseReaderWithTable.md): server.GenericDatabaseReaderWithTable - [Interface: GenericDatabaseWriter](/api/interfaces/server.GenericDatabaseWriter.md): server.GenericDatabaseWriter - [Interface: GenericDatabaseWriterWithTable](/api/interfaces/server.GenericDatabaseWriterWithTable.md): server.GenericDatabaseWriterWithTable - [Interface: GenericMutationCtx](/api/interfaces/server.GenericMutationCtx.md): server.GenericMutationCtx - [Interface: GenericQueryCtx](/api/interfaces/server.GenericQueryCtx.md): server.GenericQueryCtx - [Interface: IndexRangeBuilder](/api/interfaces/server.IndexRangeBuilder.md): server.IndexRangeBuilder - [Interface: OrderedQuery](/api/interfaces/server.OrderedQuery.md): server.OrderedQuery - [Interface: PaginationOptions](/api/interfaces/server.PaginationOptions.md): server.PaginationOptions - [Interface: PaginationResult](/api/interfaces/server.PaginationResult.md): server.PaginationResult - [Interface: Query](/api/interfaces/server.Query.md): server.Query - [Interface: QueryInitializer](/api/interfaces/server.QueryInitializer.md): server.QueryInitializer - [Interface: Scheduler](/api/interfaces/server.Scheduler.md): server.Scheduler - [Interface: SearchFilterBuilder](/api/interfaces/server.SearchFilterBuilder.md): server.SearchFilterBuilder - [Interface: SearchFilterFinalizer](/api/interfaces/server.SearchFilterFinalizer.md): server.SearchFilterFinalizer - [Interface: SearchIndexConfig](/api/interfaces/server.SearchIndexConfig.md): server.SearchIndexConfig - [Interface: StorageActionWriter](/api/interfaces/server.StorageActionWriter.md): server.StorageActionWriter - [Interface: StorageReader](/api/interfaces/server.StorageReader.md): server.StorageReader - [Interface: StorageWriter](/api/interfaces/server.StorageWriter.md): server.StorageWriter - [Interface: SystemDataModel](/api/interfaces/server.SystemDataModel.md): server.SystemDataModel - [Interface: UserIdentity](/api/interfaces/server.UserIdentity.md): server.UserIdentity - [Interface: ValidatedFunction](/api/interfaces/server.ValidatedFunction.md): server.ValidatedFunction - [Interface: VectorFilterBuilder](/api/interfaces/server.VectorFilterBuilder.md): server.VectorFilterBuilder - [Interface: VectorIndexConfig](/api/interfaces/server.VectorIndexConfig.md): server.VectorIndexConfig - [Interface: VectorSearchQuery](/api/interfaces/server.VectorSearchQuery.md): server.VectorSearchQuery - [convex](/api/modules.md): Modules - [Module: browser](/api/modules/browser.md): Tools for accessing Convex in the browser. - [Module: nextjs](/api/modules/nextjs.md): Helpers for integrating Convex into Next.js applications using server rendering. - [Module: react](/api/modules/react.md): Tools to integrate Convex into React applications. - [Module: react-auth0](/api/modules/react_auth0.md): React login component for use with Auth0. - [Module: react-clerk](/api/modules/react_clerk.md): React login component for use with Clerk. - [Module: server](/api/modules/server.md): Utilities for implementing server-side Convex query and mutation functions. - [Module: values](/api/modules/values.md): Utilities for working with values stored in Convex. - [Namespace: Base64](/api/namespaces/values.Base64.md): values.Base64 ## generated-api - [Generated Code](/generated-api.md): Auto-generated JavaScript and TypeScript code specific to your app's API - [api.js](/generated-api/api.md): Generated API references for your Convex functions and internal calls - [dataModel.d.ts](/generated-api/data-model.md): Generated TypeScript types for your database schema and documents - [server.js](/generated-api/server.md): Generated utilities for implementing Convex queries, mutations, and actions ## http-api - [Convex HTTP API](/http-api.md): Connecting to Convex directly with HTTP ## chef - [Chef](/chef.md): How to use Chef by Convex ## deployment-api - [Deployment API](/deployment-api.md): Deployment API - [Convex Deployment API](/deployment-api/convex-deployment-api.md): Admin API for interacting with deployments. - [Get canonical URLs](/deployment-api/get-canonical-urls.md): Get the canonical URLs for a deployment. - [List environment variables](/deployment-api/list-environment-variables.md): Get all environment variables in a deployment. - [Update canonical URL](/deployment-api/update-canonical-url.md): Set or unset the canonical URL for a deployment's convex.cloud or - [Update environment variables](/deployment-api/update-environment-variables.md): Update one or many environment variables in a deployment. ## deployment-platform-api - [Deployment Platform API](/deployment-platform-api.md): Deployment API ## management-api - [Management API](/management-api.md): Creating and managing Convex deployments by API - [Convex Management API](/management-api/convex-management-api.md): Management API for provisioning and managing Convex projects and deployments. - [Create custom domain](/management-api/create-custom-domain.md): Create custom domain - [Create deploy key](/management-api/create-deploy-key.md): Create a deploy key like 'dev:happy-animal-123|ey...' which can be - [Create project](/management-api/create-project.md): Create a new project on a team and provision a dev or prod deployment. - [Delete custom domain](/management-api/delete-custom-domain.md): Remove a custom domain from a deployment. - [Delete project](/management-api/delete-project.md): Delete a project. Deletes all deployments in the project as well. - [Get token details](/management-api/get-token-details.md): Returns the team ID for team tokens. - [List custom domains](/management-api/list-custom-domains.md): Get all custom domains configured for a deployment. - [List deployments](/management-api/list-deployments.md): List deployments for a projects. - [List projects](/management-api/list-projects.md): List all projects for a team. ## platform-apis - [Platform APIs](/platform-apis.md): Convex Platform APIs are in openly available in Beta. Please contact - [Embedding the dashboard](/platform-apis/embedded-dashboard.md): Convex provides a hosted dashboard that is embeddable via iframe. Embedding the - [OAuth Applications](/platform-apis/oauth-applications.md): Convex allows third-party app developers to manage a user's projects on their ## public-deployment-api - [Convex Public HTTP routes](/public-deployment-api/convex-public-http-routes.md): Endpoints that require no authentication - [Execute action](/public-deployment-api/public-action-post.md): Execute an action function. - [Execute any function](/public-deployment-api/public-function-post.md): Execute a query, mutation, or action function by name. - [Execute function by URL path](/public-deployment-api/public-function-post-with-path.md): Execute a query, mutation, or action function by path in URL. - [Get latest timestamp](/public-deployment-api/public-get-query-ts.md): Get the latest timestamp for queries. - [Execute mutation](/public-deployment-api/public-mutation-post.md): Execute a mutation function. - [Execute query at timestamp](/public-deployment-api/public-query-at-ts-post.md): Execute a query function at a specific timestamp. - [Execute query batch](/public-deployment-api/public-query-batch-post.md): Execute multiple query functions in a batch. - [Execute query (GET)](/public-deployment-api/public-query-get.md): Execute a query function via GET request. - [Execute query (POST)](/public-deployment-api/public-query-post.md): Execute a query function via POST request. ## streaming-export-api - [Streaming Export](/streaming-export-api.md): Streaming data out of Convex ## streaming-import-api - [Streaming Import](/streaming-import-api.md): Streaming data into Convex --- # Full Documentation Content # AI Agents ## Building AI Agents with Convex[​](#building-ai-agents-with-convex "Direct link to Building AI Agents with Convex") Convex provides powerful building blocks for building agentic AI applications, leveraging Components and existing Convex features. With Convex, you can separate your long-running agentic workflows from your UI, without the user losing reactivity and interactivity. The message history with an LLM is persisted by default, live updating on every client, and easily composed with other Convex features using code rather than configuration. ## Agent Component[​](#agent-component "Direct link to Agent Component") The Agent component is a core building block for building AI agents. It manages threads and messages, around which your Agents can cooperate in static or dynamic workflows. [Agent Component YouTube Video](https://www.youtube.com/embed/tUKMPUlOCHY?si=ce-M8pt6EWDZ8tfd) [Agent Component YouTube Video](https://www.youtube.com/embed/tUKMPUlOCHY?si=ce-M8pt6EWDZ8tfd) ### Core Concepts[​](#core-concepts "Direct link to Core Concepts") * Agents organize LLM prompting with associated models, prompts, and [Tools](/agents/tools.md). They can generate and stream both text and objects. * Agents can be used in any Convex action, letting you write your agentic code alongside your other business logic with all the abstraction benefits of using code rather than static configuration. * [Threads](/agents/threads.md) persist [messages](/agents/messages.md) and can be shared by multiple users and agents (including [human agents](/agents/human-agents.md)). * [Conversation context](/agents/context.md) is automatically included in each LLM call, including built-in hybrid vector/text search for messages. ### Advanced Features[​](#advanced-features "Direct link to Advanced Features") * [Workflows](/agents/workflows.md) allow building multi-step operations that can span agents, users, durably and reliably. * [RAG](/agents/rag.md) techniques are also supported for prompt augmentation either up front or as tool calls using the [RAG Component](https://www.convex.dev/components/rag). * [Files](/agents/files.md) can be used in the chat history with automatic saving to [file storage](/file-storage.md). ### Debugging and Tracking[​](#debugging-and-tracking "Direct link to Debugging and Tracking") * [Debugging](/agents/debugging.md) is supported, including the [agent playground](/agents/playground.md) where you can inspect all metadata and iterate on prompts and context settings. * [Usage tracking](/agents/usage-tracking.md) enables usage billing for users and teams. * [Rate limiting](/agents/rate-limiting.md) helps control the rate at which users can interact with agents and keep you from exceeding your LLM provider's limits. ## [Build your first Agent](/agents/getting-started.md) Learn more about the motivation by reading: [AI Agents with Built-in Memory](https://stack.convex.dev/ai-agents). Sample code: ``` import { Agent } from "@convex-dev/agents"; import { openai } from "@ai-sdk/openai"; import { components } from "./_generated/api"; import { action } from "./_generated/server"; // Define an agent const supportAgent = new Agent(components.agent, { name: "Support Agent", chat: openai.chat("gpt-4o-mini"), instructions: "You are a helpful assistant.", tools: { accountLookup, fileTicket, sendEmail }, }); // Use the agent from within a normal action: export const createThread = action({ args: { prompt: v.string() }, handler: async (ctx, { prompt }) => { const { threadId, thread } = await supportAgent.createThread(ctx); const result = await thread.generateText({ prompt }); return { threadId, text: result.text }; }, }); // Pick up where you left off, with the same or a different agent: export const continueThread = action({ args: { prompt: v.string(), threadId: v.string() }, handler: async (ctx, { prompt, threadId }) => { // This includes previous message history from the thread automatically. const { thread } = await anotherAgent.continueThread(ctx, { threadId }); const result = await thread.generateText({ prompt }); return result.text; }, }); ``` --- # Agent Definition and Usage Agents encapsulate models, prompting, tools, and other configuration. They can be defined as globals, or at runtime. They use threads to contain a series of messages used along the way, whether those messages are from a user, another Agent / LLM, or elsewhere. A thread can have multiple Agents responding, or be used by a single Agent. Agentic workflows are built up by combining contextual prompting (threads, messages, tool responses, RAG, etc.) and dynamic routing via LLM tool calls, structured LLM outputs, or a myriad of other techniques via custom code. ## Basic Agent definition[​](#basic-agent-definition "Direct link to Basic Agent definition") ``` import { components } from "./_generated/api"; import { Agent } from "@convex-dev/agent"; import { openai } from "@ai-sdk/openai"; const agent = new Agent(components.agent, { name: "Basic Agent", languageModel: openai.chat("gpt-4o-mini"), }); ``` See [below](#customizing-the-agent) for more configuration options. Everything except the name can be overridden at the call site when calling the LLM, and many features available on the agent can be used without an Agent, if this way of organizing the work is not needed for your use case. ## Dynamic Agent definition[​](#dynamic-agent-definition "Direct link to Dynamic Agent definition") You can define an Agent at runtime, which is useful if you want to create an Agent for a specific context. This allows the LLM to call tools without requiring the LLM to always pass through full context to each tool call. It also allows dynamically choosing a model or other options for the Agent. ``` import { Agent } from "@convex-dev/agent"; import { type LanguageModel } from "ai"; import type { ActionCtx } from "./_generated/server"; import type { Id } from "./_generated/dataModel"; import { components } from "./_generated/api"; function createAuthorAgent( ctx: ActionCtx, bookId: Id<"books">, model: LanguageModel, ) { return new Agent(components.agent, { name: "Author", languageModel: model, tools: { // See https://docs.convex.dev/agents/tools getChapter: getChapterTool(ctx, bookId), researchCharacter: researchCharacterTool(ctx, bookId), writeChapter: writeChapterTool(ctx, bookId), }, maxSteps: 10, // Alternative to stopWhen: stepCountIs(10) }); } ``` ## Generating text with an Agent[​](#generating-text-with-an-agent "Direct link to Generating text with an Agent") To generate a message, you provide a prompt (as a string or a list of messages) to be used as context to generate one or more messages via an LLM, using calls like `agent.streamText` or `agent.generateObject`. The arguments to `generateText` and others are the same as the AI SDK, except you don't have to provide a model. By default it will use the agent's language model. There are also extra arguments that are specific to the Agent component, such as the `promptMessageId` which we'll see below. [**See the full list of AI SDK arguments here**](https://ai-sdk.dev/docs/reference/ai-sdk-core/generate-text) The message history will be provided by default as context from the given [thread](/agents/threads.md). See [LLM Context](/agents/context.md) for details on how to configuring the context provided. Note: `authorizeThreadAccess` referenced below is a function you would write to authenticate and authorize the user to access the thread. You can see an example implementation in [threads.ts](https://github.com/get-convex/agent/blob/main/example/convex/threads.ts). See [chat/basic.ts](https://github.com/get-convex/agent/blob/main/example/convex/chat/basic.ts) or [chat/streaming.ts](https://github.com/get-convex/agent/blob/main/example/convex/chat/streaming.ts) for live code examples. ### Streaming text[​](#streaming-text "Direct link to Streaming text") Streaming text follows the same pattern as the approach below, but with a few differences, depending on the type of streaming you're doing. See [streaming](/agents/streaming.md) for more details. ### Basic approach (synchronous)[​](#basic-approach-synchronous "Direct link to Basic approach (synchronous)") ``` export const generateReplyToPrompt = action({ args: { prompt: v.string(), threadId: v.string() }, handler: async (ctx, { prompt, threadId }) => { // await authorizeThreadAccess(ctx, threadId); const result = await agent.generateText(ctx, { threadId }, { prompt }); return result.text; }, }); ``` Note: best practice is to not rely on returning data from the action. Instead, query for the thread messages via the `useThreadMessages` hook and receive the new message automatically. See below. ### Saving the prompt then generating response(s) asynchronously[​](#saving-the-prompt-then-generating-responses-asynchronously "Direct link to Saving the prompt then generating response(s) asynchronously") While the above approach is simple, generating responses asynchronously provide a few benefits: * You can set up optimistic UI updates on mutations that are transactional, so the message will be shown optimistically on the client until the message is saved and present in your message query. * You can save the message in the same mutation (transaction) as other writes to the database. This message can the be used and re-used in an action with retries, without duplicating the prompt message in the history. If the `promptMessageId` is used for multiple generations, any previous responses will automatically be included as context, so the LLM can continue where it left off. See [workflows](/agents/workflows.md) for more details. * Thanks to the idempotent guarantees of mutations, the client can safely retry mutations for days until they run exactly once. Actions can transiently fail. Any clients listing the messages will automatically get the new messages as they are created asynchronously. To generate responses asynchronously, you need to first save the message, then pass the `messageId` as `promptMessageId` to generate / stream text. ``` import { components, internal } from "./_generated/api"; import { saveMessage } from "@convex-dev/agent"; import { internalAction, mutation } from "./_generated/server"; import { v } from "convex/values"; // Step 1: Save a user message, and kick off an async response. export const sendMessage = mutation({ args: { threadId: v.id("threads"), prompt: v.string() }, handler: async (ctx, { threadId, prompt }) => { const { messageId } = await saveMessage(ctx, components.agent, { threadId, prompt, }); await ctx.scheduler.runAfter(0, internal.example.generateResponseAsync, { threadId, promptMessageId: messageId, }); }, }); // Step 2: Generate a response to a user message. export const generateResponseAsync = internalAction({ args: { threadId: v.string(), promptMessageId: v.string() }, handler: async (ctx, { threadId, promptMessageId }) => { await agent.generateText(ctx, { threadId }, { promptMessageId }); }, }); ``` Note that the action doesn't need to return anything. All messages are saved by default, so any client subscribed to the thread messages will receive the new message as it is generated asynchronously. The Step 2 code is common enough that there's a utility to save you some typing. It takes in some parameters to control streaming, etc. For more details, see [the code](https://github.com/get-convex/agent/blob/main/src/client/index.ts#L1475-L1557). ``` // Equivalent to Step 2 above. export const generateResponseAsync = agent.asTextAction(); ``` ### Generating an object[​](#generating-an-object "Direct link to Generating an object") Similar to the AI SDK, you can generate or stream an object. The same arguments apply, except you don't have to provide a model. It will use the agent's default language model. ``` import { z } from "zod/v3"; const result = await thread.generateObject({ prompt: "Generate a plan based on the conversation so far", schema: z.object({...}), }); ``` Unfortunately, object generation doesn't support using tools. One, however, is to structure your object as arguments to a tool call that returns the object. You can use a custom `stopWhen` to stop the generation when the tool call produces the result and use `toolChoice: "required"` to prevent the LLM from returning a text response. ## Customizing the agent[​](#customizing-the-agent "Direct link to Customizing the agent") The agent by default only needs a `chat` model to be configured. However, for vector search, you'll need a `textEmbeddingModel` model. A `name` is helpful to attribute each message to a specific agent. Other options are defaults that can be over-ridden at each LLM call-site. ``` import { tool, stepCountIs } from "ai"; import { openai } from "@ai-sdk/openai"; import { z } from "zod/v3"; import { Agent, createTool, type Config } from "@convex-dev/agent"; import { components } from "./_generated/api"; const sharedDefaults = { // The language model to use for the agent. languageModel: openai.chat("gpt-4o-mini"), // Embedding model to power vector search of message history (RAG). textEmbeddingModel: openai.embedding("text-embedding-3-small"), // Used for fetching context messages. See https://docs.convex.dev/agents/context contextOptions, // Used for storing messages. See https://docs.convex.dev/agents/messages storageOptions, // Used for tracking token usage. See https://docs.convex.dev/agents/usage-tracking usageHandler: async (ctx, args) => { const { usage, model, provider, agentName, threadId, userId } = args; // ... log, save usage to your database, etc. }, // Used for filtering, modifying, or enriching the context messages. See https://docs.convex.dev/agents/context contextHandler: async (ctx, args) => { return [...customMessages, args.allMessages]; }, // Useful if you want to log or record every request and response. rawResponseHandler: async (ctx, args) => { const { request, response, agentName, threadId, userId } = args; // ... log, save request/response to your database, etc. }, // Used for limiting the number of retries when a tool call fails. Default: 3. callSettings: { maxRetries: 3, temperature: 1.0 }, } satisfies Config; const supportAgent = new Agent(components.agent, { // The default system prompt if not over-ridden. instructions: "You are a helpful assistant.", tools: { // Convex tool. See https://docs.convex.dev/agents/tools myConvexTool: createTool({ description: "My Convex tool", args: z.object({...}), // Note: annotate the return type of the handler to avoid type cycles. handler: async (ctx, args): Promise => { return "Hello, world!"; }, }), // Standard AI SDK tool myTool: tool({ description, parameters, execute: () => {}}), }, // Used for limiting the number of steps when tool calls are involved. // NOTE: if you want tool calls to happen automatically with a single call, // you need to set this to something greater than 1 (the default). stopWhen: stepCountIs(5), ...sharedDefaults, }); ``` --- # LLM Context By default, the Agent will provide context based on the message history of the thread. This context is used to generate the next message. The context can include recent messages, as well as messages found via text and /or vector search. If a `promptMessageId` is provided, the context will include that message, as well as any other messages on that same `order`. More details on order are in [messages.mdx](/agents/messages.md#message-ordering), but in practice this means that if you pass the ID of the user-submitted message as the `promptMessageId` and there had already been some assistant and/or tool responses, those will be included in the context, allowing the LLM to continue the conversation. You can also use [RAG](/agents/rag.md) to add extra context to your prompt. ## Customizing the context[​](#customizing-the-context "Direct link to Customizing the context") You can customize the context provided to the agent when generating messages with custom `contextOptions`. These can be set as defaults on the `Agent`, or provided at the call-site for `generateText` or others. ``` const result = await agent.generateText( ctx, { threadId }, { prompt }, { // Values shown are the defaults. contextOptions: { // Whether to exclude tool messages in the context. excludeToolMessages: true, // How many recent messages to include. These are added after the search // messages, and do not count against the search limit. recentMessages: 100, // Options for searching messages via text and/or vector search. searchOptions: { limit: 10, // The maximum number of messages to fetch. textSearch: false, // Whether to use text search to find messages. vectorSearch: false, // Whether to use vector search to find messages. // Note, this is after the limit is applied. // E.g. this will quadruple the number of messages fetched. // (two before, and one after each message found in the search) messageRange: { before: 2, after: 1 }, }, // Whether to search across other threads for relevant messages. // By default, only the current thread is searched. searchOtherThreads: false, }, }, ); ``` ## Full context control[​](#full-context-control "Direct link to Full context control") To have full control over which messages are passed to the LLM, you can either: 1. Provide a `contextHandler` to filter, modify, or enrich the context messages. 2. Provide all messages manually via the `messages` argument and specify `contextOptions` to use no recent or search messages. See below for how to fetch context messages manually. ### Providing a contextHandler[​](#providing-a-contexthandler "Direct link to Providing a contextHandler") The Agent will combine messages from search, recent, input messages, and all messages on the same `order` as the `promptMessageId` if that is provided. You can customize how they are combined, as well as add or remove messages by providing a `contextHandler` which returns the `ModelMessage[]` which will be passed to the LLM. You can specify a `contextHandler` in the Agent constructor, or at the call-site for a single generation, which overrides any Agent default. ``` const myAgent = new Agent(components.agent, { ///... contextHandler: async (ctx, args) => { // This is the default behavior. return [ ...args.search, ...args.recent, ...args.inputMessages, ...args.inputPrompt, ...args.existingResponses, ]; // Equivalent to: return args.allMessages; }, ); ``` With this callback, you can: 1. Filter out messages you don't want to include. 2. Add memories or other context. 3. Add sample messages to guide the LLM on how it should respond. 4. Inject extra context based on the user or thread. 5. Copy in messages from other threads. 6. Summarize messages. For example: ``` // Note: when you specify it at the call-site, you can also leverage variables // available in the scope, e.g. if the user is in a specific step in a workflow. const result = await agent.generateText( ctx, { threadId }, { prompt }, { contextHandler: async (ctx, args) => { // Filter out messages that are not relevant. const relevantSearch = args.search.filter((m) => messageIsRelevant(m)); // Fetch user memories to include in every prompt. const userMemories = await getUserMemories(ctx, args.userId); // Fetch sample messages to instruct the LLM on how to respond. const sampleMessages = [ { role: "user", content: "Generate a function that adds two numbers" }, { role: "assistant", content: "function add(a, b) { return a + b; }" }, ]; // Fetch user context to include in every prompt. const userContext = await getUserContext(ctx, args.userId, args.threadId); // Fetch messages from a related / parent thread. const related = await getRelatedThreadMessages(ctx, args.threadId); return [ // Summarize or truncate context messages if they are too long. ...(await summarizeOrTruncateIfTooLong(related)), ...relevantSearch, ...userMemories, ...sampleMessages, ...userContext, ...args.recent, ...args.inputMessages, ...args.inputPrompt, ...args.existingResponses, ]; }, }, ); ``` ### Fetch context manually[​](#fetch-context-manually "Direct link to Fetch context manually") If you want to get context messages for a given prompt, without calling the LLM, you can use `fetchContextWithPrompt`. This is used internally to get the context messages passed to the AI SDK `generateText`, `streamText`, etc. As with normal generation, you can provide a `prompt` or `messages`, and/or a `promptMessageId` to fetch the context messages using a given pre-saved message as the prompt. This will return recent and search messages combined with the input messages. ``` import { fetchContextWithPrompt } from "@convex-dev/agent"; const { messages } = await fetchContextWithPrompt(ctx, components.agent, { prompt, messages, promptMessageId, userId, threadId, contextOptions, }); ``` ## Search for messages[​](#search-for-messages "Direct link to Search for messages") This is what the agent does automatically, but it can be useful to do manually, e.g. to find custom context to include. For text and vector search, you can provide a `targetMessageId` and/or `searchText`. It will embed the text for vector search. If `searchText` is not provided, it will use the target message's text. If `targetMessageId` is provided, it will only fetch search messages previous to that message, and recent messages up to and including that message's "order". This enables re-generating a response for an earlier message. ``` import type { MessageDoc } from "@convex-dev/agent"; const messages: MessageDoc[] = await agent.fetchContextMessages(ctx, { threadId, searchText: prompt, // Optional unless you want text/vector search. targetMessageId: promptMessageId, // Optionally target the search. userId, // Optional, unless `searchOtherThreads` is true. contextOptions, // Optional, defaults are used if not provided. }); ``` Note: you can also search for messages without an agent. The main difference is that in order to do vector search, you need to create the embeddings yourself, and it will not run your usage handler. ``` import { fetchRecentAndSearchMessages } from "@convex-dev/agent"; const { recentMessages, searchMessages } = await fetchRecentAndSearchMessages( ctx, components.agent, { threadId, searchText: prompt, // Optional unless you want text/vector search. targetMessageId: promptMessageId, // Optionally target the search. contextOptions, // Optional, defaults are used if not provided. getEmbedding: async (text) => { const embedding = await textEmbeddingModel.embed(text); return { embedding, textEmbeddingModel }; }, }, ); ``` ## Searching other threads[​](#searching-other-threads "Direct link to Searching other threads") If you set `searchOtherThreads` to `true`, the agent will search across all threads belonging to the provided `userId`. This can be useful to have multiple conversations that the Agent can reference. The search will use a hybrid of text and vector search. ## Passing in messages as context[​](#passing-in-messages-as-context "Direct link to Passing in messages as context") You can pass in messages as context to the Agent's LLM, for instance to implement [Retrieval-Augmented Generation](/agents/rag.md). The final messages sent to the LLM will be: 1. The system prompt, if one is provided or the agent has `instructions` 2. The messages found via contextOptions 3. The `messages` argument passed into `generateText` or other function calls. 4. If a `prompt` argument was provided, a final `{ role: "user", content: prompt }` message. This allows you to pass in messages that are not part of the thread history and will not be saved automatically, but that the LLM will receive as context. ## Manage embeddings manually[​](#manage-embeddings-manually "Direct link to Manage embeddings manually") The `textEmbeddingModel` argument to the Agent constructor allows you to specify a text embedding model to use for vector search. If you set this, the agent will automatically generate embeddings for messages and use them for vector search. When you change models or decide to start or stop using embeddings for vector search, you can manage the embeddings manually. Generate embeddings for a set of messages. Optionally pass `config` with a usage handler, which can be a globally shared `Config`. ``` import { embedMessages } from "@convex-dev/agent"; const embeddings = await embedMessages( ctx, { userId, threadId, textEmbeddingModel, ...config }, [{ role: "user", content: "What is love?" }], ); ``` Generate and save embeddings for existing messages. ``` const embeddings = await supportAgent.generateAndSaveEmbeddings(ctx, { messageIds, }); ``` Get and update embeddings, e.g. for a migration to a new model. ``` const messages = await ctx.runQuery(components.agent.vector.index.paginate, { vectorDimension: 1536, targetModel: "gpt-4o-mini", cursor: null, limit: 10, }); ``` Updating the embedding by ID. ``` const messages = await ctx.runQuery(components.agent.vector.index.updateBatch, { vectors: [{ model: "gpt-4o-mini", vector: embedding, id: msg.embeddingId }], }); ``` Note: If the dimension changes, you need to delete the old and insert the new. Delete embeddings ``` await ctx.runMutation(components.agent.vector.index.deleteBatch, { ids: [embeddingId1, embeddingId2], }); ``` Insert embeddings ``` const ids = await ctx.runMutation(components.agent.vector.index.insertBatch, { vectorDimension: 1536, vectors: [ { model: "gpt-4o-mini", table: "messages", userId: "123", threadId: "123", vector: embedding, // Optional, if you want to update the message with the embeddingId messageId: messageId, }, ], }); ``` --- # Debugging ## Debugging in the Playground[​](#debugging-in-the-playground "Direct link to Debugging in the Playground") Generally the [Playground](/agents/playground.md) gives a lot of information about what's happening, but when that is insufficient, you have other options. ## Logging the raw request and response from LLM calls[​](#logging-the-raw-request-and-response-from-llm-calls "Direct link to Logging the raw request and response from LLM calls") You can provide a `rawRequestResponseHandler` to the agent to log the raw request and response from the LLM. You could use this to log the request and response to a table, or use console logs with [Log Streaming](https://docs.convex.dev/production/integrations/log-streams/) to allow debugging and searching through Axiom or another logging service. ``` const supportAgent = new Agent(components.agent, { ... rawRequestResponseHandler: async (ctx, { request, response }) => { console.log("request", request); console.log("response", response); }, }); ``` ## Logging the context messages via the contextHandler[​](#logging-the-context-messages-via-the-contexthandler "Direct link to Logging the context messages via the contextHandler") You can log the context messages via the contextHandler, if you're curious what exactly the LLM is receiving. ``` const supportAgent = new Agent(components.agent, { ... contextHandler: async (ctx, { allMessages }) => { console.log("context", allMessages); return allMessages; }, }); ``` ## Inspecting the database in the dashboard[​](#inspecting-the-database-in-the-dashboard "Direct link to Inspecting the database in the dashboard") You can go to the Data tab in the dashboard and select the agent component above the table list to see the Agent data. The organization of the tables matches the [schema](https://github.com/get-convex/agent/blob/main/src/component/schema.ts). The most useful tables are: * `threads` has one row per thread * `messages` has a separate row for each ModelMessage - e.g. a user message, assistant tool call, tool result, assistant message, etc. The most important fields are `agentName` for which agent it's associated with, `status`, `order` and `stepOrder` which are used to order the messages, and `message` which is roughly what is passed to the LLM. * `streamingMessages` has an entry for each streamed message, until it's cleaned up. You can take the ID to look at the associated `streamDeltas` table. * `files` captures the files tracked by the Agent from content that was sent in a message that got stored in File Storage. ## Troubleshooting[​](#troubleshooting "Direct link to Troubleshooting") ### Type errors on `components.agent`[​](#type-errors-on-componentsagent "Direct link to type-errors-on-componentsagent") If you get type errors about `components.agent`, ensure you've run `npx convex dev` to generate code for the component. The types expected by the library are in the npm library, and the types for `components.agent` currently come from generated code in your project (via `npx convex dev`). ### Circular dependencies[​](#circular-dependencies "Direct link to Circular dependencies") Having the return value of workflows depend on other Convex functions can lead to circular dependencies due to the `internal.foo.bar` way of specifying functions. The way to fix this is to explicitly type the return value of the workflow. When in doubt, add return types to more `handler` functions, like this: ``` export const supportAgentWorkflow = workflow.define({ args: { prompt: v.string(), userId: v.string(), threadId: v.string() }, handler: async (step, { prompt, userId, threadId }): Promise => { // ... }, }); // And regular functions too: export const myFunction = action({ args: { prompt: v.string() }, handler: async (ctx, { prompt }): Promise => { // ... }, }); ``` --- # Files and Images in Agent messages You can add images and files for the LLM to reference in the messages. NOTE: Sending URLs to LLMs is much easier with the cloud backend, since it has publicly available storage URLs. To develop locally you can use `ngrok` or similar to proxy the traffic. Example code: * [files/autoSave.ts](https://github.com/get-convex/agent/blob/main/example/convex/files/autoSave.ts) has a simple example of how to use the automatic file saving. * [files/addFile.ts](https://github.com/get-convex/agent/blob/main/example/convex/files/addFile.ts) has an example of how to save the file, submit a question, and generate a response in separate steps. * [files/generateImage.ts](https://github.com/get-convex/agent/blob/main/example/convex/files/generateImage.ts) has an example of how to generate an image and save it in an assistant message. * [FilesImages.tsx](https://github.com/get-convex/agent/blob/main/example/ui/files/FilesImages.tsx) has client-side code. ## Running the example[​](#running-the-example "Direct link to Running the example") ``` git clone https://github.com/get-convex/agent.git cd agent npm run setup npm run example ``` ## Sending an image by uploading first and generating asynchronously[​](#sending-an-image-by-uploading-first-and-generating-asynchronously "Direct link to Sending an image by uploading first and generating asynchronously") The standard approach is to: 1. Upload the file to the database (`uploadFile` action). Note: this can be in a regular action or in an httpAction, depending on what's more convenient. 2. Send a message to the thread (`submitFileQuestion` action) 3. Send the file to the LLM to generate / stream text asynchronously (`generateResponse` action) 4. Query for the messages from the thread (`listThreadMessages` query) Rationale: It's better to submit a message in a mutation vs. an action because you can use an optimistic update on the client side to show the sent message immediately and have it disappear exactly when the message comes down in the query. However, you can't save to file storage from a mutation, so the file needs to already exist (hence the fileId). You can then asynchronously generate the response (with retries / etc) without the client waiting. ### 1: Saving the file[​](#1-saving-the-file "Direct link to 1: Saving the file") ``` import { storeFile } from "@convex-dev/agent"; import { components } from "./_generated/api"; const { file } = await storeFile( ctx, components.agent, new Blob([bytes], { type: mimeType }), { filename, sha256, }, ); const { fileId, url, storageId } = file; ``` ### 2: Sending the message[​](#2-sending-the-message "Direct link to 2: Sending the message") ``` // in your mutation const { filePart, imagePart } = await getFile(ctx, components.agent, fileId); const { messageId } = await fileAgent.saveMessage(ctx, { threadId, message: { role: "user", content: [ imagePart ?? filePart, // if it's an image, prefer that kind. { type: "text", text: "What is this image?" }, ], }, metadata: { fileIds: [fileId] }, // IMPORTANT: this tracks the file usage. }); ``` ### 3: Generating the response & querying the responses[​](#3-generating-the-response--querying-the-responses "Direct link to 3: Generating the response & querying the responses") This is done in the same way as text inputs. ``` // in an action await thread.generateText({ promptMessageId: messageId }); ``` ``` // in a query const messages = await agent.listMessages(ctx, { threadId, paginationOpts }); ``` ## Inline saving approach[​](#inline-saving-approach "Direct link to Inline saving approach") You can also pass in an image / file direction when generating text, if you're in an action. Any image or file passed in the `message` argument will automatically be saved in file storage if it's larger than 64k, and a fileId will be saved to the message. Example: ``` await thread.generateText({ message: { role: "user", content: [ { type: "image", image: imageBytes, mimeType: "image/png" }, { type: "text", text: "What is this image?" }, ], }, }); ``` ## Under the hood[​](#under-the-hood "Direct link to Under the hood") Saving to the files has 3 components: 1. Saving to file storage (in your app, not in the component's storage). This means you can access it directly with the `storageId` and generate URLs. 2. Saving a reference (the storageId) to the file in the component. This will automatically keep track of how many messages are referencing the file, so you can vacuum files that are no longer used (see [files/vacuum.ts](https://github.com/get-convex/agent/blob/main/example/convex/files/vacuum.ts)). 3. Inserting a URL in place of the data in the message sent to the LLM, along with the mimeType and other metadata provided. It will be inferred if not provided in [`guessMimeType`](https://github.com/get-convex/agent/blob/main/src/mapping.ts#L556). ### Can I just store the file myself and pass in a URL?[​](#can-i-just-store-the-file-myself-and-pass-in-a-url "Direct link to Can I just store the file myself and pass in a URL?") Yes! You can always pass a URL in the place of an image or file to the LLM. ``` const storageId = await ctx.storage.store(blob); const url = await ctx.storage.getUrl(storageId); await thread.generateText({ message: { role: "user", content: [ { type: "image", data: url, mimeType: blob.type }, { type: "text", text: "What is this image?" }, ], }, }); ``` ## Generating images[​](#generating-images "Direct link to Generating images") There's an example in [files/generateImage.ts](https://github.com/get-convex/agent/blob/main/example/convex/files/generateImage.ts) that takes a prompt, generates an image with OpenAI's dall-e 2, then saves the image to a thread. You can try it out with: ``` npx convex run files:generateImage:replyWithImage '{prompt: "make a picture of a cat" }' ``` --- # Getting Started with Agent To install the agent component, you'll need an existing Convex project. New to Convex? Go through the [tutorial](https://docs.convex.dev/tutorial/). Run `npm create convex` or follow any of the [quickstarts](https://docs.convex.dev/home) to set one up. ## Installation[​](#installation "Direct link to Installation") Install the component package: ``` npm install @convex-dev/agent ``` Create a `convex.config.ts` file in your app's `convex/` folder and install the component by calling `use`: ``` // convex/convex.config.ts import { defineApp } from "convex/server"; import agent from "@convex-dev/agent/convex.config"; const app = defineApp(); app.use(agent); export default app; ``` Then run `npx convex dev` to generate code for the component. This needs to successfully run once before you start defining Agents. ## Defining your first Agent[​](#defining-your-first-agent "Direct link to Defining your first Agent") ``` import { components } from "./_generated/api"; import { Agent } from "@convex-dev/agent"; import { openai } from "@ai-sdk/openai"; const agent = new Agent(components.agent, { name: "My Agent", languageModel: openai.chat("gpt-4o-mini"), instructions: "You are a weather forecaster.", tools: { getWeather, getGeocoding }, maxSteps: 3, }); ``` ## Basic usage[​](#basic-usage "Direct link to Basic usage") ``` import { action } from "./_generated/server"; import { v } from "convex/values"; export const helloWorld = action({ args: { city: v.string() }, handler: async (ctx, { city }) => { const threadId = await createThread(ctx, components.agent); const prompt = `What is the weather in ${city}?`; const result = await agent.generateText(ctx, { threadId }, { prompt }); return result.text; }, }); ``` If you get type errors about `components.agent`, ensure you've run `npx convex dev` to generate code for the component. That's it! Check out [Agent Usage](/agents/agent-usage.md) to see more details and options. --- # Human Agents The Agent component generally takes a prompt from a human or agent, and uses an LLM to generate a response. However, there are cases where you want to generate the reply from a human acting as an agent, such as for customer support. For full code, check out [chat/human.ts](https://github.com/get-convex/agent/blob/main/example/convex/chat/human.ts) ## Saving a user message without generating a reply[​](#saving-a-user-message-without-generating-a-reply "Direct link to Saving a user message without generating a reply") You can save a message from a user without generating a reply by using the `saveMessage` function. ``` import { saveMessage } from "@convex-dev/agent"; import { components } from "./_generated/api"; await saveMessage(ctx, components.agent, { threadId, prompt: "The user message", }); ``` ## Saving a message from a human as an agent[​](#saving-a-message-from-a-human-as-an-agent "Direct link to Saving a message from a human as an agent") Similarly, you can save a message from a human as an agent in the same way, using the `message` field to specify the role and agent name: ``` import { saveMessage } from "@convex-dev/agent"; import { components } from "./_generated/api"; await saveMessage(ctx, components.agent, { threadId, agentName: "Alex", message: { role: "assistant", content: "The human reply" }, }); ``` ## Storing additional metadata about human agents[​](#storing-additional-metadata-about-human-agents "Direct link to Storing additional metadata about human agents") You can store additional metadata about human agents by using the `saveMessage` function, and adding the `metadata` field. ``` await saveMessage(ctx, components.agent, { threadId, agentName: "Alex", message: { role: "assistant", content: "The human reply" }, metadata: { provider: "human", providerMetadata: { human: { /* ... */ }, }, }, }); ``` ## Deciding who responds next[​](#deciding-who-responds-next "Direct link to Deciding who responds next") You can choose whether the LLM or human responds next in a few ways: 1. Explicitly store in the database whether the user or LLM is assigned to the thread. 2. Using a call to a cheap and fast LLM to decide if the user question requires a human response. 3. Using vector embeddings of the user question and message history to make the decision, based on a corpus of sample questions and what questions are better handled by humans. 4. Have the LLM generate an object response that includes a field indicating whether the user question requires a human response. 5. Providing a tool to the LLM to decide if the user question requires a human response. The human response is then the tool response message. ## Human responses as tool calls[​](#human-responses-as-tool-calls "Direct link to Human responses as tool calls") You can have the LLM generate a tool call to a human agent to provide context to answer the user question by providing a tool that doesn't have a handler. Note: this generally happens when the LLM still intends to answer the question, but needs human intervention to do so, such as confirmation of a fact. ``` import { tool } from "ai"; import { z } from "zod/v3"; const askHuman = tool({ description: "Ask a human a question", parameters: z.object({ question: z.string().describe("The question to ask the human"), }), }); export const ask = action({ args: { question: v.string(), threadId: v.string() }, handler: async (ctx, { question, threadId }) => { const result = await agent.generateText( ctx, { threadId }, { prompt: question, tools: { askHuman }, }, ); const supportRequests = result.toolCalls .filter((tc) => tc.toolName === "askHuman") .map(({ toolCallId, args: { question } }) => ({ toolCallId, question, })); if (supportRequests.length > 0) { // Do something so the support agent knows they need to respond, // e.g. save a message to their inbox // await ctx.runMutation(internal.example.sendToSupport, { // threadId, // supportRequests, // }); } }, }); export const humanResponseAsToolCall = internalAction({ args: { humanName: v.string(), response: v.string(), toolCallId: v.string(), threadId: v.string(), messageId: v.string(), }, handler: async (ctx, args) => { await agent.saveMessage(ctx, { threadId: args.threadId, message: { role: "tool", content: [ { type: "tool-result", result: args.response, toolCallId: args.toolCallId, toolName: "askHuman", }, ], }, metadata: { provider: "human", providerMetadata: { human: { name: args.humanName }, }, }, }); // Continue generating a response from the LLM await agent.generateText( ctx, { threadId: args.threadId }, { promptMessageId: args.messageId, }, ); }, }); ``` --- # Messages The Agent component stores message and [thread](/agents/threads.md) history to enable conversations between humans and agents. To see how humans can act as agents, see [Human Agents](/agents/human-agents.md). ## Retrieving messages[​](#retrieving-messages "Direct link to Retrieving messages") For clients to show messages, you need to expose a query that returns the messages. For streaming, see [retrieving streamed deltas](/agents/streaming.md#retrieving-streamed-deltas) for a modified version of this query. See [chat/basic.ts](https://github.com/get-convex/agent/blob/main/example/convex/chat/basic.ts) for the server-side code, and [chat/streaming.ts](https://github.com/get-convex/agent/blob/main/example/convex/chat/streaming.ts) for the streaming example. ``` import { paginationOptsValidator } from "convex/server"; import { v } from "convex/values"; import { listUIMessages } from "@convex-dev/agent"; import { components } from "./_generated/api"; export const listThreadMessages = query({ args: { threadId: v.string(), paginationOpts: paginationOptsValidator }, handler: async (ctx, args) => { await authorizeThreadAccess(ctx, threadId); const paginated = await listUIMessages(ctx, components.agent, args); // Here you could filter out / modify the documents return paginated; }, }); ``` Note: Above we used `listUIMessages`, which returns UIMessages, specifically the Agent extension that includes some extra fields like order, status, etc. UIMessages combine multiple MessageDocs into a single UIMessage when there are multiple tool calls followed by an assistant message, making it easy to build UIs that work with the various "parts" on the UIMessage. If you want to get MessageDocs, you can use `listMessages` instead. ## Showing messages in React[​](#showing-messages-in-react "Direct link to Showing messages in React") See [ChatStreaming.tsx](https://github.com/get-convex/agent/blob/main/example/ui/chat/ChatStreaming.tsx) for a streaming example, or [ChatBasic.tsx](https://github.com/get-convex/agent/blob/main/example/ui/chat/ChatBasic.tsx) for a non-streaming example. ### `useUIMessages` hook[​](#useuimessages-hook "Direct link to useuimessages-hook") The crux is to use the `useUIMessages` hook. For streaming, pass in `stream: true` to the hook. ``` import { api } from "../convex/_generated/api"; import { useUIMessages } from "@convex-dev/agent/react"; function MyComponent({ threadId }: { threadId: string }) { const { results, status, loadMore } = useUIMessages( api.chat.streaming.listMessages, { threadId }, { initialNumItems: 10 /* stream: true */ }, ); return (
{results.map((message) => (
{message.text}
))}
); } ``` Note: If you want to work with MessageDocs instead of UIMessages, you can use the older `useThreadMessages` hook instead. However, working with UIMessages enables richer streaming capabilities, such as status on whether the agent is actively reasoning. ### UIMessage type[​](#uimessage-type "Direct link to UIMessage type") The Agent component extends the AI SDK's `UIMessage` type to provide convenient metadata for rendering messages. The core UIMessage type from the AI SDK is: * `parts` is an array of parts (e.g. "text", "file", "image", "toolCall", "toolResult") * `content` is a string of the message content. * `role` is the role of the message (e.g. "user", "assistant", "system"). The helper adds these additional fields: * `key` is a unique identifier for the message. * `order` is the order of the message in the thread. * `stepOrder` is the step order of the message in the thread. * `status` is the status of the message (or "streaming"). * `agentName` is the name of the agent that generated the message. * `text` is the text of the message. * `_creationTime` is the timestamp of the message. For streaming messages, it's currently assigned to the current time on the streaming client. To reference these, ensure you're importing `UIMessage` from `@convex-dev/agent`. #### `toUIMessages` helper[​](#touimessages-helper "Direct link to touimessages-helper") `toUIMessages` is a helper function that transforms MessageDocs into AI SDK "UIMessage"s. This is a convenient data model for displaying messages. If you are using `useThreadMessages` for instance, you can convert the messages to UIMessages like this: ``` import { toUIMessages, type UIMessage } from "@convex-dev/agent"; ... const { results } = useThreadMessages(...); const uiMessages = toUIMessages(results); ``` ### Optimistic updates for sending messages[​](#optimistic-updates-for-sending-messages "Direct link to Optimistic updates for sending messages") The `optimisticallySendMessage` function is a helper function for sending a message, so you can optimistically show a message in the message list until the mutation has completed on the server. Pass in the query that you're using to list messages, and it will insert the ephemeral message at the top of the list. ``` const sendMessage = useMutation( api.streaming.streamStoryAsynchronously, ).withOptimisticUpdate( optimisticallySendMessage(api.streaming.listThreadMessages), ); ``` If your arguments don't include `{ threadId, prompt }` then you can use it as a helper function in your optimistic update: ``` import { optimisticallySendMessage } from "@convex-dev/agent/react"; const sendMessage = useMutation( api.chatStreaming.streamStoryAsynchronously, ).withOptimisticUpdate( (store, args) => { optimisticallySendMessage(api.chatStreaming.listThreadMessages)(store, { threadId: prompt: /* change your args into the user prompt. */, }) } ); ``` ## Saving messages[​](#saving-messages "Direct link to Saving messages") By default, the Agent will save messages to the database automatically when you provide them as a prompt, as well as all generated messages. However, it is useful to save the prompt message ahead of time and use the `promptMessageId` to continue the conversation. See [Agent Usage](/agents/agent-usage.md) for more details. You can save messages to the database manually using `saveMessage` or `saveMessages`, either on the Agent class or as a direct function call. * You can pass a `prompt` or a full `message` (`ModelMessage` type) * The `metadata` argument is optional and allows you to provide more details, such as `sources`, `reasoningDetails`, `usage`, `warnings`, `error`, etc. ``` const { messageId } = await saveMessage(ctx, components.agent, { threadId, userId, message: { role: "user", content: "The user message" }, }); ``` Note: when calling `agent.generateText` with the raw prompt, embeddings are generated automatically for vector search (if you have a text embedding model configured). Similarly with `agent.saveMessage` when calling from an action. However, if you're saving messages in a mutation, where calling an LLM is not possible, it will generate them automatically if `generateText` receives a `promptMessageId` that lacks an embedding (and you have a text embedding model configured). ### Without the Agent class:[​](#without-the-agent-class "Direct link to Without the Agent class:") Note: If you aren't using the Agent class with a text embedding model set, you need to pass an `embedding` if you want to save it at the same time. ``` import { saveMessage } from "@convex-dev/agent"; const { messageId } = await saveMessage(ctx, components.agent, { threadId, userId, message: { role: "assistant", content: result }, metadata: [{ reasoning, usage, ... }] // See MessageWithMetadata type agentName: "my-agent", embedding: { vector: [0.1, 0.2, ...], model: "text-embedding-3-small" }, }); ``` ### Using the Agent class:[​](#using-the-agent-class "Direct link to Using the Agent class:") ``` const { messageId } = await agent.saveMessage(ctx, { threadId, userId, prompt, metadata, }); ``` ``` const { messages } = await agent.saveMessages(ctx, { threadId, userId, messages: [{ role, content }], metadata: [{ reasoning, usage, ... }] // See MessageWithMetadata type }); ``` If you are saving the message in a mutation and you have a text embedding model set, pass `skipEmbeddings: true`. The embeddings for the message will be generated lazily if the message is used as a prompt. Or you can provide an embedding upfront if it's available, or later explicitly generate them using `agent.generateEmbeddings`. ## Configuring the storage of messages[​](#configuring-the-storage-of-messages "Direct link to Configuring the storage of messages") Generally the defaults are fine, but if you want to pass in multiple messages and have them all saved (vs. just the last one), or avoid saving any input or output messages, you can pass in a `storageOptions` object, either to the Agent constructor or per-message. The use-case for passing in multiple messages but not saving them is if you want to include some extra messages for context to the LLM, but only the last message is the user's actual request. e.g. `messages = [...messagesFromRag, messageFromUser]`. The default is to save the prompt and all output messages. ``` const result = await thread.generateText({ messages }, { storageOptions: { saveMessages: "all" | "none" | "promptAndOutput"; }, }); ``` ## Message ordering[​](#message-ordering "Direct link to Message ordering") Each message has `order` and `stepOrder` fields, which are incrementing integers specific to a thread. When `saveMessage` or `generateText` is called, the message is added to the thread's next `order` with a `stepOrder` of 0. As response message(s) are generated in response to that message, they are added at the same `order` with the next `stepOrder`. To associate a response message with a previous message, you can pass in the `promptMessageId` to `generateText` and others. Note: if the `promptMessageId` is not the latest message in the thread, the context for the message generation will not include any messages following the `promptMessageId`. ## Deleting messages[​](#deleting-messages "Direct link to Deleting messages") You can delete messages by their `_id` (returned from `saveMessage` or `generateText`) or `order` / `stepOrder`. By ID: ``` await agent.deleteMessage(ctx, { messageId }); // batch delete await agent.deleteMessages(ctx, { messageIds }); ``` By order (start is inclusive, end is exclusive): ``` // Delete all messages with the same order as a given message: await agent.deleteMessageRange(ctx, { threadId, startOrder: message.order, endOrder: message.order + 1, }); // Delete all messages with order 1 or 2. await agent.deleteMessageRange(ctx, { threadId, startOrder: 1, endOrder: 3 }); // Delete all messages with order 1 and stepOrder 2-4 await agent.deleteMessageRange(ctx, { threadId, startOrder: 1, startStepOrder: 2, endOrder: 2, endStepOrder: 5, }); ``` ## Other utilities:[​](#other-utilities "Direct link to Other utilities:") ``` import { ... } from "@convex-dev/agent"; ``` * `serializeDataOrUrl` is a utility function that serializes an AI SDK `DataContent` or `URL` to a Convex-serializable format. * `filterOutOrphanedToolMessages` is a utility function that filters out tool call messages that don't have a corresponding tool result message. * `extractText` is a utility function that extracts text from a `ModelMessage`-like object. ### Validators and types[​](#validators-and-types "Direct link to Validators and types") There are types to validate and provide types for various values ``` import { ... } from "@convex-dev/agent"; ``` * `vMessage` is a validator for a `ModelMessage`-like object (with a `role` and `content` field e.g.). * `MessageDoc` and `vMessageDoc` are the types for a message (which includes a `.message` field with the `vMessage` type). * `Thread` is the type of a thread returned from `continueThread` or `createThread`. * `ThreadDoc` and `vThreadDoc` are the types for thread metadata. * `AgentComponent` is the type of the installed component (e.g. `components.agent`). * `ToolCtx` is the `ctx` type for calls to `createTool` tools. --- # Playground The Playground UI is a simple way to test, debug, and develop with the agent. ![Playground UI Screenshot](https://get-convex.github.io/agent/screenshot.png) * Pick a user to list their threads. * Browse the user's threads. * List the selected thread's messages, along with tool call details. * Show message metadata details. * Experiment with contextual message lookup, adjusting context options. * Send a message to the thread, with configurable saving options. * It uses api keys to communicate securely with the backend. There is also a [hosted version here](https://get-convex.github.io/agent/). ## Setup[​](#setup "Direct link to Setup") **Note**: You must already have a Convex project set up with the Agent. See the [docs](/agents/getting-started.md) for setup instructions. In your agent Convex project, make a file `convex/playground.ts` with: ``` import { definePlaygroundAPI } from "@convex-dev/agent"; import { components } from "./_generated/api"; import { weatherAgent, fashionAgent } from "./example"; /** * Here we expose the API so the frontend can access it. * Authorization is handled by passing up an apiKey that can be generated * on the dashboard or via CLI via: * npx convex run --component agent apiKeys:issue */ export const { isApiKeyValid, listAgents, listUsers, listThreads, listMessages, createThread, generateText, fetchPromptContext, } = definePlaygroundAPI(components.agent, { agents: [weatherAgent, fashionAgent], }); ``` From in your project's repo, issue yourself an API key: ``` npx convex run --component agent apiKeys:issue '{name:"..."}' ``` Note: to generate multiple keys, give a different name to each key. To revoke and reissue a key, pass the same name. Then visit the [hosted version](https://get-convex.github.io/agent/). It will ask for your Convex deployment URL, which can be found in `.env.local`. It will also ask for your API key that you generated above. If you used a different path for `convex/playground.ts` you can enter it. E.g. if you had `convex/foo/bar.ts` where you exported the playground API, you'd put in `foo/bar`. ## Running it locally[​](#running-it-locally "Direct link to Running it locally") You can run the playground locally with: ``` npx @convex-dev/agent-playground ``` It uses the `VITE_CONVEX_URL` env variable, usually pulling it from .env.local. --- # RAG (Retrieval-Augmented Generation) with the Agent component The Agent component has built-in capabilities to search message history with hybrid text & vector search. You can also use the RAG component to use other data to search for context. ## What is RAG?[​](#what-is-rag "Direct link to What is RAG?") Retrieval-Augmented Generation (RAG) is a technique that allows an LLM to search through custom knowledge bases to answer questions. RAG combines the power of Large Language Models (LLMs) with knowledge retrieval. Instead of relying solely on the model's training data, RAG allows your AI to: * Search through custom documents and knowledge bases * Retrieve relevant context for answering questions * Provide more accurate, up-to-date, and domain-specific responses * Cite sources and explain what information was used ## RAG Component[​](#rag-component "Direct link to RAG Component") [RAG Component YouTube Video](https://www.youtube.com/embed/dGmtAmdAaFs?si=ce-M8pt6EWDZ8tfd) The RAG component is a Convex component that allows you to add data that you can search. It breaks up the data into chunks and generates embeddings to use for vector search. See the [RAG component docs](https://convex.dev/components/rag) for details, but here are some key features: * **Namespaces:** Use namespaces for user-specific or team-specific data to isolate search domains. * **Add Content**: Add or replace text content by key. * **Semantic Search**: Vector-based search using configurable embedding models * **Custom Filtering:** Define filters on each document for efficient vector search. * **Chunk Context**: Get surrounding chunks for better context. * **Importance Weighting**: Weight content by providing a 0 to 1 "importance" to affect per-document vector search results. * **Chunking flexibility:** Bring your own document chunking, or use the default. * **Graceful Migrations**: Migrate content or whole namespaces without disruption. [Convex Component](https://www.convex.dev/components/rag) ### [RAG (Retrieval-Augmented Generation)](https://www.convex.dev/components/rag) [Search documents for relevant content to prompt an LLM using embeddings.](https://www.convex.dev/components/rag) ## RAG Approaches[​](#rag-approaches "Direct link to RAG Approaches") This directory contains two different approaches to implementing RAG: ### 1. Prompt-based RAG[​](#1-prompt-based-rag "Direct link to 1. Prompt-based RAG") A straightforward implementation where the system automatically searches for relevant context for a user query. * The message history will only include the original user prompt and the response, not the context. * Looks up the context and injects it into the user's prompt. * Works well if you know the user's question will *always* benefit from extra context. For example code, see [ragAsPrompt.ts](https://github.com/get-convex/agent/blob/main/example/convex/rag/ragAsPrompt.ts) for the overall code. The simplest version is: ``` const context = await rag.search(ctx, { namespace: "global", query: userPrompt, limit: 10, }); const result = await agent.generateText( ctx, { threadId }, { prompt: `# Context:\n\n ${context.text}\n\n---\n\n# Question:\n\n"""${userPrompt}\n"""`, }, ); ``` ### 2. Tool-based RAG[​](#2-tool-based-rag "Direct link to 2. Tool-based RAG") The LLM can intelligently decide when to search for context or add new information by providing a tool to search for context. * The message history will include the original user prompt and message history. * After a tool call and response, the message history will include the tool call and response for the LLM to reference. * The LLM can decide when to search for context or add new information. * This works well if you want the Agent to be able to dynamically search. See [ragAsTools.ts](https://github.com/get-convex/agent/blob/main/example/convex/rag/ragAsTools.ts) for the code. The simplest version is: ``` searchContext: createTool({ description: "Search for context related to this user prompt", args: z.object({ query: z.string().describe("Describe the context you're looking for") }), handler: async (ctx, { query }) => { const context = await rag.search(ctx, { namespace: userId, query }); return context.text; }, }), ``` ## Key Differences[​](#key-differences "Direct link to Key Differences") | Feature | Basic RAG | Tool-based RAG | | ------------------ | ---------------------------- | -------------------------------------- | | **Context Search** | Always searches | AI decides when to search | | **Adding Context** | Manual via separate function | AI can add context during conversation | | **Flexibility** | Simple, predictable | Intelligent, adaptive | | **Use Case** | FAQ systems, document search | Dynamic knowledge management | | **Predictability** | Defined by code | AI may query too much or little | ## Ingesting content[​](#ingesting-content "Direct link to Ingesting content") On the whole, the RAG component works with text. However, you can turn other files into text, either using parsing tools or asking an LLM to do it. ### Parsing images[​](#parsing-images "Direct link to Parsing images") Image parsing does oddly well with LLMs. You can use `generateText` to describe and transcribe the image, and then use that description to search for relevant context. And by storing the associated image, you can then pass the original file around once you've retrieved it via searching. [See an example here](https://github.com/get-convex/rag/blob/main/example/convex/getText.ts#L28-L42). ``` const description = await thread.generateText({ message: { role: "user", content: [{ type: "image", data: url, mimeType: blob.type }], }, }); ``` ### Parsing PDFs[​](#parsing-pdfs "Direct link to Parsing PDFs") For PDF parsing, I suggest using Pdf.js in the browser. **Why not server-side?** Opening up the pdf can use hundreds of MB of memory, and requires downloading a big pdfjs bundle - so big it's usually fetched dynamically in practice. You probably wouldn't want to load that bundle on every function call server-side, and you're more limited on memory usage in serverless environments. If the browser already has the file, it's a pretty good environment to do the heavy lifting in (and free!). There's an example in [the RAG demo](https://github.com/get-convex/rag/blob/main/example/src/pdfUtils.ts#L14), [used in the UI here](https://github.com/get-convex/rag/blob/main/example/src/components/UploadSection.tsx#L51), [with Pdf.js served statically](https://github.com/get-convex/rag/blob/main/example/public/pdf-worker/). If you really want to do it server-side and don't worry about cost or latency, you can pass it to an LLM, but note it takes a long time for big files. [See an example here](https://github.com/get-convex/rag/blob/main/example/convex/getText.ts#L50-L65). ### Parsing text files[​](#parsing-text-files "Direct link to Parsing text files") Generally you can use text files directly, for code or markdown or anything with a natural structure an LLM can understand. However, to get good embeddings, you can once again use an LLM to translate the text into a more structured format. [See an example here](https://github.com/get-convex/rag/blob/main/example/convex/getText.ts#L68-L89). ## Examples in Action[​](#examples-in-action "Direct link to Examples in Action") To see these examples in action, check out the [RAG example](https://github.com/get-convex/rag/blob/main/example/convex/example.ts). * Adding text, pdf, and image content to the RAG component * Searching and generating text based on the context. * Introspecting the context produced by searching. * Browsing the chunks of documents produced. * Try out searching globally, per-user, or with custom filters. Run the example with: ``` git clone https://github.com/get-convex/rag.git cd rag npm run setup npm run example ``` --- # Rate Limiting Rate limiting is a way to control the rate of requests to your AI agent, preventing abuse and managing API budgets. To demonstrate using the [Rate Limiter component](https://www.convex.dev/components/rate-limiter), there is an example implementation you can run yourself. It rate limits the number of messages a user can send in a given time period, as well as the total token usage for a user. When a limit is exceeded, the client can reactively tell the user how long to wait (even if they exceeded the limit in another browser tab!). For general usage tracking, see [Usage Tracking](/agents/usage-tracking.md). ## Overview[​](#overview "Direct link to Overview") The rate limiting example demonstrates two types of rate limiting: 1. **Message Rate Limiting**: Prevents users from sending messages too frequently 2. **Token Usage Rate Limiting**: Controls AI model token consumption over time ## Running the Example[​](#running-the-example "Direct link to Running the Example") ``` git clone https://github.com/get-convex/agent.git cd agent npm run setup npm run example ``` Try sending multiple questions quickly to see the rate limiting in action! ## Rate Limiting Strategy[​](#rate-limiting-strategy "Direct link to Rate Limiting Strategy") Below we'll go through each configuration. You can also see the full example implementation in [rateLimiting.ts](https://github.com/get-convex/agent/blob/main/example/convex/rate_limiting/rateLimiting.ts). ``` import { MINUTE, RateLimiter, SECOND } from "@convex-dev/rate-limiter"; import { components } from "./_generated/api"; export const rateLimiter = new RateLimiter(components.rateLimiter, { sendMessage: { kind: "fixed window", period: 5 * SECOND, rate: 1, capacity: 2, }, globalSendMessage: { kind: "token bucket", period: MINUTE, rate: 1_000 }, tokenUsagePerUser: { kind: "token bucket", period: MINUTE, rate: 2000, capacity: 10000, }, globalTokenUsage: { kind: "token bucket", period: MINUTE, rate: 100_000 }, }); ``` ### 1. Fixed Window Rate Limiting for Messages[​](#1-fixed-window-rate-limiting-for-messages "Direct link to 1. Fixed Window Rate Limiting for Messages") ``` // export const rateLimiter = new RateLimiter(components.rateLimiter, { sendMessage: { kind: "fixed window", period: 5 * SECOND, rate: 1, capacity: 2 } ``` * Allows 1 message every 5 seconds per user. * Prevents spam and rapid-fire requests. * Allows up to a 2 message burst to be sent within 5 seconds via `capacity`, if they had usage leftover from the previous 5 seconds. Global limit: ``` globalSendMessage: { kind: "token bucket", period: MINUTE, rate: 1_000 }, ``` * Allows 1000 messages per minute globally, to stay under the API limit. * As a token bucket, it will continuously accrue tokens at the rate of 1000 tokens per minute until it caps out at 1000. All available tokens can be used in quick succession. ### 2. Token Bucket Rate Limiting for Token Usage[​](#2-token-bucket-rate-limiting-for-token-usage "Direct link to 2. Token Bucket Rate Limiting for Token Usage") ``` tokenUsage: { kind: "token bucket", period: MINUTE, rate: 1_000 } globalTokenUsage: { kind: "token bucket", period: MINUTE, rate: 100_000 }, ``` * Allows 1000 tokens per minute per user (a userId is provided as the key), and 100k tokens per minute globally. * Provides burst capacity while controlling overall usage. If it hasn't been used in a while, you can consume all tokens at once. However, you'd then need need to wait for tokens to gradually accrue before making more requests. * Having a per-user limit is useful to prevent single users from hogging all of the token bandwidth you have available with your LLM provider, while a global limit helps stay under the API limit without throwing an error midway through a potentially long multi-step request. ## How It Works[​](#how-it-works "Direct link to How It Works") ### Step 1: Pre-flight Rate Limit Checks[​](#step-1-pre-flight-rate-limit-checks "Direct link to Step 1: Pre-flight Rate Limit Checks") Before processing a question, the system: 1. Checks if the user can send another message (frequency limit) 2. Estimates token usage for the question 3. Verifies the user has sufficient token allowance 4. Throws an error if either limit would be exceeded 5. If the rate limits aren't exceeded, the LLM request is made. See [rateLimiting.ts](https://github.com/get-convex/agent/blob/main/example/convex/rate_limiting/rateLimiting.ts) for the full implementation. ``` // In the mutation that would start generating a message. await rateLimiter.limit(ctx, "sendMessage", { key: userId, throws: true }); // Also check global limit. await rateLimiter.limit(ctx, "globalSendMessage", { throws: true }); // A heuristic based on the previous token usage in the thread + the question. const count = await estimateTokens(ctx, args.threadId, args.question); // Check token usage, but don't consume the tokens yet. await rateLimiter.check(ctx, "tokenUsage", { key: userId, count: estimateTokens(args.question), throws: true, }); // Also check global limit. await rateLimiter.check(ctx, "globalTokenUsage", { count, reserve: true, throws: true, }); ``` If there is not enough allowance, the rate limiter will throw an error that the client can catch and prompt the user to wait a bit before trying again. The difference between `limit` and `check` is that `limit` will consume the tokens immediately, while `check` will only check if the limit would be exceeded. We actually mark the tokens as used once the request is complete with the total usage. ### Step 2: Post-generation Usage Tracking[​](#step-2-post-generation-usage-tracking "Direct link to Step 2: Post-generation Usage Tracking") While rate limiting message sending frequency is a good way to prevent many messages being sent in a short period of time, each message could generate a very long response or use a lot of context tokens. For this we also track token usage as its own rate limit. After the AI generates a response, we mark the tokens as used using the total usage. We use `reserve: true` to allow a (temporary) negative balance, in case the generation used more tokens than estimated. A "reservation" here means allocating tokens beyond what is allowed. Typically this is done ahead of time, to "reserve" capacity for a big request that can be scheduled in advance. In this case, we're marking capacity that has already been consumed. This prevents future requests from starting until the "debt" is paid off. When using the Agent component, we can do this in the "usageHandler", which is called after the AI generates a response. ``` import { Agent, type Config } from "@convex-dev/rate-limiter"; const sharedConfig = { usageHandler: async (ctx, { usage, userId }) => { if (!userId) { return; } // We consume the token usage here, once we know the full usage. // This is too late for the first generation, but prevents further requests // until we've paid off that debt. await rateLimiter.limit(ctx, "tokenUsage", { key: userId, // You could weight different kinds of tokens differently here. count: usage.totalTokens, // Reserving the tokens means it won't fail here, but will allow it // to go negative, disallowing further requests at the `check` call below. reserve: true, }); }, } satisfies Config; // use it in your agent definitions const agent = new Agent(components.agent, { name, languageModel, ...sharedConfig, }); ``` The "trick" here is that, while a user can make a request that exceeds the limit for a single request, they then have to wait longer to accrue the tokens for another request. So averaged over time they can't consume more than the rate limit. This balances pragmatism of trying to prevent requests ahead of time with an estimate, while also rate limiting the actual usage. ## Client-side Handling[​](#client-side-handling "Direct link to Client-side Handling") See [RateLimiting.tsx](https://github.com/get-convex/agent/blob/main/example/ui/rate_limiting/RateLimiting.tsx) for the client-side code. While the client isn't the final authority on whether a request should be allowed, it can still show a waiting message while the rate limit is being checked, and an error message when the rate limit is exceeded. This prevents the user from making attempts that are likely to fail. It makes use of the `useRateLimit` hook to check the rate limits. See the full [Rate Limiting docs here](https://www.convex.dev/components/rate-limiter). ``` import { useRateLimit } from "@convex-dev/rate-limiter/react"; //... const { status } = useRateLimit(api.example.getRateLimit); ``` In `convex/example.ts` we expose `getRateLimit`: ``` export const { getRateLimit, getServerTime } = rateLimiter.hookAPI( "sendMessage", { key: (ctx) => getAuthUserId(ctx) }, ); ``` Showing a waiting message while the rate limit is being checked: ``` {status && !status.ok && (

Message sending rate limit exceeded.

Try again after

)} ``` Showing an error message when the rate limit is exceeded: ``` import { isRateLimitError } from "@convex-dev/rate-limiter"; // in a button handler await submitQuestion({ question, threadId }).catch((e) => { if (isRateLimitError(e)) { toast({ title: "Rate limit exceeded", description: `Rate limit exceeded for ${e.data.name}. Try again after ${getRelativeTime(Date.now() + e.data.retryAfter)}`, }); } }); ``` ## Token Estimation[​](#token-estimation "Direct link to Token Estimation") The example includes a simple token estimation function: ``` import { QueryCtx } from "./_generated/server"; import { fetchContextMessages } from "@convex-dev/agent"; import { components } from "./_generated/api"; // This is a rough estimate of the tokens that will be used. // It's not perfect, but it's a good enough estimate for a pre-generation check. export async function estimateTokens( ctx: QueryCtx, threadId: string | undefined, question: string, ) { // Assume roughly 4 characters per token const promptTokens = question.length / 4; // Assume a longer non-zero reply const estimatedOutputTokens = promptTokens * 3 + 1; const latestMessages = await fetchContextMessages(ctx, components.agent, { threadId, searchText: question, contextOptions: { recentMessages: 2 }, }); // Our new usage will roughly be the previous tokens + the question. // The previous tokens include the tokens for the full message history and // output tokens, which will be part of our new history. const lastUsageMessage = latestMessages .reverse() .find((message) => message.usage); const lastPromptTokens = lastUsageMessage?.usage?.totalTokens ?? 1; return lastPromptTokens + promptTokens + estimatedOutputTokens; } ``` --- # Streaming Streaming messages is a great way to give a user feedback and keep an application feeling responsive while using LLMs. Traditionally streaming happens via HTTP streaming, where the client sends a request and waits until the full response is streamed back. This works out of the box when using the Agent, in the same way you would with the AI SDK. See [below](#consuming-the-stream-yourself-with-the-agent) if that is all you're looking for. However, with the Agent component you can also stream messages asynchronously, meaning the generation doesn't have to happen in an HTTP handler (`httpAction`), and the response can be streamed back to one or more clients even if their network connection is interrupted. It works by saving the streaming parts to the database in groups (deltas), and the clients subscribe to new deltas for the given thread, as they're generated. As a bonus, you don't even need to use the Agent's version of `streamText` to use the delta streaming approach (see [below](#advanced-streaming-deltas-asynchronously-without-using-an-agent)). Example: * Server: [streaming.ts](https://github.com/get-convex/agent/blob/main/example/convex/chat/streaming.ts) * Client: [ChatStreaming.tsx](https://github.com/get-convex/agent/blob/main/example/ui/chat/ChatStreaming.tsx) ## Streaming message deltas[​](#streaming-message-deltas "Direct link to Streaming message deltas") The easiest way to stream is to pass `{ saveStreamDeltas: true }` to `agent.streamText`. This will save chunks of the response as deltas as they're generated, so all clients can subscribe to the stream and get live-updating text via normal Convex queries. ``` agent.streamText(ctx, { threadId }, { prompt }, { saveStreamDeltas: true }); ``` This can be done in an async function, where http streaming to a client is not possible. Under the hood it will chunk up the response and debounce saving the deltas to prevent excessive bandwidth usage. You can pass more options to `saveStreamDeltas` to configure the chunking and debouncing. ``` { saveStreamDeltas: { chunking: "line", throttleMs: 1000 } }, ``` * `chunking` can be "word", "line", a regex, or a custom function. * `throttleMs` is how frequently the deltas are saved. This will send multiple chunks per delta, writes sequentially, and will not write faster than the throttleMs ([single-flighted](https://stack.convex.dev/throttling-requests-by-single-flighting) ). ## Retrieving streamed deltas[​](#retrieving-streamed-deltas "Direct link to Retrieving streamed deltas") For clients to stream messages, you need to expose a query that returns the stream deltas. This is very similar to [retrieving messages](/agents/messages.md#retrieving-messages), with a few changes: ``` import { paginationOptsValidator } from "convex/server"; import { vStreamArgs, listUIMessages, syncStreams } from "@convex-dev/agent"; import { components } from "./_generated/api"; export const listThreadMessages = query({ args: { threadId: v.string(), // Pagination options for the non-streaming messages. paginationOpts: paginationOptsValidator, streamArgs: vStreamArgs, }, handler: async (ctx, args) => { await authorizeThreadAccess(ctx, threadId); // Fetches the regular non-streaming messages. const paginated = await listUIMessages(ctx, components.agent, args); const streams = await syncStreams(ctx, components.agent, args); return { ...paginated, streams }; }, }); ``` Similar to with [non-streaming messages](/agents/messages.md#useuimessages-hook), you can use the `useUIMessages` hook to fetch the messages, passing in `stream: true` to enable streaming. ``` const { results, status, loadMore } = useUIMessages( api.chat.streaming.listMessages, { threadId }, { initialNumItems: 10, stream: true }, ); ``` ### Text smoothing with `SmoothText` and `useSmoothText`[​](#text-smoothing-with-smoothtext-and-usesmoothtext "Direct link to text-smoothing-with-smoothtext-and-usesmoothtext") The `useSmoothText` hook is a simple hook that smooths the text as it changes. It can work with any text, but is especially handy for streaming text. ``` import { useSmoothText } from "@convex-dev/agent/react"; // in the component const [visibleText] = useSmoothText(message.text); ``` You can configure the initial characters per second. It will adapt over time to match the average speed of the text coming in. By default it won't stream the first text it receives unless you pass in `startStreaming: true`. To start streaming immediately when you have a mix of streaming and non-streaming messages, do: ``` import { useSmoothText, type UIMessage } from "@convex-dev/agent/react"; function Message({ message }: { message: UIMessage }) { const [visibleText] = useSmoothText(message.text, { startStreaming: message.status === "streaming", }); return
{visibleText}
; } ``` If you don't want to use the hook, you can use the `SmoothText` component. ``` import { SmoothText } from "@convex-dev/agent/react"; //... ; ``` ## Consuming the stream yourself with the Agent[​](#consuming-the-stream-yourself-with-the-agent "Direct link to Consuming the stream yourself with the Agent") You can consume the stream in all the ways you can with the underlying AI SDK - for instance iterating over the content, or using [`result.toDataStreamResponse()`](https://ai-sdk.dev/docs/reference/ai-sdk-core/stream-text#to-data-stream-response). If you are not also saving the deltas, it might look like this: ``` const result = await agent.streamText(ctx, { threadId }, { prompt }); for await (const textPart of result.textStream) { console.log(textPart); } ``` If you want to both iterate as the stream is happening, as well as save the deltas, you can pass `{ saveStreamDeltas: { returnImmediately: true } }` to `streamText`. This will return immediately, and you can then iterate over the stream live, or return the stream in an HTTP Response. ``` const result = await agent.streamText( ctx, { threadId }, { prompt }, { saveStreamDeltas: { returnImmediately: true } }, ); return result.toUIMessageStreamResponse(); ``` If you don't want to have the Agent involved at all, the next section will show you how to save the deltas yourself. ## Advanced: Streaming deltas asynchronously without using an Agent[​](#advanced-streaming-deltas-asynchronously-without-using-an-agent "Direct link to Advanced: Streaming deltas asynchronously without using an Agent") To stream messages without using the Agent's wrapper of `streamText`, you can use the `streamText` function from the AI SDK directly. It consists of using the `DeltaStreamer` class to save the deltas to the database, and then using the above approach to retrieve the messages, though you can use a more direct `useStreamingUIMessages` hook that doesn't involve reading any non-streaming messages from the database. The requirements for reading and writing the streams are just that they use a `threadId` from the Agent component, and that each stream is saved with a distinct `order`, for ordering on the client side. ``` import { components } from "./_generated/api"; import { type ActionCtx } from "./_generated/server"; import { DeltaStreamer, compressUIMessageChunks } from "@convex-dev/agent"; import { streamText } from "ai"; import { openai } from "@ai-sdk/openai"; async function stream(ctx: ActionCtx, threadId: string, order: number) { const streamer = new DeltaStreamer( components.agent, ctx, { throttleMs: 100, onAsyncAbort: async () => console.error("Aborted asynchronously"), // This will collapse multiple tiny deltas into one if they're being sent // in quick succession. compress: compressUIMessageChunks, abortSignal: undefined, }, { threadId, format: "UIMessageChunk", order, stepOrder: 0, userId: undefined, }, ); // Do the normal streaming with the AI SDK const response = streamText({ model: openai.chat("gpt-4o-mini"), prompt: "Tell me a joke", abortSignal: streamer.abortController.signal, onError: (error) => { console.error(error); streamer.fail(errorToString(error.error)); }, }); // We could await here if we wanted to wait for the stream to finish, // but instead we have it process asynchronously so we can return a streaming // http Response. void streamer.consumeStream(response.toUIMessageStream()); return { // e.g. to do `response.toTextStreamResponse()` for HTTP streaming. response, // We don't need this on the client, but with it we can have some clients // selectively not stream down deltas when they're using HTTP streaming // already. streamId: await streamer.getStreamId(), }; } ``` To fetch the deltas for the client, you can use the `syncStreams` function, as you would with normal Agent streaming. If you don't want to fetch the non-streaming messages, it can be simplified to: ``` import { v } from "convex/values"; import { vStreamArgs, syncStreams } from "@convex-dev/agent"; import { query } from "./_generated/server"; import { components } from "./_generated/api"; export const listStreams = query({ args: { threadId: v.string(), streamArgs: vStreamArgs, }, handler: async (ctx, args) => { // await authorizeThreadAccess(ctx, args.threadId); const streams = await syncStreams(ctx, components.agent, { ...args, // By default syncStreams only returns streaming messages. However, if // your messages aren't saved in the same transaction as the streaming // ends, you might want to include them here to avoid UI flashes. includeStatuses: ["streaming", "aborted", "finished"], }); return { streams }; }, }); ``` On the client side, you can use the `useStreamingUIMessages` hook to fetch the messages. If you defined more arguments than just `threadId`, they'll get passed along with `threadId` here. ``` const messages = useStreamingUIMessages(api.example.listStreams, { threadId }); ``` You can pass in another parameter to either skip certain `streamId`s or to start at some `order` to ignore previous streams. --- # Threads Threads are a way to group messages together in a linear history. All messages saved in the Agent component are associated with a thread. When a message is generated based on a prompt, it saves the user message and generated agent message(s) automatically. Threads can be associated with a user, and messages can each individually be associated with a user. By default, messages are associated with the thread's user. ## Creating a thread[​](#creating-a-thread "Direct link to Creating a thread") You can create a thread in a mutation or action. If you create it in an action, it will also return a `thread` (see below) and you can start calling LLMs and generating messages. If you specify a userId, the thread will be associated with that user and messages will be saved to the user's history. ``` import { createThread } from "@convex-dev/agent"; const threadId = await createThread(ctx, components.agent); ``` You may also pass in metadata to set on the thread: ``` const userId = await getAuthUserId(ctx); const threadId = await createThread(ctx, components.agent, { userId, title: "My thread", summary: "This is a summary of the thread", }); ``` Metadata may be provided as context to the agent automatically in the future, but for now it's a convenience that helps organize threads in the [Playground](/agents/playground.md). ## Generating a message in a thread[​](#generating-a-message-in-a-thread "Direct link to Generating a message in a thread") You can generate a message in a thread via the agent functions: `agent.generateText`, `agent.generateObject`, `agent.streamText`, and `agent.streamObject`. Any agent can generate a message in a thread created by any other agent. ``` const agent = new Agent(components.agent, { languageModel, instructions }); export const generateReplyToPrompt = action({ args: { prompt: v.string(), threadId: v.string() }, handler: async (ctx, { prompt, threadId }) => { // await authorizeThreadAccess(ctx, threadId); const result = await agent.generateText(ctx, { threadId }, { prompt }); return result.text; }, }); ``` See [Messages](/agents/messages.md) for more details on creating and saving messages. ## Continuing a thread using the `thread` object from `agent.continueThread`[​](#continuing-a-thread-using-the-thread-object-from-agentcontinuethread "Direct link to continuing-a-thread-using-the-thread-object-from-agentcontinuethread") You can also continue a thread by creating an agent-specific `thread` object, either when calling `agent.createThread` or `agent.continueThread` from within an action. This allows calling methods without specifying those parameters each time. ``` const { thread } = await agent.continueThread(ctx, { threadId }); const result = await thread.generateText({ prompt }); ``` The `thread` from `continueThread` or `createThread` (available in actions only) is a `Thread` object, which has convenience methods that are thread-specific: * `thread.getMetadata()` to get the `userId`, `title`, `summary` etc. * `thread.updateMetadata({ patch: { title, summary, userId} })` to update the metadata * `thread.generateText({ prompt, ... })` - equivalent to `agent.generateText(ctx, { threadId }, { prompt, ... })` * `thread.streamText({ prompt, ... })` - equivalent to `agent.streamText(ctx, { threadId }, { prompt, ... })` * `thread.generateObject({ prompt, ... })` - equivalent to `agent.generateObject(ctx, { threadId }, { prompt, ... })` * `thread.streamObject({ prompt, ... })` - equivalent to `agent.streamObject(ctx, { threadId }, { prompt, ... })` See [Messages docs](/agents/messages.md) for more details on generating messages. ## Deleting threads[​](#deleting-threads "Direct link to Deleting threads") You can delete threads by their `threadId`. Asynchronously (from a mutation or action): ``` await agent.deleteThreadAsync(ctx, { threadId }); ``` Synchronously in batches (from an action): ``` await agent.deleteThreadSync(ctx, { threadId }); ``` You can also delete all threads by a user by their `userId`. ``` await agent.deleteThreadsByUserId(ctx, { userId }); ``` ## Getting all threads owned by a user[​](#getting-all-threads-owned-by-a-user "Direct link to Getting all threads owned by a user") ``` const threads = await ctx.runQuery( components.agent.threads.listThreadsByUserId, { userId, paginationOpts: args.paginationOpts }, ); ``` ## Deleting all threads and messages associated with a user[​](#deleting-all-threads-and-messages-associated-with-a-user "Direct link to Deleting all threads and messages associated with a user") Asynchronously (from a mutation or action): ``` await ctx.runMutation(components.agent.users.deleteAllForUserIdAsync, { userId, }); ``` Synchronously (from an action): ``` await ctx.runMutation(components.agent.users.deleteAllForUserId, { userId }); ``` ## Getting messages in a thread[​](#getting-messages-in-a-thread "Direct link to Getting messages in a thread") See [messages.mdx](/agents/messages.md) for more details. ``` import { listMessages } from "@convex-dev/agent"; const messages = await listMessages(ctx, components.agent, { threadId, excludeToolMessages: true, paginationOpts: { cursor: null, numItems: 10 }, // null means start from the beginning }); ``` Or for the UIMessage type (easier for rendering UIs): ``` import { listUIMessages } from "@convex-dev/agent"; const messages = await listUIMessages(ctx, components.agent, { threadId, paginationOpts: { cursor: null, numItems: 10 }, }); ``` --- # Tools The Agent component supports tool calls, which are a way to allow an LLM to call out to external services or functions. This can be useful for: * Retrieving data from the database * Writing or updating data in the database * Searching the web for more context * Calling an external API * Requesting that a user takes an action before proceeding (human-in-the-loop) ## Defining tools[​](#defining-tools "Direct link to Defining tools") You can provide tools at different times: * Agent constructor: (`new Agent(components.agent, { tools: {...} })`) * Creating a thread: `createThread(ctx, { tools: {...} })` * Continuing a thread: `continueThread(ctx, { tools: {...} })` * On thread functions: `thread.generateText({ tools: {...} })` * Outside of a thread: `supportAgent.generateText(ctx, {}, { tools: {...} })` Specifying tools at each layer will overwrite the defaults. The tools will be `args.tools ?? thread.tools ?? agent.options.tools`. This allows you to create tools in a context that is convenient. ## Using tools[​](#using-tools "Direct link to Using tools") The Agent component will automatically handle passing tool call results back in and re-generating if you pass `stopWhen: stepCountIs(num)` where `num > 1` to `generateText` or `streamText`. The tool call and result will be stored as messages in the thread associated with the source message. See [Messages](/agents/messages.md) for more details. ## Creating a tool with a Convex context[​](#creating-a-tool-with-a-convex-context "Direct link to Creating a tool with a Convex context") There are two ways to create a tool that has access to the Convex context. 1. Use the `createTool` function, which is a wrapper around the AI SDK's `tool` function. ``` export const ideaSearch = createTool({ description: "Search for ideas in the database", args: z.object({ query: z.string().describe("The query to search for") }), handler: async (ctx, args, options): Promise> => { // ctx has agent, userId, threadId, messageId // as well as ActionCtx properties like auth, storage, runMutation, and runAction const ideas = await ctx.runQuery(api.ideas.searchIdeas, { query: args.query, }); console.log("found ideas", ideas); return ideas; }, }); ``` 2. Define tools at runtime in a context with the variables you want to use. ``` async function createTool(ctx: ActionCtx, teamId: Id<"teams">) { const myTool = tool({ description: "My tool", parameters: z.object({...}).describe("The arguments for the tool"), execute: async (args, options): Promise => { return await ctx.runQuery(internal.foo.bar, args); }, }); } ``` In both cases, the args and options match the underlying AI SDK's `tool` function. If you run into type errors, ensure you're annotating the return type of the execute function, and if necessary, the return type of the `handler`s of any functions you call with `ctx.run*`. Note: it's highly recommended to use zod with `.describe` to provide details about each parameter. This will be used to provide a description of the tool to the LLM. ### Adding custom context to tools[​](#adding-custom-context-to-tools "Direct link to Adding custom context to tools") It's often useful to have extra metadata in the context of a tool. By default, the context passed to a tool is a `ToolCtx` with: * `agent` - the Agent instance calling it * `userId` - the user ID associated with the call, if any * `threadId` - the thread ID, if any * `messageId` - the message ID of the prompt message passed to generate/stream. * Everything in `ActionCtx`, such as `auth`, `storage`, `runQuery`, etc. Note: in scheduled functions, workflows, etc, the auth user will be `null`. To add more fields to the context, you can pass a custom context to the call, such as `agent.generateText({ ...ctx, orgId: "123" })`. You can enforce the type of the context by passing a type when constructing the Agent. ``` const myAgent = new Agent<{ orgId: string }>(...); ``` Then, in your tools, you can use the `orgId` field. ``` type MyCtx = ToolCtx & { orgId: string }; const myTool = createTool({ args: z.object({ ... }), description: "...", handler: async (ctx: MyCtx, args) => { // use ctx.orgId }, }); ``` ## Using an LLM or Agent as a tool[​](#using-an-llm-or-agent-as-a-tool "Direct link to Using an LLM or Agent as a tool") You can do generation within a tool call, for instance if you wanted one Agent to ask another Agent a question. Note: you don't have to structure agents calling each other as tool calls. You could instead decide which Agent should respond next based on other context and have many Agents contributing in the same thread. The simplest way to model Agents as tool calls is to have each tool call work in an independent thread, or do generation without a thread at all. Then, the output is returned as the tool call result for the next LLM step to use. When you do it this way, you **don't** need to explicitly save the tool call result to the parent thread. ### Direct LLM generation without a thread:[​](#direct-llm-generation-without-a-thread "Direct link to Direct LLM generation without a thread:") ``` const llmTool = createTool({ description: "Ask a question to some LLM", args: z.object({ message: z.string().describe("The message to ask the LLM"), }), handler: async (ctx, args): Promise => { const result = await generateText({ system: "You are a helpful assistant.", // Pass through all messages from the current generation prompt: [...options.messages, { role: "user", content: args.message }], model: myLanguageModel, }); return result.text; }, }); ``` ### Using an Agent as a tool[​](#using-an-agent-as-a-tool "Direct link to Using an Agent as a tool") ``` const agentTool = createTool({ description: `Ask a question to agent ${agent.name}`, args: z.object({ message: z.string().describe("The message to ask the agent"), }), handler: async (ctx, args, options): Promise => { const { userId } = ctx; const { thread } = await agent.createThread(ctx, { userId }); const result = await thread.generateText( { // Pass through all messages from the current generation prompt: [...options.messages, { role: "user", content: args.message }], }, // Save all the messages from the current generation to this thread. { storageOptions: { saveMessages: "all" } }, ); // Optionally associate the child thread with the parent thread in your own // tables. await saveThreadAsChild(ctx, ctx.threadId, thread.threadId); return result.text; }, }); ``` --- # Usage Tracking You can provide a `usageHandler` to the agent to track token usage. See an example in [this demo](https://github.com/get-convex/agent/blob/main/example/convex/usage_tracking/usageHandler.ts) that captures usage to a table, then scans it to generate per-user invoices. You can provide a `usageHandler` to the agent, per-thread, or per-message. ``` const supportAgent = new Agent(components.agent, { ... usageHandler: async (ctx, args) => { const { // Who used the tokens userId, threadId, agentName, // What LLM was used model, provider, // How many tokens were used (extra info is available in providerMetadata) usage, providerMetadata } = args; // ... log, save usage to your database, etc. }, }); ``` Tip: Define the `usageHandler` within a function where you have more variables available to attribute the usage to a different user, team, project, etc. ## Storing usage in a table[​](#storing-usage-in-a-table "Direct link to Storing usage in a table") To track usage for e.g. billing, you can define a table in your schema and insert usage into it for later processing. ``` export const usageHandler: UsageHandler = async (ctx, args) => { if (!args.userId) { console.debug("Not tracking usage for anonymous user"); return; } await ctx.runMutation(internal.example.insertRawUsage, { userId: args.userId, agentName: args.agentName, model: args.model, provider: args.provider, usage: args.usage, providerMetadata: args.providerMetadata, }); }; export const insertRawUsage = internalMutation({ args: { userId: v.string(), agentName: v.optional(v.string()), model: v.string(), provider: v.string(), usage: vUsage, providerMetadata: v.optional(vProviderMetadata), }, handler: async (ctx, args) => { const billingPeriod = getBillingPeriod(Date.now()); return await ctx.db.insert("rawUsage", { ...args, billingPeriod, }); }, }); function getBillingPeriod(at: number) { const now = new Date(at); const startOfMonth = new Date(now.getFullYear(), now.getMonth()); return startOfMonth.toISOString().split("T")[0]; } ``` With an associated schema in `convex/schema.ts`: ``` export const schema = defineSchema({ rawUsage: defineTable({ userId: v.string(), agentName: v.optional(v.string()), model: v.string(), provider: v.string(), // stats usage: vUsage, providerMetadata: v.optional(vProviderMetadata), // In this case, we're setting it to the first day of the current month, // using UTC time for the month boundaries. // You could alternatively store it as a timestamp number. // You can then fetch all the usage at the end of the billing period // and calculate the total cost. billingPeriod: v.string(), // When the usage period ended }).index("billingPeriod_userId", ["billingPeriod", "userId"]), invoices: defineTable({ userId: v.string(), billingPeriod: v.string(), amount: v.number(), status: v.union( v.literal("pending"), v.literal("paid"), v.literal("failed"), ), }).index("billingPeriod_userId", ["billingPeriod", "userId"]), // ... other tables }); ``` ## Generating invoices via a cron job[​](#generating-invoices-via-a-cron-job "Direct link to Generating invoices via a cron job") You can use a cron job to generate invoices at the end of the billing period. See [usage\_tracking/invoicing.ts](https://github.com/get-convex/agent/blob/main/example/convex/usage_tracking/invoicing.ts) for an example of how to generate invoices. You can then add it to `convex/crons.ts`: ``` import { cronJobs } from "convex/server"; import { internal } from "./_generated/api"; const crons = cronJobs(); // Generate invoices for the previous month crons.monthly( "generateInvoices", // Wait a day after the new month starts to generate invoices { day: 2, hourUTC: 0, minuteUTC: 0 }, internal.usage.generateInvoices, {}, ); export default crons; ``` --- # Workflows Agentic Workflows can be decomposed into two elements: 1. Prompting an LLM (including message history, context, etc.). 2. Deciding what to do with the LLM's response. We generally call them workflows when there are multiple steps involved, they involve dynamically deciding what to do next, are long-lived, or have a mix of business logic and LLM calls. Tool calls and MCP come into play when the LLM's response is a specific request for an action to take. The list of available tools and result of the calls are used in the prompt to the LLM. One especially powerful form of Workflows are those that can be modeled as [durable functions](https://stack.convex.dev/durable-workflows-and-strong-guarantees) that can be long-lived, survive server restarts, and have strong guarantees around retrying, idempotency, and completing. The simplest version of this could be doing a couple pre-defined steps, such as first getting the weather forecast, then getting fashion advice based on the weather. For a code example, see [workflows/chaining.ts](https://github.com/get-convex/agent/blob/main/example/convex/workflows/chaining.ts). ``` export const getAdvice = action({ args: { location: v.string(), threadId: v.string() }, handler: async (ctx, { location, threadId }) => { // This uses tool calls to get the weather forecast. await weatherAgent.generateText( ctx, { threadId }, { prompt: `What is the weather in ${location}?` }, ); // This includes previous message history from the thread automatically and // uses tool calls to get user-specific fashion advice. await fashionAgent.generateText( ctx, { threadId }, { prompt: `What should I wear based on the weather?` }, ); // We don't need to return anything, since the messages are saved // automatically and clients will get the response via subscriptions. }, }); ``` ## Building reliable workflows[​](#building-reliable-workflows "Direct link to Building reliable workflows") One common pitfall when working with LLMs is their unreliability. API providers have outages, and LLMs can be flaky. To build reliable workflows, you often need three properties: 1. Reliable retries 2. Load balancing 3. Durability and idempotency for multi-step workflows Thankfully there are Convex components to leverage for these properties. ### Retries[​](#retries "Direct link to Retries") By default, Convex mutations have these properties by default. However, calling LLMs require side-effects and using the network calls, which necessitates using actions. If you are only worried about retries, you can use the [Action Retrier](https://convex.dev/components/retrier) component. However, keep reading, as the [Workpool](https://convex.dev/components/workpool) and [Workflow](https://convex.dev/components/workflow) components provide more robust solutions, including retries. ### Load balancing[​](#load-balancing "Direct link to Load balancing") With long-running actions in a serverless environment, you may consume a lot of resources. And with tasks like ingesting data for RAG or other spiky workloads, there's a risk of running out of resources. To mitigate this, you can use the [Workpool](https://convex.dev/components/workpool) component. You can set a limit on the number of concurrent workers and add work asynchronously, with configurable retries and a callback to handle eventual success / failure. However, if you also want to manage multi-step workflows, you should use the [Workflow](https://convex.dev/components/workflow) component, which also provides retries and load balancing out of the box. ### Durability and idempotency for multi-step workflows[​](#durability-and-idempotency-for-multi-step-workflows "Direct link to Durability and idempotency for multi-step workflows") When doing multi-step workflows that can fail mid-way, you need to ensure that the workflow can be resumed from where it left off, without duplicating work. The [Workflow](https://convex.dev/components/workflow) builds on the [Workpool](https://convex.dev/components/workpool) to provide durable execution of long running functions with retries and delays. Each step in the workflow is run, with the result recorded. Even if the server fails mid-way, it will resume with the latest incomplete step, with configurable retry settings. ## Using the Workflow component for long-lived durable workflows[​](#using-the-workflow-component-for-long-lived-durable-workflows "Direct link to Using the Workflow component for long-lived durable workflows") The [Workflow component](https://convex.dev/components/workflow) is a great way to build long-lived, durable workflows. It handles retries and guarantees of eventually completing, surviving server restarts, and more. Read more about durable workflows in [this Stack post](https://stack.convex.dev/durable-workflows-and-strong-guarantees). To use the agent alongside workflows, you can run individual idempotent steps that the workflow can run, each with configurable retries, with guarantees that the workflow will eventually complete. Even if the server crashes mid-workflow, the workflow will pick up from where it left off and run the next step. If a step fails and isn't caught by the workflow, the workflow's onComplete handler will get the error result. ### Exposing the agent as Convex actions[​](#exposing-the-agent-as-convex-actions "Direct link to Exposing the agent as Convex actions") You can expose the agent's capabilities as Convex functions to be used as steps in a workflow. To create a thread as a standalone mutation, similar to `createThread`: ``` export const createThread = supportAgent.createThreadMutation(); ``` For an action that generates text in a thread, similar to `thread.generateText`: ``` export const getSupport = supportAgent.asTextAction({ stopWhen: stepCountIs(10), }); ``` You can also expose a standalone action that generates an object. ``` export const getStructuredSupport = supportAgent.asObjectAction({ schema: z.object({ analysis: z.string().describe("A detailed analysis of the user's request."), suggestion: z.string().describe("A suggested action to take."), }), }); ``` To save messages explicitly as a mutation, similar to `agent.saveMessages`: ``` export const saveMessages = supportAgent.asSaveMessagesMutation(); ``` This is useful for idempotency, as you can first create the user's message, then generate a response in an unreliable action with retries, passing in the existing messageId instead of a prompt. ### Using the agent actions within a workflow[​](#using-the-agent-actions-within-a-workflow "Direct link to Using the agent actions within a workflow") You can use the [Workflow component](https://convex.dev/components/workflow) to run agent flows. It handles retries and guarantees of eventually completing, surviving server restarts, and more. Read more about durable workflows [in this Stack post](https://stack.convex.dev/durable-workflows-and-strong-guarantees). ``` const workflow = new WorkflowManager(components.workflow); export const supportAgentWorkflow = workflow.define({ args: { prompt: v.string(), userId: v.string() }, handler: async (step, { prompt, userId }) => { const { threadId } = await step.runMutation(internal.example.createThread, { userId, title: "Support Request", }); const suggestion = await step.runAction(internal.example.getSupport, { threadId, userId, prompt, }); const { object } = await step.runAction( internal.example.getStructuredSupport, { userId, message: suggestion, }, ); await step.runMutation(internal.example.sendUserMessage, { userId, message: object.suggestion, }); }, }); ``` See the code in [workflows/chaining.ts](https://github.com/get-convex/agent/blob/main/example/convex/workflows/chaining.ts). ## Complex workflow patterns[​](#complex-workflow-patterns "Direct link to Complex workflow patterns") While there is only an example of a simple workflow here, there are many complex patterns that can be built with the Agent component: * Dynamic routing to agents based on an LLM call or vector search * Fanning out to LLM calls, then combining the results * Orchestrating multiple agents * Cycles of Reasoning and Acting (ReAct) * Modeling a network of agents messaging each other * Workflows that can be paused and resumed [Convex Component](https://www.convex.dev/components/retrier) ### [Action Retrier](https://www.convex.dev/components/retrier) [Add reliability to unreliable external service calls. Retry idempotent calls with exponential backoff until success.](https://www.convex.dev/components/retrier) [Convex Component](https://www.convex.dev/components/workpool) ### [Workpool](https://www.convex.dev/components/workpool) [Builds on the Action Retrier to provide parallelism limits and retries to manage large numbers of external requests efficiently.](https://www.convex.dev/components/workpool) [Convex Component](https://www.convex.dev/components/workflow) ### [Workflow](https://www.convex.dev/components/workflow) [Builds on the Workpool to provide durable execution of long running functions with retries and delays.](https://www.convex.dev/components/workflow) --- # AI Code Generation ## [Prompt to build an app with Convex Chef](https://chef.convex.dev) Convex is designed around a small set of composable abstractions with strong guarantees that result in code that is not only faster to write, but easier to read and maintain, whether written by a team member or an LLM. Key features make sure you get bug-free AI generated code: 1. **Queries are Just TypeScript** Your database queries are pure TypeScript functions with end-to-end type safety and IDE support. This means AI can generate database code using the large training set of TypeScript code without switching to SQL. 2. **Less Code for the Same Work** Since so much infrastructure and boiler plate is automatically managed by Convex there is less code to write, and thus less code to get wrong. 3. **Automatic Reactivity** The reactive system automatically tracks data dependencies and updates your UI. AI doesn't need to manually manage subscriptions, WebSocket connections, or complex state synchronization—Convex handles all of this automatically. 4. **Transactional Guarantees** Queries are read-only and mutations run in transactions. These constraints make it nearly impossible for AI to write code that could corrupt your data or leave your app in an inconsistent state. Together, these features mean AI can focus on your business logic while Convex's guarantees prevent common failure modes. For up-to-date information on which models work best with Convex, check out our LLM [leaderboard](https://convex.dev/llm-leaderboard). ## Convex AI rules[​](#convex-ai-rules "Direct link to Convex AI rules") AI code generation is most effective when you provide it with a set of rules to follow. See these documents for install instructions: * [Cursor](/ai/using-cursor.md#add-convex-cursorrules) * [Windsurf](/ai/using-windsurf.md#add-convex-rules) * [GitHub Copilot](/ai/using-github-copilot.md#add-convex-instructions) For all other IDEs, add the following rules file to your project and refer to it when prompting for changes: * [convex\_rules.txt](https://convex.link/convex_rules.txt) We're constantly working on improving the quality of these rules for Convex by using rigorous evals. You can help by [contributing to our evals repo](https://github.com/get-convex/convex-evals). ## Using Convex with Background Agents[​](#using-convex-with-background-agents "Direct link to Using Convex with Background Agents") Remote cloud-based coding agents like Jules, Devin, Codex, and Cursor background agents can use Convex deployments when the CLI is in [Agent Mode](/cli/agent-mode.md). This limits the permissions necessary for these remote dev environments while letting agents run codegen, iterate on code, run tests, run one-off functions. A good setup script for e.g. ChatGPT Codex might include ``` npm i CONVEX_AGENT_MODE=anonymous npx convex dev --once ``` or ``` bun i CONVEX_AGENT_MODE=anonymous bun x convex dev --once ``` This command requires "full" internet access to download the binary. ## Convex MCP Server[​](#convex-mcp-server "Direct link to Convex MCP Server") [Setup the Convex MCP server](/ai/convex-mcp-server.md) to give your AI coding agent access to your Convex deployment to query and optimize your project. --- # Convex MCP Server The Convex [Model Context Protocol](https://docs.cursor.com/context/model-context-protocol) (MCP) server provides several tools that allow AI agents to interact with your Convex deployment. ## Setup[​](#setup "Direct link to Setup") Add the following command to your MCP servers configuration: `npx -y convex@latest mcp start` For Cursor you can use this quick link to install: [![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=convex\&config=eyJjb21tYW5kIjoibnB4IC15IGNvbnZleEBsYXRlc3QgbWNwIHN0YXJ0In0%3D) or see editor specific instructions: * [Cursor](/ai/using-cursor.md#setup-the-convex-mcp-server) * [Windsurf](/ai/using-windsurf.md#setup-the-convex-mcp-server) * [VS Code](/ai/using-github-copilot.md#setup-the-convex-mcp-server) * Claude Code: add the MCP server and test with ``` claude mcp add-json convex '{"type":"stdio","command":"npx","args":["convex","mcp","start"]}' claude mcp get convex ``` ## Available Tools[​](#available-tools "Direct link to Available Tools") ### Deployment Tools[​](#deployment-tools "Direct link to Deployment Tools") * **`status`**: Queries available deployments and returns a deployment selector that can be used with other tools. This is typically the first tool you'll use to find your Convex deployment. ### Table Tools[​](#table-tools "Direct link to Table Tools") * **`tables`**: Lists all tables in a deployment along with their: * Declared schemas (if present) * Inferred schemas (automatically tracked by Convex) * Table names and metadata * **`data`**: Allows pagination through documents in a specified table. * **`runOneoffQuery`**: Enables writing and executing sandboxed JavaScript queries against your deployment's data. These queries are read-only and cannot modify the database. ### Function Tools[​](#function-tools "Direct link to Function Tools") * **`functionSpec`**: Provides metadata about all deployed functions, including: * Function types * Visibility settings * Interface specifications * **`run`**: Executes deployed Convex functions with provided arguments. * **`logs`**: Fetches a chunk of recent function execution log entries, similar to `npx convex logs` but as structured objects. ### Environment Variable Tools[​](#environment-variable-tools "Direct link to Environment Variable Tools") * **`envList`**: Lists all environment variables for a deployment * **`envGet`**: Retrieves the value of a specific environment variable * **`envSet`**: Sets a new environment variable or updates an existing one * **`envRemove`**: Removes an environment variable from the deployment [Read more about how to use the Convex MCP Server](https://stack.convex.dev/convex-mcp-server) --- # Using Cursor with Convex [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 `.cursor/rules`[​](#add-convex-cursorrules "Direct link to add-convex-cursorrules") To get the best results from Cursor put the model specific `.mdc` files in your project's `.cursor/rules` directory. * [Convex Cursor Rules](https://convex.link/convex_rules.mdc) [](/video/showing_where_to_put_convex_rules.mp4) We're constantly working on improving the quality of these rules for Convex by using rigorous evals. You can help by [contributing to our evals repo](https://github.com/get-convex/convex-evals). ## Setup the Convex MCP Server[​](#setup-the-convex-mcp-server "Direct link to Setup the Convex MCP Server") The Convex CLI comes with a [Convex Model Context Protocol](/ai/convex-mcp-server.md) (MCP) server built in. The Convex MCP server gives your AI coding agent access to the your Convex deployment to query and optimize your project. ### Quick Install[​](#quick-install "Direct link to Quick Install") You can click this handy deep-link below: [![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=convex\&config=eyJjb21tYW5kIjoibnB4IC15IGNvbnZleEBsYXRlc3QgbWNwIHN0YXJ0In0%3D) ### Manual Install[​](#manual-install "Direct link to Manual Install") To get started with Cursor, open "Cursor Settings > Tools & Integrations", click on "New MCP Server", and add a "convex" section to "mcpServers" in the `mcp.json` file that's opened. ``` { "mcpServers": { "convex": { "command": "npx", "args": ["-y", "convex@latest", "mcp", "start"] } } } ``` You can also install the Convex MCP [for just one project](https://docs.cursor.com/en/context/mcp#configuration-locations). After adding the server, ensure the "convex" server is enabled and lit up green (it make take a minute the first time while the NPM package downloads). Now start asking it questions like: * Evaluate my convex schema and suggest improvements * What are this app's public endpoints? * Run the `my_convex_function` query ## Tips and tricks[​](#tips-and-tricks "Direct link to Tips and tricks") ### Install and run Convex yourself[​](#install-and-run-convex-yourself "Direct link to 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. ### Keep your requests small[​](#keep-your-requests-small "Direct link to Keep your requests small") The best results when using agentic LLMs can be found when keeping the amount of changes you want to make small and git commit frequently. 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`[​](#update-and-reference-your-readmemd "Direct link to update-and-reference-your-readmemd") 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. ### Add Convex docs[​](#add-convex-docs "Direct link to Add Convex docs") Adding Convex docs can let you specifically refer to Convex features when building your app. From **`Cursor Settings`** > **`Indexing & Docs`** > **`Docs`** add new doc, use the URL "" ![Chat UI](data:image/webp;base64,UklGRioQAABXRUJQVlA4WAoAAAAIAAAAxwIAtwAAVlA4IEoPAABwWwCdASrIArgAPm02mEkkIyKhIxRoaIANiWlu56AOKacwricHdL8p/RO/Gqz9UWrN5Php/oHqm/7PTz9FHmA/QD9kveJ9AHQ8f+H2QvQA/Y71wvVe/z3SAf//gnfEXX//fvC3wkeoM7vHn1I6jvxr8Lfs/7r5595Pw01Avxz+WeYj67/ke0K0T+w/9b1AvbD6b3nWov7Mfav1f+AD+R/0f/nepX+R8Ab6r/l/2I+AD+X/27/0f4P3Qv5n/0/5/zX/nv+L/83+e+AP+X/2X9gvaw9eP7n+zj+8Afklr8gKqLtmQisC1+QFVF2zIRV9WhjAK7YRWBa/ICqi7ZkIrAtfkBVRdsx+cx03GIhBEn33Vs7nGk++6tnc40n33Vs7nGbeqErGPkYVUXbMhFYFr8gKqLtmQisC1+Jj4KrtkwzBk/3QQcSfJ2jkJFGWNALX5AVUXbMhFYFr8gHfHreowkztt6086WygVFHMh3zVobE9AH+RJHY5/5hi9sSeUu0Jhoe55xtv//kpCmf/+GfB/WHwCqi7ZkIrAtfkBVRdrYmrMnuf1OsbdEi4YimtTsnPK6AYtohUktI5EiU0X68G1PIb+oNmxm/acSbAdpOKfLhKN3P/vnCfdYEsrDpDw7aPGDCYV9D1UyRtpYx9fN3kO9R9UcqQR9u8kpeteWqZCKwLX5AVUVoIhrjLj6Z05p7mYw/nkaktYxh/IWs07xV/sIz2RY90DCqi7ZkIrAtfri1SNUpiP0PtBZKWD9UAXP89HPOtGvs8GpnmXEJzIu/aOMGmoYQbrNKAkEavpaYYUN2B7Rj1bADOzKJSs16ECkP/rn3aNDJnHbVMW04Qq9QCXqS8qudJfaBwZlLlK69R4N6SAWvyAqou2ZB7siKtMh0QC1+QFVF2zIRWBa/ICqi6Rqku/hLAX31UpIk++6tnc40n33Vs7nGk++6tkTlsehkrZgwqou2ZCKwLX5AVUXbMhFYFrb4uAAD+/6XVIiHfE26tm6tm6tmAAt9pCZYWPxBtiMPM+ZXAkCvAC0yZhTgq5cxNTZSAB5XrwUAADAiMROKuXyhL+YTGHHTZgV88/bFAoaemKxBxlaHlwXLu3ltF7lIUE9sIlX5pEqC+2LeSXVktHV8ru6ioG4TAj2XMxps/rpGFSkU+YiM4fbB+tq+wpdDeqmMAbJm3oq+Q6iP9QkU24SfpuKnXIpZKO9bv/dI/VaV3yg0G7l1cocZ6FacPqXrMiZv1Vb3T7vCFk/ATtoL2xbPIgR9sYBBLl5gwX6AGudbsevWLFTQ3PtblZrFmBZMrQS0v4HJRTLe3nRYGFet5BVh8OSWpHxzpjeBmSeB5tLeTuKLTD7Ev1+sz+e3qjlWb247YMLHnrdwuRbfdtzoRI28kO1bB1kfT6FL5SR62dQ4OCLUpzMwGPhq/ExiIo6yixqI12WnDA9P6Poymr7fQSiYq4aDu2O+Rk34MJScxpfrdpLtJ4maPIjXwwkcTV7/L9EbjlLH1SYycrUgRxtvT+KDnFPFXo7ZoRairxaBBSpPc8yjf6pB50c+u17QWll27Ue4zFPAwad78g8tXBucLj77Lp9kMWWrjelHc6ZlIjm5FLHKaMOiMMSp+s/AlGKq2sjJ87QXf5KbJUAeE9VqHTq+PY/1yZig7BRyh/7hCdO51pLRHveWWdAb5vjmZslkR3VFNJ5TrrbDiLDEi6fjcAKhb9Yrj+judlnfbImM9BSqsh4Su3vfyJ2X1ezwj93lKWj095iM0sm5DrNoLsDcbQE7WQrG7D0+6WX1juPOVAmmdd0tDzCeq6+wU7RKhL5Mz1FwWtX2JH//72Wa1BU0uOKYyX8S9hu8C/GUfX//lk8cLaGabEQFkfoqDXUj86LZiysSR8HynYEQ3fVujz9EEW+X5anJGSZ6Xf5jTLxYRtgdezBBakaUNJwvdLHr74wNh6m7x1JlPCd4IFHUKWj4NdM9T0ZDbcRMBGSUfwrDKgaTcCBi4TboEpK2rrex464sl4IFuMUGAJgzCKpIvNNhDPoqNkHFM7jsyoxs+PssHvY9zyskcqp76Ldo9FpBpIXfP/AfMpveODyigBCFPjQ3L4utbccgdZup+P7royBeiDzynez9/I5XT7jf392hj4rby74bwTlDFL3X9e+DHOOcnC6/YlCSPkmtbAbuLNOujJRPX3SPuwVehYAA6yPs8Xn36xZg9358IjJTbNo+rpGKNslUq1qFHdW0sZB18Ajy9bu6/69UFVI4Q6MDwv0FLXhWfqac98myRlU70iv7difZ0ZNgUz2+/lo2Spg8zIivJcthciJi7qFJE/EdhuN8ki0TqogaP0UKXDeA7iswSmX7wWfUdzX/SxUCrmOY9vl+pAPvY7EcnEwRJCGvzm7yzddbsMDI6BJH9D/LDZhAcCDs0Qayy0kSyE8oS6MXXEV5w1sJxJuwQVj6tM/qMqSo6H9Lwh9LJxN+p7BQPa1fABsq6uI6YPlsb209di84INwHrBRGTOmPVQAPKPppuIEoVKtsw1ksyb+9Tdk8ZzoJZZiuAt4Yo/BlCyp707Z3XHpXcrLCDjhJgDGporrb2C9dPTK+H+OW85rgt0OTaUkzX2ROl71I3uijFUGVtDTMvfAI97luMg27SurpFVNfJNkicb5ilFLunAConZZah3BUEPK3AbQtG+29PmRk3t7bNGIKr0p/K37XBfVGZ4a7dPQfEQ1sQlsPeYFyTyNQ/G04O/DhDP3r2z2ACyRNjeczUpPwE7U6z/9YkSiJl1CDhJsBA8JT7p4p1wpw5OoBfcgphbY8UIbS7wS+JNrktIUA+J3PcwFjIg1PNG8E4j7Lu3BXYGyc8L86EuIiA4RVajze1G6I7BVM4r81mz9SaSkJsbbfEg8tsrUfLxp2mm96a4+5+EfwJ+MZEeG2Sgjok/LkkdR3xrBgt5+H17chTnfNhCvOVCC3GTOwl6CD61jgH5pXDy0u9w7kg126N/Dsiw6zJz7MNhH/vI2QrGTZSyxKXB1fdYtReFWTUHsgsR5IETm89n44TN9kcHlHVJxZCjQwa7Q80aAwUnk/QZdvFJh5e2zzIOFgCGoS7tMWVzdrczSTjgzbsLmIck7CCZapSyqOL/C1II15IfuQ8VW3gV3M1cVXuQkHCWb386hzSQDBSwGJbJdjDKn6CbOqHYvhnFWFEo+Wfy/o1TZsD30oC2iiv6TwU+zIzzwHlM538/WOQPbEvS4/rIcANXPa/48/SiWuOlEsBvYK2Rr7J+/mhIYvHfLanjf3kIZSgqoQPgq+CfCzVMwQ8a1dOdPzdhPmWJ+W5tLgQ1lzXi1cViWRMXT/IC5ueLFYvdNhUSBkpbafrRISoFHvDVSG+tr5RBbbxA3tGDq1aryYE+xEAavFx7VQnrKEl1Kp5znBJy0d9IUu0ONWvvNHPzrsyMeid/Rf1pkXq6AJM88223NUjZZsLxJr/+NyEqg1orzbIbUo6k5uSha3/uEzqrmFJ2ahspFHSQrM17EAnG/25COrPFbWK+/p3wlJfo2MPVbuwYi/f8OQUmGo6sCmm53RDAZxOEPWLU076v7bG6fkstbEpzPZc/uPZNKPrBZ34OxaC/2whiyTWHpq0J2E2yUq5jA4MQFyo7f+4kGA7B1mGwP8UVGJO39Jz8ClFAAAABekHtleniGp8UH9sn7KEwPCcAAAA6sn1hmHO3PeA1s6r5cz4C1IQY4zfazA6PJLmeoWkQKUgAGEKt0D7uBruTMrmMk6pTJpkCTFT4P8+AmSuLnFCN0pFTyQ2AkS1Lr+zTHy9wWSx4YNobr9FvkIh7t/Dz6bPdZ0Mjm6ciodWiTO2muI3wN9HO3igaNTRXZAJAUXuYq7BbIHgBfTCvZnNNDZ1mMeIQzQm9tiEdrRbeg+zIRshCk5grIbRb1OUHgboo3gBRWS6EKYJEDOFYCWGjWprISrCmYydKB2fjbWM+Nj3i9vyHlse/FDj/6DlZWktNqRRSFW2071ExQKzBtXQSVJNsZ9zCcEwlQCmP1p16MB9NSv7WezLLkmVY4ILtVIRyFj52n4LmJK9+8Id1+GllESQNBY1FlxFHzvpSe5Tvq9d0j3mg/nKthAdtedk/lTtR1fK0uZBe4k1L6Uy7T8eIJuuuEgUyYIoCeUR12Oxxha13sY/qFpZILh4YWsfzfLs6PUpOmWnmLB1Kb2kQIxU5PpRlqVKX4hrZWV1SlDO8kAb8VQMhm2Y+fKxWWlIaMElnAEvmpFChnC4Cf2BOb5gA6UHb+pEH0JErS/V0sFMBKApqZQWtn1pMGGT89A1I9+7CFLVJSI6ST8pSCK3PsR+LCMkypcgkI3lw45G5P4DxruhP5QdDpAI726Tcf27sIQirtTgOUm8Wi+3S9dNOTd4I5jE7y9IMwClAzDZu08UhCAWIgIrX0sjXN23uYsL/LG5MexaRwdIgoZoBWfL30QrvVeVJeYJynjg5kRbWnAZ1AUNRXTBYjE4iyrghlC+M+4qvpguo7yS9odJjECMwIUB2otY0epHAjBbUIjspcEzaSiTcKbiVbjc7X5K7uicFJGHjYgbx6eDDfbnSV72LXuaNtoGWpDxgi9hAWjHMvT4qbr0BZRWcP9K/niJDT6JNtWw+iCTqP3SyLdzwOqqctIz+d5nptTJZGNSM/R2RFT04feG+Eoipi27DXekBdT+xuI5fFEGx/OA1R+OFaKW8g6qFLiBwQrdpEksEA++T2Q0TMaTQ+dvyrSilUYaHDjWczc88eD/M4hpXBLYa6y4GkcmPmNBr2KTkoeE/AqE4GO5kw7e9VCrWn6fLrAAt4ZRSk1St3oP/X+QyENCNHf0I0cAia/dkWTgMV00Cnl9UNkqqiNbK0lF4dYpmaLo6YQxifAiObMjq8J4bZ/EDzXxAxVn+0rKhZewee6rn+Fywe4IjccVWdgGBV6mDEIDZurmU25N/lDq0pSQxz3pLiAsnhIei5dL5A9GeNq9zpZTU1C5Z3eyN3IVFjJFve2Q9BmlmwUmb3iJ+aDCxt38Fj3Q3N/NFvWzwisqGNNeE0ZeGaQNhC0VeIO3GiYImZUav0hu5zyzSC5MBgUlgxOpIt7mkQe4mRfZbdEdUQjxOkn5jPOAJGYaa7kiaMEa+7iTms9nJkUP0NNqd+7MBSL3R/z3lB7LNHiWNxSnh17JaQeXXvlG+B0XbGSKjrCleT7wn6EE1Hag0G5+lJIAAF7dn8Hyv8ABaAA8jdFi4AAAAEVYSUa6AAAARXhpZgAASUkqAAgAAAAGABIBAwABAAAAAQAAABoBBQABAAAAVgAAABsBBQABAAAAXgAAACgBAwABAAAAAgAAABMCAwABAAAAAQAAAGmHBAABAAAAZgAAAAAAAABIAAAAAQAAAEgAAAABAAAABgAAkAcABAAAADAyMTABkQcABAAAAAECAwAAoAcABAAAADAxMDABoAMAAQAAAP//AAACoAQAAQAAAMgCAAADoAQAAQAAALgAAAAAAAAA) Cursor will then index all of the Convex docs for the LLM to use. ![Chat UI](/assets/images/indexed_docs-90bb59330756c00540015c53da6a484c.webp) You can then reference those docs in your prompt with the `@Convex` symbol. ![Chat UI](/assets/images/reference_convex_docs-c791c41ddbd7663244fda1c4c59a43d9.webp) Add more Convex knowledge You can perform the above steps for too if you would like to provide even more context to the agent. --- # Using GitHub Copilot with Convex [GitHub Copilot](https://github.com/features/copilot), the AI built into VS Code, makes it easy to write and maintain apps built with Convex. Let's walk through how to setup GitHub Copilot for the best possible results with Convex. ## Add Convex Instructions[​](#add-convex-instructions "Direct link to Add Convex Instructions") Add the following [instructions](https://code.visualstudio.com/docs/copilot/copilot-customization#_instruction-files) file to your `.github/instructions` directory in your project and it will automatically be included when working with TypeScript or JavaScript files: * [convex.instructions.md](https://convex.link/convex_github_copilot_instructions) ![Showing Where to Put GitHub Copilot Instructions](/assets/images/showing-where-to-put-convex-instructions-1d22c1b802b42443b4808e0dd27f0746.png) If you would rather that the instructions file is NOT automatically pulled into context then open the file in your editor and alter the `applyTo` field at the top. Read more about instructions files here: We're constantly working on improving the quality of these rules for Convex by using rigorous evals. You can help by [contributing to our evals repo](https://github.com/get-convex/convex-evals). ## Setup the Convex MCP Server[​](#setup-the-convex-mcp-server "Direct link to Setup the Convex MCP Server") The Convex CLI comes with a [Convex Model Context Protocol](/ai/convex-mcp-server.md) (MCP) server built in. The Convex MCP server gives your AI coding agent access to the your Convex deployment to query and optimize your project. To get started with [MCP in VS Code](https://code.visualstudio.com/docs/copilot/chat/mcp-servers) then create a file in `.vscode/mcp.json` and add the following: ``` { "servers": { "convex-mcp": { "type": "stdio", "command": "npx", "args": ["-y", "convex@latest", "mcp", "start"] } } } ``` Once this is done it will take a few seconds to start up the MCP server and then you should see the Convex tool listed in the codelens: ![Convex Tool in Codelens](/assets/images/convex-tool-in-codelens-0cf36ed79938643797e93dd08ef3565c.png) and in the selection of tools that the model has access to in chat: ![Convex Tool in Chat](/assets/images/convex-tools-in-chat-eef97848e328479e7e1b06452b7934ea.png) Now start asking it questions like: * Evaluate and convex schema and suggest improvements * What are this app's public endpoints? * Run the `my_convex_function` query If you want to use the MCP server globally for all your projects then you can add it to your user settings, please see these docs for more information: --- # Using Windsurf with Convex [Windsurf](https://codeium.com/windsurf), the AI code editor, makes it easy to write and maintain apps built with Convex. Let's walk through how to setup Windsurf for the best possible results with Convex. ## Add Convex Rules[​](#add-convex-rules "Direct link to Add Convex Rules") Add the following rules file to your project and refer to it directly when prompting for changes: * [Convex Rules](https://convex.link/convex_rules.txt) We're constantly working on improving the quality of these rules for Convex by using rigorous evals. You can help by [contributing to our evals repo](https://github.com/get-convex/convex-evals). ## Setup the Convex MCP Server[​](#setup-the-convex-mcp-server "Direct link to Setup the Convex MCP Server") The Convex CLI comes with a [Convex Model Context Protocol](/ai/convex-mcp-server.md) (MCP) server built in. The Convex MCP server gives your AI coding agent access to the your Convex deployment to query and optimize your project. To get started with Windsurf, open "Windsurf Settings > Cascade > Model Context Protocol (MCP) Servers", click on "Add Server", click "Add custom server", and add the following configuration for Convex. ``` { "mcpServers": { "convex": { "command": "npx", "args": ["-y", "convex@latest", "mcp", "start"] } } } ``` After adding the server return to the "Windsurf Settings > Cascade > Model Context Protocol (MCP) Servers" screen an click "Refresh" button for Windsurf to pick up the new server. Once this is done you should see the Convex tool listed in the servers: ![Chat UI](/assets/images/windsurf_convex_mcp-ed91858fc5df64ae0b900f95b69ae2ad.png) Now start asking it questions like: * Evaluate and convex schema and suggest improvements * What are this app's public endpoints? * Run the `my_convex_function` query --- # Convex TypeScript backend SDK, 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): SDK for defining a Convex backend functions, defining a database schema, etc. * [`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. * [`convex/nextjs`](https://docs.convex.dev/api/modules/nextjs): Server-side helpers for SSR, usable by Next.js and other React frameworks. This package also includes [`convex`](https://docs.convex.dev/using/cli), the command-line interface for managing Convex projects. --- # Class: BaseConvexClient [browser](/api/modules/browser.md).BaseConvexClient Low-level client for directly integrating state management libraries with Convex. Most developers should use higher level clients, like the [ConvexHttpClient](/api/classes/browser.ConvexHttpClient.md) or the React hook based [ConvexReactClient](/api/classes/react.ConvexReactClient.md). ## Constructors[​](#constructors "Direct link to Constructors") ### constructor[​](#constructor "Direct link to constructor") • **new BaseConvexClient**(`address`, `onTransition`, `options?`) #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | Description | | -------------- | ----------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `address` | `string` | The url of your Convex deployment, often provided by an environment variable. E.g. `https://small-mouse-123.convex.cloud`. | | `onTransition` | (`updatedQueries`: [`QueryToken`](/api/modules/browser.md#querytoken)\[]) => `void` | A callback receiving an array of query tokens corresponding to query results that have changed -- additional handlers can be added via `addOnTransitionHandler`. | | `options?` | [`BaseConvexClientOptions`](/api/interfaces/browser.BaseConvexClientOptions.md) | See [BaseConvexClientOptions](/api/interfaces/browser.BaseConvexClientOptions.md) for a full description. | #### Defined in[​](#defined-in "Direct link to Defined in") [browser/sync/client.ts:277](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L277) ## Accessors[​](#accessors "Direct link to Accessors") ### url[​](#url "Direct link to url") • `get` **url**(): `string` Return the address for this client, useful for creating a new client. Not guaranteed to match the address with which this client was constructed: it may be canonicalized. #### Returns[​](#returns "Direct link to Returns") `string` #### Defined in[​](#defined-in-1 "Direct link to Defined in") [browser/sync/client.ts:1037](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L1037) ## Methods[​](#methods "Direct link to Methods") ### getMaxObservedTimestamp[​](#getmaxobservedtimestamp "Direct link to getMaxObservedTimestamp") ▸ **getMaxObservedTimestamp**(): `undefined` | `Long` #### Returns[​](#returns-1 "Direct link to Returns") `undefined` | `Long` #### Defined in[​](#defined-in-2 "Direct link to Defined in") [browser/sync/client.ts:542](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L542) *** ### addOnTransitionHandler[​](#addontransitionhandler "Direct link to addOnTransitionHandler") ▸ **addOnTransitionHandler**(`fn`): () => `boolean` Add a handler that will be called on a transition. Any external side effects (e.g. setting React state) should be handled here. #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | | ---- | -------------------------------------- | | `fn` | (`transition`: `Transition`) => `void` | #### Returns[​](#returns-2 "Direct link to Returns") `fn` ▸ (): `boolean` ##### Returns[​](#returns-3 "Direct link to Returns") `boolean` #### Defined in[​](#defined-in-3 "Direct link to Defined in") [browser/sync/client.ts:621](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L621) *** ### getCurrentAuthClaims[​](#getcurrentauthclaims "Direct link to getCurrentAuthClaims") ▸ **getCurrentAuthClaims**(): `undefined` | { `token`: `string` ; `decoded`: `Record`<`string`, `any`> } Get the current JWT auth token and decoded claims. #### Returns[​](#returns-4 "Direct link to Returns") `undefined` | { `token`: `string` ; `decoded`: `Record`<`string`, `any`> } #### Defined in[​](#defined-in-4 "Direct link to Defined in") [browser/sync/client.ts:630](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L630) *** ### setAuth[​](#setauth "Direct link to setAuth") ▸ **setAuth**(`fetchToken`, `onChange`): `void` Set the authentication token to be used for subsequent queries and mutations. `fetchToken` will be called automatically again if a token expires. `fetchToken` should return `null` if the token cannot be retrieved, for example when the user's rights were permanently revoked. #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | Description | | ------------ | -------------------------------------------------------------- | ------------------------------------------------------------------------- | | `fetchToken` | [`AuthTokenFetcher`](/api/modules/browser.md#authtokenfetcher) | an async function returning the JWT-encoded OpenID Connect Identity Token | | `onChange` | (`isAuthenticated`: `boolean`) => `void` | a callback that will be called when the authentication status changes | #### Returns[​](#returns-5 "Direct link to Returns") `void` #### Defined in[​](#defined-in-5 "Direct link to Defined in") [browser/sync/client.ts:655](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L655) *** ### hasAuth[​](#hasauth "Direct link to hasAuth") ▸ **hasAuth**(): `boolean` #### Returns[​](#returns-6 "Direct link to Returns") `boolean` #### Defined in[​](#defined-in-6 "Direct link to Defined in") [browser/sync/client.ts:662](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L662) *** ### clearAuth[​](#clearauth "Direct link to clearAuth") ▸ **clearAuth**(): `void` #### Returns[​](#returns-7 "Direct link to Returns") `void` #### Defined in[​](#defined-in-7 "Direct link to Defined in") [browser/sync/client.ts:672](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L672) *** ### subscribe[​](#subscribe "Direct link to subscribe") ▸ **subscribe**(`name`, `args?`, `options?`): `Object` Subscribe to a query function. Whenever this query's result changes, the `onTransition` callback passed into the constructor will be called. #### Parameters[​](#parameters-3 "Direct link to Parameters") | Name | Type | Description | | ---------- | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | | `name` | `string` | The name of the query. | | `args?` | `Record`<`string`, [`Value`](/api/modules/values.md#value)> | An arguments object for the query. If this is omitted, the arguments will be `{}`. | | `options?` | [`SubscribeOptions`](/api/interfaces/browser.SubscribeOptions.md) | A [SubscribeOptions](/api/interfaces/browser.SubscribeOptions.md) options object for this query. | #### Returns[​](#returns-8 "Direct link to Returns") `Object` An object containing a [QueryToken](/api/modules/browser.md#querytoken) corresponding to this query and an `unsubscribe` callback. | Name | Type | | ------------- | -------------------------------------------------- | | `queryToken` | [`QueryToken`](/api/modules/browser.md#querytoken) | | `unsubscribe` | () => `void` | #### Defined in[​](#defined-in-8 "Direct link to Defined in") [browser/sync/client.ts:691](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L691) *** ### localQueryResult[​](#localqueryresult "Direct link to localQueryResult") ▸ **localQueryResult**(`udfPath`, `args?`): `undefined` | [`Value`](/api/modules/values.md#value) A query result based only on the current, local state. The only way this will return a value is if we're already subscribed to the query or its value has been set optimistically. #### Parameters[​](#parameters-4 "Direct link to Parameters") | Name | Type | | --------- | ----------------------------------------------------------- | | `udfPath` | `string` | | `args?` | `Record`<`string`, [`Value`](/api/modules/values.md#value)> | #### Returns[​](#returns-9 "Direct link to Returns") `undefined` | [`Value`](/api/modules/values.md#value) #### Defined in[​](#defined-in-9 "Direct link to Defined in") [browser/sync/client.ts:724](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L724) *** ### queryJournal[​](#queryjournal "Direct link to queryJournal") ▸ **queryJournal**(`name`, `args?`): `undefined` | [`QueryJournal`](/api/modules/browser.md#queryjournal) Retrieve the current [QueryJournal](/api/modules/browser.md#queryjournal) for this query function. If we have not yet received a result for this query, this will be `undefined`. #### Parameters[​](#parameters-5 "Direct link to Parameters") | Name | Type | Description | | ------- | ----------------------------------------------------------- | ------------------------------------ | | `name` | `string` | The name of the query. | | `args?` | `Record`<`string`, [`Value`](/api/modules/values.md#value)> | The arguments object for this query. | #### Returns[​](#returns-10 "Direct link to Returns") `undefined` | [`QueryJournal`](/api/modules/browser.md#queryjournal) The query's [QueryJournal](/api/modules/browser.md#queryjournal) or `undefined`. #### Defined in[​](#defined-in-10 "Direct link to Defined in") [browser/sync/client.ts:777](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L777) *** ### connectionState[​](#connectionstate "Direct link to connectionState") ▸ **connectionState**(): [`ConnectionState`](/api/modules/browser.md#connectionstate) Get the current [ConnectionState](/api/modules/browser.md#connectionstate) between the client and the Convex backend. #### Returns[​](#returns-11 "Direct link to Returns") [`ConnectionState`](/api/modules/browser.md#connectionstate) The [ConnectionState](/api/modules/browser.md#connectionstate) with the Convex backend. #### Defined in[​](#defined-in-11 "Direct link to Defined in") [browser/sync/client.ts:792](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L792) *** ### subscribeToConnectionState[​](#subscribetoconnectionstate "Direct link to subscribeToConnectionState") ▸ **subscribeToConnectionState**(`cb`): () => `void` Subscribe to the [ConnectionState](/api/modules/browser.md#connectionstate) between the client and the Convex backend, calling a callback each time it changes. Subscribed callbacks will be called when any part of ConnectionState changes. ConnectionState may grow in future versions (e.g. to provide a array of inflight requests) in which case callbacks would be called more frequently. #### Parameters[​](#parameters-6 "Direct link to Parameters") | Name | Type | | ---- | ------------------------------------------------------------------------------------------- | | `cb` | (`connectionState`: [`ConnectionState`](/api/modules/browser.md#connectionstate)) => `void` | #### Returns[​](#returns-12 "Direct link to Returns") `fn` An unsubscribe function to stop listening. ▸ (): `void` Subscribe to the [ConnectionState](/api/modules/browser.md#connectionstate) between the client and the Convex backend, calling a callback each time it changes. Subscribed callbacks will be called when any part of ConnectionState changes. ConnectionState may grow in future versions (e.g. to provide a array of inflight requests) in which case callbacks would be called more frequently. ##### Returns[​](#returns-13 "Direct link to Returns") `void` An unsubscribe function to stop listening. #### Defined in[​](#defined-in-12 "Direct link to Defined in") [browser/sync/client.ts:838](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L838) *** ### mutation[​](#mutation "Direct link to mutation") ▸ **mutation**(`name`, `args?`, `options?`): `Promise`<`any`> Execute a mutation function. #### Parameters[​](#parameters-7 "Direct link to Parameters") | Name | Type | Description | | ---------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | | `name` | `string` | The name of the mutation. | | `args?` | `Record`<`string`, [`Value`](/api/modules/values.md#value)> | An arguments object for the mutation. If this is omitted, the arguments will be `{}`. | | `options?` | [`MutationOptions`](/api/interfaces/browser.MutationOptions.md) | A [MutationOptions](/api/interfaces/browser.MutationOptions.md) options object for this mutation. | #### Returns[​](#returns-14 "Direct link to Returns") `Promise`<`any`> * A promise of the mutation's result. #### Defined in[​](#defined-in-13 "Direct link to Defined in") [browser/sync/client.ts:858](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L858) *** ### action[​](#action "Direct link to action") ▸ **action**(`name`, `args?`): `Promise`<`any`> Execute an action function. #### Parameters[​](#parameters-8 "Direct link to Parameters") | Name | Type | Description | | ------- | ----------------------------------------------------------- | ----------------------------------------------------------------------------------- | | `name` | `string` | The name of the action. | | `args?` | `Record`<`string`, [`Value`](/api/modules/values.md#value)> | An arguments object for the action. If this is omitted, the arguments will be `{}`. | #### Returns[​](#returns-15 "Direct link to Returns") `Promise`<`any`> A promise of the action's result. #### Defined in[​](#defined-in-14 "Direct link to Defined in") [browser/sync/client.ts:979](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L979) *** ### close[​](#close "Direct link to close") ▸ **close**(): `Promise`<`void`> Close any network handles associated with this client and stop all subscriptions. Call this method when you're done with an [BaseConvexClient](/api/classes/browser.BaseConvexClient.md) to dispose of its sockets and resources. #### Returns[​](#returns-16 "Direct link to Returns") `Promise`<`void`> A `Promise` fulfilled when the connection has been completely closed. #### Defined in[​](#defined-in-15 "Direct link to Defined in") [browser/sync/client.ts:1026](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L1026) --- # Class: ConvexClient [browser](/api/modules/browser.md).ConvexClient Subscribes to Convex query functions and executes mutations and actions over a WebSocket. Optimistic updates for mutations are not provided for this client. Third party clients may choose to wrap [BaseConvexClient](/api/classes/browser.BaseConvexClient.md) for additional control. ``` const client = new ConvexClient("https://happy-otter-123.convex.cloud"); const unsubscribe = client.onUpdate(api.messages.list, {}, (messages) => { console.log(messages[0].body); }); ``` ## Constructors[​](#constructors "Direct link to Constructors") ### constructor[​](#constructor "Direct link to constructor") • **new ConvexClient**(`address`, `options?`) Construct a client and immediately initiate a WebSocket connection to the passed address. #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | --------- | -------------------------------------------------------------------- | | `address` | `string` | | `options` | [`ConvexClientOptions`](/api/modules/browser.md#convexclientoptions) | #### Defined in[​](#defined-in "Direct link to Defined in") [browser/simple\_client.ts:119](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L119) ## Accessors[​](#accessors "Direct link to Accessors") ### closed[​](#closed "Direct link to closed") • `get` **closed**(): `boolean` Once closed no registered callbacks will fire again. #### Returns[​](#returns "Direct link to Returns") `boolean` #### Defined in[​](#defined-in-1 "Direct link to Defined in") [browser/simple\_client.ts:96](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L96) *** ### client[​](#client "Direct link to client") • `get` **client**(): [`BaseConvexClient`](/api/classes/browser.BaseConvexClient.md) #### Returns[​](#returns-1 "Direct link to Returns") [`BaseConvexClient`](/api/classes/browser.BaseConvexClient.md) #### Defined in[​](#defined-in-2 "Direct link to Defined in") [browser/simple\_client.ts:99](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L99) *** ### disabled[​](#disabled "Direct link to disabled") • `get` **disabled**(): `boolean` #### Returns[​](#returns-2 "Direct link to Returns") `boolean` #### Defined in[​](#defined-in-3 "Direct link to Defined in") [browser/simple\_client.ts:110](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L110) ## Methods[​](#methods "Direct link to Methods") ### onUpdate[​](#onupdate "Direct link to onUpdate") ▸ **onUpdate**<`Query`>(`query`, `args`, `callback`, `onError?`): `Unsubscribe`<`Query`\[`"_returnType"`]> Call a callback whenever a new result for a query is received. The callback will run soon after being registered if a result for the query is already in memory. The return value is an Unsubscribe object which is both a function an an object with properties. Both of the patterns below work with this object: ``` // call the return value as a function const unsubscribe = client.onUpdate(api.messages.list, {}, (messages) => { console.log(messages); }); unsubscribe(); // unpack the return value into its properties const { getCurrentValue, unsubscribe, } = client.onUpdate(api.messages.list, {}, (messages) => { console.log(messages); }); ``` #### Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"query"`> | #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | Description | | ---------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | `query` | `Query` | A [FunctionReference](/api/modules/server.md#functionreference) for the public query to run. | | `args` | [`FunctionArgs`](/api/modules/server.md#functionargs)<`Query`> | The arguments to run the query with. | | `callback` | (`result`: [`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`>) => `unknown` | Function to call when the query result updates. | | `onError?` | (`e`: `Error`) => `unknown` | Function to call when the query result updates with an error. If not provided, errors will be thrown instead of calling the callback. | #### Returns[​](#returns-3 "Direct link to Returns") `Unsubscribe`<`Query`\[`"_returnType"`]> an Unsubscribe function to stop calling the onUpdate function. #### Defined in[​](#defined-in-4 "Direct link to Defined in") [browser/simple\_client.ts:185](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L185) *** ### onPaginatedUpdate\_experimental[​](#onpaginatedupdate_experimental "Direct link to onPaginatedUpdate_experimental") ▸ **onPaginatedUpdate\_experimental**<`Query`>(`query`, `args`, `options`, `callback`, `onError?`): `Unsubscribe`<`PaginatedQueryResult`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`>\[]>> Call a callback whenever a new result for a paginated query is received. This is an experimental preview: the final API may change. In particular, caching behavior, page splitting, and required paginated query options may change. #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"query"`> | #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | Description | | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | | `query` | `Query` | A [FunctionReference](/api/modules/server.md#functionreference) for the public query to run. | | `args` | [`FunctionArgs`](/api/modules/server.md#functionargs)<`Query`> | The arguments to run the query with. | | `options` | `Object` | Options for the paginated query including initialNumItems and id. | | `options.initialNumItems` | `number` | - | | `callback` | (`result`: [`PaginationResult`](/api/interfaces/server.PaginationResult.md)<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`>>) => `unknown` | Function to call when the query result updates. | | `onError?` | (`e`: `Error`) => `unknown` | Function to call when the query result updates with an error. | #### Returns[​](#returns-4 "Direct link to Returns") `Unsubscribe`<`PaginatedQueryResult`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`>\[]>> an Unsubscribe function to stop calling the callback. #### Defined in[​](#defined-in-5 "Direct link to Defined in") [browser/simple\_client.ts:263](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L263) *** ### close[​](#close "Direct link to close") ▸ **close**(): `Promise`<`void`> #### Returns[​](#returns-5 "Direct link to Returns") `Promise`<`void`> #### Defined in[​](#defined-in-6 "Direct link to Defined in") [browser/simple\_client.ts:366](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L366) *** ### getAuth[​](#getauth "Direct link to getAuth") ▸ **getAuth**(): `undefined` | { `token`: `string` ; `decoded`: `Record`<`string`, `any`> } Get the current JWT auth token and decoded claims. #### Returns[​](#returns-6 "Direct link to Returns") `undefined` | { `token`: `string` ; `decoded`: `Record`<`string`, `any`> } #### Defined in[​](#defined-in-7 "Direct link to Defined in") [browser/simple\_client.ts:380](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L380) *** ### setAuth[​](#setauth "Direct link to setAuth") ▸ **setAuth**(`fetchToken`, `onChange?`): `void` Set the authentication token to be used for subsequent queries and mutations. `fetchToken` will be called automatically again if a token expires. `fetchToken` should return `null` if the token cannot be retrieved, for example when the user's rights were permanently revoked. #### Parameters[​](#parameters-3 "Direct link to Parameters") | Name | Type | Description | | ------------ | -------------------------------------------------------------- | -------------------------------------------------------------------------------- | | `fetchToken` | [`AuthTokenFetcher`](/api/modules/browser.md#authtokenfetcher) | an async function returning the JWT (typically an OpenID Connect Identity Token) | | `onChange?` | (`isAuthenticated`: `boolean`) => `void` | a callback that will be called when the authentication status changes | #### Returns[​](#returns-7 "Direct link to Returns") `void` #### Defined in[​](#defined-in-8 "Direct link to Defined in") [browser/simple\_client.ts:393](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L393) *** ### mutation[​](#mutation "Direct link to mutation") ▸ **mutation**<`Mutation`>(`mutation`, `args`, `options?`): `Promise`<`Awaited`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Mutation`>>> Execute a mutation function. #### Type parameters[​](#type-parameters-2 "Direct link to Type parameters") | Name | Type | | ---------- | ------------------------------------------------------------------------------------- | | `Mutation` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"mutation"`> | #### Parameters[​](#parameters-4 "Direct link to Parameters") | Name | Type | Description | | ---------- | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | | `mutation` | `Mutation` | A [FunctionReference](/api/modules/server.md#functionreference) for the public mutation to run. | | `args` | [`FunctionArgs`](/api/modules/server.md#functionargs)<`Mutation`> | An arguments object for the mutation. | | `options?` | [`MutationOptions`](/api/interfaces/browser.MutationOptions.md) | A [MutationOptions](/api/interfaces/browser.MutationOptions.md) options object for the mutation. | #### Returns[​](#returns-8 "Direct link to Returns") `Promise`<`Awaited`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Mutation`>>> A promise of the mutation's result. #### Defined in[​](#defined-in-9 "Direct link to Defined in") [browser/simple\_client.ts:488](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L488) *** ### action[​](#action "Direct link to action") ▸ **action**<`Action`>(`action`, `args`): `Promise`<`Awaited`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Action`>>> Execute an action function. #### Type parameters[​](#type-parameters-3 "Direct link to Type parameters") | Name | Type | | -------- | ----------------------------------------------------------------------------------- | | `Action` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"action"`> | #### Parameters[​](#parameters-5 "Direct link to Parameters") | Name | Type | Description | | -------- | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | | `action` | `Action` | A [FunctionReference](/api/modules/server.md#functionreference) for the public action to run. | | `args` | [`FunctionArgs`](/api/modules/server.md#functionargs)<`Action`> | An arguments object for the action. | #### Returns[​](#returns-9 "Direct link to Returns") `Promise`<`Awaited`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Action`>>> A promise of the action's result. #### Defined in[​](#defined-in-10 "Direct link to Defined in") [browser/simple\_client.ts:505](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L505) *** ### query[​](#query "Direct link to query") ▸ **query**<`Query`>(`query`, `args`): `Promise`<`Awaited`<`Query`\[`"_returnType"`]>> Fetch a query result once. #### Type parameters[​](#type-parameters-4 "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"query"`> | #### Parameters[​](#parameters-6 "Direct link to Parameters") | Name | Type | Description | | ------- | ------------------- | -------------------------------------------------------------------------------------------- | | `query` | `Query` | A [FunctionReference](/api/modules/server.md#functionreference) for the public query to run. | | `args` | `Query`\[`"_args"`] | An arguments object for the query. | #### Returns[​](#returns-10 "Direct link to Returns") `Promise`<`Awaited`<`Query`\[`"_returnType"`]>> A promise of the query's result. #### Defined in[​](#defined-in-11 "Direct link to Defined in") [browser/simple\_client.ts:521](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L521) *** ### connectionState[​](#connectionstate "Direct link to connectionState") ▸ **connectionState**(): [`ConnectionState`](/api/modules/browser.md#connectionstate) Get the current [ConnectionState](/api/modules/browser.md#connectionstate) between the client and the Convex backend. #### Returns[​](#returns-11 "Direct link to Returns") [`ConnectionState`](/api/modules/browser.md#connectionstate) The [ConnectionState](/api/modules/browser.md#connectionstate) with the Convex backend. #### Defined in[​](#defined-in-12 "Direct link to Defined in") [browser/simple\_client.ts:553](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L553) *** ### subscribeToConnectionState[​](#subscribetoconnectionstate "Direct link to subscribeToConnectionState") ▸ **subscribeToConnectionState**(`cb`): () => `void` Subscribe to the [ConnectionState](/api/modules/browser.md#connectionstate) between the client and the Convex backend, calling a callback each time it changes. Subscribed callbacks will be called when any part of ConnectionState changes. ConnectionState may grow in future versions (e.g. to provide a array of inflight requests) in which case callbacks would be called more frequently. #### Parameters[​](#parameters-7 "Direct link to Parameters") | Name | Type | | ---- | ------------------------------------------------------------------------------------------- | | `cb` | (`connectionState`: [`ConnectionState`](/api/modules/browser.md#connectionstate)) => `void` | #### Returns[​](#returns-12 "Direct link to Returns") `fn` An unsubscribe function to stop listening. ▸ (): `void` Subscribe to the [ConnectionState](/api/modules/browser.md#connectionstate) between the client and the Convex backend, calling a callback each time it changes. Subscribed callbacks will be called when any part of ConnectionState changes. ConnectionState may grow in future versions (e.g. to provide a array of inflight requests) in which case callbacks would be called more frequently. ##### Returns[​](#returns-13 "Direct link to Returns") `void` An unsubscribe function to stop listening. #### Defined in[​](#defined-in-13 "Direct link to Defined in") [browser/simple\_client.ts:568](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L568) --- # Class: ConvexHttpClient [browser](/api/modules/browser.md).ConvexHttpClient A Convex client that runs queries and mutations over HTTP. This client is stateful (it has user credentials and queues mutations) so take care to avoid sharing it between requests in a server. This is appropriate for server-side code (like Netlify Lambdas) or non-reactive webapps. ## Constructors[​](#constructors "Direct link to Constructors") ### constructor[​](#constructor "Direct link to constructor") • **new ConvexHttpClient**(`address`, `options?`) Create a new [ConvexHttpClient](/api/classes/browser.ConvexHttpClient.md). #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | Description | | --------------------------------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `address` | `string` | The url of your Convex deployment, often provided by an environment variable. E.g. `https://small-mouse-123.convex.cloud`. | | `options?` | `Object` | An object of options. - `skipConvexDeploymentUrlCheck` - 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. - `logger` - A logger or a boolean. If not provided, logs to the console. You can construct your own logger to customize logging to log elsewhere or not log at all, or use `false` as a shorthand for a no-op logger. A logger is an object with 4 methods: log(), warn(), error(), and logVerbose(). These methods can receive multiple arguments of any types, like console.log(). - `auth` - A JWT containing identity claims accessible in Convex functions. This identity may expire so it may be necessary to call `setAuth()` later, but for short-lived clients it's convenient to specify this value here. | | `options.skipConvexDeploymentUrlCheck?` | `boolean` | - | | `options.logger?` | `boolean` \| `Logger` | - | | `options.auth?` | `string` | - | #### Defined in[​](#defined-in "Direct link to Defined in") [browser/http\_client.ts:95](https://github.com/get-convex/convex-js/blob/main/src/browser/http_client.ts#L95) ## Accessors[​](#accessors "Direct link to Accessors") ### url[​](#url "Direct link to url") • `get` **url**(): `string` Return the address for this client, useful for creating a new client. Not guaranteed to match the address with which this client was constructed: it may be canonicalized. #### Returns[​](#returns "Direct link to Returns") `string` #### Defined in[​](#defined-in-1 "Direct link to Defined in") [browser/http\_client.ts:143](https://github.com/get-convex/convex-js/blob/main/src/browser/http_client.ts#L143) ## Methods[​](#methods "Direct link to Methods") ### backendUrl[​](#backendurl "Direct link to backendUrl") ▸ **backendUrl**(): `string` Obtain the [ConvexHttpClient](/api/classes/browser.ConvexHttpClient.md)'s URL to its backend. **`Deprecated`** Use url, which returns the url without /api at the end. #### Returns[​](#returns-1 "Direct link to Returns") `string` The URL to the Convex backend, including the client's API version. #### Defined in[​](#defined-in-2 "Direct link to Defined in") [browser/http\_client.ts:133](https://github.com/get-convex/convex-js/blob/main/src/browser/http_client.ts#L133) *** ### setAuth[​](#setauth "Direct link to setAuth") ▸ **setAuth**(`value`): `void` Set the authentication token to be used for subsequent queries and mutations. Should be called whenever the token changes (i.e. due to expiration and refresh). #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | Description | | ------- | -------- | ------------------------------------------ | | `value` | `string` | JWT-encoded OpenID Connect identity token. | #### Returns[​](#returns-2 "Direct link to Returns") `void` #### Defined in[​](#defined-in-3 "Direct link to Defined in") [browser/http\_client.ts:154](https://github.com/get-convex/convex-js/blob/main/src/browser/http_client.ts#L154) *** ### clearAuth[​](#clearauth "Direct link to clearAuth") ▸ **clearAuth**(): `void` Clear the current authentication token if set. #### Returns[​](#returns-3 "Direct link to Returns") `void` #### Defined in[​](#defined-in-4 "Direct link to Defined in") [browser/http\_client.ts:180](https://github.com/get-convex/convex-js/blob/main/src/browser/http_client.ts#L180) *** ### consistentQuery[​](#consistentquery "Direct link to consistentQuery") ▸ **consistentQuery**<`Query`>(`query`, `...args`): `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`>> This API is experimental: it may change or disappear. Execute a Convex query function at the same timestamp as every other consistent query execution run by this HTTP client. This doesn't make sense for long-lived ConvexHttpClients as Convex backends can read a limited amount into the past: beyond 30 seconds in the past may not be available. Create a new client to use a consistent time. **`Deprecated`** This API is experimental: it may change or disappear. #### Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"query"`> | #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | Description | | --------- | ---------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | | `query` | `Query` | - | | `...args` | [`OptionalRestArgs`](/api/modules/server.md#optionalrestargs)<`Query`> | The arguments object for the query. If this is omitted, the arguments will be `{}`. | #### Returns[​](#returns-4 "Direct link to Returns") `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`>> A promise of the query's result. #### Defined in[​](#defined-in-5 "Direct link to Defined in") [browser/http\_client.ts:222](https://github.com/get-convex/convex-js/blob/main/src/browser/http_client.ts#L222) *** ### query[​](#query "Direct link to query") ▸ **query**<`Query`>(`query`, `...args`): `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`>> Execute a Convex query function. #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"query"`> | #### Parameters[​](#parameters-3 "Direct link to Parameters") | Name | Type | Description | | --------- | ---------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | | `query` | `Query` | - | | `...args` | [`OptionalRestArgs`](/api/modules/server.md#optionalrestargs)<`Query`> | The arguments object for the query. If this is omitted, the arguments will be `{}`. | #### Returns[​](#returns-5 "Direct link to Returns") `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`>> A promise of the query's result. #### Defined in[​](#defined-in-6 "Direct link to Defined in") [browser/http\_client.ts:266](https://github.com/get-convex/convex-js/blob/main/src/browser/http_client.ts#L266) *** ### mutation[​](#mutation "Direct link to mutation") ▸ **mutation**<`Mutation`>(`mutation`, `...args`): `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Mutation`>> Execute a Convex mutation function. Mutations are queued by default. #### Type parameters[​](#type-parameters-2 "Direct link to Type parameters") | Name | Type | | ---------- | ------------------------------------------------------------------------------------- | | `Mutation` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"mutation"`> | #### Parameters[​](#parameters-4 "Direct link to Parameters") | Name | Type | Description | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | | `mutation` | `Mutation` | - | | `...args` | [`ArgsAndOptions`](/api/modules/server.md#argsandoptions)<`Mutation`, [`HttpMutationOptions`](/api/modules/browser.md#httpmutationoptions)> | The arguments object for the mutation. If this is omitted, the arguments will be `{}`. | #### Returns[​](#returns-6 "Direct link to Returns") `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Mutation`>> A promise of the mutation's result. #### Defined in[​](#defined-in-7 "Direct link to Defined in") [browser/http\_client.ts:426](https://github.com/get-convex/convex-js/blob/main/src/browser/http_client.ts#L426) *** ### action[​](#action "Direct link to action") ▸ **action**<`Action`>(`action`, `...args`): `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Action`>> Execute a Convex action function. Actions are not queued. #### Type parameters[​](#type-parameters-3 "Direct link to Type parameters") | Name | Type | | -------- | ----------------------------------------------------------------------------------- | | `Action` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"action"`> | #### Parameters[​](#parameters-5 "Direct link to Parameters") | Name | Type | Description | | --------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | | `action` | `Action` | - | | `...args` | [`OptionalRestArgs`](/api/modules/server.md#optionalrestargs)<`Action`> | The arguments object for the action. If this is omitted, the arguments will be `{}`. | #### Returns[​](#returns-7 "Direct link to Returns") `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Action`>> A promise of the action's result. #### Defined in[​](#defined-in-8 "Direct link to Defined in") [browser/http\_client.ts:449](https://github.com/get-convex/convex-js/blob/main/src/browser/http_client.ts#L449) --- # Class: ConvexReactClient [react](/api/modules/react.md).ConvexReactClient A Convex client for use within React. This loads reactive queries and executes mutations over a WebSocket. ## Constructors[​](#constructors "Direct link to Constructors") ### constructor[​](#constructor "Direct link to constructor") • **new ConvexReactClient**(`address`, `options?`) #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | Description | | ---------- | ------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | | `address` | `string` | The url of your Convex deployment, often provided by an environment variable. E.g. `https://small-mouse-123.convex.cloud`. | | `options?` | [`ConvexReactClientOptions`](/api/interfaces/react.ConvexReactClientOptions.md) | See [ConvexReactClientOptions](/api/interfaces/react.ConvexReactClientOptions.md) for a full description. | #### Defined in[​](#defined-in "Direct link to Defined in") [react/client.ts:317](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L317) ## Accessors[​](#accessors "Direct link to Accessors") ### url[​](#url "Direct link to url") • `get` **url**(): `string` Return the address for this client, useful for creating a new client. Not guaranteed to match the address with which this client was constructed: it may be canonicalized. #### Returns[​](#returns "Direct link to Returns") `string` #### Defined in[​](#defined-in-1 "Direct link to Defined in") [react/client.ts:352](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L352) *** ### logger[​](#logger "Direct link to logger") • `get` **logger**(): `Logger` Get the logger for this client. #### Returns[​](#returns-1 "Direct link to Returns") `Logger` The Logger for this client. #### Defined in[​](#defined-in-2 "Direct link to Defined in") [react/client.ts:713](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L713) ## Methods[​](#methods "Direct link to Methods") ### setAuth[​](#setauth "Direct link to setAuth") ▸ **setAuth**(`fetchToken`, `onChange?`): `void` Set the authentication token to be used for subsequent queries and mutations. `fetchToken` will be called automatically again if a token expires. `fetchToken` should return `null` if the token cannot be retrieved, for example when the user's rights were permanently revoked. #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | Description | | ------------ | -------------------------------------------------------------- | ------------------------------------------------------------------------- | | `fetchToken` | [`AuthTokenFetcher`](/api/modules/browser.md#authtokenfetcher) | an async function returning the JWT-encoded OpenID Connect Identity Token | | `onChange?` | (`isAuthenticated`: `boolean`) => `void` | a callback that will be called when the authentication status changes | #### Returns[​](#returns-2 "Direct link to Returns") `void` #### Defined in[​](#defined-in-3 "Direct link to Defined in") [react/client.ts:408](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L408) *** ### clearAuth[​](#clearauth "Direct link to clearAuth") ▸ **clearAuth**(): `void` Clear the current authentication token if set. #### Returns[​](#returns-3 "Direct link to Returns") `void` #### Defined in[​](#defined-in-4 "Direct link to Defined in") [react/client.ts:430](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L430) *** ### watchQuery[​](#watchquery "Direct link to watchQuery") ▸ **watchQuery**<`Query`>(`query`, `...argsAndOptions`): [`Watch`](/api/interfaces/react.Watch.md)<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`>> Construct a new [Watch](/api/interfaces/react.Watch.md) on a Convex query function. **Most application code should not call this method directly. Instead use the [useQuery](/api/modules/react.md#usequery) hook.** The act of creating a watch does nothing, a Watch is stateless. #### Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"query"`> | #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | Description | | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | | `query` | `Query` | A [FunctionReference](/api/modules/server.md#functionreference) for the public query to run. | | `...argsAndOptions` | [`ArgsAndOptions`](/api/modules/server.md#argsandoptions)<`Query`, [`WatchQueryOptions`](/api/interfaces/react.WatchQueryOptions.md)> | - | #### Returns[​](#returns-4 "Direct link to Returns") [`Watch`](/api/interfaces/react.Watch.md)<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`>> The [Watch](/api/interfaces/react.Watch.md) object. #### Defined in[​](#defined-in-5 "Direct link to Defined in") [react/client.ts:463](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L463) *** ### prewarmQuery[​](#prewarmquery "Direct link to prewarmQuery") ▸ **prewarmQuery**<`Query`>(`queryOptions`): `void` Indicates likely future interest in a query subscription. The implementation currently immediately subscribes to a query. In the future this method may prioritize some queries over others, fetch the query result without subscribing, or do nothing in slow network connections or high load scenarios. To use this in a React component, call useQuery() and ignore the return value. #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"query"`> | #### Parameters[​](#parameters-3 "Direct link to Parameters") | Name | Type | Description | | -------------- | ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | | `queryOptions` | `ConvexQueryOptions`<`Query`> & { `extendSubscriptionFor?`: `number` } | A query (function reference from an api object) and its args, plus an optional extendSubscriptionFor for how long to subscribe to the query. | #### Returns[​](#returns-5 "Direct link to Returns") `void` #### Defined in[​](#defined-in-6 "Direct link to Defined in") [react/client.ts:539](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L539) *** ### mutation[​](#mutation "Direct link to mutation") ▸ **mutation**<`Mutation`>(`mutation`, `...argsAndOptions`): `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Mutation`>> Execute a mutation function. #### Type parameters[​](#type-parameters-2 "Direct link to Type parameters") | Name | Type | | ---------- | ------------------------------------------------------------------------------------- | | `Mutation` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"mutation"`> | #### Parameters[​](#parameters-4 "Direct link to Parameters") | Name | Type | Description | | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | | `mutation` | `Mutation` | A [FunctionReference](/api/modules/server.md#functionreference) for the public mutation to run. | | `...argsAndOptions` | [`ArgsAndOptions`](/api/modules/server.md#argsandoptions)<`Mutation`, [`MutationOptions`](/api/interfaces/react.MutationOptions.md)<[`FunctionArgs`](/api/modules/server.md#functionargs)<`Mutation`>>> | - | #### Returns[​](#returns-6 "Direct link to Returns") `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Mutation`>> A promise of the mutation's result. #### Defined in[​](#defined-in-7 "Direct link to Defined in") [react/client.ts:618](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L618) *** ### action[​](#action "Direct link to action") ▸ **action**<`Action`>(`action`, `...args`): `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Action`>> Execute an action function. #### Type parameters[​](#type-parameters-3 "Direct link to Type parameters") | Name | Type | | -------- | ----------------------------------------------------------------------------------- | | `Action` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"action"`> | #### Parameters[​](#parameters-5 "Direct link to Parameters") | Name | Type | Description | | --------- | ----------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | | `action` | `Action` | A [FunctionReference](/api/modules/server.md#functionreference) for the public action to run. | | `...args` | [`OptionalRestArgs`](/api/modules/server.md#optionalrestargs)<`Action`> | An arguments object for the action. If this is omitted, the arguments will be `{}`. | #### Returns[​](#returns-7 "Direct link to Returns") `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Action`>> A promise of the action's result. #### Defined in[​](#defined-in-8 "Direct link to Defined in") [react/client.ts:639](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L639) *** ### query[​](#query "Direct link to query") ▸ **query**<`Query`>(`query`, `...args`): `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`>> Fetch a query result once. **Most application code should subscribe to queries instead, using the [useQuery](/api/modules/react.md#usequery) hook.** #### Type parameters[​](#type-parameters-4 "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"query"`> | #### Parameters[​](#parameters-6 "Direct link to Parameters") | Name | Type | Description | | --------- | ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | | `query` | `Query` | A [FunctionReference](/api/modules/server.md#functionreference) for the public query to run. | | `...args` | [`OptionalRestArgs`](/api/modules/server.md#optionalrestargs)<`Query`> | An arguments object for the query. If this is omitted, the arguments will be `{}`. | #### Returns[​](#returns-8 "Direct link to Returns") `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`>> A promise of the query's result. #### Defined in[​](#defined-in-9 "Direct link to Defined in") [react/client.ts:659](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L659) *** ### connectionState[​](#connectionstate "Direct link to connectionState") ▸ **connectionState**(): [`ConnectionState`](/api/modules/browser.md#connectionstate) Get the current [ConnectionState](/api/modules/browser.md#connectionstate) between the client and the Convex backend. #### Returns[​](#returns-9 "Direct link to Returns") [`ConnectionState`](/api/modules/browser.md#connectionstate) The [ConnectionState](/api/modules/browser.md#connectionstate) with the Convex backend. #### Defined in[​](#defined-in-10 "Direct link to Defined in") [react/client.ts:686](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L686) *** ### subscribeToConnectionState[​](#subscribetoconnectionstate "Direct link to subscribeToConnectionState") ▸ **subscribeToConnectionState**(`cb`): () => `void` Subscribe to the [ConnectionState](/api/modules/browser.md#connectionstate) between the client and the Convex backend, calling a callback each time it changes. Subscribed callbacks will be called when any part of ConnectionState changes. ConnectionState may grow in future versions (e.g. to provide a array of inflight requests) in which case callbacks would be called more frequently. ConnectionState may also *lose* properties in future versions as we figure out what information is most useful. As such this API is considered unstable. #### Parameters[​](#parameters-7 "Direct link to Parameters") | Name | Type | | ---- | ------------------------------------------------------------------------------------------- | | `cb` | (`connectionState`: [`ConnectionState`](/api/modules/browser.md#connectionstate)) => `void` | #### Returns[​](#returns-10 "Direct link to Returns") `fn` An unsubscribe function to stop listening. ▸ (): `void` Subscribe to the [ConnectionState](/api/modules/browser.md#connectionstate) between the client and the Convex backend, calling a callback each time it changes. Subscribed callbacks will be called when any part of ConnectionState changes. ConnectionState may grow in future versions (e.g. to provide a array of inflight requests) in which case callbacks would be called more frequently. ConnectionState may also *lose* properties in future versions as we figure out what information is most useful. As such this API is considered unstable. ##### Returns[​](#returns-11 "Direct link to Returns") `void` An unsubscribe function to stop listening. #### Defined in[​](#defined-in-11 "Direct link to Defined in") [react/client.ts:702](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L702) *** ### close[​](#close "Direct link to close") ▸ **close**(): `Promise`<`void`> Close any network handles associated with this client and stop all subscriptions. Call this method when you're done with a [ConvexReactClient](/api/classes/react.ConvexReactClient.md) to dispose of its sockets and resources. #### Returns[​](#returns-12 "Direct link to Returns") `Promise`<`void`> A `Promise` fulfilled when the connection has been completely closed. #### Defined in[​](#defined-in-12 "Direct link to Defined in") [react/client.ts:725](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L725) --- # Class: Crons [server](/api/modules/server.md).Crons A class for scheduling cron jobs. To learn more see the documentation at ## Constructors[​](#constructors "Direct link to Constructors") ### constructor[​](#constructor "Direct link to constructor") • **new Crons**() #### Defined in[​](#defined-in "Direct link to Defined in") [server/cron.ts:246](https://github.com/get-convex/convex-js/blob/main/src/server/cron.ts#L246) ## Properties[​](#properties "Direct link to Properties") ### crons[​](#crons "Direct link to crons") • **crons**: `Record`<`string`, [`CronJob`](/api/interfaces/server.CronJob.md)> #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/cron.ts:244](https://github.com/get-convex/convex-js/blob/main/src/server/cron.ts#L244) *** ### isCrons[​](#iscrons "Direct link to isCrons") • **isCrons**: `true` #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/cron.ts:245](https://github.com/get-convex/convex-js/blob/main/src/server/cron.ts#L245) ## Methods[​](#methods "Direct link to Methods") ### interval[​](#interval "Direct link to interval") ▸ **interval**<`FuncRef`>(`cronIdentifier`, `schedule`, `functionReference`, `...args`): `void` Schedule a mutation or action to run at some interval. ``` crons.interval("Clear presence data", {seconds: 30}, api.presence.clear); ``` #### Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | --------- | --------------------------------------------------------------------------------------------- | | `FuncRef` | extends [`SchedulableFunctionReference`](/api/modules/server.md#schedulablefunctionreference) | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | Description | | ------------------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------- | | `cronIdentifier` | `string` | - | | `schedule` | `Interval` | The time between runs for this scheduled job. | | `functionReference` | `FuncRef` | A [FunctionReference](/api/modules/server.md#functionreference) for the function to schedule. | | `...args` | [`OptionalRestArgs`](/api/modules/server.md#optionalrestargs)<`FuncRef`> | The arguments to the function. | #### Returns[​](#returns "Direct link to Returns") `void` #### Defined in[​](#defined-in-3 "Direct link to Defined in") [server/cron.ts:283](https://github.com/get-convex/convex-js/blob/main/src/server/cron.ts#L283) *** ### hourly[​](#hourly "Direct link to hourly") ▸ **hourly**<`FuncRef`>(`cronIdentifier`, `schedule`, `functionReference`, `...args`): `void` Schedule a mutation or action to run on an hourly basis. ``` crons.hourly( "Reset high scores", { minuteUTC: 30, }, api.scores.reset ) ``` #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | --------- | --------------------------------------------------------------------------------------------- | | `FuncRef` | extends [`SchedulableFunctionReference`](/api/modules/server.md#schedulablefunctionreference) | #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | Description | | ------------------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------- | | `cronIdentifier` | `string` | A unique name for this scheduled job. | | `schedule` | `Hourly` | What time (UTC) each day to run this function. | | `functionReference` | `FuncRef` | A [FunctionReference](/api/modules/server.md#functionreference) for the function to schedule. | | `...args` | [`OptionalRestArgs`](/api/modules/server.md#optionalrestargs)<`FuncRef`> | The arguments to the function. | #### Returns[​](#returns-1 "Direct link to Returns") `void` #### Defined in[​](#defined-in-4 "Direct link to Defined in") [server/cron.ts:331](https://github.com/get-convex/convex-js/blob/main/src/server/cron.ts#L331) *** ### daily[​](#daily "Direct link to daily") ▸ **daily**<`FuncRef`>(`cronIdentifier`, `schedule`, `functionReference`, `...args`): `void` Schedule a mutation or action to run on a daily basis. ``` crons.daily( "Reset high scores", { hourUTC: 17, // (9:30am Pacific/10:30am Daylight Savings Pacific) minuteUTC: 30, }, api.scores.reset ) ``` #### Type parameters[​](#type-parameters-2 "Direct link to Type parameters") | Name | Type | | --------- | --------------------------------------------------------------------------------------------- | | `FuncRef` | extends [`SchedulableFunctionReference`](/api/modules/server.md#schedulablefunctionreference) | #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | Description | | ------------------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------- | | `cronIdentifier` | `string` | A unique name for this scheduled job. | | `schedule` | `Daily` | What time (UTC) each day to run this function. | | `functionReference` | `FuncRef` | A [FunctionReference](/api/modules/server.md#functionreference) for the function to schedule. | | `...args` | [`OptionalRestArgs`](/api/modules/server.md#optionalrestargs)<`FuncRef`> | The arguments to the function. | #### Returns[​](#returns-2 "Direct link to Returns") `void` #### Defined in[​](#defined-in-5 "Direct link to Defined in") [server/cron.ts:366](https://github.com/get-convex/convex-js/blob/main/src/server/cron.ts#L366) *** ### weekly[​](#weekly "Direct link to weekly") ▸ **weekly**<`FuncRef`>(`cronIdentifier`, `schedule`, `functionReference`, `...args`): `void` Schedule a mutation or action to run on a weekly basis. ``` crons.weekly( "Weekly re-engagement email", { dayOfWeek: "Tuesday", hourUTC: 17, // (9:30am Pacific/10:30am Daylight Savings Pacific) minuteUTC: 30, }, api.emails.send ) ``` #### Type parameters[​](#type-parameters-3 "Direct link to Type parameters") | Name | Type | | --------- | --------------------------------------------------------------------------------------------- | | `FuncRef` | extends [`SchedulableFunctionReference`](/api/modules/server.md#schedulablefunctionreference) | #### Parameters[​](#parameters-3 "Direct link to Parameters") | Name | Type | Description | | ------------------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------- | | `cronIdentifier` | `string` | A unique name for this scheduled job. | | `schedule` | `Weekly` | What day and time (UTC) each week to run this function. | | `functionReference` | `FuncRef` | A [FunctionReference](/api/modules/server.md#functionreference) for the function to schedule. | | `...args` | [`OptionalRestArgs`](/api/modules/server.md#optionalrestargs)<`FuncRef`> | - | #### Returns[​](#returns-3 "Direct link to Returns") `void` #### Defined in[​](#defined-in-6 "Direct link to Defined in") [server/cron.ts:402](https://github.com/get-convex/convex-js/blob/main/src/server/cron.ts#L402) *** ### monthly[​](#monthly "Direct link to monthly") ▸ **monthly**<`FuncRef`>(`cronIdentifier`, `schedule`, `functionReference`, `...args`): `void` Schedule a mutation or action to run on a monthly basis. Note that some months have fewer days than others, so e.g. a function scheduled to run on the 30th will not run in February. ``` crons.monthly( "Bill customers at ", { hourUTC: 17, // (9:30am Pacific/10:30am Daylight Savings Pacific) minuteUTC: 30, day: 1, }, api.billing.billCustomers ) ``` #### Type parameters[​](#type-parameters-4 "Direct link to Type parameters") | Name | Type | | --------- | --------------------------------------------------------------------------------------------- | | `FuncRef` | extends [`SchedulableFunctionReference`](/api/modules/server.md#schedulablefunctionreference) | #### Parameters[​](#parameters-4 "Direct link to Parameters") | Name | Type | Description | | ------------------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------- | | `cronIdentifier` | `string` | A unique name for this scheduled job. | | `schedule` | `Monthly` | What day and time (UTC) each month to run this function. | | `functionReference` | `FuncRef` | A [FunctionReference](/api/modules/server.md#functionreference) for the function to schedule. | | `...args` | [`OptionalRestArgs`](/api/modules/server.md#optionalrestargs)<`FuncRef`> | The arguments to the function. | #### Returns[​](#returns-4 "Direct link to Returns") `void` #### Defined in[​](#defined-in-7 "Direct link to Defined in") [server/cron.ts:443](https://github.com/get-convex/convex-js/blob/main/src/server/cron.ts#L443) *** ### cron[​](#cron "Direct link to cron") ▸ **cron**<`FuncRef`>(`cronIdentifier`, `cron`, `functionReference`, `...args`): `void` Schedule a mutation or action to run on a recurring basis. Like the unix command `cron`, Sunday is 0, Monday is 1, etc. ``` ┌─ minute (0 - 59) │ ┌─ hour (0 - 23) │ │ ┌─ day of the month (1 - 31) │ │ │ ┌─ month (1 - 12) │ │ │ │ ┌─ day of the week (0 - 6) (Sunday to Saturday) "* * * * *" ``` #### Type parameters[​](#type-parameters-5 "Direct link to Type parameters") | Name | Type | | --------- | --------------------------------------------------------------------------------------------- | | `FuncRef` | extends [`SchedulableFunctionReference`](/api/modules/server.md#schedulablefunctionreference) | #### Parameters[​](#parameters-5 "Direct link to Parameters") | Name | Type | Description | | ------------------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------- | | `cronIdentifier` | `string` | A unique name for this scheduled job. | | `cron` | `string` | Cron string like `"15 7 * * *"` (Every day at 7:15 UTC) | | `functionReference` | `FuncRef` | A [FunctionReference](/api/modules/server.md#functionreference) for the function to schedule. | | `...args` | [`OptionalRestArgs`](/api/modules/server.md#optionalrestargs)<`FuncRef`> | The arguments to the function. | #### Returns[​](#returns-5 "Direct link to Returns") `void` #### Defined in[​](#defined-in-8 "Direct link to Defined in") [server/cron.ts:480](https://github.com/get-convex/convex-js/blob/main/src/server/cron.ts#L480) --- # Class: Expression\ [server](/api/modules/server.md).Expression Expressions are evaluated to produce a [Value](/api/modules/values.md#value) in the course of executing a query. To construct an expression, use the [FilterBuilder](/api/interfaces/server.FilterBuilder.md) provided within [filter](/api/interfaces/server.OrderedQuery.md#filter). ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | Description | | ---- | -------------------------------------------------------------- | ------------------------------------------- | | `T` | extends [`Value`](/api/modules/values.md#value) \| `undefined` | The type that this expression evaluates to. | --- # Class: FilterExpression\ [server](/api/modules/server.md).FilterExpression Expressions are evaluated to produce a [Value](/api/modules/values.md#value) in the course of executing a query. To construct an expression, use the [VectorFilterBuilder](/api/interfaces/server.VectorFilterBuilder.md) provided within [VectorSearchQuery](/api/interfaces/server.VectorSearchQuery.md). ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | Description | | ---- | -------------------------------------------------------------- | ------------------------------------------- | | `T` | extends [`Value`](/api/modules/values.md#value) \| `undefined` | The type that this expression evaluates to. | --- # Class: HttpRouter [server](/api/modules/server.md).HttpRouter HTTP router for specifying the paths and methods of [httpActionGeneric](/api/modules/server.md#httpactiongeneric)s An example `convex/http.js` file might look like this. ``` import { httpRouter } from "convex/server"; import { getMessagesByAuthor } from "./getMessagesByAuthor"; import { httpAction } from "./_generated/server"; const http = httpRouter(); // HTTP actions can be defined inline... http.route({ path: "/message", method: "POST", handler: httpAction(async ({ runMutation }, request) => { const { author, body } = await request.json(); await runMutation(api.sendMessage.default, { body, author }); return new Response(null, { status: 200, }); }) }); // ...or they can be imported from other files. http.route({ path: "/getMessagesByAuthor", method: "GET", handler: getMessagesByAuthor, }); // Convex expects the router to be the default export of `convex/http.js`. export default http; ``` ## Constructors[​](#constructors "Direct link to Constructors") ### constructor[​](#constructor "Direct link to constructor") • **new HttpRouter**() ## Properties[​](#properties "Direct link to Properties") ### exactRoutes[​](#exactroutes "Direct link to exactRoutes") • **exactRoutes**: `Map`<`string`, `Map`<`"GET"` | `"POST"` | `"PUT"` | `"DELETE"` | `"OPTIONS"` | `"PATCH"`, [`PublicHttpAction`](/api/modules/server.md#publichttpaction)>> #### Defined in[​](#defined-in "Direct link to Defined in") [server/router.ts:143](https://github.com/get-convex/convex-js/blob/main/src/server/router.ts#L143) *** ### prefixRoutes[​](#prefixroutes "Direct link to prefixRoutes") • **prefixRoutes**: `Map`<`"GET"` | `"POST"` | `"PUT"` | `"DELETE"` | `"OPTIONS"` | `"PATCH"`, `Map`<`string`, [`PublicHttpAction`](/api/modules/server.md#publichttpaction)>> #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/router.ts:144](https://github.com/get-convex/convex-js/blob/main/src/server/router.ts#L144) *** ### isRouter[​](#isrouter "Direct link to isRouter") • **isRouter**: `true` #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/router.ts:145](https://github.com/get-convex/convex-js/blob/main/src/server/router.ts#L145) ## Methods[​](#methods "Direct link to Methods") ### route[​](#route "Direct link to route") ▸ **route**(`spec`): `void` Specify an HttpAction to be used to respond to requests for an HTTP method (e.g. "GET") and a path or pathPrefix. Paths must begin with a slash. Path prefixes must also end in a slash. ``` // matches `/profile` (but not `/profile/`) http.route({ path: "/profile", method: "GET", handler: getProfile}) // matches `/profiles/`, `/profiles/abc`, and `/profiles/a/c/b` (but not `/profile`) http.route({ pathPrefix: "/profile/", method: "GET", handler: getProfile}) ``` #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | ------ | ----------------------------------------------- | | `spec` | [`RouteSpec`](/api/modules/server.md#routespec) | #### Returns[​](#returns "Direct link to Returns") `void` #### Defined in[​](#defined-in-3 "Direct link to Defined in") [server/router.ts:161](https://github.com/get-convex/convex-js/blob/main/src/server/router.ts#L161) *** ### getRoutes[​](#getroutes "Direct link to getRoutes") ▸ **getRoutes**(): readonly \[`string`, `"GET"` | `"POST"` | `"PUT"` | `"DELETE"` | `"OPTIONS"` | `"PATCH"`, [`PublicHttpAction`](/api/modules/server.md#publichttpaction)]\[] Returns a list of routed HTTP actions. These are used to populate the list of routes shown in the Functions page of the Convex dashboard. #### Returns[​](#returns-1 "Direct link to Returns") readonly \[`string`, `"GET"` | `"POST"` | `"PUT"` | `"DELETE"` | `"OPTIONS"` | `"PATCH"`, [`PublicHttpAction`](/api/modules/server.md#publichttpaction)]\[] * an array of \[path, method, endpoint] tuples. #### Defined in[​](#defined-in-4 "Direct link to Defined in") [server/router.ts:229](https://github.com/get-convex/convex-js/blob/main/src/server/router.ts#L229) *** ### lookup[​](#lookup "Direct link to lookup") ▸ **lookup**(`path`, `method`): `null` | readonly \[[`PublicHttpAction`](/api/modules/server.md#publichttpaction), `"GET"` | `"POST"` | `"PUT"` | `"DELETE"` | `"OPTIONS"` | `"PATCH"`, `string`] Returns the appropriate HTTP action and its routed request path and method. The path and method returned are used for logging and metrics, and should match up with one of the routes returned by `getRoutes`. For example, ``` http.route({ pathPrefix: "/profile/", method: "GET", handler: getProfile}); http.lookup("/profile/abc", "GET") // returns [getProfile, "GET", "/profile/*"] ``` #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | | -------- | ------------------------------------------------------------------------------------ | | `path` | `string` | | `method` | `"GET"` \| `"POST"` \| `"PUT"` \| `"DELETE"` \| `"OPTIONS"` \| `"PATCH"` \| `"HEAD"` | #### Returns[​](#returns-2 "Direct link to Returns") `null` | readonly \[[`PublicHttpAction`](/api/modules/server.md#publichttpaction), `"GET"` | `"POST"` | `"PUT"` | `"DELETE"` | `"OPTIONS"` | `"PATCH"`, `string`] * a tuple \[[PublicHttpAction](/api/modules/server.md#publichttpaction), method, path] or null. #### Defined in[​](#defined-in-5 "Direct link to Defined in") [server/router.ts:275](https://github.com/get-convex/convex-js/blob/main/src/server/router.ts#L275) *** ### runRequest[​](#runrequest "Direct link to runRequest") ▸ **runRequest**(`argsStr`, `requestRoute`): `Promise`<`string`> Given a JSON string representation of a Request object, return a Response by routing the request and running the appropriate endpoint or returning a 404 Response. #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | Description | | -------------- | -------- | -------------------------------------------- | | `argsStr` | `string` | a JSON string representing a Request object. | | `requestRoute` | `string` | - | #### Returns[​](#returns-3 "Direct link to Returns") `Promise`<`string`> * a Response object. #### Defined in[​](#defined-in-6 "Direct link to Defined in") [server/router.ts:304](https://github.com/get-convex/convex-js/blob/main/src/server/router.ts#L304) --- # Class: IndexRange [server](/api/modules/server.md).IndexRange An expression representing an index range created by [IndexRangeBuilder](/api/interfaces/server.IndexRangeBuilder.md). --- # Class: SchemaDefinition\ [server](/api/modules/server.md).SchemaDefinition The definition of a Convex project schema. This should be produced by using [defineSchema](/api/modules/server.md#defineschema). ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ------------------ | --------------------------------------------------------------- | | `Schema` | extends [`GenericSchema`](/api/modules/server.md#genericschema) | | `StrictTableTypes` | extends `boolean` | ## Properties[​](#properties "Direct link to Properties") ### tables[​](#tables "Direct link to tables") • **tables**: `Schema` #### Defined in[​](#defined-in "Direct link to Defined in") [server/schema.ts:658](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L658) *** ### strictTableNameTypes[​](#stricttablenametypes "Direct link to strictTableNameTypes") • **strictTableNameTypes**: `StrictTableTypes` #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/schema.ts:659](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L659) *** ### schemaValidation[​](#schemavalidation "Direct link to schemaValidation") • `Readonly` **schemaValidation**: `boolean` #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/schema.ts:660](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L660) --- # Class: SearchFilter [server](/api/modules/server.md).SearchFilter An expression representing a search filter created by [SearchFilterBuilder](/api/interfaces/server.SearchFilterBuilder.md). ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * **`SearchFilter`** ↳ [`SearchFilterFinalizer`](/api/interfaces/server.SearchFilterFinalizer.md) --- # Class: TableDefinition\ [server](/api/modules/server.md).TableDefinition The definition of a table within a schema. This should be produced by using [defineTable](/api/modules/server.md#definetable). ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | `DocumentType` | extends [`Validator`](/api/modules/values.md#validator)<`any`, `any`, `any`> = [`Validator`](/api/modules/values.md#validator)<`any`, `any`, `any`> | | `Indexes` | extends [`GenericTableIndexes`](/api/modules/server.md#generictableindexes) = | | `SearchIndexes` | extends [`GenericTableSearchIndexes`](/api/modules/server.md#generictablesearchindexes) = | | `VectorIndexes` | extends [`GenericTableVectorIndexes`](/api/modules/server.md#generictablevectorindexes) = | ## Properties[​](#properties "Direct link to Properties") ### validator[​](#validator "Direct link to validator") • **validator**: `DocumentType` #### Defined in[​](#defined-in "Direct link to Defined in") [server/schema.ts:199](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L199) ## Methods[​](#methods "Direct link to Methods") ### indexes[​](#indexes "Direct link to indexes") ▸ \*\* indexes\*\*(): { `indexDescriptor`: `string` ; `fields`: `string`\[] }\[] This API is experimental: it may change or disappear. Returns indexes defined on this table. Intended for the advanced use cases of dynamically deciding which index to use for a query. If you think you need this, please chime in on ths issue in the Convex JS GitHub repo. #### Returns[​](#returns "Direct link to Returns") { `indexDescriptor`: `string` ; `fields`: `string`\[] }\[] #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/schema.ts:222](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L222) *** ### index[​](#index "Direct link to index") ▸ **index**<`IndexName`, `FirstFieldPath`, `RestFieldPaths`>(`name`, `indexConfig`): [`TableDefinition`](/api/classes/server.TableDefinition.md)<`DocumentType`, [`Expand`](/api/modules/server.md#expand)<`Indexes` & `Record`<`IndexName`, \[`FirstFieldPath`, ...RestFieldPaths\[], `"_creationTime"`]>>, `SearchIndexes`, `VectorIndexes`> Define an index on this table. To learn about indexes, see [Defining Indexes](https://docs.convex.dev/using/indexes). #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ---------------- | ---------------------------------------------- | | `IndexName` | extends `string` | | `FirstFieldPath` | extends `any` | | `RestFieldPaths` | extends `ExtractFieldPaths`<`DocumentType`>\[] | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | Description | | --------------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | `IndexName` | The name of the index. | | `indexConfig` | `Object` | The index configuration object. | | `indexConfig.fields` | \[`FirstFieldPath`, ...RestFieldPaths\[]] | The fields to index, in order. Must specify at least one field. | | `indexConfig.staged?` | `false` | Whether the index should be staged. For large tables, index backfill can be slow. Staging an index allows you to push the schema and enable the index later. If `staged` is `true`, the index will be staged and will not be enabled until the staged flag is removed. Staged indexes do not block push completion. Staged indexes cannot be used in queries. | #### Returns[​](#returns-1 "Direct link to Returns") [`TableDefinition`](/api/classes/server.TableDefinition.md)<`DocumentType`, [`Expand`](/api/modules/server.md#expand)<`Indexes` & `Record`<`IndexName`, \[`FirstFieldPath`, ...RestFieldPaths\[], `"_creationTime"`]>>, `SearchIndexes`, `VectorIndexes`> A [TableDefinition](/api/classes/server.TableDefinition.md) with this index included. #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/schema.ts:235](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L235) ▸ **index**<`IndexName`, `FirstFieldPath`, `RestFieldPaths`>(`name`, `fields`): [`TableDefinition`](/api/classes/server.TableDefinition.md)<`DocumentType`, [`Expand`](/api/modules/server.md#expand)<`Indexes` & `Record`<`IndexName`, \[`FirstFieldPath`, ...RestFieldPaths\[], `"_creationTime"`]>>, `SearchIndexes`, `VectorIndexes`> Define an index on this table. To learn about indexes, see [Defining Indexes](https://docs.convex.dev/using/indexes). #### Type parameters[​](#type-parameters-2 "Direct link to Type parameters") | Name | Type | | ---------------- | ---------------------------------------------- | | `IndexName` | extends `string` | | `FirstFieldPath` | extends `any` | | `RestFieldPaths` | extends `ExtractFieldPaths`<`DocumentType`>\[] | #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | Description | | -------- | ----------------------------------------- | --------------------------------------------------------------- | | `name` | `IndexName` | The name of the index. | | `fields` | \[`FirstFieldPath`, ...RestFieldPaths\[]] | The fields to index, in order. Must specify at least one field. | #### Returns[​](#returns-2 "Direct link to Returns") [`TableDefinition`](/api/classes/server.TableDefinition.md)<`DocumentType`, [`Expand`](/api/modules/server.md#expand)<`Indexes` & `Record`<`IndexName`, \[`FirstFieldPath`, ...RestFieldPaths\[], `"_creationTime"`]>>, `SearchIndexes`, `VectorIndexes`> A [TableDefinition](/api/classes/server.TableDefinition.md) with this index included. #### Defined in[​](#defined-in-3 "Direct link to Defined in") [server/schema.ts:268](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L268) ▸ **index**<`IndexName`, `FirstFieldPath`, `RestFieldPaths`>(`name`, `indexConfig`): [`TableDefinition`](/api/classes/server.TableDefinition.md)<`DocumentType`, `Indexes`, `SearchIndexes`, `VectorIndexes`> Define a staged index on this table. For large tables, index backfill can be slow. Staging an index allows you to push the schema and enable the index later. If `staged` is `true`, the index will be staged and will not be enabled until the staged flag is removed. Staged indexes do not block push completion. Staged indexes cannot be used in queries. To learn about indexes, see [Defining Indexes](https://docs.convex.dev/using/indexes). #### Type parameters[​](#type-parameters-3 "Direct link to Type parameters") | Name | Type | | ---------------- | ---------------------------------------------- | | `IndexName` | extends `string` | | `FirstFieldPath` | extends `any` | | `RestFieldPaths` | extends `ExtractFieldPaths`<`DocumentType`>\[] | #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | Description | | -------------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | `IndexName` | The name of the index. | | `indexConfig` | `Object` | The index configuration object. | | `indexConfig.fields` | \[`FirstFieldPath`, ...RestFieldPaths\[]] | The fields to index, in order. Must specify at least one field. | | `indexConfig.staged` | `true` | Whether the index should be staged. For large tables, index backfill can be slow. Staging an index allows you to push the schema and enable the index later. If `staged` is `true`, the index will be staged and will not be enabled until the staged flag is removed. Staged indexes do not block push completion. Staged indexes cannot be used in queries. | #### Returns[​](#returns-3 "Direct link to Returns") [`TableDefinition`](/api/classes/server.TableDefinition.md)<`DocumentType`, `Indexes`, `SearchIndexes`, `VectorIndexes`> A [TableDefinition](/api/classes/server.TableDefinition.md) with this index included. #### Defined in[​](#defined-in-4 "Direct link to Defined in") [server/schema.ts:304](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L304) *** ### searchIndex[​](#searchindex "Direct link to searchIndex") ▸ **searchIndex**<`IndexName`, `SearchField`, `FilterFields`>(`name`, `indexConfig`): [`TableDefinition`](/api/classes/server.TableDefinition.md)<`DocumentType`, `Indexes`, [`Expand`](/api/modules/server.md#expand)<`SearchIndexes` & `Record`<`IndexName`, { `searchField`: `SearchField` ; `filterFields`: `FilterFields` }>>, `VectorIndexes`> Define a search index on this table. To learn about search indexes, see [Search](https://docs.convex.dev/text-search). #### Type parameters[​](#type-parameters-4 "Direct link to Type parameters") | Name | Type | | -------------- | ----------------------- | | `IndexName` | extends `string` | | `SearchField` | extends `any` | | `FilterFields` | extends `any` = `never` | #### Parameters[​](#parameters-3 "Direct link to Parameters") | Name | Type | Description | | --------------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | `IndexName` | The name of the index. | | `indexConfig` | `Object` | The search index configuration object. | | `indexConfig.searchField` | `SearchField` | The field to index for full text search. This must be a field of type `string`. | | `indexConfig.filterFields?` | `FilterFields`\[] | Additional fields to index for fast filtering when running search queries. | | `indexConfig.staged?` | `false` | Whether the index should be staged. For large tables, index backfill can be slow. Staging an index allows you to push the schema and enable the index later. If `staged` is `true`, the index will be staged and will not be enabled until the staged flag is removed. Staged indexes do not block push completion. Staged indexes cannot be used in queries. | #### Returns[​](#returns-4 "Direct link to Returns") [`TableDefinition`](/api/classes/server.TableDefinition.md)<`DocumentType`, `Indexes`, [`Expand`](/api/modules/server.md#expand)<`SearchIndexes` & `Record`<`IndexName`, { `searchField`: `SearchField` ; `filterFields`: `FilterFields` }>>, `VectorIndexes`> A [TableDefinition](/api/classes/server.TableDefinition.md) with this search index included. #### Defined in[​](#defined-in-5 "Direct link to Defined in") [server/schema.ts:357](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L357) ▸ **searchIndex**<`IndexName`, `SearchField`, `FilterFields`>(`name`, `indexConfig`): [`TableDefinition`](/api/classes/server.TableDefinition.md)<`DocumentType`, `Indexes`, `SearchIndexes`, `VectorIndexes`> Define a staged search index on this table. For large tables, index backfill can be slow. Staging an index allows you to push the schema and enable the index later. If `staged` is `true`, the index will be staged and will not be enabled until the staged flag is removed. Staged indexes do not block push completion. Staged indexes cannot be used in queries. To learn about search indexes, see [Search](https://docs.convex.dev/text-search). #### Type parameters[​](#type-parameters-5 "Direct link to Type parameters") | Name | Type | | -------------- | ----------------------- | | `IndexName` | extends `string` | | `SearchField` | extends `any` | | `FilterFields` | extends `any` = `never` | #### Parameters[​](#parameters-4 "Direct link to Parameters") | Name | Type | Description | | --------------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | `IndexName` | The name of the index. | | `indexConfig` | `Object` | The search index configuration object. | | `indexConfig.searchField` | `SearchField` | The field to index for full text search. This must be a field of type `string`. | | `indexConfig.filterFields?` | `FilterFields`\[] | Additional fields to index for fast filtering when running search queries. | | `indexConfig.staged` | `true` | Whether the index should be staged. For large tables, index backfill can be slow. Staging an index allows you to push the schema and enable the index later. If `staged` is `true`, the index will be staged and will not be enabled until the staged flag is removed. Staged indexes do not block push completion. Staged indexes cannot be used in queries. | #### Returns[​](#returns-5 "Direct link to Returns") [`TableDefinition`](/api/classes/server.TableDefinition.md)<`DocumentType`, `Indexes`, `SearchIndexes`, `VectorIndexes`> A [TableDefinition](/api/classes/server.TableDefinition.md) with this search index included. #### Defined in[​](#defined-in-6 "Direct link to Defined in") [server/schema.ts:401](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L401) *** ### vectorIndex[​](#vectorindex "Direct link to vectorIndex") ▸ **vectorIndex**<`IndexName`, `VectorField`, `FilterFields`>(`name`, `indexConfig`): [`TableDefinition`](/api/classes/server.TableDefinition.md)<`DocumentType`, `Indexes`, `SearchIndexes`, [`Expand`](/api/modules/server.md#expand)<`VectorIndexes` & `Record`<`IndexName`, { `vectorField`: `VectorField` ; `dimensions`: `number` ; `filterFields`: `FilterFields` }>>> Define a vector index on this table. To learn about vector indexes, see [Vector Search](https://docs.convex.dev/vector-search). #### Type parameters[​](#type-parameters-6 "Direct link to Type parameters") | Name | Type | | -------------- | ----------------------- | | `IndexName` | extends `string` | | `VectorField` | extends `any` | | `FilterFields` | extends `any` = `never` | #### Parameters[​](#parameters-5 "Direct link to Parameters") | Name | Type | Description | | --------------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | `IndexName` | The name of the index. | | `indexConfig` | `Object` | The vector index configuration object. | | `indexConfig.vectorField` | `VectorField` | The field to index for vector search. This must be a field of type `v.array(v.float64())` (or a union) | | `indexConfig.dimensions` | `number` | The length of the vectors indexed. This must be between 2 and 2048 inclusive. | | `indexConfig.filterFields?` | `FilterFields`\[] | Additional fields to index for fast filtering when running vector searches. | | `indexConfig.staged?` | `false` | Whether the index should be staged. For large tables, index backfill can be slow. Staging an index allows you to push the schema and enable the index later. If `staged` is `true`, the index will be staged and will not be enabled until the staged flag is removed. Staged indexes do not block push completion. Staged indexes cannot be used in queries. | #### Returns[​](#returns-6 "Direct link to Returns") [`TableDefinition`](/api/classes/server.TableDefinition.md)<`DocumentType`, `Indexes`, `SearchIndexes`, [`Expand`](/api/modules/server.md#expand)<`VectorIndexes` & `Record`<`IndexName`, { `vectorField`: `VectorField` ; `dimensions`: `number` ; `filterFields`: `FilterFields` }>>> A [TableDefinition](/api/classes/server.TableDefinition.md) with this vector index included. #### Defined in[​](#defined-in-7 "Direct link to Defined in") [server/schema.ts:448](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L448) ▸ **vectorIndex**<`IndexName`, `VectorField`, `FilterFields`>(`name`, `indexConfig`): [`TableDefinition`](/api/classes/server.TableDefinition.md)<`DocumentType`, `Indexes`, `SearchIndexes`, `VectorIndexes`> Define a staged vector index on this table. For large tables, index backfill can be slow. Staging an index allows you to push the schema and enable the index later. If `staged` is `true`, the index will be staged and will not be enabled until the staged flag is removed. Staged indexes do not block push completion. Staged indexes cannot be used in queries. To learn about vector indexes, see [Vector Search](https://docs.convex.dev/vector-search). #### Type parameters[​](#type-parameters-7 "Direct link to Type parameters") | Name | Type | | -------------- | ----------------------- | | `IndexName` | extends `string` | | `VectorField` | extends `any` | | `FilterFields` | extends `any` = `never` | #### Parameters[​](#parameters-6 "Direct link to Parameters") | Name | Type | Description | | --------------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | `IndexName` | The name of the index. | | `indexConfig` | `Object` | The vector index configuration object. | | `indexConfig.vectorField` | `VectorField` | The field to index for vector search. This must be a field of type `v.array(v.float64())` (or a union) | | `indexConfig.dimensions` | `number` | The length of the vectors indexed. This must be between 2 and 2048 inclusive. | | `indexConfig.filterFields?` | `FilterFields`\[] | Additional fields to index for fast filtering when running vector searches. | | `indexConfig.staged` | `true` | Whether the index should be staged. For large tables, index backfill can be slow. Staging an index allows you to push the schema and enable the index later. If `staged` is `true`, the index will be staged and will not be enabled until the staged flag is removed. Staged indexes do not block push completion. Staged indexes cannot be used in queries. | #### Returns[​](#returns-7 "Direct link to Returns") [`TableDefinition`](/api/classes/server.TableDefinition.md)<`DocumentType`, `Indexes`, `SearchIndexes`, `VectorIndexes`> A [TableDefinition](/api/classes/server.TableDefinition.md) with this vector index included. #### Defined in[​](#defined-in-8 "Direct link to Defined in") [server/schema.ts:491](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L491) *** ### self[​](#self "Direct link to self") ▸ `Protected` **self**(): [`TableDefinition`](/api/classes/server.TableDefinition.md)<`DocumentType`, `Indexes`, `SearchIndexes`, `VectorIndexes`> Work around for #### Returns[​](#returns-8 "Direct link to Returns") [`TableDefinition`](/api/classes/server.TableDefinition.md)<`DocumentType`, `Indexes`, `SearchIndexes`, `VectorIndexes`> #### Defined in[​](#defined-in-9 "Direct link to Defined in") [server/schema.ts:534](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L534) --- # Class: ConvexError\ [values](/api/modules/values.md).ConvexError ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ------- | ----------------------------------------------- | | `TData` | extends [`Value`](/api/modules/values.md#value) | ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * `Error` ↳ **`ConvexError`** ## Constructors[​](#constructors "Direct link to Constructors") ### constructor[​](#constructor "Direct link to constructor") • **new ConvexError**<`TData`>(`data`) #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ------- | ----------------------------------------------- | | `TData` | extends [`Value`](/api/modules/values.md#value) | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | ------ | ------- | | `data` | `TData` | #### Overrides[​](#overrides "Direct link to Overrides") Error.constructor #### Defined in[​](#defined-in "Direct link to Defined in") [values/errors.ts:10](https://github.com/get-convex/convex-js/blob/main/src/values/errors.ts#L10) ## Properties[​](#properties "Direct link to Properties") ### stackTraceLimit[​](#stacktracelimit "Direct link to stackTraceLimit") ▪ `Static` **stackTraceLimit**: `number` The `Error.stackTraceLimit` property specifies the number of stack frames collected by a stack trace (whether generated by `new Error().stack` or `Error.captureStackTrace(obj)`). The default value is `10` but may be set to any valid JavaScript number. Changes will affect any stack trace captured *after* the value has been changed. If set to a non-number value, or set to a negative number, stack traces will not capture any frames. #### Inherited from[​](#inherited-from "Direct link to Inherited from") Error.stackTraceLimit #### Defined in[​](#defined-in-1 "Direct link to Defined in") ../../common/temp/node\_modules/.pnpm/@types+node\@18.19.130/node\_modules/@types/node/globals.d.ts:68 *** ### cause[​](#cause "Direct link to cause") • `Optional` **cause**: `unknown` #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from") Error.cause #### Defined in[​](#defined-in-2 "Direct link to Defined in") ../../common/temp/node\_modules/.pnpm/typescript\@5.0.4/node\_modules/typescript/lib/lib.es2022.error.d.ts:24 *** ### message[​](#message "Direct link to message") • **message**: `string` #### Inherited from[​](#inherited-from-2 "Direct link to Inherited from") Error.message #### Defined in[​](#defined-in-3 "Direct link to Defined in") ../../common/temp/node\_modules/.pnpm/typescript\@5.0.4/node\_modules/typescript/lib/lib.es5.d.ts:1055 *** ### stack[​](#stack "Direct link to stack") • `Optional` **stack**: `string` #### Inherited from[​](#inherited-from-3 "Direct link to Inherited from") Error.stack #### Defined in[​](#defined-in-4 "Direct link to Defined in") ../../common/temp/node\_modules/.pnpm/typescript\@5.0.4/node\_modules/typescript/lib/lib.es5.d.ts:1056 *** ### name[​](#name "Direct link to name") • **name**: `string` = `"ConvexError"` #### Overrides[​](#overrides-1 "Direct link to Overrides") Error.name #### Defined in[​](#defined-in-5 "Direct link to Defined in") [values/errors.ts:6](https://github.com/get-convex/convex-js/blob/main/src/values/errors.ts#L6) *** ### data[​](#data "Direct link to data") • **data**: `TData` #### Defined in[​](#defined-in-6 "Direct link to Defined in") [values/errors.ts:7](https://github.com/get-convex/convex-js/blob/main/src/values/errors.ts#L7) *** ### \[IDENTIFYING\_FIELD][​](#identifying_field "Direct link to \[IDENTIFYING_FIELD]") • **\[IDENTIFYING\_FIELD]**: `boolean` = `true` #### Defined in[​](#defined-in-7 "Direct link to Defined in") [values/errors.ts:8](https://github.com/get-convex/convex-js/blob/main/src/values/errors.ts#L8) ## Methods[​](#methods "Direct link to Methods") ### captureStackTrace[​](#capturestacktrace "Direct link to captureStackTrace") ▸ `Static` **captureStackTrace**(`targetObject`, `constructorOpt?`): `void` Creates a `.stack` property on `targetObject`, which when accessed returns a string representing the location in the code at which `Error.captureStackTrace()` was called. ``` const myObject = {}; Error.captureStackTrace(myObject); myObject.stack; // Similar to `new Error().stack` ``` The first line of the trace will be prefixed with `${myObject.name}: ${myObject.message}`. The optional `constructorOpt` argument accepts a function. If given, all frames above `constructorOpt`, including `constructorOpt`, will be omitted from the generated stack trace. The `constructorOpt` argument is useful for hiding implementation details of error generation from the user. For instance: ``` function a() { b(); } function b() { c(); } function c() { // Create an error without stack trace to avoid calculating the stack trace twice. const { stackTraceLimit } = Error; Error.stackTraceLimit = 0; const error = new Error(); Error.stackTraceLimit = stackTraceLimit; // Capture the stack trace above function b Error.captureStackTrace(error, b); // Neither function c, nor b is included in the stack trace throw error; } a(); ``` #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | | ----------------- | ---------- | | `targetObject` | `object` | | `constructorOpt?` | `Function` | #### Returns[​](#returns "Direct link to Returns") `void` #### Inherited from[​](#inherited-from-4 "Direct link to Inherited from") Error.captureStackTrace #### Defined in[​](#defined-in-8 "Direct link to Defined in") ../../common/temp/node\_modules/.pnpm/@types+node\@18.19.130/node\_modules/@types/node/globals.d.ts:52 *** ### prepareStackTrace[​](#preparestacktrace "Direct link to prepareStackTrace") ▸ `Static` **prepareStackTrace**(`err`, `stackTraces`): `any` **`See`** #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | | ------------- | ------------- | | `err` | `Error` | | `stackTraces` | `CallSite`\[] | #### Returns[​](#returns-1 "Direct link to Returns") `any` #### Inherited from[​](#inherited-from-5 "Direct link to Inherited from") Error.prepareStackTrace #### Defined in[​](#defined-in-9 "Direct link to Defined in") ../../common/temp/node\_modules/.pnpm/@types+node\@18.19.130/node\_modules/@types/node/globals.d.ts:56 --- # Class: VAny\ [values](/api/modules/values.md).VAny The type of the `v.any()` validator. ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ------------ | ------------------------------------------------------------------------------------ | | `Type` | `any` | | `IsOptional` | extends [`OptionalProperty`](/api/modules/values.md#optionalproperty) = `"required"` | | `FieldPaths` | extends `string` = `string` | ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * `BaseValidator`<`Type`, `IsOptional`, `FieldPaths`> ↳ **`VAny`** ## Constructors[​](#constructors "Direct link to Constructors") ### constructor[​](#constructor "Direct link to constructor") • **new VAny**<`Type`, `IsOptional`, `FieldPaths`>(`«destructured»`) #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ------------ | ------------------------------------------------------------------------------------ | | `Type` | `any` | | `IsOptional` | extends [`OptionalProperty`](/api/modules/values.md#optionalproperty) = `"required"` | | `FieldPaths` | extends `string` = `string` | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | ---------------- | ------------ | | `«destructured»` | `Object` | | › `isOptional` | `IsOptional` | #### Inherited from[​](#inherited-from "Direct link to Inherited from") BaseValidator\.constructor #### Defined in[​](#defined-in "Direct link to Defined in") [values/validators.ts:39](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L39) ## Properties[​](#properties "Direct link to Properties") ### type[​](#type "Direct link to type") • `Readonly` **type**: `Type` Only for TypeScript, the TS type of the JS values validated by this validator. #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from") BaseValidator.type #### Defined in[​](#defined-in-1 "Direct link to Defined in") [values/validators.ts:22](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L22) *** ### fieldPaths[​](#fieldpaths "Direct link to fieldPaths") • `Readonly` **fieldPaths**: `FieldPaths` Only for TypeScript, if this an Object validator, then this is the TS type of its property names. #### Inherited from[​](#inherited-from-2 "Direct link to Inherited from") BaseValidator.fieldPaths #### Defined in[​](#defined-in-2 "Direct link to Defined in") [values/validators.ts:27](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L27) *** ### isOptional[​](#isoptional "Direct link to isOptional") • `Readonly` **isOptional**: `IsOptional` Whether this is an optional Object property value validator. #### Inherited from[​](#inherited-from-3 "Direct link to Inherited from") BaseValidator.isOptional #### Defined in[​](#defined-in-3 "Direct link to Defined in") [values/validators.ts:32](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L32) *** ### isConvexValidator[​](#isconvexvalidator "Direct link to isConvexValidator") • `Readonly` **isConvexValidator**: `true` Always `"true"`. #### Inherited from[​](#inherited-from-4 "Direct link to Inherited from") BaseValidator.isConvexValidator #### Defined in[​](#defined-in-4 "Direct link to Defined in") [values/validators.ts:37](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L37) *** ### kind[​](#kind "Direct link to kind") • `Readonly` **kind**: `"any"` The kind of validator, `"any"`. #### Defined in[​](#defined-in-5 "Direct link to Defined in") [values/validators.ts:246](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L246) --- # Class: VArray\ [values](/api/modules/values.md).VArray The type of the `v.array()` validator. ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ------------ | ------------------------------------------------------------------------------------ | | `Type` | `Type` | | `Element` | extends [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`> | | `IsOptional` | extends [`OptionalProperty`](/api/modules/values.md#optionalproperty) = `"required"` | ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * `BaseValidator`<`Type`, `IsOptional`> ↳ **`VArray`** ## Constructors[​](#constructors "Direct link to Constructors") ### constructor[​](#constructor "Direct link to constructor") • **new VArray**<`Type`, `Element`, `IsOptional`>(`«destructured»`) Usually you'd use `v.array(element)` instead. #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ------------ | ------------------------------------------------------------------------------------ | | `Type` | `Type` | | `Element` | extends [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`> | | `IsOptional` | extends [`OptionalProperty`](/api/modules/values.md#optionalproperty) = `"required"` | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | ---------------- | ------------ | | `«destructured»` | `Object` | | › `isOptional` | `IsOptional` | | › `element` | `Element` | #### Overrides[​](#overrides "Direct link to Overrides") BaseValidator\<Type, IsOptional\>.constructor #### Defined in[​](#defined-in "Direct link to Defined in") [values/validators.ts:472](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L472) ## Properties[​](#properties "Direct link to Properties") ### type[​](#type "Direct link to type") • `Readonly` **type**: `Type` Only for TypeScript, the TS type of the JS values validated by this validator. #### Inherited from[​](#inherited-from "Direct link to Inherited from") BaseValidator.type #### Defined in[​](#defined-in-1 "Direct link to Defined in") [values/validators.ts:22](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L22) *** ### fieldPaths[​](#fieldpaths "Direct link to fieldPaths") • `Readonly` **fieldPaths**: `never` Only for TypeScript, if this an Object validator, then this is the TS type of its property names. #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from") BaseValidator.fieldPaths #### Defined in[​](#defined-in-2 "Direct link to Defined in") [values/validators.ts:27](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L27) *** ### isOptional[​](#isoptional "Direct link to isOptional") • `Readonly` **isOptional**: `IsOptional` Whether this is an optional Object property value validator. #### Inherited from[​](#inherited-from-2 "Direct link to Inherited from") BaseValidator.isOptional #### Defined in[​](#defined-in-3 "Direct link to Defined in") [values/validators.ts:32](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L32) *** ### isConvexValidator[​](#isconvexvalidator "Direct link to isConvexValidator") • `Readonly` **isConvexValidator**: `true` Always `"true"`. #### Inherited from[​](#inherited-from-3 "Direct link to Inherited from") BaseValidator.isConvexValidator #### Defined in[​](#defined-in-4 "Direct link to Defined in") [values/validators.ts:37](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L37) *** ### element[​](#element "Direct link to element") • `Readonly` **element**: `Element` The validator for the elements of the array. #### Defined in[​](#defined-in-5 "Direct link to Defined in") [values/validators.ts:462](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L462) *** ### kind[​](#kind "Direct link to kind") • `Readonly` **kind**: `"array"` The kind of validator, `"array"`. #### Defined in[​](#defined-in-6 "Direct link to Defined in") [values/validators.ts:467](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L467) --- # Class: VBoolean\ [values](/api/modules/values.md).VBoolean The type of the `v.boolean()` validator. ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ------------ | ------------------------------------------------------------------------------------ | | `Type` | `boolean` | | `IsOptional` | extends [`OptionalProperty`](/api/modules/values.md#optionalproperty) = `"required"` | ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * `BaseValidator`<`Type`, `IsOptional`> ↳ **`VBoolean`** ## Constructors[​](#constructors "Direct link to Constructors") ### constructor[​](#constructor "Direct link to constructor") • **new VBoolean**<`Type`, `IsOptional`>(`«destructured»`) #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ------------ | ------------------------------------------------------------------------------------ | | `Type` | `boolean` | | `IsOptional` | extends [`OptionalProperty`](/api/modules/values.md#optionalproperty) = `"required"` | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | ---------------- | ------------ | | `«destructured»` | `Object` | | › `isOptional` | `IsOptional` | #### Inherited from[​](#inherited-from "Direct link to Inherited from") BaseValidator\.constructor #### Defined in[​](#defined-in "Direct link to Defined in") [values/validators.ts:39](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L39) ## Properties[​](#properties "Direct link to Properties") ### type[​](#type "Direct link to type") • `Readonly` **type**: `Type` Only for TypeScript, the TS type of the JS values validated by this validator. #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from") BaseValidator.type #### Defined in[​](#defined-in-1 "Direct link to Defined in") [values/validators.ts:22](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L22) *** ### fieldPaths[​](#fieldpaths "Direct link to fieldPaths") • `Readonly` **fieldPaths**: `never` Only for TypeScript, if this an Object validator, then this is the TS type of its property names. #### Inherited from[​](#inherited-from-2 "Direct link to Inherited from") BaseValidator.fieldPaths #### Defined in[​](#defined-in-2 "Direct link to Defined in") [values/validators.ts:27](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L27) *** ### isOptional[​](#isoptional "Direct link to isOptional") • `Readonly` **isOptional**: `IsOptional` Whether this is an optional Object property value validator. #### Inherited from[​](#inherited-from-3 "Direct link to Inherited from") BaseValidator.isOptional #### Defined in[​](#defined-in-3 "Direct link to Defined in") [values/validators.ts:32](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L32) *** ### isConvexValidator[​](#isconvexvalidator "Direct link to isConvexValidator") • `Readonly` **isConvexValidator**: `true` Always `"true"`. #### Inherited from[​](#inherited-from-4 "Direct link to Inherited from") BaseValidator.isConvexValidator #### Defined in[​](#defined-in-4 "Direct link to Defined in") [values/validators.ts:37](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L37) *** ### kind[​](#kind "Direct link to kind") • `Readonly` **kind**: `"boolean"` The kind of validator, `"boolean"`. #### Defined in[​](#defined-in-5 "Direct link to Defined in") [values/validators.ts:153](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L153) --- # Class: VBytes\ [values](/api/modules/values.md).VBytes The type of the `v.bytes()` validator. ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ------------ | ------------------------------------------------------------------------------------ | | `Type` | `ArrayBuffer` | | `IsOptional` | extends [`OptionalProperty`](/api/modules/values.md#optionalproperty) = `"required"` | ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * `BaseValidator`<`Type`, `IsOptional`> ↳ **`VBytes`** ## Constructors[​](#constructors "Direct link to Constructors") ### constructor[​](#constructor "Direct link to constructor") • **new VBytes**<`Type`, `IsOptional`>(`«destructured»`) #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ------------ | ------------------------------------------------------------------------------------ | | `Type` | `ArrayBuffer` | | `IsOptional` | extends [`OptionalProperty`](/api/modules/values.md#optionalproperty) = `"required"` | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | ---------------- | ------------ | | `«destructured»` | `Object` | | › `isOptional` | `IsOptional` | #### Inherited from[​](#inherited-from "Direct link to Inherited from") BaseValidator\.constructor #### Defined in[​](#defined-in "Direct link to Defined in") [values/validators.ts:39](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L39) ## Properties[​](#properties "Direct link to Properties") ### type[​](#type "Direct link to type") • `Readonly` **type**: `Type` Only for TypeScript, the TS type of the JS values validated by this validator. #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from") BaseValidator.type #### Defined in[​](#defined-in-1 "Direct link to Defined in") [values/validators.ts:22](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L22) *** ### fieldPaths[​](#fieldpaths "Direct link to fieldPaths") • `Readonly` **fieldPaths**: `never` Only for TypeScript, if this an Object validator, then this is the TS type of its property names. #### Inherited from[​](#inherited-from-2 "Direct link to Inherited from") BaseValidator.fieldPaths #### Defined in[​](#defined-in-2 "Direct link to Defined in") [values/validators.ts:27](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L27) *** ### isOptional[​](#isoptional "Direct link to isOptional") • `Readonly` **isOptional**: `IsOptional` Whether this is an optional Object property value validator. #### Inherited from[​](#inherited-from-3 "Direct link to Inherited from") BaseValidator.isOptional #### Defined in[​](#defined-in-3 "Direct link to Defined in") [values/validators.ts:32](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L32) *** ### isConvexValidator[​](#isconvexvalidator "Direct link to isConvexValidator") • `Readonly` **isConvexValidator**: `true` Always `"true"`. #### Inherited from[​](#inherited-from-4 "Direct link to Inherited from") BaseValidator.isConvexValidator #### Defined in[​](#defined-in-4 "Direct link to Defined in") [values/validators.ts:37](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L37) *** ### kind[​](#kind "Direct link to kind") • `Readonly` **kind**: `"bytes"` The kind of validator, `"bytes"`. #### Defined in[​](#defined-in-5 "Direct link to Defined in") [values/validators.ts:177](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L177) --- # Class: VFloat64\ [values](/api/modules/values.md).VFloat64 The type of the `v.float64()` validator. ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ------------ | ------------------------------------------------------------------------------------ | | `Type` | `number` | | `IsOptional` | extends [`OptionalProperty`](/api/modules/values.md#optionalproperty) = `"required"` | ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * `BaseValidator`<`Type`, `IsOptional`> ↳ **`VFloat64`** ## Constructors[​](#constructors "Direct link to Constructors") ### constructor[​](#constructor "Direct link to constructor") • **new VFloat64**<`Type`, `IsOptional`>(`«destructured»`) #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ------------ | ------------------------------------------------------------------------------------ | | `Type` | `number` | | `IsOptional` | extends [`OptionalProperty`](/api/modules/values.md#optionalproperty) = `"required"` | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | ---------------- | ------------ | | `«destructured»` | `Object` | | › `isOptional` | `IsOptional` | #### Inherited from[​](#inherited-from "Direct link to Inherited from") BaseValidator\.constructor #### Defined in[​](#defined-in "Direct link to Defined in") [values/validators.ts:39](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L39) ## Properties[​](#properties "Direct link to Properties") ### type[​](#type "Direct link to type") • `Readonly` **type**: `Type` Only for TypeScript, the TS type of the JS values validated by this validator. #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from") BaseValidator.type #### Defined in[​](#defined-in-1 "Direct link to Defined in") [values/validators.ts:22](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L22) *** ### fieldPaths[​](#fieldpaths "Direct link to fieldPaths") • `Readonly` **fieldPaths**: `never` Only for TypeScript, if this an Object validator, then this is the TS type of its property names. #### Inherited from[​](#inherited-from-2 "Direct link to Inherited from") BaseValidator.fieldPaths #### Defined in[​](#defined-in-2 "Direct link to Defined in") [values/validators.ts:27](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L27) *** ### isOptional[​](#isoptional "Direct link to isOptional") • `Readonly` **isOptional**: `IsOptional` Whether this is an optional Object property value validator. #### Inherited from[​](#inherited-from-3 "Direct link to Inherited from") BaseValidator.isOptional #### Defined in[​](#defined-in-3 "Direct link to Defined in") [values/validators.ts:32](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L32) *** ### isConvexValidator[​](#isconvexvalidator "Direct link to isConvexValidator") • `Readonly` **isConvexValidator**: `true` Always `"true"`. #### Inherited from[​](#inherited-from-4 "Direct link to Inherited from") BaseValidator.isConvexValidator #### Defined in[​](#defined-in-4 "Direct link to Defined in") [values/validators.ts:37](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L37) *** ### kind[​](#kind "Direct link to kind") • `Readonly` **kind**: `"float64"` The kind of validator, `"float64"`. #### Defined in[​](#defined-in-5 "Direct link to Defined in") [values/validators.ts:105](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L105) --- # Class: VId\ [values](/api/modules/values.md).VId The type of the `v.id(tableName)` validator. ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ------------ | ------------------------------------------------------------------------------------ | | `Type` | `Type` | | `IsOptional` | extends [`OptionalProperty`](/api/modules/values.md#optionalproperty) = `"required"` | ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * `BaseValidator`<`Type`, `IsOptional`> ↳ **`VId`** ## Constructors[​](#constructors "Direct link to Constructors") ### constructor[​](#constructor "Direct link to constructor") • **new VId**<`Type`, `IsOptional`>(`«destructured»`) Usually you'd use `v.id(tableName)` instead. #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ------------ | ------------------------------------------------------------------------------------ | | `Type` | `Type` | | `IsOptional` | extends [`OptionalProperty`](/api/modules/values.md#optionalproperty) = `"required"` | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | ---------------- | --------------------------- | | `«destructured»` | `Object` | | › `isOptional` | `IsOptional` | | › `tableName` | `TableNameFromType`<`Type`> | #### Overrides[​](#overrides "Direct link to Overrides") BaseValidator\<Type, IsOptional\>.constructor #### Defined in[​](#defined-in "Direct link to Defined in") [values/validators.ts:69](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L69) ## Properties[​](#properties "Direct link to Properties") ### type[​](#type "Direct link to type") • `Readonly` **type**: `Type` Only for TypeScript, the TS type of the JS values validated by this validator. #### Inherited from[​](#inherited-from "Direct link to Inherited from") BaseValidator.type #### Defined in[​](#defined-in-1 "Direct link to Defined in") [values/validators.ts:22](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L22) *** ### fieldPaths[​](#fieldpaths "Direct link to fieldPaths") • `Readonly` **fieldPaths**: `never` Only for TypeScript, if this an Object validator, then this is the TS type of its property names. #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from") BaseValidator.fieldPaths #### Defined in[​](#defined-in-2 "Direct link to Defined in") [values/validators.ts:27](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L27) *** ### isOptional[​](#isoptional "Direct link to isOptional") • `Readonly` **isOptional**: `IsOptional` Whether this is an optional Object property value validator. #### Inherited from[​](#inherited-from-2 "Direct link to Inherited from") BaseValidator.isOptional #### Defined in[​](#defined-in-3 "Direct link to Defined in") [values/validators.ts:32](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L32) *** ### isConvexValidator[​](#isconvexvalidator "Direct link to isConvexValidator") • `Readonly` **isConvexValidator**: `true` Always `"true"`. #### Inherited from[​](#inherited-from-3 "Direct link to Inherited from") BaseValidator.isConvexValidator #### Defined in[​](#defined-in-4 "Direct link to Defined in") [values/validators.ts:37](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L37) *** ### tableName[​](#tablename "Direct link to tableName") • `Readonly` **tableName**: `TableNameFromType`<`Type`> The name of the table that the validated IDs must belong to. #### Defined in[​](#defined-in-5 "Direct link to Defined in") [values/validators.ts:59](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L59) *** ### kind[​](#kind "Direct link to kind") • `Readonly` **kind**: `"id"` The kind of validator, `"id"`. #### Defined in[​](#defined-in-6 "Direct link to Defined in") [values/validators.ts:64](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L64) --- # Class: VInt64\ [values](/api/modules/values.md).VInt64 The type of the `v.int64()` validator. ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ------------ | ------------------------------------------------------------------------------------ | | `Type` | `bigint` | | `IsOptional` | extends [`OptionalProperty`](/api/modules/values.md#optionalproperty) = `"required"` | ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * `BaseValidator`<`Type`, `IsOptional`> ↳ **`VInt64`** ## Constructors[​](#constructors "Direct link to Constructors") ### constructor[​](#constructor "Direct link to constructor") • **new VInt64**<`Type`, `IsOptional`>(`«destructured»`) #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ------------ | ------------------------------------------------------------------------------------ | | `Type` | `bigint` | | `IsOptional` | extends [`OptionalProperty`](/api/modules/values.md#optionalproperty) = `"required"` | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | ---------------- | ------------ | | `«destructured»` | `Object` | | › `isOptional` | `IsOptional` | #### Inherited from[​](#inherited-from "Direct link to Inherited from") BaseValidator\.constructor #### Defined in[​](#defined-in "Direct link to Defined in") [values/validators.ts:39](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L39) ## Properties[​](#properties "Direct link to Properties") ### type[​](#type "Direct link to type") • `Readonly` **type**: `Type` Only for TypeScript, the TS type of the JS values validated by this validator. #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from") BaseValidator.type #### Defined in[​](#defined-in-1 "Direct link to Defined in") [values/validators.ts:22](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L22) *** ### fieldPaths[​](#fieldpaths "Direct link to fieldPaths") • `Readonly` **fieldPaths**: `never` Only for TypeScript, if this an Object validator, then this is the TS type of its property names. #### Inherited from[​](#inherited-from-2 "Direct link to Inherited from") BaseValidator.fieldPaths #### Defined in[​](#defined-in-2 "Direct link to Defined in") [values/validators.ts:27](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L27) *** ### isOptional[​](#isoptional "Direct link to isOptional") • `Readonly` **isOptional**: `IsOptional` Whether this is an optional Object property value validator. #### Inherited from[​](#inherited-from-3 "Direct link to Inherited from") BaseValidator.isOptional #### Defined in[​](#defined-in-3 "Direct link to Defined in") [values/validators.ts:32](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L32) *** ### isConvexValidator[​](#isconvexvalidator "Direct link to isConvexValidator") • `Readonly` **isConvexValidator**: `true` Always `"true"`. #### Inherited from[​](#inherited-from-4 "Direct link to Inherited from") BaseValidator.isConvexValidator #### Defined in[​](#defined-in-4 "Direct link to Defined in") [values/validators.ts:37](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L37) *** ### kind[​](#kind "Direct link to kind") • `Readonly` **kind**: `"int64"` The kind of validator, `"int64"`. #### Defined in[​](#defined-in-5 "Direct link to Defined in") [values/validators.ts:130](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L130) --- # Class: VLiteral\ [values](/api/modules/values.md).VLiteral The type of the `v.literal()` validator. ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ------------ | ------------------------------------------------------------------------------------ | | `Type` | `Type` | | `IsOptional` | extends [`OptionalProperty`](/api/modules/values.md#optionalproperty) = `"required"` | ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * `BaseValidator`<`Type`, `IsOptional`> ↳ **`VLiteral`** ## Constructors[​](#constructors "Direct link to Constructors") ### constructor[​](#constructor "Direct link to constructor") • **new VLiteral**<`Type`, `IsOptional`>(`«destructured»`) Usually you'd use `v.literal(value)` instead. #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ------------ | ------------------------------------------------------------------------------------ | | `Type` | `Type` | | `IsOptional` | extends [`OptionalProperty`](/api/modules/values.md#optionalproperty) = `"required"` | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | ---------------- | ------------ | | `«destructured»` | `Object` | | › `isOptional` | `IsOptional` | | › `value` | `Type` | #### Overrides[​](#overrides "Direct link to Overrides") BaseValidator\<Type, IsOptional\>.constructor #### Defined in[​](#defined-in "Direct link to Defined in") [values/validators.ts:423](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L423) ## Properties[​](#properties "Direct link to Properties") ### type[​](#type "Direct link to type") • `Readonly` **type**: `Type` Only for TypeScript, the TS type of the JS values validated by this validator. #### Inherited from[​](#inherited-from "Direct link to Inherited from") BaseValidator.type #### Defined in[​](#defined-in-1 "Direct link to Defined in") [values/validators.ts:22](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L22) *** ### fieldPaths[​](#fieldpaths "Direct link to fieldPaths") • `Readonly` **fieldPaths**: `never` Only for TypeScript, if this an Object validator, then this is the TS type of its property names. #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from") BaseValidator.fieldPaths #### Defined in[​](#defined-in-2 "Direct link to Defined in") [values/validators.ts:27](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L27) *** ### isOptional[​](#isoptional "Direct link to isOptional") • `Readonly` **isOptional**: `IsOptional` Whether this is an optional Object property value validator. #### Inherited from[​](#inherited-from-2 "Direct link to Inherited from") BaseValidator.isOptional #### Defined in[​](#defined-in-3 "Direct link to Defined in") [values/validators.ts:32](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L32) *** ### isConvexValidator[​](#isconvexvalidator "Direct link to isConvexValidator") • `Readonly` **isConvexValidator**: `true` Always `"true"`. #### Inherited from[​](#inherited-from-3 "Direct link to Inherited from") BaseValidator.isConvexValidator #### Defined in[​](#defined-in-4 "Direct link to Defined in") [values/validators.ts:37](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L37) *** ### value[​](#value "Direct link to value") • `Readonly` **value**: `Type` The value that the validated values must be equal to. #### Defined in[​](#defined-in-5 "Direct link to Defined in") [values/validators.ts:413](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L413) *** ### kind[​](#kind "Direct link to kind") • `Readonly` **kind**: `"literal"` The kind of validator, `"literal"`. #### Defined in[​](#defined-in-6 "Direct link to Defined in") [values/validators.ts:418](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L418) --- # Class: VNull\ [values](/api/modules/values.md).VNull The type of the `v.null()` validator. ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ------------ | ------------------------------------------------------------------------------------ | | `Type` | `null` | | `IsOptional` | extends [`OptionalProperty`](/api/modules/values.md#optionalproperty) = `"required"` | ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * `BaseValidator`<`Type`, `IsOptional`> ↳ **`VNull`** ## Constructors[​](#constructors "Direct link to Constructors") ### constructor[​](#constructor "Direct link to constructor") • **new VNull**<`Type`, `IsOptional`>(`«destructured»`) #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ------------ | ------------------------------------------------------------------------------------ | | `Type` | `null` | | `IsOptional` | extends [`OptionalProperty`](/api/modules/values.md#optionalproperty) = `"required"` | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | ---------------- | ------------ | | `«destructured»` | `Object` | | › `isOptional` | `IsOptional` | #### Inherited from[​](#inherited-from "Direct link to Inherited from") BaseValidator\.constructor #### Defined in[​](#defined-in "Direct link to Defined in") [values/validators.ts:39](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L39) ## Properties[​](#properties "Direct link to Properties") ### type[​](#type "Direct link to type") • `Readonly` **type**: `Type` Only for TypeScript, the TS type of the JS values validated by this validator. #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from") BaseValidator.type #### Defined in[​](#defined-in-1 "Direct link to Defined in") [values/validators.ts:22](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L22) *** ### fieldPaths[​](#fieldpaths "Direct link to fieldPaths") • `Readonly` **fieldPaths**: `never` Only for TypeScript, if this an Object validator, then this is the TS type of its property names. #### Inherited from[​](#inherited-from-2 "Direct link to Inherited from") BaseValidator.fieldPaths #### Defined in[​](#defined-in-2 "Direct link to Defined in") [values/validators.ts:27](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L27) *** ### isOptional[​](#isoptional "Direct link to isOptional") • `Readonly` **isOptional**: `IsOptional` Whether this is an optional Object property value validator. #### Inherited from[​](#inherited-from-3 "Direct link to Inherited from") BaseValidator.isOptional #### Defined in[​](#defined-in-3 "Direct link to Defined in") [values/validators.ts:32](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L32) *** ### isConvexValidator[​](#isconvexvalidator "Direct link to isConvexValidator") • `Readonly` **isConvexValidator**: `true` Always `"true"`. #### Inherited from[​](#inherited-from-4 "Direct link to Inherited from") BaseValidator.isConvexValidator #### Defined in[​](#defined-in-4 "Direct link to Defined in") [values/validators.ts:37](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L37) *** ### kind[​](#kind "Direct link to kind") • `Readonly` **kind**: `"null"` The kind of validator, `"null"`. #### Defined in[​](#defined-in-5 "Direct link to Defined in") [values/validators.ts:223](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L223) --- # Class: VObject\ [values](/api/modules/values.md).VObject The type of the `v.object()` validator. ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Type` | `Type` | | `Fields` | extends `Record`<`string`, [`GenericValidator`](/api/modules/values.md#genericvalidator)> | | `IsOptional` | extends [`OptionalProperty`](/api/modules/values.md#optionalproperty) = `"required"` | | `FieldPaths` | extends `string` = { \[Property in keyof Fields]: JoinFieldPaths\ \| Property }\[keyof `Fields`] & `string` | ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * `BaseValidator`<`Type`, `IsOptional`, `FieldPaths`> ↳ **`VObject`** ## Constructors[​](#constructors "Direct link to Constructors") ### constructor[​](#constructor "Direct link to constructor") • **new VObject**<`Type`, `Fields`, `IsOptional`, `FieldPaths`>(`«destructured»`) Usually you'd use `v.object({ ... })` instead. #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Type` | `Type` | | `Fields` | extends `Record`<`string`, [`GenericValidator`](/api/modules/values.md#genericvalidator)> | | `IsOptional` | extends [`OptionalProperty`](/api/modules/values.md#optionalproperty) = `"required"` | | `FieldPaths` | extends `string` = { \[Property in string \| number \| symbol]: Property \| \`${Property & string}.${Fields\[Property]\["fieldPaths"]}\` }\[keyof `Fields`] & `string` | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | ---------------- | ------------ | | `«destructured»` | `Object` | | › `isOptional` | `IsOptional` | | › `fields` | `Fields` | #### Overrides[​](#overrides "Direct link to Overrides") BaseValidator\<Type, IsOptional, FieldPaths\>.constructor #### Defined in[​](#defined-in "Direct link to Defined in") [values/validators.ts:289](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L289) ## Properties[​](#properties "Direct link to Properties") ### type[​](#type "Direct link to type") • `Readonly` **type**: `Type` Only for TypeScript, the TS type of the JS values validated by this validator. #### Inherited from[​](#inherited-from "Direct link to Inherited from") BaseValidator.type #### Defined in[​](#defined-in-1 "Direct link to Defined in") [values/validators.ts:22](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L22) *** ### fieldPaths[​](#fieldpaths "Direct link to fieldPaths") • `Readonly` **fieldPaths**: `FieldPaths` Only for TypeScript, if this an Object validator, then this is the TS type of its property names. #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from") BaseValidator.fieldPaths #### Defined in[​](#defined-in-2 "Direct link to Defined in") [values/validators.ts:27](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L27) *** ### isOptional[​](#isoptional "Direct link to isOptional") • `Readonly` **isOptional**: `IsOptional` Whether this is an optional Object property value validator. #### Inherited from[​](#inherited-from-2 "Direct link to Inherited from") BaseValidator.isOptional #### Defined in[​](#defined-in-3 "Direct link to Defined in") [values/validators.ts:32](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L32) *** ### isConvexValidator[​](#isconvexvalidator "Direct link to isConvexValidator") • `Readonly` **isConvexValidator**: `true` Always `"true"`. #### Inherited from[​](#inherited-from-3 "Direct link to Inherited from") BaseValidator.isConvexValidator #### Defined in[​](#defined-in-4 "Direct link to Defined in") [values/validators.ts:37](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L37) *** ### fields[​](#fields "Direct link to fields") • `Readonly` **fields**: `Fields` An object with the validator for each property. #### Defined in[​](#defined-in-5 "Direct link to Defined in") [values/validators.ts:279](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L279) *** ### kind[​](#kind "Direct link to kind") • `Readonly` **kind**: `"object"` The kind of validator, `"object"`. #### Defined in[​](#defined-in-6 "Direct link to Defined in") [values/validators.ts:284](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L284) ## Methods[​](#methods "Direct link to Methods") ### omit[​](#omit "Direct link to omit") ▸ **omit**<`K`>(`...fields`): [`VObject`](/api/classes/values.VObject.md)<[`Expand`](/api/modules/server.md#expand)<`Omit`<`Type`, `K`>>, [`Expand`](/api/modules/server.md#expand)<`Omit`<`Fields`, `K`>>, `IsOptional`, { \[Property in string | number | symbol]: Property | \`${Property & string}.${Expand\>\[Property]\["fieldPaths"]}\` }\[keyof [`Expand`](/api/modules/server.md#expand)<`Omit`<`Fields`, `K`>>] & `string`> Create a new VObject with the specified fields omitted. #### Type parameters[​](#type-parameters-2 "Direct link to Type parameters") | Name | Type | | ---- | ---------------- | | `K` | extends `string` | #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | Description | | ----------- | ------ | ------------------------------------------ | | `...fields` | `K`\[] | The field names to omit from this VObject. | #### Returns[​](#returns "Direct link to Returns") [`VObject`](/api/classes/values.VObject.md)<[`Expand`](/api/modules/server.md#expand)<`Omit`<`Type`, `K`>>, [`Expand`](/api/modules/server.md#expand)<`Omit`<`Fields`, `K`>>, `IsOptional`, { \[Property in string | number | symbol]: Property | \`${Property & string}.${Expand\>\[Property]\["fieldPaths"]}\` }\[keyof [`Expand`](/api/modules/server.md#expand)<`Omit`<`Fields`, `K`>>] & `string`> #### Defined in[​](#defined-in-7 "Direct link to Defined in") [values/validators.ts:331](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L331) *** ### pick[​](#pick "Direct link to pick") ▸ **pick**<`K`>(`...fields`): [`VObject`](/api/classes/values.VObject.md)<[`Expand`](/api/modules/server.md#expand)<`Pick`<`Type`, `Extract`\>>, [`Expand`](/api/modules/server.md#expand)<`Pick`<`Fields`, `K`>>, `IsOptional`, { \[Property in string | number | symbol]: Property | \`${Property & string}.${Expand\>\[Property]\["fieldPaths"]}\` }\[keyof [`Expand`](/api/modules/server.md#expand)<`Pick`<`Fields`, `K`>>] & `string`> Create a new VObject with only the specified fields. #### Type parameters[​](#type-parameters-3 "Direct link to Type parameters") | Name | Type | | ---- | ---------------- | | `K` | extends `string` | #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | Description | | ----------- | ------ | ------------------------------------------ | | `...fields` | `K`\[] | The field names to pick from this VObject. | #### Returns[​](#returns-1 "Direct link to Returns") [`VObject`](/api/classes/values.VObject.md)<[`Expand`](/api/modules/server.md#expand)<`Pick`<`Type`, `Extract`\>>, [`Expand`](/api/modules/server.md#expand)<`Pick`<`Fields`, `K`>>, `IsOptional`, { \[Property in string | number | symbol]: Property | \`${Property & string}.${Expand\>\[Property]\["fieldPaths"]}\` }\[keyof [`Expand`](/api/modules/server.md#expand)<`Pick`<`Fields`, `K`>>] & `string`> #### Defined in[​](#defined-in-8 "Direct link to Defined in") [values/validators.ts:348](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L348) *** ### partial[​](#partial "Direct link to partial") ▸ **partial**(): [`VObject`](/api/classes/values.VObject.md)<{ \[K in string | number | symbol]?: Type\[K] }, { \[K in string | number | symbol]: VOptional\ }, `IsOptional`, { \[Property in string | number | symbol]: Property | \`${Property & string}.${{ \[K in string | number | symbol]: VOptional\ }\[Property]\["fieldPaths"]}\` }\[keyof `Fields`] & `string`> Create a new VObject with all fields marked as optional. #### Returns[​](#returns-2 "Direct link to Returns") [`VObject`](/api/classes/values.VObject.md)<{ \[K in string | number | symbol]?: Type\[K] }, { \[K in string | number | symbol]: VOptional\ }, `IsOptional`, { \[Property in string | number | symbol]: Property | \`${Property & string}.${{ \[K in string | number | symbol]: VOptional\ }\[Property]\["fieldPaths"]}\` }\[keyof `Fields`] & `string`> #### Defined in[​](#defined-in-9 "Direct link to Defined in") [values/validators.ts:368](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L368) *** ### extend[​](#extend "Direct link to extend") ▸ **extend**<`NewFields`>(`fields`): [`VObject`](/api/classes/values.VObject.md)<[`Expand`](/api/modules/server.md#expand)<`Type` & [`ObjectType`](/api/modules/values.md#objecttype)<`NewFields`>>, [`Expand`](/api/modules/server.md#expand)<`Fields` & `NewFields`>, `IsOptional`, { \[Property in string | number | symbol]: Property | \`${Property & string}.${Expand\\[Property]\["fieldPaths"]}\` }\[keyof [`Expand`](/api/modules/server.md#expand)<`Fields` & `NewFields`>] & `string`> Create a new VObject with additional fields merged in. #### Type parameters[​](#type-parameters-4 "Direct link to Type parameters") | Name | Type | | ----------- | ----------------------------------------------------------------------------------------- | | `NewFields` | extends `Record`<`string`, [`GenericValidator`](/api/modules/values.md#genericvalidator)> | #### Parameters[​](#parameters-3 "Direct link to Parameters") | Name | Type | Description | | -------- | ----------- | ---------------------------------------------------------------- | | `fields` | `NewFields` | An object with additional validators to merge into this VObject. | #### Returns[​](#returns-3 "Direct link to Returns") [`VObject`](/api/classes/values.VObject.md)<[`Expand`](/api/modules/server.md#expand)<`Type` & [`ObjectType`](/api/modules/values.md#objecttype)<`NewFields`>>, [`Expand`](/api/modules/server.md#expand)<`Fields` & `NewFields`>, `IsOptional`, { \[Property in string | number | symbol]: Property | \`${Property & string}.${Expand\\[Property]\["fieldPaths"]}\` }\[keyof [`Expand`](/api/modules/server.md#expand)<`Fields` & `NewFields`>] & `string`> #### Defined in[​](#defined-in-10 "Direct link to Defined in") [values/validators.ts:389](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L389) --- # Class: VRecord\ [values](/api/modules/values.md).VRecord The type of the `v.record()` validator. ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ------------ | -------------------------------------------------------------------------------------- | | `Type` | `Type` | | `Key` | extends [`Validator`](/api/modules/values.md#validator)<`string`, `"required"`, `any`> | | `Value` | extends [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`> | | `IsOptional` | extends [`OptionalProperty`](/api/modules/values.md#optionalproperty) = `"required"` | | `FieldPaths` | extends `string` = `string` | ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * `BaseValidator`<`Type`, `IsOptional`, `FieldPaths`> ↳ **`VRecord`** ## Constructors[​](#constructors "Direct link to Constructors") ### constructor[​](#constructor "Direct link to constructor") • **new VRecord**<`Type`, `Key`, `Value`, `IsOptional`, `FieldPaths`>(`«destructured»`) Usually you'd use `v.record(key, value)` instead. #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ------------ | -------------------------------------------------------------------------------------- | | `Type` | `Type` | | `Key` | extends [`Validator`](/api/modules/values.md#validator)<`string`, `"required"`, `any`> | | `Value` | extends [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`> | | `IsOptional` | extends [`OptionalProperty`](/api/modules/values.md#optionalproperty) = `"required"` | | `FieldPaths` | extends `string` = `string` | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | ---------------- | ------------ | | `«destructured»` | `Object` | | › `isOptional` | `IsOptional` | | › `key` | `Key` | | › `value` | `Value` | #### Overrides[​](#overrides "Direct link to Overrides") BaseValidator\<Type, IsOptional, FieldPaths\>.constructor #### Defined in[​](#defined-in "Direct link to Defined in") [values/validators.ts:526](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L526) ## Properties[​](#properties "Direct link to Properties") ### type[​](#type "Direct link to type") • `Readonly` **type**: `Type` Only for TypeScript, the TS type of the JS values validated by this validator. #### Inherited from[​](#inherited-from "Direct link to Inherited from") BaseValidator.type #### Defined in[​](#defined-in-1 "Direct link to Defined in") [values/validators.ts:22](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L22) *** ### fieldPaths[​](#fieldpaths "Direct link to fieldPaths") • `Readonly` **fieldPaths**: `FieldPaths` Only for TypeScript, if this an Object validator, then this is the TS type of its property names. #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from") BaseValidator.fieldPaths #### Defined in[​](#defined-in-2 "Direct link to Defined in") [values/validators.ts:27](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L27) *** ### isOptional[​](#isoptional "Direct link to isOptional") • `Readonly` **isOptional**: `IsOptional` Whether this is an optional Object property value validator. #### Inherited from[​](#inherited-from-2 "Direct link to Inherited from") BaseValidator.isOptional #### Defined in[​](#defined-in-3 "Direct link to Defined in") [values/validators.ts:32](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L32) *** ### isConvexValidator[​](#isconvexvalidator "Direct link to isConvexValidator") • `Readonly` **isConvexValidator**: `true` Always `"true"`. #### Inherited from[​](#inherited-from-3 "Direct link to Inherited from") BaseValidator.isConvexValidator #### Defined in[​](#defined-in-4 "Direct link to Defined in") [values/validators.ts:37](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L37) *** ### key[​](#key "Direct link to key") • `Readonly` **key**: `Key` The validator for the keys of the record. #### Defined in[​](#defined-in-5 "Direct link to Defined in") [values/validators.ts:511](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L511) *** ### value[​](#value "Direct link to value") • `Readonly` **value**: `Value` The validator for the values of the record. #### Defined in[​](#defined-in-6 "Direct link to Defined in") [values/validators.ts:516](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L516) *** ### kind[​](#kind "Direct link to kind") • `Readonly` **kind**: `"record"` The kind of validator, `"record"`. #### Defined in[​](#defined-in-7 "Direct link to Defined in") [values/validators.ts:521](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L521) --- # Class: VString\ [values](/api/modules/values.md).VString The type of the `v.string()` validator. ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ------------ | ------------------------------------------------------------------------------------ | | `Type` | `string` | | `IsOptional` | extends [`OptionalProperty`](/api/modules/values.md#optionalproperty) = `"required"` | ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * `BaseValidator`<`Type`, `IsOptional`> ↳ **`VString`** ## Constructors[​](#constructors "Direct link to Constructors") ### constructor[​](#constructor "Direct link to constructor") • **new VString**<`Type`, `IsOptional`>(`«destructured»`) #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ------------ | ------------------------------------------------------------------------------------ | | `Type` | `string` | | `IsOptional` | extends [`OptionalProperty`](/api/modules/values.md#optionalproperty) = `"required"` | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | ---------------- | ------------ | | `«destructured»` | `Object` | | › `isOptional` | `IsOptional` | #### Inherited from[​](#inherited-from "Direct link to Inherited from") BaseValidator\.constructor #### Defined in[​](#defined-in "Direct link to Defined in") [values/validators.ts:39](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L39) ## Properties[​](#properties "Direct link to Properties") ### type[​](#type "Direct link to type") • `Readonly` **type**: `Type` Only for TypeScript, the TS type of the JS values validated by this validator. #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from") BaseValidator.type #### Defined in[​](#defined-in-1 "Direct link to Defined in") [values/validators.ts:22](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L22) *** ### fieldPaths[​](#fieldpaths "Direct link to fieldPaths") • `Readonly` **fieldPaths**: `never` Only for TypeScript, if this an Object validator, then this is the TS type of its property names. #### Inherited from[​](#inherited-from-2 "Direct link to Inherited from") BaseValidator.fieldPaths #### Defined in[​](#defined-in-2 "Direct link to Defined in") [values/validators.ts:27](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L27) *** ### isOptional[​](#isoptional "Direct link to isOptional") • `Readonly` **isOptional**: `IsOptional` Whether this is an optional Object property value validator. #### Inherited from[​](#inherited-from-3 "Direct link to Inherited from") BaseValidator.isOptional #### Defined in[​](#defined-in-3 "Direct link to Defined in") [values/validators.ts:32](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L32) *** ### isConvexValidator[​](#isconvexvalidator "Direct link to isConvexValidator") • `Readonly` **isConvexValidator**: `true` Always `"true"`. #### Inherited from[​](#inherited-from-4 "Direct link to Inherited from") BaseValidator.isConvexValidator #### Defined in[​](#defined-in-4 "Direct link to Defined in") [values/validators.ts:37](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L37) *** ### kind[​](#kind "Direct link to kind") • `Readonly` **kind**: `"string"` The kind of validator, `"string"`. #### Defined in[​](#defined-in-5 "Direct link to Defined in") [values/validators.ts:199](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L199) --- # Class: VUnion\ [values](/api/modules/values.md).VUnion The type of the `v.union()` validator. ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ------------ | -------------------------------------------------------------------------------------- | | `Type` | `Type` | | `T` | extends [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`>\[] | | `IsOptional` | extends [`OptionalProperty`](/api/modules/values.md#optionalproperty) = `"required"` | | `FieldPaths` | extends `string` = `T`\[`number`]\[`"fieldPaths"`] | ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * `BaseValidator`<`Type`, `IsOptional`, `FieldPaths`> ↳ **`VUnion`** ## Constructors[​](#constructors "Direct link to Constructors") ### constructor[​](#constructor "Direct link to constructor") • **new VUnion**<`Type`, `T`, `IsOptional`, `FieldPaths`>(`«destructured»`) Usually you'd use `v.union(...members)` instead. #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ------------ | -------------------------------------------------------------------------------------- | | `Type` | `Type` | | `T` | extends [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`>\[] | | `IsOptional` | extends [`OptionalProperty`](/api/modules/values.md#optionalproperty) = `"required"` | | `FieldPaths` | extends `string` = `T`\[`number`]\[`"fieldPaths"`] | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | ---------------- | ------------ | | `«destructured»` | `Object` | | › `isOptional` | `IsOptional` | | › `members` | `T` | #### Overrides[​](#overrides "Direct link to Overrides") BaseValidator\<Type, IsOptional, FieldPaths\>.constructor #### Defined in[​](#defined-in "Direct link to Defined in") [values/validators.ts:592](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L592) ## Properties[​](#properties "Direct link to Properties") ### type[​](#type "Direct link to type") • `Readonly` **type**: `Type` Only for TypeScript, the TS type of the JS values validated by this validator. #### Inherited from[​](#inherited-from "Direct link to Inherited from") BaseValidator.type #### Defined in[​](#defined-in-1 "Direct link to Defined in") [values/validators.ts:22](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L22) *** ### fieldPaths[​](#fieldpaths "Direct link to fieldPaths") • `Readonly` **fieldPaths**: `FieldPaths` Only for TypeScript, if this an Object validator, then this is the TS type of its property names. #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from") BaseValidator.fieldPaths #### Defined in[​](#defined-in-2 "Direct link to Defined in") [values/validators.ts:27](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L27) *** ### isOptional[​](#isoptional "Direct link to isOptional") • `Readonly` **isOptional**: `IsOptional` Whether this is an optional Object property value validator. #### Inherited from[​](#inherited-from-2 "Direct link to Inherited from") BaseValidator.isOptional #### Defined in[​](#defined-in-3 "Direct link to Defined in") [values/validators.ts:32](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L32) *** ### isConvexValidator[​](#isconvexvalidator "Direct link to isConvexValidator") • `Readonly` **isConvexValidator**: `true` Always `"true"`. #### Inherited from[​](#inherited-from-3 "Direct link to Inherited from") BaseValidator.isConvexValidator #### Defined in[​](#defined-in-4 "Direct link to Defined in") [values/validators.ts:37](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L37) *** ### members[​](#members "Direct link to members") • `Readonly` **members**: `T` The array of validators, one of which must match the value. #### Defined in[​](#defined-in-5 "Direct link to Defined in") [values/validators.ts:582](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L582) *** ### kind[​](#kind "Direct link to kind") • `Readonly` **kind**: `"union"` The kind of validator, `"union"`. #### Defined in[​](#defined-in-6 "Direct link to Defined in") [values/validators.ts:587](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L587) --- # Interface: BaseConvexClientOptions [browser](/api/modules/browser.md).BaseConvexClientOptions Options for [BaseConvexClient](/api/classes/browser.BaseConvexClient.md). ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * **`BaseConvexClientOptions`** ↳ [`ConvexReactClientOptions`](/api/interfaces/react.ConvexReactClientOptions.md) ## Properties[​](#properties "Direct link to Properties") ### unsavedChangesWarning[​](#unsavedchangeswarning "Direct link to unsavedChangesWarning") • `Optional` **unsavedChangesWarning**: `boolean` Whether to prompt the user if they have unsaved changes pending when navigating away or closing a web page. This is only possible when the `window` object exists, i.e. in a browser. The default value is `true` in browsers. #### Defined in[​](#defined-in "Direct link to Defined in") [browser/sync/client.ts:69](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L69) *** ### webSocketConstructor[​](#websocketconstructor "Direct link to webSocketConstructor") • `Optional` **webSocketConstructor**: `Object` #### Call signature[​](#call-signature "Direct link to Call signature") • **new webSocketConstructor**(`url`, `protocols?`): `WebSocket` Specifies an alternate [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) constructor to use for client communication with the Convex cloud. The default behavior is to use `WebSocket` from the global environment. ##### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | ------------ | ----------------------- | | `url` | `string` \| `URL` | | `protocols?` | `string` \| `string`\[] | ##### Returns[​](#returns "Direct link to Returns") `WebSocket` #### Type declaration[​](#type-declaration "Direct link to Type declaration") | Name | Type | | ------------ | ----------- | | `prototype` | `WebSocket` | | `CONNECTING` | `0` | | `OPEN` | `1` | | `CLOSING` | `2` | | `CLOSED` | `3` | #### Defined in[​](#defined-in-1 "Direct link to Defined in") [browser/sync/client.ts:76](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L76) *** ### verbose[​](#verbose "Direct link to verbose") • `Optional` **verbose**: `boolean` Adds additional logging for debugging purposes. The default value is `false`. #### Defined in[​](#defined-in-2 "Direct link to Defined in") [browser/sync/client.ts:82](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L82) *** ### logger[​](#logger "Direct link to logger") • `Optional` **logger**: `boolean` | `Logger` A logger, `true`, or `false`. If not provided or `true`, logs to the console. If `false`, logs are not printed anywhere. You can construct your own logger to customize logging to log elsewhere. A logger is an object with 4 methods: log(), warn(), error(), and logVerbose(). These methods can receive multiple arguments of any types, like console.log(). #### Defined in[​](#defined-in-3 "Direct link to Defined in") [browser/sync/client.ts:91](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L91) *** ### reportDebugInfoToConvex[​](#reportdebuginfotoconvex "Direct link to reportDebugInfoToConvex") • `Optional` **reportDebugInfoToConvex**: `boolean` Sends additional metrics to Convex for debugging purposes. The default value is `false`. #### Defined in[​](#defined-in-4 "Direct link to Defined in") [browser/sync/client.ts:97](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L97) *** ### onServerDisconnectError[​](#onserverdisconnecterror "Direct link to onServerDisconnectError") • `Optional` **onServerDisconnectError**: (`message`: `string`) => `void` #### Type declaration[​](#type-declaration-1 "Direct link to Type declaration") ▸ (`message`): `void` This API is experimental: it may change or disappear. A function to call on receiving abnormal WebSocket close messages from the connected Convex deployment. The content of these messages is not stable, it is an implementation detail that may change. Consider this API an observability stopgap until higher level codes with recommendations on what to do are available, which could be a more stable interface instead of `string`. Check `connectionState` for more quantitative metrics about connection status. ##### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | | --------- | -------- | | `message` | `string` | ##### Returns[​](#returns-1 "Direct link to Returns") `void` #### Defined in[​](#defined-in-5 "Direct link to Defined in") [browser/sync/client.ts:111](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L111) *** ### skipConvexDeploymentUrlCheck[​](#skipconvexdeploymenturlcheck "Direct link to skipConvexDeploymentUrlCheck") • `Optional` **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[​](#defined-in-6 "Direct link to Defined in") [browser/sync/client.ts:121](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L121) *** ### authRefreshTokenLeewaySeconds[​](#authrefreshtokenleewayseconds "Direct link to authRefreshTokenLeewaySeconds") • `Optional` **authRefreshTokenLeewaySeconds**: `number` If using auth, the number of seconds before a token expires that we should refresh it. The default value is `2`. #### Defined in[​](#defined-in-7 "Direct link to Defined in") [browser/sync/client.ts:127](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L127) *** ### expectAuth[​](#expectauth "Direct link to expectAuth") • `Optional` **expectAuth**: `boolean` This API is experimental: it may change or disappear. Whether query, mutation, and action requests should be held back until the first auth token can be sent. Opting into this behavior works well for pages that should only be viewed by authenticated clients. Defaults to false, not waiting for an auth token. #### Defined in[​](#defined-in-8 "Direct link to Defined in") [browser/sync/client.ts:139](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L139) --- # Interface: MutationOptions [browser](/api/modules/browser.md).MutationOptions Options for [mutation](/api/classes/browser.BaseConvexClient.md#mutation). ## Properties[​](#properties "Direct link to Properties") ### optimisticUpdate[​](#optimisticupdate "Direct link to optimisticUpdate") • `Optional` **optimisticUpdate**: [`OptimisticUpdate`](/api/modules/browser.md#optimisticupdate)<`any`> An optimistic update to apply along with this mutation. An optimistic update locally updates queries while a mutation is pending. Once the mutation completes, the update will be rolled back. #### Defined in[​](#defined-in "Direct link to Defined in") [browser/sync/client.ts:210](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L210) --- # Interface: OptimisticLocalStore [browser](/api/modules/browser.md).OptimisticLocalStore A view of the query results currently in the Convex client for use within optimistic updates. ## Methods[​](#methods "Direct link to Methods") ### getQuery[​](#getquery "Direct link to getQuery") ▸ **getQuery**<`Query`>(`query`, `...args`): `undefined` | [`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`> Retrieve the result of a query from the client. Important: Query results should be treated as immutable! Always make new copies of structures within query results to avoid corrupting data within the client. #### Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"query"`> | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | Description | | --------- | ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | | `query` | `Query` | A [FunctionReference](/api/modules/server.md#functionreference) for the query to get. | | `...args` | [`OptionalRestArgs`](/api/modules/server.md#optionalrestargs)<`Query`> | The arguments object for this query. | #### Returns[​](#returns "Direct link to Returns") `undefined` | [`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`> The query result or `undefined` if the query is not currently in the client. #### Defined in[​](#defined-in "Direct link to Defined in") [browser/sync/optimistic\_updates.ts:28](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/optimistic_updates.ts#L28) *** ### getAllQueries[​](#getallqueries "Direct link to getAllQueries") ▸ **getAllQueries**<`Query`>(`query`): { `args`: [`FunctionArgs`](/api/modules/server.md#functionargs)<`Query`> ; `value`: `undefined` | [`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`> }\[] Retrieve the results and arguments of all queries with a given name. This is useful for complex optimistic updates that need to inspect and update many query results (for example updating a paginated list). Important: Query results should be treated as immutable! Always make new copies of structures within query results to avoid corrupting data within the client. #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"query"`> | #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | Description | | ------- | ------- | ------------------------------------------------------------------------------------- | | `query` | `Query` | A [FunctionReference](/api/modules/server.md#functionreference) for the query to get. | #### Returns[​](#returns-1 "Direct link to Returns") { `args`: [`FunctionArgs`](/api/modules/server.md#functionargs)<`Query`> ; `value`: `undefined` | [`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`> }\[] An array of objects, one for each query of the given name. Each object includes: * `args` - The arguments object for the query. * `value` The query result or `undefined` if the query is loading. #### Defined in[​](#defined-in-1 "Direct link to Defined in") [browser/sync/optimistic\_updates.ts:49](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/optimistic_updates.ts#L49) *** ### setQuery[​](#setquery "Direct link to setQuery") ▸ **setQuery**<`Query`>(`query`, `args`, `value`): `void` Optimistically update the result of a query. This can either be a new value (perhaps derived from the old value from [getQuery](/api/interfaces/browser.OptimisticLocalStore.md#getquery)) or `undefined` to remove the query. Removing a query is useful to create loading states while Convex recomputes the query results. #### Type parameters[​](#type-parameters-2 "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"query"`> | #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | Description | | ------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | | `query` | `Query` | A [FunctionReference](/api/modules/server.md#functionreference) for the query to set. | | `args` | [`FunctionArgs`](/api/modules/server.md#functionargs)<`Query`> | The arguments object for this query. | | `value` | `undefined` \| [`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`> | The new value to set the query to or `undefined` to remove it from the client. | #### Returns[​](#returns-2 "Direct link to Returns") `void` #### Defined in[​](#defined-in-2 "Direct link to Defined in") [browser/sync/optimistic\_updates.ts:69](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/optimistic_updates.ts#L69) --- # Interface: SubscribeOptions [browser](/api/modules/browser.md).SubscribeOptions Options for [subscribe](/api/classes/browser.BaseConvexClient.md#subscribe). ## Properties[​](#properties "Direct link to Properties") ### journal[​](#journal "Direct link to journal") • `Optional` **journal**: [`QueryJournal`](/api/modules/browser.md#queryjournal) An (optional) journal produced from a previous execution of this query function. If there is an existing subscription to a query function with the same name and arguments, this journal will have no effect. #### Defined in[​](#defined-in "Direct link to Defined in") [browser/sync/client.ts:190](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L190) --- # Interface: ConvexReactClientOptions [react](/api/modules/react.md).ConvexReactClientOptions Options for [ConvexReactClient](/api/classes/react.ConvexReactClient.md). ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * [`BaseConvexClientOptions`](/api/interfaces/browser.BaseConvexClientOptions.md) ↳ **`ConvexReactClientOptions`** ## Properties[​](#properties "Direct link to Properties") ### unsavedChangesWarning[​](#unsavedchangeswarning "Direct link to unsavedChangesWarning") • `Optional` **unsavedChangesWarning**: `boolean` Whether to prompt the user if they have unsaved changes pending when navigating away or closing a web page. This is only possible when the `window` object exists, i.e. in a browser. The default value is `true` in browsers. #### Inherited from[​](#inherited-from "Direct link to Inherited from") [BaseConvexClientOptions](/api/interfaces/browser.BaseConvexClientOptions.md).[unsavedChangesWarning](/api/interfaces/browser.BaseConvexClientOptions.md#unsavedchangeswarning) #### Defined in[​](#defined-in "Direct link to Defined in") [browser/sync/client.ts:69](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L69) *** ### webSocketConstructor[​](#websocketconstructor "Direct link to webSocketConstructor") • `Optional` **webSocketConstructor**: `Object` #### Call signature[​](#call-signature "Direct link to Call signature") • **new webSocketConstructor**(`url`, `protocols?`): `WebSocket` Specifies an alternate [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) constructor to use for client communication with the Convex cloud. The default behavior is to use `WebSocket` from the global environment. ##### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | ------------ | ----------------------- | | `url` | `string` \| `URL` | | `protocols?` | `string` \| `string`\[] | ##### Returns[​](#returns "Direct link to Returns") `WebSocket` #### Type declaration[​](#type-declaration "Direct link to Type declaration") | Name | Type | | ------------ | ----------- | | `prototype` | `WebSocket` | | `CONNECTING` | `0` | | `OPEN` | `1` | | `CLOSING` | `2` | | `CLOSED` | `3` | #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from") [BaseConvexClientOptions](/api/interfaces/browser.BaseConvexClientOptions.md).[webSocketConstructor](/api/interfaces/browser.BaseConvexClientOptions.md#websocketconstructor) #### Defined in[​](#defined-in-1 "Direct link to Defined in") [browser/sync/client.ts:76](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L76) *** ### verbose[​](#verbose "Direct link to verbose") • `Optional` **verbose**: `boolean` Adds additional logging for debugging purposes. The default value is `false`. #### Inherited from[​](#inherited-from-2 "Direct link to Inherited from") [BaseConvexClientOptions](/api/interfaces/browser.BaseConvexClientOptions.md).[verbose](/api/interfaces/browser.BaseConvexClientOptions.md#verbose) #### Defined in[​](#defined-in-2 "Direct link to Defined in") [browser/sync/client.ts:82](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L82) *** ### logger[​](#logger "Direct link to logger") • `Optional` **logger**: `boolean` | `Logger` A logger, `true`, or `false`. If not provided or `true`, logs to the console. If `false`, logs are not printed anywhere. You can construct your own logger to customize logging to log elsewhere. A logger is an object with 4 methods: log(), warn(), error(), and logVerbose(). These methods can receive multiple arguments of any types, like console.log(). #### Inherited from[​](#inherited-from-3 "Direct link to Inherited from") [BaseConvexClientOptions](/api/interfaces/browser.BaseConvexClientOptions.md).[logger](/api/interfaces/browser.BaseConvexClientOptions.md#logger) #### Defined in[​](#defined-in-3 "Direct link to Defined in") [browser/sync/client.ts:91](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L91) *** ### reportDebugInfoToConvex[​](#reportdebuginfotoconvex "Direct link to reportDebugInfoToConvex") • `Optional` **reportDebugInfoToConvex**: `boolean` Sends additional metrics to Convex for debugging purposes. The default value is `false`. #### Inherited from[​](#inherited-from-4 "Direct link to Inherited from") [BaseConvexClientOptions](/api/interfaces/browser.BaseConvexClientOptions.md).[reportDebugInfoToConvex](/api/interfaces/browser.BaseConvexClientOptions.md#reportdebuginfotoconvex) #### Defined in[​](#defined-in-4 "Direct link to Defined in") [browser/sync/client.ts:97](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L97) *** ### onServerDisconnectError[​](#onserverdisconnecterror "Direct link to onServerDisconnectError") • `Optional` **onServerDisconnectError**: (`message`: `string`) => `void` #### Type declaration[​](#type-declaration-1 "Direct link to Type declaration") ▸ (`message`): `void` This API is experimental: it may change or disappear. A function to call on receiving abnormal WebSocket close messages from the connected Convex deployment. The content of these messages is not stable, it is an implementation detail that may change. Consider this API an observability stopgap until higher level codes with recommendations on what to do are available, which could be a more stable interface instead of `string`. Check `connectionState` for more quantitative metrics about connection status. ##### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | | --------- | -------- | | `message` | `string` | ##### Returns[​](#returns-1 "Direct link to Returns") `void` #### Inherited from[​](#inherited-from-5 "Direct link to Inherited from") [BaseConvexClientOptions](/api/interfaces/browser.BaseConvexClientOptions.md).[onServerDisconnectError](/api/interfaces/browser.BaseConvexClientOptions.md#onserverdisconnecterror) #### Defined in[​](#defined-in-5 "Direct link to Defined in") [browser/sync/client.ts:111](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L111) *** ### skipConvexDeploymentUrlCheck[​](#skipconvexdeploymenturlcheck "Direct link to skipConvexDeploymentUrlCheck") • `Optional` **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` #### Inherited from[​](#inherited-from-6 "Direct link to Inherited from") [BaseConvexClientOptions](/api/interfaces/browser.BaseConvexClientOptions.md).[skipConvexDeploymentUrlCheck](/api/interfaces/browser.BaseConvexClientOptions.md#skipconvexdeploymenturlcheck) #### Defined in[​](#defined-in-6 "Direct link to Defined in") [browser/sync/client.ts:121](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L121) *** ### authRefreshTokenLeewaySeconds[​](#authrefreshtokenleewayseconds "Direct link to authRefreshTokenLeewaySeconds") • `Optional` **authRefreshTokenLeewaySeconds**: `number` If using auth, the number of seconds before a token expires that we should refresh it. The default value is `2`. #### Inherited from[​](#inherited-from-7 "Direct link to Inherited from") [BaseConvexClientOptions](/api/interfaces/browser.BaseConvexClientOptions.md).[authRefreshTokenLeewaySeconds](/api/interfaces/browser.BaseConvexClientOptions.md#authrefreshtokenleewayseconds) #### Defined in[​](#defined-in-7 "Direct link to Defined in") [browser/sync/client.ts:127](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L127) *** ### expectAuth[​](#expectauth "Direct link to expectAuth") • `Optional` **expectAuth**: `boolean` This API is experimental: it may change or disappear. Whether query, mutation, and action requests should be held back until the first auth token can be sent. Opting into this behavior works well for pages that should only be viewed by authenticated clients. Defaults to false, not waiting for an auth token. #### Inherited from[​](#inherited-from-8 "Direct link to Inherited from") [BaseConvexClientOptions](/api/interfaces/browser.BaseConvexClientOptions.md).[expectAuth](/api/interfaces/browser.BaseConvexClientOptions.md#expectauth) #### Defined in[​](#defined-in-8 "Direct link to Defined in") [browser/sync/client.ts:139](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L139) --- # Interface: MutationOptions\ [react](/api/modules/react.md).MutationOptions Options for [mutation](/api/classes/react.ConvexReactClient.md#mutation). ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ------ | ------------------------------------------------------------------- | | `Args` | extends `Record`<`string`, [`Value`](/api/modules/values.md#value)> | ## Properties[​](#properties "Direct link to Properties") ### optimisticUpdate[​](#optimisticupdate "Direct link to optimisticUpdate") • `Optional` **optimisticUpdate**: [`OptimisticUpdate`](/api/modules/browser.md#optimisticupdate)<`Args`> An optimistic update to apply along with this mutation. An optimistic update locally updates queries while a mutation is pending. Once the mutation completes, the update will be rolled back. #### Defined in[​](#defined-in "Direct link to Defined in") [react/client.ts:282](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L282) --- # Interface: ReactAction\ [react](/api/modules/react.md).ReactAction An interface to execute a Convex action on the server. ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | -------- | ----------------------------------------------------------------------------------- | | `Action` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"action"`> | ## Callable[​](#callable "Direct link to Callable") ### ReactAction[​](#reactaction "Direct link to ReactAction") ▸ **ReactAction**(`...args`): `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Action`>> Execute the function on the server, returning a `Promise` of its return value. #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | Description | | --------- | ----------------------------------------------------------------------- | ---------------------------------------------------- | | `...args` | [`OptionalRestArgs`](/api/modules/server.md#optionalrestargs)<`Action`> | Arguments for the function to pass up to the server. | #### Returns[​](#returns "Direct link to Returns") `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Action`>> The return value of the server-side function call. #### Defined in[​](#defined-in "Direct link to Defined in") [react/client.ts:136](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L136) --- # Interface: ReactMutation\ [react](/api/modules/react.md).ReactMutation An interface to execute a Convex mutation function on the server. ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ---------- | ------------------------------------------------------------------------------------- | | `Mutation` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"mutation"`> | ## Callable[​](#callable "Direct link to Callable") ### ReactMutation[​](#reactmutation "Direct link to ReactMutation") ▸ **ReactMutation**(`...args`): `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Mutation`>> Execute the mutation on the server, returning a `Promise` of its return value. #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | Description | | --------- | ------------------------------------------------------------------------- | ---------------------------------------------------- | | `...args` | [`OptionalRestArgs`](/api/modules/server.md#optionalrestargs)<`Mutation`> | Arguments for the mutation to pass up to the server. | #### Returns[​](#returns "Direct link to Returns") `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Mutation`>> The return value of the server-side function call. #### Defined in[​](#defined-in "Direct link to Defined in") [react/client.ts:64](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L64) ## Methods[​](#methods "Direct link to Methods") ### withOptimisticUpdate[​](#withoptimisticupdate "Direct link to withOptimisticUpdate") ▸ **withOptimisticUpdate**<`T`>(`optimisticUpdate`): [`ReactMutation`](/api/interfaces/react.ReactMutation.md)<`Mutation`> Define an optimistic update to apply as part of this mutation. This is a temporary update to the local query results to facilitate a fast, interactive UI. It enables query results to update before a mutation executed on the server. When the mutation is invoked, the optimistic update will be applied. Optimistic updates can also be used to temporarily remove queries from the client and create loading experiences until a mutation completes and the new query results are synced. The update will be automatically rolled back when the mutation is fully completed and queries have been updated. #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ---- | ----------------------------------------------------------------------------------------------------------------------------------------- | | `T` | extends [`OptimisticUpdate`](/api/modules/browser.md#optimisticupdate)<[`FunctionArgs`](/api/modules/server.md#functionargs)<`Mutation`>> | #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | Description | | ------------------ | ------------------------------------------------------------------------------------------------------- | ------------------------------- | | `optimisticUpdate` | `T` & `ReturnType`<`T`> extends `Promise`<`any`> ? `"Optimistic update handlers must be synchronous"` : | The optimistic update to apply. | #### Returns[​](#returns-1 "Direct link to Returns") [`ReactMutation`](/api/interfaces/react.ReactMutation.md)<`Mutation`> A new `ReactMutation` with the update configured. #### Defined in[​](#defined-in-1 "Direct link to Defined in") [react/client.ts:87](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L87) --- # Interface: Watch\ [react](/api/modules/react.md).Watch A watch on the output of a Convex query function. ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | | ---- | | `T` | ## Methods[​](#methods "Direct link to Methods") ### onUpdate[​](#onupdate "Direct link to onUpdate") ▸ **onUpdate**(`callback`): () => `void` Initiate a watch on the output of a query. This will subscribe to this query and call the callback whenever the query result changes. **Important: If the client is already subscribed to this query with the same arguments this callback will not be invoked until the query result is updated.** To get the current, local result call [localQueryResult](/api/interfaces/react.Watch.md#localqueryresult). #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | Description | | ---------- | ------------ | ---------------------------------------------------------- | | `callback` | () => `void` | Function that is called whenever the query result changes. | #### Returns[​](#returns "Direct link to Returns") `fn` * A function that disposes of the subscription. ▸ (): `void` Initiate a watch on the output of a query. This will subscribe to this query and call the callback whenever the query result changes. **Important: If the client is already subscribed to this query with the same arguments this callback will not be invoked until the query result is updated.** To get the current, local result call [localQueryResult](/api/interfaces/react.Watch.md#localqueryresult). ##### Returns[​](#returns-1 "Direct link to Returns") `void` * A function that disposes of the subscription. #### Defined in[​](#defined-in "Direct link to Defined in") [react/client.ts:170](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L170) *** ### localQueryResult[​](#localqueryresult "Direct link to localQueryResult") ▸ **localQueryResult**(): `undefined` | `T` Get the current result of a query. This will only return a result if we're already subscribed to the query and have received a result from the server or the query value has been set optimistically. **`Throws`** An error if the query encountered an error on the server. #### Returns[​](#returns-2 "Direct link to Returns") `undefined` | `T` The result of the query or `undefined` if it isn't known. #### Defined in[​](#defined-in-1 "Direct link to Defined in") [react/client.ts:182](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L182) *** ### journal[​](#journal "Direct link to journal") ▸ **journal**(): `undefined` | [`QueryJournal`](/api/modules/browser.md#queryjournal) Get the current [QueryJournal](/api/modules/browser.md#queryjournal) for this query. If we have not yet received a result for this query, this will be `undefined`. #### Returns[​](#returns-3 "Direct link to Returns") `undefined` | [`QueryJournal`](/api/modules/browser.md#queryjournal) #### Defined in[​](#defined-in-2 "Direct link to Defined in") [react/client.ts:194](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L194) --- # Interface: WatchQueryOptions [react](/api/modules/react.md).WatchQueryOptions Options for [watchQuery](/api/classes/react.ConvexReactClient.md#watchquery). ## Properties[​](#properties "Direct link to Properties") ### journal[​](#journal "Direct link to journal") • `Optional` **journal**: [`QueryJournal`](/api/modules/browser.md#queryjournal) An (optional) journal produced from a previous execution of this query function. If there is an existing subscription to a query function with the same name and arguments, this journal will have no effect. #### Defined in[​](#defined-in "Direct link to Defined in") [react/client.ts:241](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L241) --- # Interface: Auth [server](/api/modules/server.md).Auth An interface to access information about the currently authenticated user within Convex query and mutation functions. ## Methods[​](#methods "Direct link to Methods") ### getUserIdentity[​](#getuseridentity "Direct link to getUserIdentity") ▸ **getUserIdentity**(): `Promise`<`null` | [`UserIdentity`](/api/interfaces/server.UserIdentity.md)> Get details about the currently authenticated user. #### Returns[​](#returns "Direct link to Returns") `Promise`<`null` | [`UserIdentity`](/api/interfaces/server.UserIdentity.md)> A promise that resolves to a [UserIdentity](/api/interfaces/server.UserIdentity.md) if the Convex client was configured with a valid ID token, or if not, will: * returns `null` on Convex queries, mutations, actions. * `throw` on HTTP Actions. #### Defined in[​](#defined-in "Direct link to Defined in") [server/authentication.ts:236](https://github.com/get-convex/convex-js/blob/main/src/server/authentication.ts#L236) --- # Interface: BaseTableReader\ [server](/api/modules/server.md).BaseTableReader ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ----------- | -------------------------------------------------------------------------------------------- | | `DataModel` | extends [`GenericDataModel`](/api/modules/server.md#genericdatamodel) | | `TableName` | extends [`TableNamesInDataModel`](/api/modules/server.md#tablenamesindatamodel)<`DataModel`> | ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * **`BaseTableReader`** ↳ [`BaseTableWriter`](/api/interfaces/server.BaseTableWriter.md) ## Methods[​](#methods "Direct link to Methods") ### get[​](#get "Direct link to get") ▸ **get**(`id`): `Promise`<`null` | [`DocumentByName`](/api/modules/server.md#documentbyname)<`DataModel`, `TableName`>> Fetch a single document from the table by its [GenericId](/api/modules/values.md#genericid). #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | Description | | ---- | ------------------------------------------------------------ | --------------------------------------------------------------------------------------------- | | `id` | [`GenericId`](/api/modules/values.md#genericid)<`TableName`> | The [GenericId](/api/modules/values.md#genericid) of the document to fetch from the database. | #### Returns[​](#returns "Direct link to Returns") `Promise`<`null` | [`DocumentByName`](/api/modules/server.md#documentbyname)<`DataModel`, `TableName`>> * The [GenericDocument](/api/modules/server.md#genericdocument) of the document at the given [GenericId](/api/modules/values.md#genericid), or `null` if it no longer exists. #### Defined in[​](#defined-in "Direct link to Defined in") [server/database.ts:90](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L90) *** ### query[​](#query "Direct link to query") ▸ **query**(): [`QueryInitializer`](/api/interfaces/server.QueryInitializer.md)<[`NamedTableInfo`](/api/modules/server.md#namedtableinfo)<`DataModel`, `TableName`>> Begin a query for the table. Queries don't execute immediately, so calling this method and extending its query are free until the results are actually used. #### Returns[​](#returns-1 "Direct link to Returns") [`QueryInitializer`](/api/interfaces/server.QueryInitializer.md)<[`NamedTableInfo`](/api/modules/server.md#namedtableinfo)<`DataModel`, `TableName`>> * A [QueryInitializer](/api/interfaces/server.QueryInitializer.md) object to start building a query. #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/database.ts:102](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L102) --- # Interface: BaseTableWriter\ [server](/api/modules/server.md).BaseTableWriter ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ----------- | -------------------------------------------------------------------------------------------- | | `DataModel` | extends [`GenericDataModel`](/api/modules/server.md#genericdatamodel) | | `TableName` | extends [`TableNamesInDataModel`](/api/modules/server.md#tablenamesindatamodel)<`DataModel`> | ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * [`BaseTableReader`](/api/interfaces/server.BaseTableReader.md)<`DataModel`, `TableName`> ↳ **`BaseTableWriter`** ## Methods[​](#methods "Direct link to Methods") ### get[​](#get "Direct link to get") ▸ **get**(`id`): `Promise`<`null` | [`DocumentByName`](/api/modules/server.md#documentbyname)<`DataModel`, `TableName`>> Fetch a single document from the table by its [GenericId](/api/modules/values.md#genericid). #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | Description | | ---- | ------------------------------------------------------------ | --------------------------------------------------------------------------------------------- | | `id` | [`GenericId`](/api/modules/values.md#genericid)<`TableName`> | The [GenericId](/api/modules/values.md#genericid) of the document to fetch from the database. | #### Returns[​](#returns "Direct link to Returns") `Promise`<`null` | [`DocumentByName`](/api/modules/server.md#documentbyname)<`DataModel`, `TableName`>> * The [GenericDocument](/api/modules/server.md#genericdocument) of the document at the given [GenericId](/api/modules/values.md#genericid), or `null` if it no longer exists. #### Inherited from[​](#inherited-from "Direct link to Inherited from") [BaseTableReader](/api/interfaces/server.BaseTableReader.md).[get](/api/interfaces/server.BaseTableReader.md#get) #### Defined in[​](#defined-in "Direct link to Defined in") [server/database.ts:90](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L90) *** ### query[​](#query "Direct link to query") ▸ **query**(): [`QueryInitializer`](/api/interfaces/server.QueryInitializer.md)<[`NamedTableInfo`](/api/modules/server.md#namedtableinfo)<`DataModel`, `TableName`>> Begin a query for the table. Queries don't execute immediately, so calling this method and extending its query are free until the results are actually used. #### Returns[​](#returns-1 "Direct link to Returns") [`QueryInitializer`](/api/interfaces/server.QueryInitializer.md)<[`NamedTableInfo`](/api/modules/server.md#namedtableinfo)<`DataModel`, `TableName`>> * A [QueryInitializer](/api/interfaces/server.QueryInitializer.md) object to start building a query. #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from") [BaseTableReader](/api/interfaces/server.BaseTableReader.md).[query](/api/interfaces/server.BaseTableReader.md#query) #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/database.ts:102](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L102) *** ### insert[​](#insert "Direct link to insert") ▸ **insert**(`value`): `Promise`<[`GenericId`](/api/modules/values.md#genericid)<`TableName`>> Insert a new document into the table. #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | Description | | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | | `value` | [`WithoutSystemFields`](/api/modules/server.md#withoutsystemfields)<[`DocumentByName`](/api/modules/server.md#documentbyname)<`DataModel`, `TableName`>> | The [Value](/api/modules/values.md#value) to insert into the given table. | #### Returns[​](#returns-2 "Direct link to Returns") `Promise`<[`GenericId`](/api/modules/values.md#genericid)<`TableName`>> * [GenericId](/api/modules/values.md#genericid) of the new document. #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/database.ts:297](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L297) *** ### patch[​](#patch "Direct link to patch") ▸ **patch**(`id`, `value`): `Promise`<`void`> 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. #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | Description | | ------- | ------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | [`GenericId`](/api/modules/values.md#genericid)<`TableName`> | The [GenericId](/api/modules/values.md#genericid) of the document to patch. | | `value` | `PatchValue`<[`DocumentByName`](/api/modules/server.md#documentbyname)<`DataModel`, `TableName`>> | The partial [GenericDocument](/api/modules/server.md#genericdocument) to merge into the specified document. If this new value specifies system fields like `_id`, they must match the document's existing field values. | #### Returns[​](#returns-3 "Direct link to Returns") `Promise`<`void`> #### Defined in[​](#defined-in-3 "Direct link to Defined in") [server/database.ts:312](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L312) *** ### replace[​](#replace "Direct link to replace") ▸ **replace**(`id`, `value`): `Promise`<`void`> Replace the value of an existing document, overwriting its old value. #### Parameters[​](#parameters-3 "Direct link to Parameters") | Name | Type | Description | | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | [`GenericId`](/api/modules/values.md#genericid)<`TableName`> | The [GenericId](/api/modules/values.md#genericid) of the document to replace. | | `value` | [`WithOptionalSystemFields`](/api/modules/server.md#withoptionalsystemfields)<[`DocumentByName`](/api/modules/server.md#documentbyname)<`DataModel`, `TableName`>> | The new [GenericDocument](/api/modules/server.md#genericdocument) for the document. This value can omit the system fields, and the database will fill them in. | #### Returns[​](#returns-4 "Direct link to Returns") `Promise`<`void`> #### Defined in[​](#defined-in-4 "Direct link to Defined in") [server/database.ts:324](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L324) *** ### delete[​](#delete "Direct link to delete") ▸ **delete**(`id`): `Promise`<`void`> Delete an existing document. #### Parameters[​](#parameters-4 "Direct link to Parameters") | Name | Type | Description | | ---- | ------------------------------------------------------------ | ---------------------------------------------------------------------------- | | `id` | [`GenericId`](/api/modules/values.md#genericid)<`TableName`> | The [GenericId](/api/modules/values.md#genericid) of the document to remove. | #### Returns[​](#returns-5 "Direct link to Returns") `Promise`<`void`> #### Defined in[​](#defined-in-5 "Direct link to Defined in") [server/database.ts:334](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L334) --- # Interface: CronJob [server](/api/modules/server.md).CronJob A schedule to run a Convex mutation or action on. You can schedule Convex functions to run regularly with interval and exporting it. ## Properties[​](#properties "Direct link to Properties") ### name[​](#name "Direct link to name") • **name**: `string` #### Defined in[​](#defined-in "Direct link to Defined in") [server/cron.ts:153](https://github.com/get-convex/convex-js/blob/main/src/server/cron.ts#L153) *** ### args[​](#args "Direct link to args") • **args**: [`JSONValue`](/api/modules/values.md#jsonvalue) #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/cron.ts:154](https://github.com/get-convex/convex-js/blob/main/src/server/cron.ts#L154) *** ### schedule[​](#schedule "Direct link to schedule") • **schedule**: `Schedule` #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/cron.ts:155](https://github.com/get-convex/convex-js/blob/main/src/server/cron.ts#L155) --- # Interface: DefineSchemaOptions\ [server](/api/modules/server.md).DefineSchemaOptions Options for [defineSchema](/api/modules/server.md#defineschema). ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ---------------------- | ----------------- | | `StrictTableNameTypes` | extends `boolean` | ## Properties[​](#properties "Direct link to Properties") ### schemaValidation[​](#schemavalidation "Direct link to schemaValidation") • `Optional` **schemaValidation**: `boolean` Whether Convex should validate at runtime that all documents match your schema. If `schemaValidation` is `true`, Convex will: 1. Check that all existing documents match your schema when your schema is pushed. 2. Check that all insertions and updates match your schema during mutations. If `schemaValidation` is `false`, 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. By default, `schemaValidation` is `true`. #### Defined in[​](#defined-in "Direct link to Defined in") [server/schema.ts:727](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L727) *** ### strictTableNameTypes[​](#stricttablenametypes "Direct link to strictTableNameTypes") • `Optional` **strictTableNameTypes**: `StrictTableNameTypes` Whether the TypeScript types should allow accessing tables not in the schema. If `strictTableNameTypes` is `true`, using tables not listed in the schema will generate a TypeScript compilation error. If `strictTableNameTypes` is `false`, you'll be able to access tables not listed in the schema and their document type will be `any`. `strictTableNameTypes: false` is useful for rapid prototyping. 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 other tables on the dashboard or in JavaScript mutations. By default, `strictTableNameTypes` is `true`. #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/schema.ts:746](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L746) --- # Interface: FilterBuilder\ [server](/api/modules/server.md).FilterBuilder An interface for defining filters in queries. `FilterBuilder` has various methods that produce [Expression](/api/classes/server.Expression.md)s. These expressions can be nested together along with constants to express a filter predicate. `FilterBuilder` is used within [filter](/api/interfaces/server.OrderedQuery.md#filter) to create query filters. Here are the available methods: | | | | ---------------------------- | --------------------------------------------- | | **Comparisons** | Error when `l` and `r` are not the same type. | | [`eq(l, r)`](#eq) | `l === r` | | [`neq(l, r)`](#neq) | `l !== r` | | [`lt(l, r)`](#lt) | `l < r` | | [`lte(l, r)`](#lte) | `l <= r` | | [`gt(l, r)`](#gt) | `l > r` | | [`gte(l, r)`](#gte) | `l >= r` | | | | | **Arithmetic** | Error when `l` and `r` are not the same type. | | [`add(l, r)`](#add) | `l + r` | | [`sub(l, r)`](#sub) | `l - r` | | [`mul(l, r)`](#mul) | `l * r` | | [`div(l, r)`](#div) | `l / r` | | [`mod(l, r)`](#mod) | `l % r` | | [`neg(x)`](#neg) | `-x` | | | | | **Logic** | Error if any param is not a `bool`. | | [`not(x)`](#not) | `!x` | | [`and(a, b, ..., z)`](#and) | `a && b && ... && z` | | [`or(a, b, ..., z)`](#or) | `a \|\| b \|\| ... \|\| z` | | | | | **Other** | | | [`field(fieldPath)`](#field) | Evaluates to the field at `fieldPath`. | ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `TableInfo` | extends [`GenericTableInfo`](/api/modules/server.md#generictableinfo) | ## Methods[​](#methods "Direct link to Methods") ### eq[​](#eq "Direct link to eq") ▸ **eq**<`T`>(`l`, `r`): [`Expression`](/api/classes/server.Expression.md)<`boolean`> `l === r` #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ---- | -------------------------------------------------------------- | | `T` | extends `undefined` \| [`Value`](/api/modules/values.md#value) | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | ---- | -------------------------------------------------------------------- | | `l` | [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`T`> | | `r` | [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`T`> | #### Returns[​](#returns "Direct link to Returns") [`Expression`](/api/classes/server.Expression.md)<`boolean`> #### Defined in[​](#defined-in "Direct link to Defined in") [server/filter\_builder.ts:87](https://github.com/get-convex/convex-js/blob/main/src/server/filter_builder.ts#L87) *** ### neq[​](#neq "Direct link to neq") ▸ **neq**<`T`>(`l`, `r`): [`Expression`](/api/classes/server.Expression.md)<`boolean`> `l !== r` #### Type parameters[​](#type-parameters-2 "Direct link to Type parameters") | Name | Type | | ---- | -------------------------------------------------------------- | | `T` | extends `undefined` \| [`Value`](/api/modules/values.md#value) | #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | | ---- | -------------------------------------------------------------------- | | `l` | [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`T`> | | `r` | [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`T`> | #### Returns[​](#returns-1 "Direct link to Returns") [`Expression`](/api/classes/server.Expression.md)<`boolean`> #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/filter\_builder.ts:97](https://github.com/get-convex/convex-js/blob/main/src/server/filter_builder.ts#L97) *** ### lt[​](#lt "Direct link to lt") ▸ **lt**<`T`>(`l`, `r`): [`Expression`](/api/classes/server.Expression.md)<`boolean`> `l < r` #### Type parameters[​](#type-parameters-3 "Direct link to Type parameters") | Name | Type | | ---- | ----------------------------------------------- | | `T` | extends [`Value`](/api/modules/values.md#value) | #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | | ---- | -------------------------------------------------------------------- | | `l` | [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`T`> | | `r` | [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`T`> | #### Returns[​](#returns-2 "Direct link to Returns") [`Expression`](/api/classes/server.Expression.md)<`boolean`> #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/filter\_builder.ts:107](https://github.com/get-convex/convex-js/blob/main/src/server/filter_builder.ts#L107) *** ### lte[​](#lte "Direct link to lte") ▸ **lte**<`T`>(`l`, `r`): [`Expression`](/api/classes/server.Expression.md)<`boolean`> `l <= r` #### Type parameters[​](#type-parameters-4 "Direct link to Type parameters") | Name | Type | | ---- | ----------------------------------------------- | | `T` | extends [`Value`](/api/modules/values.md#value) | #### Parameters[​](#parameters-3 "Direct link to Parameters") | Name | Type | | ---- | -------------------------------------------------------------------- | | `l` | [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`T`> | | `r` | [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`T`> | #### Returns[​](#returns-3 "Direct link to Returns") [`Expression`](/api/classes/server.Expression.md)<`boolean`> #### Defined in[​](#defined-in-3 "Direct link to Defined in") [server/filter\_builder.ts:117](https://github.com/get-convex/convex-js/blob/main/src/server/filter_builder.ts#L117) *** ### gt[​](#gt "Direct link to gt") ▸ **gt**<`T`>(`l`, `r`): [`Expression`](/api/classes/server.Expression.md)<`boolean`> `l > r` #### Type parameters[​](#type-parameters-5 "Direct link to Type parameters") | Name | Type | | ---- | ----------------------------------------------- | | `T` | extends [`Value`](/api/modules/values.md#value) | #### Parameters[​](#parameters-4 "Direct link to Parameters") | Name | Type | | ---- | -------------------------------------------------------------------- | | `l` | [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`T`> | | `r` | [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`T`> | #### Returns[​](#returns-4 "Direct link to Returns") [`Expression`](/api/classes/server.Expression.md)<`boolean`> #### Defined in[​](#defined-in-4 "Direct link to Defined in") [server/filter\_builder.ts:127](https://github.com/get-convex/convex-js/blob/main/src/server/filter_builder.ts#L127) *** ### gte[​](#gte "Direct link to gte") ▸ **gte**<`T`>(`l`, `r`): [`Expression`](/api/classes/server.Expression.md)<`boolean`> `l >= r` #### Type parameters[​](#type-parameters-6 "Direct link to Type parameters") | Name | Type | | ---- | ----------------------------------------------- | | `T` | extends [`Value`](/api/modules/values.md#value) | #### Parameters[​](#parameters-5 "Direct link to Parameters") | Name | Type | | ---- | -------------------------------------------------------------------- | | `l` | [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`T`> | | `r` | [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`T`> | #### Returns[​](#returns-5 "Direct link to Returns") [`Expression`](/api/classes/server.Expression.md)<`boolean`> #### Defined in[​](#defined-in-5 "Direct link to Defined in") [server/filter\_builder.ts:137](https://github.com/get-convex/convex-js/blob/main/src/server/filter_builder.ts#L137) *** ### add[​](#add "Direct link to add") ▸ **add**<`T`>(`l`, `r`): [`Expression`](/api/classes/server.Expression.md)<`T`> `l + r` #### Type parameters[​](#type-parameters-7 "Direct link to Type parameters") | Name | Type | | ---- | ------------------------------------------------------------- | | `T` | extends [`NumericValue`](/api/modules/values.md#numericvalue) | #### Parameters[​](#parameters-6 "Direct link to Parameters") | Name | Type | | ---- | -------------------------------------------------------------------- | | `l` | [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`T`> | | `r` | [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`T`> | #### Returns[​](#returns-6 "Direct link to Returns") [`Expression`](/api/classes/server.Expression.md)<`T`> #### Defined in[​](#defined-in-6 "Direct link to Defined in") [server/filter\_builder.ts:149](https://github.com/get-convex/convex-js/blob/main/src/server/filter_builder.ts#L149) *** ### sub[​](#sub "Direct link to sub") ▸ **sub**<`T`>(`l`, `r`): [`Expression`](/api/classes/server.Expression.md)<`T`> `l - r` #### Type parameters[​](#type-parameters-8 "Direct link to Type parameters") | Name | Type | | ---- | ------------------------------------------------------------- | | `T` | extends [`NumericValue`](/api/modules/values.md#numericvalue) | #### Parameters[​](#parameters-7 "Direct link to Parameters") | Name | Type | | ---- | -------------------------------------------------------------------- | | `l` | [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`T`> | | `r` | [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`T`> | #### Returns[​](#returns-7 "Direct link to Returns") [`Expression`](/api/classes/server.Expression.md)<`T`> #### Defined in[​](#defined-in-7 "Direct link to Defined in") [server/filter\_builder.ts:159](https://github.com/get-convex/convex-js/blob/main/src/server/filter_builder.ts#L159) *** ### mul[​](#mul "Direct link to mul") ▸ **mul**<`T`>(`l`, `r`): [`Expression`](/api/classes/server.Expression.md)<`T`> `l * r` #### Type parameters[​](#type-parameters-9 "Direct link to Type parameters") | Name | Type | | ---- | ------------------------------------------------------------- | | `T` | extends [`NumericValue`](/api/modules/values.md#numericvalue) | #### Parameters[​](#parameters-8 "Direct link to Parameters") | Name | Type | | ---- | -------------------------------------------------------------------- | | `l` | [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`T`> | | `r` | [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`T`> | #### Returns[​](#returns-8 "Direct link to Returns") [`Expression`](/api/classes/server.Expression.md)<`T`> #### Defined in[​](#defined-in-8 "Direct link to Defined in") [server/filter\_builder.ts:169](https://github.com/get-convex/convex-js/blob/main/src/server/filter_builder.ts#L169) *** ### div[​](#div "Direct link to div") ▸ **div**<`T`>(`l`, `r`): [`Expression`](/api/classes/server.Expression.md)<`T`> `l / r` #### Type parameters[​](#type-parameters-10 "Direct link to Type parameters") | Name | Type | | ---- | ------------------------------------------------------------- | | `T` | extends [`NumericValue`](/api/modules/values.md#numericvalue) | #### Parameters[​](#parameters-9 "Direct link to Parameters") | Name | Type | | ---- | -------------------------------------------------------------------- | | `l` | [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`T`> | | `r` | [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`T`> | #### Returns[​](#returns-9 "Direct link to Returns") [`Expression`](/api/classes/server.Expression.md)<`T`> #### Defined in[​](#defined-in-9 "Direct link to Defined in") [server/filter\_builder.ts:179](https://github.com/get-convex/convex-js/blob/main/src/server/filter_builder.ts#L179) *** ### mod[​](#mod "Direct link to mod") ▸ **mod**<`T`>(`l`, `r`): [`Expression`](/api/classes/server.Expression.md)<`T`> `l % r` #### Type parameters[​](#type-parameters-11 "Direct link to Type parameters") | Name | Type | | ---- | ------------------------------------------------------------- | | `T` | extends [`NumericValue`](/api/modules/values.md#numericvalue) | #### Parameters[​](#parameters-10 "Direct link to Parameters") | Name | Type | | ---- | -------------------------------------------------------------------- | | `l` | [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`T`> | | `r` | [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`T`> | #### Returns[​](#returns-10 "Direct link to Returns") [`Expression`](/api/classes/server.Expression.md)<`T`> #### Defined in[​](#defined-in-10 "Direct link to Defined in") [server/filter\_builder.ts:189](https://github.com/get-convex/convex-js/blob/main/src/server/filter_builder.ts#L189) *** ### neg[​](#neg "Direct link to neg") ▸ **neg**<`T`>(`x`): [`Expression`](/api/classes/server.Expression.md)<`T`> `-x` #### Type parameters[​](#type-parameters-12 "Direct link to Type parameters") | Name | Type | | ---- | ------------------------------------------------------------- | | `T` | extends [`NumericValue`](/api/modules/values.md#numericvalue) | #### Parameters[​](#parameters-11 "Direct link to Parameters") | Name | Type | | ---- | -------------------------------------------------------------------- | | `x` | [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`T`> | #### Returns[​](#returns-11 "Direct link to Returns") [`Expression`](/api/classes/server.Expression.md)<`T`> #### Defined in[​](#defined-in-11 "Direct link to Defined in") [server/filter\_builder.ts:199](https://github.com/get-convex/convex-js/blob/main/src/server/filter_builder.ts#L199) *** ### and[​](#and "Direct link to and") ▸ **and**(`...exprs`): [`Expression`](/api/classes/server.Expression.md)<`boolean`> `exprs[0] && exprs[1] && ... && exprs[n]` #### Parameters[​](#parameters-12 "Direct link to Parameters") | Name | Type | | ---------- | ----------------------------------------------------------------------------- | | `...exprs` | [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`boolean`>\[] | #### Returns[​](#returns-12 "Direct link to Returns") [`Expression`](/api/classes/server.Expression.md)<`boolean`> #### Defined in[​](#defined-in-12 "Direct link to Defined in") [server/filter\_builder.ts:208](https://github.com/get-convex/convex-js/blob/main/src/server/filter_builder.ts#L208) *** ### or[​](#or "Direct link to or") ▸ **or**(`...exprs`): [`Expression`](/api/classes/server.Expression.md)<`boolean`> `exprs[0] || exprs[1] || ... || exprs[n]` #### Parameters[​](#parameters-13 "Direct link to Parameters") | Name | Type | | ---------- | ----------------------------------------------------------------------------- | | `...exprs` | [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`boolean`>\[] | #### Returns[​](#returns-13 "Direct link to Returns") [`Expression`](/api/classes/server.Expression.md)<`boolean`> #### Defined in[​](#defined-in-13 "Direct link to Defined in") [server/filter\_builder.ts:215](https://github.com/get-convex/convex-js/blob/main/src/server/filter_builder.ts#L215) *** ### not[​](#not "Direct link to not") ▸ **not**(`x`): [`Expression`](/api/classes/server.Expression.md)<`boolean`> `!x` #### Parameters[​](#parameters-14 "Direct link to Parameters") | Name | Type | | ---- | -------------------------------------------------------------------------- | | `x` | [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`boolean`> | #### Returns[​](#returns-14 "Direct link to Returns") [`Expression`](/api/classes/server.Expression.md)<`boolean`> #### Defined in[​](#defined-in-14 "Direct link to Defined in") [server/filter\_builder.ts:222](https://github.com/get-convex/convex-js/blob/main/src/server/filter_builder.ts#L222) *** ### field[​](#field "Direct link to field") ▸ **field**<`FieldPath`>(`fieldPath`): [`Expression`](/api/classes/server.Expression.md)<[`FieldTypeFromFieldPath`](/api/modules/server.md#fieldtypefromfieldpath)<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>, `FieldPath`>> Evaluates to the field at the given `fieldPath`. For example, in [filter](/api/interfaces/server.OrderedQuery.md#filter) this can be used to examine the values being filtered. #### Example[​](#example "Direct link to Example") On this object: ``` { "user": { "isActive": true } } ``` `field("user.isActive")` evaluates to `true`. #### Type parameters[​](#type-parameters-13 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------- | | `FieldPath` | extends `string` | #### Parameters[​](#parameters-15 "Direct link to Parameters") | Name | Type | | ----------- | ----------- | | `fieldPath` | `FieldPath` | #### Returns[​](#returns-15 "Direct link to Returns") [`Expression`](/api/classes/server.Expression.md)<[`FieldTypeFromFieldPath`](/api/modules/server.md#fieldtypefromfieldpath)<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>, `FieldPath`>> #### Defined in[​](#defined-in-15 "Direct link to Defined in") [server/filter\_builder.ts:246](https://github.com/get-convex/convex-js/blob/main/src/server/filter_builder.ts#L246) --- # Interface: GenericActionCtx\ [server](/api/modules/server.md).GenericActionCtx A set of services for use within Convex action functions. The context is passed as the first argument to any Convex action run on the server. If you're using code generation, use the `ActionCtx` type in `convex/_generated/server.d.ts` which is typed for your data model. ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `DataModel` | extends [`GenericDataModel`](/api/modules/server.md#genericdatamodel) | ## Properties[​](#properties "Direct link to Properties") ### scheduler[​](#scheduler "Direct link to scheduler") • **scheduler**: [`Scheduler`](/api/interfaces/server.Scheduler.md) A utility for scheduling Convex functions to run in the future. #### Defined in[​](#defined-in "Direct link to Defined in") [server/registration.ts:236](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L236) *** ### auth[​](#auth "Direct link to auth") • **auth**: [`Auth`](/api/interfaces/server.Auth.md) Information about the currently authenticated user. #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/registration.ts:241](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L241) *** ### storage[​](#storage "Direct link to storage") • **storage**: [`StorageActionWriter`](/api/interfaces/server.StorageActionWriter.md) A utility for reading and writing files in storage. #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/registration.ts:246](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L246) ## Methods[​](#methods "Direct link to Methods") ### runQuery[​](#runquery "Direct link to runQuery") ▸ **runQuery**<`Query`>(`query`, `...args`): `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`>> Run the Convex query with the given name and arguments. Consider using an internalQuery to prevent users from calling the query directly. #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ------- | -------------------------------------------------------------------------------------------------------------- | | `Query` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"query"`, `"public"` \| `"internal"`> | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | Description | | --------- | ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | | `query` | `Query` | A [FunctionReference](/api/modules/server.md#functionreference) for the query to run. | | `...args` | [`OptionalRestArgs`](/api/modules/server.md#optionalrestargs)<`Query`> | The arguments to the query function. | #### Returns[​](#returns "Direct link to Returns") `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`>> A promise of the query's result. #### Defined in[​](#defined-in-3 "Direct link to Defined in") [server/registration.ts:196](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L196) *** ### runMutation[​](#runmutation "Direct link to runMutation") ▸ **runMutation**<`Mutation`>(`mutation`, `...args`): `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Mutation`>> Run the Convex mutation with the given name and arguments. Consider using an internalMutation to prevent users from calling the mutation directly. #### Type parameters[​](#type-parameters-2 "Direct link to Type parameters") | Name | Type | | ---------- | ----------------------------------------------------------------------------------------------------------------- | | `Mutation` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"mutation"`, `"public"` \| `"internal"`> | #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | Description | | ---------- | ------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | | `mutation` | `Mutation` | A [FunctionReference](/api/modules/server.md#functionreference) for the mutation to run. | | `...args` | [`OptionalRestArgs`](/api/modules/server.md#optionalrestargs)<`Mutation`> | The arguments to the mutation function. | #### Returns[​](#returns-1 "Direct link to Returns") `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Mutation`>> A promise of the mutation's result. #### Defined in[​](#defined-in-4 "Direct link to Defined in") [server/registration.ts:211](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L211) *** ### runAction[​](#runaction "Direct link to runAction") ▸ **runAction**<`Action`>(`action`, `...args`): `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Action`>> Run the Convex action with the given name and arguments. Consider using an internalAction to prevent users from calling the action directly. #### Type parameters[​](#type-parameters-3 "Direct link to Type parameters") | Name | Type | | -------- | --------------------------------------------------------------------------------------------------------------- | | `Action` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"action"`, `"public"` \| `"internal"`> | #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | Description | | --------- | ----------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | | `action` | `Action` | A [FunctionReference](/api/modules/server.md#functionreference) for the action to run. | | `...args` | [`OptionalRestArgs`](/api/modules/server.md#optionalrestargs)<`Action`> | The arguments to the action function. | #### Returns[​](#returns-2 "Direct link to Returns") `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Action`>> A promise of the action's result. #### Defined in[​](#defined-in-5 "Direct link to Defined in") [server/registration.ts:228](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L228) *** ### vectorSearch[​](#vectorsearch "Direct link to vectorSearch") ▸ **vectorSearch**<`TableName`, `IndexName`>(`tableName`, `indexName`, `query`): `Promise`<{ `_id`: [`GenericId`](/api/modules/values.md#genericid)<`TableName`> ; `_score`: `number` }\[]> Run a vector search on the given table and index. #### Type parameters[​](#type-parameters-4 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------------------------------- | | `TableName` | extends `string` | | `IndexName` | extends `string` \| `number` \| `symbol` | #### Parameters[​](#parameters-3 "Direct link to Parameters") | Name | Type | Description | | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `tableName` | `TableName` | The name of the table to query. | | `indexName` | `IndexName` | The name of the vector index on the table to query. | | `query` | `Object` | A [VectorSearchQuery](/api/interfaces/server.VectorSearchQuery.md) containing the vector to query, the number of results to return, and any filters. | | `query.vector` | `number`\[] | The query vector. This must have the same length as the `dimensions` of the index. This vector search will return the IDs of the documents most similar to this vector. | | `query.limit?` | `number` | The number of results to return. If specified, must be between 1 and 256 inclusive. **`Default`** `ts 10` | | `query.filter?` | (`q`: [`VectorFilterBuilder`](/api/interfaces/server.VectorFilterBuilder.md)<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<[`NamedTableInfo`](/api/modules/server.md#namedtableinfo)<`DataModel`, `TableName`>>, [`NamedVectorIndex`](/api/modules/server.md#namedvectorindex)<[`NamedTableInfo`](/api/modules/server.md#namedtableinfo)<`DataModel`, `TableName`>, `IndexName`>>) => [`FilterExpression`](/api/classes/server.FilterExpression.md)<`boolean`> | Optional filter expression made up of `q.or` and `q.eq` operating over the filter fields of the index. e.g. `filter: q => q.or(q.eq("genre", "comedy"), q.eq("genre", "drama"))` | #### Returns[​](#returns-3 "Direct link to Returns") `Promise`<{ `_id`: [`GenericId`](/api/modules/values.md#genericid)<`TableName`> ; `_score`: `number` }\[]> A promise of IDs and scores for the documents with the nearest vectors #### Defined in[​](#defined-in-6 "Direct link to Defined in") [server/registration.ts:258](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L258) --- # Interface: GenericDatabaseReader\ [server](/api/modules/server.md).GenericDatabaseReader An interface to read from the database within Convex query functions. The two entry points are: * [get](/api/interfaces/server.GenericDatabaseReader.md#get), which fetches a single document by its [GenericId](/api/modules/values.md#genericid). * [query](/api/interfaces/server.GenericDatabaseReader.md#query), which starts building a query. If you're using code generation, use the `DatabaseReader` type in `convex/_generated/server.d.ts` which is typed for your data model. ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `DataModel` | extends [`GenericDataModel`](/api/modules/server.md#genericdatamodel) | ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * `BaseDatabaseReader`<`DataModel`> ↳ **`GenericDatabaseReader`** ↳↳ [`GenericDatabaseWriter`](/api/interfaces/server.GenericDatabaseWriter.md) ## Properties[​](#properties "Direct link to Properties") ### system[​](#system "Direct link to system") • **system**: `BaseDatabaseReader`<[`SystemDataModel`](/api/interfaces/server.SystemDataModel.md)> An interface to read from the system tables within Convex query functions The two entry points are: * [get](/api/interfaces/server.GenericDatabaseReader.md#get), which fetches a single document by its [GenericId](/api/modules/values.md#genericid). * [query](/api/interfaces/server.GenericDatabaseReader.md#query), which starts building a query. #### Defined in[​](#defined-in "Direct link to Defined in") [server/database.ts:130](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L130) ## Methods[​](#methods "Direct link to Methods") ### get[​](#get "Direct link to get") ▸ **get**<`TableName`>(`id`): `Promise`<`null` | [`DocumentByName`](/api/modules/server.md#documentbyname)<`DataModel`, `TableName`>> Fetch a single document from the database by its [GenericId](/api/modules/values.md#genericid). #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------- | | `TableName` | extends `string` | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | Description | | ---- | ------------------------------------------------------------ | --------------------------------------------------------------------------------------------- | | `id` | [`GenericId`](/api/modules/values.md#genericid)<`TableName`> | The [GenericId](/api/modules/values.md#genericid) of the document to fetch from the database. | #### Returns[​](#returns "Direct link to Returns") `Promise`<`null` | [`DocumentByName`](/api/modules/server.md#documentbyname)<`DataModel`, `TableName`>> * The [GenericDocument](/api/modules/server.md#genericdocument) of the document at the given [GenericId](/api/modules/values.md#genericid), or `null` if it no longer exists. #### Inherited from[​](#inherited-from "Direct link to Inherited from") BaseDatabaseReader.get #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/database.ts:36](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L36) *** ### query[​](#query "Direct link to query") ▸ **query**<`TableName`>(`tableName`): [`QueryInitializer`](/api/interfaces/server.QueryInitializer.md)<[`NamedTableInfo`](/api/modules/server.md#namedtableinfo)<`DataModel`, `TableName`>> Begin a query for the given table name. Queries don't execute immediately, so calling this method and extending its query are free until the results are actually used. #### Type parameters[​](#type-parameters-2 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------- | | `TableName` | extends `string` | #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | Description | | ----------- | ----------- | ------------------------------- | | `tableName` | `TableName` | The name of the table to query. | #### Returns[​](#returns-1 "Direct link to Returns") [`QueryInitializer`](/api/interfaces/server.QueryInitializer.md)<[`NamedTableInfo`](/api/modules/server.md#namedtableinfo)<`DataModel`, `TableName`>> * A [QueryInitializer](/api/interfaces/server.QueryInitializer.md) object to start building a query. #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from") BaseDatabaseReader.query #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/database.ts:49](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L49) *** ### normalizeId[​](#normalizeid "Direct link to normalizeId") ▸ **normalizeId**<`TableName`>(`tableName`, `id`): `null` | [`GenericId`](/api/modules/values.md#genericid)<`TableName`> Returns the string ID format for the ID in a given table, or null if the ID is from a different table or is not a valid ID. This accepts the string ID format as well as the `.toString()` representation of the legacy class-based ID format. This does not guarantee that the ID exists (i.e. `db.get(id)` may return `null`). #### Type parameters[​](#type-parameters-3 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------- | | `TableName` | extends `string` | #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | Description | | ----------- | ----------- | ---------------------- | | `tableName` | `TableName` | The name of the table. | | `id` | `string` | The ID string. | #### Returns[​](#returns-2 "Direct link to Returns") `null` | [`GenericId`](/api/modules/values.md#genericid)<`TableName`> #### Inherited from[​](#inherited-from-2 "Direct link to Inherited from") BaseDatabaseReader.normalizeId #### Defined in[​](#defined-in-3 "Direct link to Defined in") [server/database.ts:65](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L65) --- # Interface: GenericDatabaseReaderWithTable\ [server](/api/modules/server.md).GenericDatabaseReaderWithTable ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `DataModel` | extends [`GenericDataModel`](/api/modules/server.md#genericdatamodel) | ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * `BaseDatabaseReaderWithTable`<`DataModel`> ↳ **`GenericDatabaseReaderWithTable`** ↳↳ [`GenericDatabaseWriterWithTable`](/api/interfaces/server.GenericDatabaseWriterWithTable.md) ## Properties[​](#properties "Direct link to Properties") ### system[​](#system "Direct link to system") • **system**: `BaseDatabaseReaderWithTable`<[`SystemDataModel`](/api/interfaces/server.SystemDataModel.md)> An interface to read from the system tables within Convex query functions The two entry points are: * [get](/api/interfaces/server.GenericDatabaseReader.md#get), which fetches a single document by its [GenericId](/api/modules/values.md#genericid). * [query](/api/interfaces/server.GenericDatabaseReader.md#query), which starts building a query. #### Defined in[​](#defined-in "Direct link to Defined in") [server/database.ts:146](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L146) ## Methods[​](#methods "Direct link to Methods") ### table[​](#table "Direct link to table") ▸ **table**<`TableName`>(`tableName`): [`BaseTableReader`](/api/interfaces/server.BaseTableReader.md)<`DataModel`, `TableName`> Scope the database to a specific table. #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------- | | `TableName` | extends `string` | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | ----------- | ----------- | | `tableName` | `TableName` | #### Returns[​](#returns "Direct link to Returns") [`BaseTableReader`](/api/interfaces/server.BaseTableReader.md)<`DataModel`, `TableName`> #### Inherited from[​](#inherited-from "Direct link to Inherited from") BaseDatabaseReaderWithTable.table #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/database.ts:75](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L75) --- # Interface: GenericDatabaseWriter\ [server](/api/modules/server.md).GenericDatabaseWriter An interface to read from and write to the database within Convex mutation functions. Convex guarantees that all writes within a single mutation are executed atomically, so you never have to worry about partial writes leaving your data in an inconsistent state. See [the Convex Guide](https://docs.convex.dev/understanding/convex-fundamentals/functions#atomicity-and-optimistic-concurrency-control) for the guarantees Convex provides your functions. If you're using code generation, use the `DatabaseReader` type in `convex/_generated/server.d.ts` which is typed for your data model. ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `DataModel` | extends [`GenericDataModel`](/api/modules/server.md#genericdatamodel) | ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * [`GenericDatabaseReader`](/api/interfaces/server.GenericDatabaseReader.md)<`DataModel`> ↳ **`GenericDatabaseWriter`** ## Properties[​](#properties "Direct link to Properties") ### system[​](#system "Direct link to system") • **system**: `BaseDatabaseReader`<[`SystemDataModel`](/api/interfaces/server.SystemDataModel.md)> An interface to read from the system tables within Convex query functions The two entry points are: * [get](/api/interfaces/server.GenericDatabaseReader.md#get), which fetches a single document by its [GenericId](/api/modules/values.md#genericid). * [query](/api/interfaces/server.GenericDatabaseReader.md#query), which starts building a query. #### Inherited from[​](#inherited-from "Direct link to Inherited from") [GenericDatabaseReader](/api/interfaces/server.GenericDatabaseReader.md).[system](/api/interfaces/server.GenericDatabaseReader.md#system) #### Defined in[​](#defined-in "Direct link to Defined in") [server/database.ts:130](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L130) ## Methods[​](#methods "Direct link to Methods") ### get[​](#get "Direct link to get") ▸ **get**<`TableName`>(`id`): `Promise`<`null` | [`DocumentByName`](/api/modules/server.md#documentbyname)<`DataModel`, `TableName`>> Fetch a single document from the database by its [GenericId](/api/modules/values.md#genericid). #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------- | | `TableName` | extends `string` | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | Description | | ---- | ------------------------------------------------------------ | --------------------------------------------------------------------------------------------- | | `id` | [`GenericId`](/api/modules/values.md#genericid)<`TableName`> | The [GenericId](/api/modules/values.md#genericid) of the document to fetch from the database. | #### Returns[​](#returns "Direct link to Returns") `Promise`<`null` | [`DocumentByName`](/api/modules/server.md#documentbyname)<`DataModel`, `TableName`>> * The [GenericDocument](/api/modules/server.md#genericdocument) of the document at the given [GenericId](/api/modules/values.md#genericid), or `null` if it no longer exists. #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from") [GenericDatabaseReader](/api/interfaces/server.GenericDatabaseReader.md).[get](/api/interfaces/server.GenericDatabaseReader.md#get) #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/database.ts:36](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L36) *** ### query[​](#query "Direct link to query") ▸ **query**<`TableName`>(`tableName`): [`QueryInitializer`](/api/interfaces/server.QueryInitializer.md)<[`NamedTableInfo`](/api/modules/server.md#namedtableinfo)<`DataModel`, `TableName`>> Begin a query for the given table name. Queries don't execute immediately, so calling this method and extending its query are free until the results are actually used. #### Type parameters[​](#type-parameters-2 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------- | | `TableName` | extends `string` | #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | Description | | ----------- | ----------- | ------------------------------- | | `tableName` | `TableName` | The name of the table to query. | #### Returns[​](#returns-1 "Direct link to Returns") [`QueryInitializer`](/api/interfaces/server.QueryInitializer.md)<[`NamedTableInfo`](/api/modules/server.md#namedtableinfo)<`DataModel`, `TableName`>> * A [QueryInitializer](/api/interfaces/server.QueryInitializer.md) object to start building a query. #### Inherited from[​](#inherited-from-2 "Direct link to Inherited from") [GenericDatabaseReader](/api/interfaces/server.GenericDatabaseReader.md).[query](/api/interfaces/server.GenericDatabaseReader.md#query) #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/database.ts:49](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L49) *** ### normalizeId[​](#normalizeid "Direct link to normalizeId") ▸ **normalizeId**<`TableName`>(`tableName`, `id`): `null` | [`GenericId`](/api/modules/values.md#genericid)<`TableName`> Returns the string ID format for the ID in a given table, or null if the ID is from a different table or is not a valid ID. This accepts the string ID format as well as the `.toString()` representation of the legacy class-based ID format. This does not guarantee that the ID exists (i.e. `db.get(id)` may return `null`). #### Type parameters[​](#type-parameters-3 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------- | | `TableName` | extends `string` | #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | Description | | ----------- | ----------- | ---------------------- | | `tableName` | `TableName` | The name of the table. | | `id` | `string` | The ID string. | #### Returns[​](#returns-2 "Direct link to Returns") `null` | [`GenericId`](/api/modules/values.md#genericid)<`TableName`> #### Inherited from[​](#inherited-from-3 "Direct link to Inherited from") [GenericDatabaseReader](/api/interfaces/server.GenericDatabaseReader.md).[normalizeId](/api/interfaces/server.GenericDatabaseReader.md#normalizeid) #### Defined in[​](#defined-in-3 "Direct link to Defined in") [server/database.ts:65](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L65) *** ### insert[​](#insert "Direct link to insert") ▸ **insert**<`TableName`>(`table`, `value`): `Promise`<[`GenericId`](/api/modules/values.md#genericid)<`TableName`>> Insert a new document into a table. #### Type parameters[​](#type-parameters-4 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------- | | `TableName` | extends `string` | #### Parameters[​](#parameters-3 "Direct link to Parameters") | Name | Type | Description | | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | | `table` | `TableName` | The name of the table to insert a new document into. | | `value` | [`WithoutSystemFields`](/api/modules/server.md#withoutsystemfields)<[`DocumentByName`](/api/modules/server.md#documentbyname)<`DataModel`, `TableName`>> | The [Value](/api/modules/values.md#value) to insert into the given table. | #### Returns[​](#returns-3 "Direct link to Returns") `Promise`<[`GenericId`](/api/modules/values.md#genericid)<`TableName`>> * [GenericId](/api/modules/values.md#genericid) of the new document. #### Defined in[​](#defined-in-4 "Direct link to Defined in") [server/database.ts:172](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L172) *** ### patch[​](#patch "Direct link to patch") ▸ **patch**<`TableName`>(`id`, `value`): `Promise`<`void`> 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. #### Type parameters[​](#type-parameters-5 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------- | | `TableName` | extends `string` | #### Parameters[​](#parameters-4 "Direct link to Parameters") | Name | Type | Description | | ------- | ------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | [`GenericId`](/api/modules/values.md#genericid)<`TableName`> | The [GenericId](/api/modules/values.md#genericid) of the document to patch. | | `value` | `PatchValue`<[`DocumentByName`](/api/modules/server.md#documentbyname)<`DataModel`, `TableName`>> | The partial [GenericDocument](/api/modules/server.md#genericdocument) to merge into the specified document. If this new value specifies system fields like `_id`, they must match the document's existing field values. | #### Returns[​](#returns-4 "Direct link to Returns") `Promise`<`void`> #### Defined in[​](#defined-in-5 "Direct link to Defined in") [server/database.ts:208](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L208) *** ### replace[​](#replace "Direct link to replace") ▸ **replace**<`TableName`>(`id`, `value`): `Promise`<`void`> Replace the value of an existing document, overwriting its old value. #### Type parameters[​](#type-parameters-6 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------- | | `TableName` | extends `string` | #### Parameters[​](#parameters-5 "Direct link to Parameters") | Name | Type | Description | | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | [`GenericId`](/api/modules/values.md#genericid)<`TableName`> | The [GenericId](/api/modules/values.md#genericid) of the document to replace. | | `value` | [`WithOptionalSystemFields`](/api/modules/server.md#withoptionalsystemfields)<[`DocumentByName`](/api/modules/server.md#documentbyname)<`DataModel`, `TableName`>> | The new [GenericDocument](/api/modules/server.md#genericdocument) for the document. This value can omit the system fields, and the database will fill them in. | #### Returns[​](#returns-5 "Direct link to Returns") `Promise`<`void`> #### Defined in[​](#defined-in-6 "Direct link to Defined in") [server/database.ts:236](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L236) *** ### delete[​](#delete "Direct link to delete") ▸ **delete**(`id`): `Promise`<`void`> Delete an existing document. #### Parameters[​](#parameters-6 "Direct link to Parameters") | Name | Type | Description | | ---- | ------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | | `id` | [`GenericId`](/api/modules/values.md#genericid)<[`TableNamesInDataModel`](/api/modules/server.md#tablenamesindatamodel)<`DataModel`>> | The [GenericId](/api/modules/values.md#genericid) of the document to remove. | #### Returns[​](#returns-6 "Direct link to Returns") `Promise`<`void`> #### Defined in[​](#defined-in-7 "Direct link to Defined in") [server/database.ts:259](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L259) --- # Interface: GenericDatabaseWriterWithTable\ [server](/api/modules/server.md).GenericDatabaseWriterWithTable An interface to read from and write to the database within Convex mutation functions. Convex guarantees that all writes within a single mutation are executed atomically, so you never have to worry about partial writes leaving your data in an inconsistent state. See [the Convex Guide](https://docs.convex.dev/understanding/convex-fundamentals/functions#atomicity-and-optimistic-concurrency-control) for the guarantees Convex provides your functions. If you're using code generation, use the `DatabaseReader` type in `convex/_generated/server.d.ts` which is typed for your data model. ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `DataModel` | extends [`GenericDataModel`](/api/modules/server.md#genericdatamodel) | ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * [`GenericDatabaseReaderWithTable`](/api/interfaces/server.GenericDatabaseReaderWithTable.md)<`DataModel`> ↳ **`GenericDatabaseWriterWithTable`** ## Properties[​](#properties "Direct link to Properties") ### system[​](#system "Direct link to system") • **system**: `BaseDatabaseReaderWithTable`<[`SystemDataModel`](/api/interfaces/server.SystemDataModel.md)> An interface to read from the system tables within Convex query functions The two entry points are: * [get](/api/interfaces/server.GenericDatabaseReader.md#get), which fetches a single document by its [GenericId](/api/modules/values.md#genericid). * [query](/api/interfaces/server.GenericDatabaseReader.md#query), which starts building a query. #### Inherited from[​](#inherited-from "Direct link to Inherited from") [GenericDatabaseReaderWithTable](/api/interfaces/server.GenericDatabaseReaderWithTable.md).[system](/api/interfaces/server.GenericDatabaseReaderWithTable.md#system) #### Defined in[​](#defined-in "Direct link to Defined in") [server/database.ts:146](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L146) ## Methods[​](#methods "Direct link to Methods") ### table[​](#table "Direct link to table") ▸ **table**<`TableName`>(`tableName`): [`BaseTableWriter`](/api/interfaces/server.BaseTableWriter.md)<`DataModel`, `TableName`> Scope the database to a specific table. #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------- | | `TableName` | extends `string` | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | ----------- | ----------- | | `tableName` | `TableName` | #### Returns[​](#returns "Direct link to Returns") [`BaseTableWriter`](/api/interfaces/server.BaseTableWriter.md)<`DataModel`, `TableName`> #### Overrides[​](#overrides "Direct link to Overrides") [GenericDatabaseReaderWithTable](/api/interfaces/server.GenericDatabaseReaderWithTable.md).[table](/api/interfaces/server.GenericDatabaseReaderWithTable.md#table) #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/database.ts:282](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L282) --- # Interface: GenericMutationCtx\ [server](/api/modules/server.md).GenericMutationCtx 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[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `DataModel` | extends [`GenericDataModel`](/api/modules/server.md#genericdatamodel) | ## Properties[​](#properties "Direct link to Properties") ### db[​](#db "Direct link to db") • **db**: [`GenericDatabaseWriter`](/api/interfaces/server.GenericDatabaseWriter.md)<`DataModel`> A utility for reading and writing data in the database. #### Defined in[​](#defined-in "Direct link to Defined in") [server/registration.ts:50](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L50) *** ### auth[​](#auth "Direct link to auth") • **auth**: [`Auth`](/api/interfaces/server.Auth.md) Information about the currently authenticated user. #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/registration.ts:55](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L55) *** ### storage[​](#storage "Direct link to storage") • **storage**: [`StorageWriter`](/api/interfaces/server.StorageWriter.md) A utility for reading and writing files in storage. #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/registration.ts:60](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L60) *** ### scheduler[​](#scheduler "Direct link to scheduler") • **scheduler**: [`Scheduler`](/api/interfaces/server.Scheduler.md) A utility for scheduling Convex functions to run in the future. #### Defined in[​](#defined-in-3 "Direct link to Defined in") [server/registration.ts:65](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L65) *** ### runQuery[​](#runquery "Direct link to runQuery") • **runQuery**: \(`query`: `Query`, ...`args`: [`OptionalRestArgs`](/api/modules/server.md#optionalrestargs)<`Query`>) => `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`>> #### Type declaration[​](#type-declaration "Direct link to Type declaration") ▸ <`Query`>(`query`, `...args`): `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`>> Call a query function within the same transaction. NOTE: often you can call the query's function directly instead of using this. `runQuery` incurs overhead of running argument and return value validation, and creating a new isolated JS context. ##### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ------- | -------------------------------------------------------------------------------------------------------------- | | `Query` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"query"`, `"public"` \| `"internal"`> | ##### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | --------- | ---------------------------------------------------------------------- | | `query` | `Query` | | `...args` | [`OptionalRestArgs`](/api/modules/server.md#optionalrestargs)<`Query`> | ##### Returns[​](#returns "Direct link to Returns") `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`>> #### Defined in[​](#defined-in-4 "Direct link to Defined in") [server/registration.ts:74](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L74) *** ### runMutation[​](#runmutation "Direct link to runMutation") • **runMutation**: \(`mutation`: `Mutation`, ...`args`: [`OptionalRestArgs`](/api/modules/server.md#optionalrestargs)<`Mutation`>) => `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Mutation`>> #### Type declaration[​](#type-declaration-1 "Direct link to Type declaration") ▸ <`Mutation`>(`mutation`, `...args`): `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Mutation`>> Call a mutation function within the same transaction. NOTE: often you can call the mutation's function directly instead of using this. `runMutation` incurs overhead of running argument and return value validation, and creating a new isolated JS context. The mutation runs in a sub-transaction, so if the mutation throws an error, all of its writes will be rolled back. Additionally, a successful mutation's writes will be serializable with other writes in the transaction. ##### Type parameters[​](#type-parameters-2 "Direct link to Type parameters") | Name | Type | | ---------- | ----------------------------------------------------------------------------------------------------------------- | | `Mutation` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"mutation"`, `"public"` \| `"internal"`> | ##### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | | ---------- | ------------------------------------------------------------------------- | | `mutation` | `Mutation` | | `...args` | [`OptionalRestArgs`](/api/modules/server.md#optionalrestargs)<`Mutation`> | ##### Returns[​](#returns-1 "Direct link to Returns") `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Mutation`>> #### Defined in[​](#defined-in-5 "Direct link to Defined in") [server/registration.ts:90](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L90) --- # Interface: GenericQueryCtx\ [server](/api/modules/server.md).GenericQueryCtx 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[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `DataModel` | extends [`GenericDataModel`](/api/modules/server.md#genericdatamodel) | ## Properties[​](#properties "Direct link to Properties") ### db[​](#db "Direct link to db") • **db**: [`GenericDatabaseReader`](/api/interfaces/server.GenericDatabaseReader.md)<`DataModel`> A utility for reading data in the database. #### Defined in[​](#defined-in "Direct link to Defined in") [server/registration.ts:130](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L130) *** ### auth[​](#auth "Direct link to auth") • **auth**: [`Auth`](/api/interfaces/server.Auth.md) Information about the currently authenticated user. #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/registration.ts:135](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L135) *** ### storage[​](#storage "Direct link to storage") • **storage**: [`StorageReader`](/api/interfaces/server.StorageReader.md) A utility for reading files in storage. #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/registration.ts:140](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L140) *** ### runQuery[​](#runquery "Direct link to runQuery") • **runQuery**: \(`query`: `Query`, ...`args`: [`OptionalRestArgs`](/api/modules/server.md#optionalrestargs)<`Query`>) => `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`>> #### Type declaration[​](#type-declaration "Direct link to Type declaration") ▸ <`Query`>(`query`, `...args`): `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`>> Call a query function within the same transaction. NOTE: often you can call the query's function directly instead of using this. `runQuery` incurs overhead of running argument and return value validation, and creating a new isolated JS context. ##### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ------- | -------------------------------------------------------------------------------------------------------------- | | `Query` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"query"`, `"public"` \| `"internal"`> | ##### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | --------- | ---------------------------------------------------------------------- | | `query` | `Query` | | `...args` | [`OptionalRestArgs`](/api/modules/server.md#optionalrestargs)<`Query`> | ##### Returns[​](#returns "Direct link to Returns") `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`>> #### Defined in[​](#defined-in-3 "Direct link to Defined in") [server/registration.ts:149](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L149) --- # Interface: IndexRangeBuilder\ [server](/api/modules/server.md).IndexRangeBuilder Builder to define an index range to query. An index range is a description of which documents Convex should consider when running the query. An index range is always a chained list of: 1. 0 or more equality expressions defined with `.eq`. 2. \[Optionally] A lower bound expression defined with `.gt` or `.gte`. 3. \[Optionally] An upper bound expression defined with `.lt` or `.lte`. **You must step through fields in index order.** Each equality expression must compare a different index field, starting from the beginning and in order. The upper and lower bounds must follow the equality expressions and compare the next field. For example, if there is an index of messages on `["projectId", "priority"]`, a range searching for "messages in 'myProjectId' with priority at least 100" would look like: ``` q.eq("projectId", myProjectId) .gte("priority", 100) ``` **The performance of your query is based on the specificity of the range.** This class is designed to only allow you to specify ranges that Convex can efficiently use your index to find. For all other filtering use [filter](/api/interfaces/server.OrderedQuery.md#filter). To learn about indexes, see [Indexes](https://docs.convex.dev/using/indexes). ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ------------- | ------------------------------------------------------------------------- | | `Document` | extends [`GenericDocument`](/api/modules/server.md#genericdocument) | | `IndexFields` | extends [`GenericIndexFields`](/api/modules/server.md#genericindexfields) | | `FieldNum` | extends `number` = `0` | ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * `LowerBoundIndexRangeBuilder`<`Document`, `IndexFields`\[`FieldNum`]> ↳ **`IndexRangeBuilder`** ## Methods[​](#methods "Direct link to Methods") ### eq[​](#eq "Direct link to eq") ▸ **eq**(`fieldName`, `value`): `NextIndexRangeBuilder`<`Document`, `IndexFields`, `FieldNum`> Restrict this range to documents where `doc[fieldName] === value`. #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | Description | | ----------- | ----------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | | `fieldName` | `IndexFields`\[`FieldNum`] | The name of the field to compare. Must be the next field in the index. | | `value` | [`FieldTypeFromFieldPath`](/api/modules/server.md#fieldtypefromfieldpath)<`Document`, `IndexFields`\[`FieldNum`]> | The value to compare against. | #### Returns[​](#returns "Direct link to Returns") `NextIndexRangeBuilder`<`Document`, `IndexFields`, `FieldNum`> #### Defined in[​](#defined-in "Direct link to Defined in") [server/index\_range\_builder.ts:76](https://github.com/get-convex/convex-js/blob/main/src/server/index_range_builder.ts#L76) *** ### gt[​](#gt "Direct link to gt") ▸ **gt**(`fieldName`, `value`): `UpperBoundIndexRangeBuilder`<`Document`, `IndexFields`\[`FieldNum`]> Restrict this range to documents where `doc[fieldName] > value`. #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | Description | | ----------- | ----------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | | `fieldName` | `IndexFields`\[`FieldNum`] | The name of the field to compare. Must be the next field in the index. | | `value` | [`FieldTypeFromFieldPath`](/api/modules/server.md#fieldtypefromfieldpath)<`Document`, `IndexFields`\[`FieldNum`]> | The value to compare against. | #### Returns[​](#returns-1 "Direct link to Returns") `UpperBoundIndexRangeBuilder`<`Document`, `IndexFields`\[`FieldNum`]> #### Inherited from[​](#inherited-from "Direct link to Inherited from") LowerBoundIndexRangeBuilder.gt #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/index\_range\_builder.ts:115](https://github.com/get-convex/convex-js/blob/main/src/server/index_range_builder.ts#L115) *** ### gte[​](#gte "Direct link to gte") ▸ **gte**(`fieldName`, `value`): `UpperBoundIndexRangeBuilder`<`Document`, `IndexFields`\[`FieldNum`]> Restrict this range to documents where `doc[fieldName] >= value`. #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | Description | | ----------- | ----------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | | `fieldName` | `IndexFields`\[`FieldNum`] | The name of the field to compare. Must be the next field in the index. | | `value` | [`FieldTypeFromFieldPath`](/api/modules/server.md#fieldtypefromfieldpath)<`Document`, `IndexFields`\[`FieldNum`]> | The value to compare against. | #### Returns[​](#returns-2 "Direct link to Returns") `UpperBoundIndexRangeBuilder`<`Document`, `IndexFields`\[`FieldNum`]> #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from") LowerBoundIndexRangeBuilder.gte #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/index\_range\_builder.ts:126](https://github.com/get-convex/convex-js/blob/main/src/server/index_range_builder.ts#L126) *** ### lt[​](#lt "Direct link to lt") ▸ **lt**(`fieldName`, `value`): [`IndexRange`](/api/classes/server.IndexRange.md) Restrict this range to documents where `doc[fieldName] < value`. #### Parameters[​](#parameters-3 "Direct link to Parameters") | Name | Type | Description | | ----------- | ----------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | `fieldName` | `IndexFields`\[`FieldNum`] | The name of the field to compare. Must be the same index field used in the lower bound (`.gt` or `.gte`) or the next field if no lower bound was specified. | | `value` | [`FieldTypeFromFieldPath`](/api/modules/server.md#fieldtypefromfieldpath)<`Document`, `IndexFields`\[`FieldNum`]> | The value to compare against. | #### Returns[​](#returns-3 "Direct link to Returns") [`IndexRange`](/api/classes/server.IndexRange.md) #### Inherited from[​](#inherited-from-2 "Direct link to Inherited from") LowerBoundIndexRangeBuilder.lt #### Defined in[​](#defined-in-3 "Direct link to Defined in") [server/index\_range\_builder.ts:151](https://github.com/get-convex/convex-js/blob/main/src/server/index_range_builder.ts#L151) *** ### lte[​](#lte "Direct link to lte") ▸ **lte**(`fieldName`, `value`): [`IndexRange`](/api/classes/server.IndexRange.md) Restrict this range to documents where `doc[fieldName] <= value`. #### Parameters[​](#parameters-4 "Direct link to Parameters") | Name | Type | Description | | ----------- | ----------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | `fieldName` | `IndexFields`\[`FieldNum`] | The name of the field to compare. Must be the same index field used in the lower bound (`.gt` or `.gte`) or the next field if no lower bound was specified. | | `value` | [`FieldTypeFromFieldPath`](/api/modules/server.md#fieldtypefromfieldpath)<`Document`, `IndexFields`\[`FieldNum`]> | The value to compare against. | #### Returns[​](#returns-4 "Direct link to Returns") [`IndexRange`](/api/classes/server.IndexRange.md) #### Inherited from[​](#inherited-from-3 "Direct link to Inherited from") LowerBoundIndexRangeBuilder.lte #### Defined in[​](#defined-in-4 "Direct link to Defined in") [server/index\_range\_builder.ts:164](https://github.com/get-convex/convex-js/blob/main/src/server/index_range_builder.ts#L164) --- # Interface: OrderedQuery\ [server](/api/modules/server.md).OrderedQuery A [Query](/api/interfaces/server.Query.md) with an order that has already been defined. ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `TableInfo` | extends [`GenericTableInfo`](/api/modules/server.md#generictableinfo) | ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * `AsyncIterable`<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>> ↳ **`OrderedQuery`** ↳↳ [`Query`](/api/interfaces/server.Query.md) ## Methods[​](#methods "Direct link to Methods") ### \[asyncIterator][​](#asynciterator "Direct link to \[asyncIterator]") ▸ **\[asyncIterator]**(): `AsyncIterator`<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>, `any`, `undefined`> #### Returns[​](#returns "Direct link to Returns") `AsyncIterator`<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>, `any`, `undefined`> #### Inherited from[​](#inherited-from "Direct link to Inherited from") AsyncIterable.\[asyncIterator] #### Defined in[​](#defined-in "Direct link to Defined in") ../../common/temp/node\_modules/.pnpm/typescript\@5.0.4/node\_modules/typescript/lib/lib.es2018.asynciterable.d.ts:38 *** ### filter[​](#filter "Direct link to filter") ▸ **filter**(`predicate`): [`OrderedQuery`](/api/interfaces/server.OrderedQuery.md)<`TableInfo`> Filter the query output, returning only the values for which `predicate` evaluates to true. #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | Description | | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `predicate` | (`q`: [`FilterBuilder`](/api/interfaces/server.FilterBuilder.md)<`TableInfo`>) => [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`boolean`> | An [Expression](/api/classes/server.Expression.md) constructed with the supplied [FilterBuilder](/api/interfaces/server.FilterBuilder.md) that specifies which documents to keep. | #### Returns[​](#returns-1 "Direct link to Returns") [`OrderedQuery`](/api/interfaces/server.OrderedQuery.md)<`TableInfo`> * A new [OrderedQuery](/api/interfaces/server.OrderedQuery.md) with the given filter predicate applied. #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/query.ts:165](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L165) *** ### paginate[​](#paginate "Direct link to paginate") ▸ **paginate**(`paginationOpts`): `Promise`<[`PaginationResult`](/api/interfaces/server.PaginationResult.md)<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>>> Load a page of `n` results and obtain a [Cursor](/api/modules/server.md#cursor) for loading more. Note: If this is called from a reactive query function the number of results may not match `paginationOpts.numItems`! `paginationOpts.numItems` is only an initial value. After the first invocation, `paginate` will return all items in the original query range. This ensures that all pages will remain adjacent and non-overlapping. #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | Description | | ---------------- | ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | | `paginationOpts` | [`PaginationOptions`](/api/interfaces/server.PaginationOptions.md) | A [PaginationOptions](/api/interfaces/server.PaginationOptions.md) object containing the number of items to load and the cursor to start at. | #### Returns[​](#returns-2 "Direct link to Returns") `Promise`<[`PaginationResult`](/api/interfaces/server.PaginationResult.md)<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>>> A [PaginationResult](/api/interfaces/server.PaginationResult.md) containing the page of results and a cursor to continue paginating. #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/query.ts:194](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L194) *** ### collect[​](#collect "Direct link to collect") ▸ **collect**(): `Promise`<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>\[]> Execute the query and return all of the results as an array. Note: when processing a query with a lot of results, it's often better to use the `Query` as an `AsyncIterable` instead. #### Returns[​](#returns-3 "Direct link to Returns") `Promise`<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>\[]> * An array of all of the query's results. #### Defined in[​](#defined-in-3 "Direct link to Defined in") [server/query.ts:206](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L206) *** ### take[​](#take "Direct link to take") ▸ **take**(`n`): `Promise`<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>\[]> Execute the query and return the first `n` results. #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | Description | | ---- | -------- | ---------------------------- | | `n` | `number` | The number of items to take. | #### Returns[​](#returns-4 "Direct link to Returns") `Promise`<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>\[]> * An array of the first `n` results of the query (or less if the query doesn't have `n` results). #### Defined in[​](#defined-in-4 "Direct link to Defined in") [server/query.ts:215](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L215) *** ### first[​](#first "Direct link to first") ▸ **first**(): `Promise`<`null` | [`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>> Execute the query and return the first result if there is one. #### Returns[​](#returns-5 "Direct link to Returns") `Promise`<`null` | [`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>> * The first value of the query or `null` if the query returned no results. #### Defined in[​](#defined-in-5 "Direct link to Defined in") [server/query.ts:222](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L222) *** ### unique[​](#unique "Direct link to unique") ▸ **unique**(): `Promise`<`null` | [`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>> Execute the query and return the singular result if there is one. **`Throws`** Will throw an error if the query returns more than one result. #### Returns[​](#returns-6 "Direct link to Returns") `Promise`<`null` | [`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>> * The single result returned from the query or null if none exists. #### Defined in[​](#defined-in-6 "Direct link to Defined in") [server/query.ts:230](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L230) --- # Interface: PaginationOptions [server](/api/modules/server.md).PaginationOptions The options passed to [paginate](/api/interfaces/server.OrderedQuery.md#paginate). To use this type in [argument validation](https://docs.convex.dev/functions/validation), use the [paginationOptsValidator](/api/modules/server.md#paginationoptsvalidator). ## Properties[​](#properties "Direct link to Properties") ### numItems[​](#numitems "Direct link to numItems") • **numItems**: `number` Number of items to load in this page of results. Note: This is only an initial value! If you are running this paginated query in a reactive query function, you may receive more or less items than this if items were added to or removed from the query range. #### Defined in[​](#defined-in "Direct link to Defined in") [server/pagination.ts:78](https://github.com/get-convex/convex-js/blob/main/src/server/pagination.ts#L78) *** ### cursor[​](#cursor "Direct link to cursor") • **cursor**: `null` | `string` A [Cursor](/api/modules/server.md#cursor) representing the start of this page or `null` to start at the beginning of the query results. #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/pagination.ts:84](https://github.com/get-convex/convex-js/blob/main/src/server/pagination.ts#L84) --- # Interface: PaginationResult\ [server](/api/modules/server.md).PaginationResult The result of paginating using [paginate](/api/interfaces/server.OrderedQuery.md#paginate). ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | | ---- | | `T` | ## Properties[​](#properties "Direct link to Properties") ### page[​](#page "Direct link to page") • **page**: `T`\[] The page of results. #### Defined in[​](#defined-in "Direct link to Defined in") [server/pagination.ts:32](https://github.com/get-convex/convex-js/blob/main/src/server/pagination.ts#L32) *** ### isDone[​](#isdone "Direct link to isDone") • **isDone**: `boolean` Have we reached the end of the results? #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/pagination.ts:37](https://github.com/get-convex/convex-js/blob/main/src/server/pagination.ts#L37) *** ### continueCursor[​](#continuecursor "Direct link to continueCursor") • **continueCursor**: `string` A [Cursor](/api/modules/server.md#cursor) to continue loading more results. #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/pagination.ts:42](https://github.com/get-convex/convex-js/blob/main/src/server/pagination.ts#L42) *** ### splitCursor[​](#splitcursor "Direct link to splitCursor") • `Optional` **splitCursor**: `null` | `string` A [Cursor](/api/modules/server.md#cursor) to split the page into two, so the page from (cursor, continueCursor] can be replaced by two pages (cursor, splitCursor] and (splitCursor, continueCursor]. #### Defined in[​](#defined-in-3 "Direct link to Defined in") [server/pagination.ts:49](https://github.com/get-convex/convex-js/blob/main/src/server/pagination.ts#L49) *** ### pageStatus[​](#pagestatus "Direct link to pageStatus") • `Optional` **pageStatus**: `null` | `"SplitRecommended"` | `"SplitRequired"` When a query reads too much data, it may return 'SplitRecommended' to indicate that the page should be split into two with `splitCursor`. When a query reads so much data that `page` might be incomplete, its status becomes 'SplitRequired'. #### Defined in[​](#defined-in-4 "Direct link to Defined in") [server/pagination.ts:57](https://github.com/get-convex/convex-js/blob/main/src/server/pagination.ts#L57) --- # Interface: Query\ [server](/api/modules/server.md).Query The [Query](/api/interfaces/server.Query.md) interface allows functions to read values out of the database. **If you only need to load an object by ID, use `db.get(id)` instead.** Executing a query consists of calling 1. (Optional) [order](/api/interfaces/server.Query.md#order) to define the order 2. (Optional) [filter](/api/interfaces/server.OrderedQuery.md#filter) to refine the results 3. A *consumer* method to obtain the results Queries are lazily evaluated. No work is done until iteration begins, so constructing and extending a query is free. The query is executed incrementally as the results are iterated over, so early terminating also reduces the cost of the query. It is more efficient to use `filter` expression rather than executing JavaScript to filter. | | | | -------------------------------------------- | ---------------------------------------------------------------------- | | **Ordering** | | | [`order("asc")`](#order) | Define the order of query results. | | | | | **Filtering** | | | [`filter(...)`](#filter) | Filter the query results to only the values that match some condition. | | | | | **Consuming** | Execute a query and return results in different ways. | | [`[Symbol.asyncIterator]()`](#asynciterator) | The query's results can be iterated over using a `for await..of` loop. | | [`collect()`](#collect) | Return all of the results as an array. | | [`take(n: number)`](#take) | Return the first `n` results as an array. | | [`first()`](#first) | Return the first result. | | [`unique()`](#unique) | Return the only result, and throw if there is more than one result. | To learn more about how to write queries, see [Querying the Database](https://docs.convex.dev/using/database-queries). ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `TableInfo` | extends [`GenericTableInfo`](/api/modules/server.md#generictableinfo) | ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * [`OrderedQuery`](/api/interfaces/server.OrderedQuery.md)<`TableInfo`> ↳ **`Query`** ↳↳ [`QueryInitializer`](/api/interfaces/server.QueryInitializer.md) ## Methods[​](#methods "Direct link to Methods") ### \[asyncIterator][​](#asynciterator "Direct link to \[asyncIterator]") ▸ **\[asyncIterator]**(): `AsyncIterator`<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>, `any`, `undefined`> #### Returns[​](#returns "Direct link to Returns") `AsyncIterator`<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>, `any`, `undefined`> #### Inherited from[​](#inherited-from "Direct link to Inherited from") [OrderedQuery](/api/interfaces/server.OrderedQuery.md).[\[asyncIterator\]](/api/interfaces/server.OrderedQuery.md#%5Basynciterator%5D) #### Defined in[​](#defined-in "Direct link to Defined in") ../../common/temp/node\_modules/.pnpm/typescript\@5.0.4/node\_modules/typescript/lib/lib.es2018.asynciterable.d.ts:38 *** ### order[​](#order "Direct link to order") ▸ **order**(`order`): [`OrderedQuery`](/api/interfaces/server.OrderedQuery.md)<`TableInfo`> Define the order of the query output. Use `"asc"` for an ascending order and `"desc"` for a descending order. If not specified, the order defaults to ascending. #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | Description | | ------- | ------------------- | ------------------------------- | | `order` | `"asc"` \| `"desc"` | The order to return results in. | #### Returns[​](#returns-1 "Direct link to Returns") [`OrderedQuery`](/api/interfaces/server.OrderedQuery.md)<`TableInfo`> #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/query.ts:149](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L149) *** ### filter[​](#filter "Direct link to filter") ▸ **filter**(`predicate`): [`Query`](/api/interfaces/server.Query.md)<`TableInfo`> Filter the query output, returning only the values for which `predicate` evaluates to true. #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | Description | | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `predicate` | (`q`: [`FilterBuilder`](/api/interfaces/server.FilterBuilder.md)<`TableInfo`>) => [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`boolean`> | An [Expression](/api/classes/server.Expression.md) constructed with the supplied [FilterBuilder](/api/interfaces/server.FilterBuilder.md) that specifies which documents to keep. | #### Returns[​](#returns-2 "Direct link to Returns") [`Query`](/api/interfaces/server.Query.md)<`TableInfo`> * A new [OrderedQuery](/api/interfaces/server.OrderedQuery.md) with the given filter predicate applied. #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from") [OrderedQuery](/api/interfaces/server.OrderedQuery.md).[filter](/api/interfaces/server.OrderedQuery.md#filter) #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/query.ts:165](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L165) *** ### paginate[​](#paginate "Direct link to paginate") ▸ **paginate**(`paginationOpts`): `Promise`<[`PaginationResult`](/api/interfaces/server.PaginationResult.md)<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>>> Load a page of `n` results and obtain a [Cursor](/api/modules/server.md#cursor) for loading more. Note: If this is called from a reactive query function the number of results may not match `paginationOpts.numItems`! `paginationOpts.numItems` is only an initial value. After the first invocation, `paginate` will return all items in the original query range. This ensures that all pages will remain adjacent and non-overlapping. #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | Description | | ---------------- | ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | | `paginationOpts` | [`PaginationOptions`](/api/interfaces/server.PaginationOptions.md) | A [PaginationOptions](/api/interfaces/server.PaginationOptions.md) object containing the number of items to load and the cursor to start at. | #### Returns[​](#returns-3 "Direct link to Returns") `Promise`<[`PaginationResult`](/api/interfaces/server.PaginationResult.md)<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>>> A [PaginationResult](/api/interfaces/server.PaginationResult.md) containing the page of results and a cursor to continue paginating. #### Inherited from[​](#inherited-from-2 "Direct link to Inherited from") [OrderedQuery](/api/interfaces/server.OrderedQuery.md).[paginate](/api/interfaces/server.OrderedQuery.md#paginate) #### Defined in[​](#defined-in-3 "Direct link to Defined in") [server/query.ts:194](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L194) *** ### collect[​](#collect "Direct link to collect") ▸ **collect**(): `Promise`<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>\[]> Execute the query and return all of the results as an array. Note: when processing a query with a lot of results, it's often better to use the `Query` as an `AsyncIterable` instead. #### Returns[​](#returns-4 "Direct link to Returns") `Promise`<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>\[]> * An array of all of the query's results. #### Inherited from[​](#inherited-from-3 "Direct link to Inherited from") [OrderedQuery](/api/interfaces/server.OrderedQuery.md).[collect](/api/interfaces/server.OrderedQuery.md#collect) #### Defined in[​](#defined-in-4 "Direct link to Defined in") [server/query.ts:206](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L206) *** ### take[​](#take "Direct link to take") ▸ **take**(`n`): `Promise`<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>\[]> Execute the query and return the first `n` results. #### Parameters[​](#parameters-3 "Direct link to Parameters") | Name | Type | Description | | ---- | -------- | ---------------------------- | | `n` | `number` | The number of items to take. | #### Returns[​](#returns-5 "Direct link to Returns") `Promise`<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>\[]> * An array of the first `n` results of the query (or less if the query doesn't have `n` results). #### Inherited from[​](#inherited-from-4 "Direct link to Inherited from") [OrderedQuery](/api/interfaces/server.OrderedQuery.md).[take](/api/interfaces/server.OrderedQuery.md#take) #### Defined in[​](#defined-in-5 "Direct link to Defined in") [server/query.ts:215](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L215) *** ### first[​](#first "Direct link to first") ▸ **first**(): `Promise`<`null` | [`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>> Execute the query and return the first result if there is one. #### Returns[​](#returns-6 "Direct link to Returns") `Promise`<`null` | [`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>> * The first value of the query or `null` if the query returned no results. #### Inherited from[​](#inherited-from-5 "Direct link to Inherited from") [OrderedQuery](/api/interfaces/server.OrderedQuery.md).[first](/api/interfaces/server.OrderedQuery.md#first) #### Defined in[​](#defined-in-6 "Direct link to Defined in") [server/query.ts:222](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L222) *** ### unique[​](#unique "Direct link to unique") ▸ **unique**(): `Promise`<`null` | [`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>> Execute the query and return the singular result if there is one. **`Throws`** Will throw an error if the query returns more than one result. #### Returns[​](#returns-7 "Direct link to Returns") `Promise`<`null` | [`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>> * The single result returned from the query or null if none exists. #### Inherited from[​](#inherited-from-6 "Direct link to Inherited from") [OrderedQuery](/api/interfaces/server.OrderedQuery.md).[unique](/api/interfaces/server.OrderedQuery.md#unique) #### Defined in[​](#defined-in-7 "Direct link to Defined in") [server/query.ts:230](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L230) --- # Interface: QueryInitializer\ [server](/api/modules/server.md).QueryInitializer The [QueryInitializer](/api/interfaces/server.QueryInitializer.md) interface is the entry point for building a [Query](/api/interfaces/server.Query.md) over a Convex database table. There are two types of queries: 1. Full table scans: Queries created with [fullTableScan](/api/interfaces/server.QueryInitializer.md#fulltablescan) which iterate over all of the documents in the table in insertion order. 2. Indexed Queries: Queries created with [withIndex](/api/interfaces/server.QueryInitializer.md#withindex) which iterate over an index range in index order. For convenience, [QueryInitializer](/api/interfaces/server.QueryInitializer.md) extends the [Query](/api/interfaces/server.Query.md) interface, implicitly starting a full table scan. ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `TableInfo` | extends [`GenericTableInfo`](/api/modules/server.md#generictableinfo) | ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * [`Query`](/api/interfaces/server.Query.md)<`TableInfo`> ↳ **`QueryInitializer`** ## Methods[​](#methods "Direct link to Methods") ### \[asyncIterator][​](#asynciterator "Direct link to \[asyncIterator]") ▸ **\[asyncIterator]**(): `AsyncIterator`<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>, `any`, `undefined`> #### Returns[​](#returns "Direct link to Returns") `AsyncIterator`<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>, `any`, `undefined`> #### Inherited from[​](#inherited-from "Direct link to Inherited from") [Query](/api/interfaces/server.Query.md).[\[asyncIterator\]](/api/interfaces/server.Query.md#%5Basynciterator%5D) #### Defined in[​](#defined-in "Direct link to Defined in") ../../common/temp/node\_modules/.pnpm/typescript\@5.0.4/node\_modules/typescript/lib/lib.es2018.asynciterable.d.ts:38 *** ### fullTableScan[​](#fulltablescan "Direct link to fullTableScan") ▸ **fullTableScan**(): [`Query`](/api/interfaces/server.Query.md)<`TableInfo`> Query by reading all of the values out of this table. This query's cost is relative to the size of the entire table, so this should only be used on tables that will stay very small (say between a few hundred and a few thousand documents) and are updated infrequently. #### Returns[​](#returns-1 "Direct link to Returns") [`Query`](/api/interfaces/server.Query.md)<`TableInfo`> * The [Query](/api/interfaces/server.Query.md) that iterates over every document of the table. #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/query.ts:40](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L40) *** ### withIndex[​](#withindex "Direct link to withIndex") ▸ **withIndex**<`IndexName`>(`indexName`, `indexRange?`): [`Query`](/api/interfaces/server.Query.md)<`TableInfo`> Query by reading documents from an index on this table. This query's cost is relative to the number of documents that match the index range expression. Results will be returned in index order. To learn about indexes, see [Indexes](https://docs.convex.dev/using/indexes). #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------------------------------- | | `IndexName` | extends `string` \| `number` \| `symbol` | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | Description | | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `indexName` | `IndexName` | The name of the index to query. | | `indexRange?` | (`q`: [`IndexRangeBuilder`](/api/interfaces/server.IndexRangeBuilder.md)<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>, [`NamedIndex`](/api/modules/server.md#namedindex)<`TableInfo`, `IndexName`>, `0`>) => [`IndexRange`](/api/classes/server.IndexRange.md) | An optional index range constructed with the supplied [IndexRangeBuilder](/api/interfaces/server.IndexRangeBuilder.md). An index range is a description of which documents Convex should consider when running the query. If no index range is present, the query will consider all documents in the index. | #### Returns[​](#returns-2 "Direct link to Returns") [`Query`](/api/interfaces/server.Query.md)<`TableInfo`> * The query that yields documents in the index. #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/query.ts:59](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L59) *** ### withSearchIndex[​](#withsearchindex "Direct link to withSearchIndex") ▸ **withSearchIndex**<`IndexName`>(`indexName`, `searchFilter`): [`OrderedQuery`](/api/interfaces/server.OrderedQuery.md)<`TableInfo`> Query by running a full text search against a search index. Search queries must always search for some text within the index's `searchField`. This query can optionally add equality filters for any `filterFields` specified in the index. Documents will be returned in relevance order based on how well they match the search text. To learn about full text search, see [Indexes](https://docs.convex.dev/text-search). #### Type parameters[​](#type-parameters-2 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------------------------------- | | `IndexName` | extends `string` \| `number` \| `symbol` | #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `indexName` | `IndexName` | The name of the search index to query. | | `searchFilter` | (`q`: [`SearchFilterBuilder`](/api/interfaces/server.SearchFilterBuilder.md)<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>, [`NamedSearchIndex`](/api/modules/server.md#namedsearchindex)<`TableInfo`, `IndexName`>>) => [`SearchFilter`](/api/classes/server.SearchFilter.md) | A search filter expression constructed with the supplied [SearchFilterBuilder](/api/interfaces/server.SearchFilterBuilder.md). This defines the full text search to run along with equality filtering to run within the search index. | #### Returns[​](#returns-3 "Direct link to Returns") [`OrderedQuery`](/api/interfaces/server.OrderedQuery.md)<`TableInfo`> * A query that searches for matching documents, returning them in relevancy order. #### Defined in[​](#defined-in-3 "Direct link to Defined in") [server/query.ts:88](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L88) *** ### order[​](#order "Direct link to order") ▸ **order**(`order`): [`OrderedQuery`](/api/interfaces/server.OrderedQuery.md)<`TableInfo`> Define the order of the query output. Use `"asc"` for an ascending order and `"desc"` for a descending order. If not specified, the order defaults to ascending. #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | Description | | ------- | ------------------- | ------------------------------- | | `order` | `"asc"` \| `"desc"` | The order to return results in. | #### Returns[​](#returns-4 "Direct link to Returns") [`OrderedQuery`](/api/interfaces/server.OrderedQuery.md)<`TableInfo`> #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from") [Query](/api/interfaces/server.Query.md).[order](/api/interfaces/server.Query.md#order) #### Defined in[​](#defined-in-4 "Direct link to Defined in") [server/query.ts:149](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L149) *** ### filter[​](#filter "Direct link to filter") ▸ **filter**(`predicate`): [`QueryInitializer`](/api/interfaces/server.QueryInitializer.md)<`TableInfo`> Filter the query output, returning only the values for which `predicate` evaluates to true. #### Parameters[​](#parameters-3 "Direct link to Parameters") | Name | Type | Description | | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `predicate` | (`q`: [`FilterBuilder`](/api/interfaces/server.FilterBuilder.md)<`TableInfo`>) => [`ExpressionOrValue`](/api/modules/server.md#expressionorvalue)<`boolean`> | An [Expression](/api/classes/server.Expression.md) constructed with the supplied [FilterBuilder](/api/interfaces/server.FilterBuilder.md) that specifies which documents to keep. | #### Returns[​](#returns-5 "Direct link to Returns") [`QueryInitializer`](/api/interfaces/server.QueryInitializer.md)<`TableInfo`> * A new [OrderedQuery](/api/interfaces/server.OrderedQuery.md) with the given filter predicate applied. #### Inherited from[​](#inherited-from-2 "Direct link to Inherited from") [Query](/api/interfaces/server.Query.md).[filter](/api/interfaces/server.Query.md#filter) #### Defined in[​](#defined-in-5 "Direct link to Defined in") [server/query.ts:165](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L165) *** ### paginate[​](#paginate "Direct link to paginate") ▸ **paginate**(`paginationOpts`): `Promise`<[`PaginationResult`](/api/interfaces/server.PaginationResult.md)<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>>> Load a page of `n` results and obtain a [Cursor](/api/modules/server.md#cursor) for loading more. Note: If this is called from a reactive query function the number of results may not match `paginationOpts.numItems`! `paginationOpts.numItems` is only an initial value. After the first invocation, `paginate` will return all items in the original query range. This ensures that all pages will remain adjacent and non-overlapping. #### Parameters[​](#parameters-4 "Direct link to Parameters") | Name | Type | Description | | ---------------- | ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | | `paginationOpts` | [`PaginationOptions`](/api/interfaces/server.PaginationOptions.md) | A [PaginationOptions](/api/interfaces/server.PaginationOptions.md) object containing the number of items to load and the cursor to start at. | #### Returns[​](#returns-6 "Direct link to Returns") `Promise`<[`PaginationResult`](/api/interfaces/server.PaginationResult.md)<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>>> A [PaginationResult](/api/interfaces/server.PaginationResult.md) containing the page of results and a cursor to continue paginating. #### Inherited from[​](#inherited-from-3 "Direct link to Inherited from") [Query](/api/interfaces/server.Query.md).[paginate](/api/interfaces/server.Query.md#paginate) #### Defined in[​](#defined-in-6 "Direct link to Defined in") [server/query.ts:194](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L194) *** ### collect[​](#collect "Direct link to collect") ▸ **collect**(): `Promise`<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>\[]> Execute the query and return all of the results as an array. Note: when processing a query with a lot of results, it's often better to use the `Query` as an `AsyncIterable` instead. #### Returns[​](#returns-7 "Direct link to Returns") `Promise`<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>\[]> * An array of all of the query's results. #### Inherited from[​](#inherited-from-4 "Direct link to Inherited from") [Query](/api/interfaces/server.Query.md).[collect](/api/interfaces/server.Query.md#collect) #### Defined in[​](#defined-in-7 "Direct link to Defined in") [server/query.ts:206](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L206) *** ### take[​](#take "Direct link to take") ▸ **take**(`n`): `Promise`<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>\[]> Execute the query and return the first `n` results. #### Parameters[​](#parameters-5 "Direct link to Parameters") | Name | Type | Description | | ---- | -------- | ---------------------------- | | `n` | `number` | The number of items to take. | #### Returns[​](#returns-8 "Direct link to Returns") `Promise`<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>\[]> * An array of the first `n` results of the query (or less if the query doesn't have `n` results). #### Inherited from[​](#inherited-from-5 "Direct link to Inherited from") [Query](/api/interfaces/server.Query.md).[take](/api/interfaces/server.Query.md#take) #### Defined in[​](#defined-in-8 "Direct link to Defined in") [server/query.ts:215](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L215) *** ### first[​](#first "Direct link to first") ▸ **first**(): `Promise`<`null` | [`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>> Execute the query and return the first result if there is one. #### Returns[​](#returns-9 "Direct link to Returns") `Promise`<`null` | [`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>> * The first value of the query or `null` if the query returned no results. #### Inherited from[​](#inherited-from-6 "Direct link to Inherited from") [Query](/api/interfaces/server.Query.md).[first](/api/interfaces/server.Query.md#first) #### Defined in[​](#defined-in-9 "Direct link to Defined in") [server/query.ts:222](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L222) *** ### unique[​](#unique "Direct link to unique") ▸ **unique**(): `Promise`<`null` | [`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>> Execute the query and return the singular result if there is one. **`Throws`** Will throw an error if the query returns more than one result. #### Returns[​](#returns-10 "Direct link to Returns") `Promise`<`null` | [`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>> * The single result returned from the query or null if none exists. #### Inherited from[​](#inherited-from-7 "Direct link to Inherited from") [Query](/api/interfaces/server.Query.md).[unique](/api/interfaces/server.Query.md#unique) #### Defined in[​](#defined-in-10 "Direct link to Defined in") [server/query.ts:230](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L230) --- # Interface: Scheduler [server](/api/modules/server.md).Scheduler An interface to schedule Convex functions. You can schedule either mutations or actions. Mutations are guaranteed to execute exactly once - they are automatically retried on transient errors and either execute successfully or fail deterministically due to developer error in defining the function. Actions execute at most once - they are not retried and might fail due to transient errors. Consider using an internalMutation or internalAction to enforce that these functions cannot be called directly from a Convex client. ## Methods[​](#methods "Direct link to Methods") ### runAfter[​](#runafter "Direct link to runAfter") ▸ **runAfter**<`FuncRef`>(`delayMs`, `functionReference`, `...args`): `Promise`<[`GenericId`](/api/modules/values.md#genericid)<`"_scheduled_functions"`>> Schedule a function to execute after a delay. #### Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | --------- | --------------------------------------------------------------------------------------------- | | `FuncRef` | extends [`SchedulableFunctionReference`](/api/modules/server.md#schedulablefunctionreference) | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | Description | | ------------------- | ------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `delayMs` | `number` | Delay in milliseconds. Must be non-negative. If the delay is zero, the scheduled function will be due to execute immediately after the scheduling one completes. | | `functionReference` | `FuncRef` | A [FunctionReference](/api/modules/server.md#functionreference) for the function to schedule. | | `...args` | [`OptionalRestArgs`](/api/modules/server.md#optionalrestargs)<`FuncRef`> | Arguments to call the scheduled functions with. | #### Returns[​](#returns "Direct link to Returns") `Promise`<[`GenericId`](/api/modules/values.md#genericid)<`"_scheduled_functions"`>> #### Defined in[​](#defined-in "Direct link to Defined in") [server/scheduler.ts:41](https://github.com/get-convex/convex-js/blob/main/src/server/scheduler.ts#L41) *** ### runAt[​](#runat "Direct link to runAt") ▸ **runAt**<`FuncRef`>(`timestamp`, `functionReference`, `...args`): `Promise`<[`GenericId`](/api/modules/values.md#genericid)<`"_scheduled_functions"`>> Schedule a function to execute at a given timestamp. #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | --------- | --------------------------------------------------------------------------------------------- | | `FuncRef` | extends [`SchedulableFunctionReference`](/api/modules/server.md#schedulablefunctionreference) | #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | Description | | ------------------- | ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `timestamp` | `number` \| `Date` | A Date or a timestamp (milliseconds since the epoch). If the timestamp is in the past, the scheduled function will be due to execute immediately after the scheduling one completes. The timestamp can't be more than five years in the past or more than five years in the future. | | `functionReference` | `FuncRef` | A [FunctionReference](/api/modules/server.md#functionreference) for the function to schedule. | | `...args` | [`OptionalRestArgs`](/api/modules/server.md#optionalrestargs)<`FuncRef`> | arguments to call the scheduled functions with. | #### Returns[​](#returns-1 "Direct link to Returns") `Promise`<[`GenericId`](/api/modules/values.md#genericid)<`"_scheduled_functions"`>> #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/scheduler.ts:58](https://github.com/get-convex/convex-js/blob/main/src/server/scheduler.ts#L58) *** ### cancel[​](#cancel "Direct link to cancel") ▸ **cancel**(`id`): `Promise`<`void`> Cancels a previously scheduled function if it has not started yet. If the scheduled function is already in progress, it will continue running but any new functions that it tries to schedule will be canceled. #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | | ---- | ------------------------------------------------------------------------- | | `id` | [`GenericId`](/api/modules/values.md#genericid)<`"_scheduled_functions"`> | #### Returns[​](#returns-2 "Direct link to Returns") `Promise`<`void`> #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/scheduler.ts:71](https://github.com/get-convex/convex-js/blob/main/src/server/scheduler.ts#L71) --- # Interface: SearchFilterBuilder\ [server](/api/modules/server.md).SearchFilterBuilder Builder for defining search filters. A search filter is a chained list of: 1. One search expression constructed with `.search`. 2. Zero or more equality expressions constructed with `.eq`. The search expression must search for text in the index's `searchField`. The filter expressions can use any of the `filterFields` defined in the index. For all other filtering use [filter](/api/interfaces/server.OrderedQuery.md#filter). To learn about full text search, see [Indexes](https://docs.convex.dev/text-search). ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ------------------- | ------------------------------------------------------------------------------------- | | `Document` | extends [`GenericDocument`](/api/modules/server.md#genericdocument) | | `SearchIndexConfig` | extends [`GenericSearchIndexConfig`](/api/modules/server.md#genericsearchindexconfig) | ## Methods[​](#methods "Direct link to Methods") ### search[​](#search "Direct link to search") ▸ **search**(`fieldName`, `query`): [`SearchFilterFinalizer`](/api/interfaces/server.SearchFilterFinalizer.md)<`Document`, `SearchIndexConfig`> Search for the terms in `query` within `doc[fieldName]`. This will do a full text search that returns results where any word of of `query` appears in the field. Documents will be returned based on their relevance to the query. This takes into account: * How many words in the query appear in the text? * How many times do they appear? * How long is the text field? #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | Description | | ----------- | ------------------------------------- | ------------------------------------------------------------------------------------- | | `fieldName` | `SearchIndexConfig`\[`"searchField"`] | The name of the field to search in. This must be listed as the index's `searchField`. | | `query` | `string` | The query text to search for. | #### Returns[​](#returns "Direct link to Returns") [`SearchFilterFinalizer`](/api/interfaces/server.SearchFilterFinalizer.md)<`Document`, `SearchIndexConfig`> #### Defined in[​](#defined-in "Direct link to Defined in") [server/search\_filter\_builder.ts:42](https://github.com/get-convex/convex-js/blob/main/src/server/search_filter_builder.ts#L42) --- # Interface: SearchFilterFinalizer\ [server](/api/modules/server.md).SearchFilterFinalizer Builder to define equality expressions as part of a search filter. See [SearchFilterBuilder](/api/interfaces/server.SearchFilterBuilder.md). ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ------------------- | ------------------------------------------------------------------------------------- | | `Document` | extends [`GenericDocument`](/api/modules/server.md#genericdocument) | | `SearchIndexConfig` | extends [`GenericSearchIndexConfig`](/api/modules/server.md#genericsearchindexconfig) | ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * [`SearchFilter`](/api/classes/server.SearchFilter.md) ↳ **`SearchFilterFinalizer`** ## Methods[​](#methods "Direct link to Methods") ### eq[​](#eq "Direct link to eq") ▸ **eq**<`FieldName`>(`fieldName`, `value`): [`SearchFilterFinalizer`](/api/interfaces/server.SearchFilterFinalizer.md)<`Document`, `SearchIndexConfig`> Restrict this query to documents where `doc[fieldName] === value`. #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------- | | `FieldName` | extends `string` | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | Description | | ----------- | -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | | `fieldName` | `FieldName` | The name of the field to compare. This must be listed in the search index's `filterFields`. | | `value` | [`FieldTypeFromFieldPath`](/api/modules/server.md#fieldtypefromfieldpath)<`Document`, `FieldName`> | The value to compare against. | #### Returns[​](#returns "Direct link to Returns") [`SearchFilterFinalizer`](/api/interfaces/server.SearchFilterFinalizer.md)<`Document`, `SearchIndexConfig`> #### Defined in[​](#defined-in "Direct link to Defined in") [server/search\_filter\_builder.ts:66](https://github.com/get-convex/convex-js/blob/main/src/server/search_filter_builder.ts#L66) --- # Interface: SearchIndexConfig\ [server](/api/modules/server.md).SearchIndexConfig The configuration for a full text search index. ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | -------------- | ---------------- | | `SearchField` | extends `string` | | `FilterFields` | extends `string` | ## Properties[​](#properties "Direct link to Properties") ### searchField[​](#searchfield "Direct link to searchField") • **searchField**: `SearchField` The field to index for full text search. This must be a field of type `string`. #### Defined in[​](#defined-in "Direct link to Defined in") [server/schema.ts:101](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L101) *** ### filterFields[​](#filterfields "Direct link to filterFields") • `Optional` **filterFields**: `FilterFields`\[] Additional fields to index for fast filtering when running search queries. #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/schema.ts:106](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L106) --- # Interface: StorageActionWriter [server](/api/modules/server.md).StorageActionWriter An interface to read and write files to storage within Convex actions and HTTP actions. ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * [`StorageWriter`](/api/interfaces/server.StorageWriter.md) ↳ **`StorageActionWriter`** ## Methods[​](#methods "Direct link to Methods") ### getUrl[​](#geturl "Direct link to getUrl") ▸ **getUrl**(`storageId`): `Promise`<`null` | `string`> Get the URL for a file in storage by its `Id<"_storage">`. The GET response includes a standard HTTP Digest header with a sha256 checksum. #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | Description | | ----------- | ------------------------------------------------------------- | -------------------------------------------------------------- | | `storageId` | [`GenericId`](/api/modules/values.md#genericid)<`"_storage"`> | The `Id<"_storage">` of the file to fetch from Convex storage. | #### Returns[​](#returns "Direct link to Returns") `Promise`<`null` | `string`> * A url which fetches the file via an HTTP GET, or `null` if it no longer exists. #### Inherited from[​](#inherited-from "Direct link to Inherited from") [StorageWriter](/api/interfaces/server.StorageWriter.md).[getUrl](/api/interfaces/server.StorageWriter.md#geturl) #### Defined in[​](#defined-in "Direct link to Defined in") [server/storage.ts:51](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L51) ▸ **getUrl**<`T`>(`storageId`): `Promise`<`null` | `string`> **`Deprecated`** Passing a string is deprecated, use `storage.getUrl(Id<"_storage">)` instead. Get the URL for a file in storage by its [StorageId](/api/modules/server.md#storageid). The GET response includes a standard HTTP Digest header with a sha256 checksum. #### Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ---- | ---------------- | | `T` | extends `string` | #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | Description | | ----------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------- | | `storageId` | `T` extends { `__tableName`: `any` } ? `never` : `T` | The [StorageId](/api/modules/server.md#storageid) of the file to fetch from Convex storage. | #### Returns[​](#returns-1 "Direct link to Returns") `Promise`<`null` | `string`> * A url which fetches the file via an HTTP GET, or `null` if it no longer exists. #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from") [StorageWriter](/api/interfaces/server.StorageWriter.md).[getUrl](/api/interfaces/server.StorageWriter.md#geturl) #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/storage.ts:63](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L63) *** ### getMetadata[​](#getmetadata "Direct link to getMetadata") ▸ **getMetadata**(`storageId`): `Promise`<`null` | [`FileMetadata`](/api/modules/server.md#filemetadata)> **`Deprecated`** This function is deprecated, use `db.system.get(Id<"_storage">)` instead. Get metadata for a file. #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | Description | | ----------- | ------------------------------------------------------------- | --------------------------------- | | `storageId` | [`GenericId`](/api/modules/values.md#genericid)<`"_storage"`> | The `Id<"_storage">` of the file. | #### Returns[​](#returns-2 "Direct link to Returns") `Promise`<`null` | [`FileMetadata`](/api/modules/server.md#filemetadata)> * A [FileMetadata](/api/modules/server.md#filemetadata) object if found or `null` if not found. #### Inherited from[​](#inherited-from-2 "Direct link to Inherited from") [StorageWriter](/api/interfaces/server.StorageWriter.md).[getMetadata](/api/interfaces/server.StorageWriter.md#getmetadata) #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/storage.ts:75](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L75) ▸ **getMetadata**<`T`>(`storageId`): `Promise`<`null` | [`FileMetadata`](/api/modules/server.md#filemetadata)> **`Deprecated`** This function is deprecated, use `db.system.get(Id<"_storage">)` instead. Get metadata for a file. #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ---- | ---------------- | | `T` | extends `string` | #### Parameters[​](#parameters-3 "Direct link to Parameters") | Name | Type | Description | | ----------- | ---------------------------------------------------- | -------------------------------------------------------------- | | `storageId` | `T` extends { `__tableName`: `any` } ? `never` : `T` | The [StorageId](/api/modules/server.md#storageid) of the file. | #### Returns[​](#returns-3 "Direct link to Returns") `Promise`<`null` | [`FileMetadata`](/api/modules/server.md#filemetadata)> * A [FileMetadata](/api/modules/server.md#filemetadata) object if found or `null` if not found. #### Inherited from[​](#inherited-from-3 "Direct link to Inherited from") [StorageWriter](/api/interfaces/server.StorageWriter.md).[getMetadata](/api/interfaces/server.StorageWriter.md#getmetadata) #### Defined in[​](#defined-in-3 "Direct link to Defined in") [server/storage.ts:85](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L85) *** ### generateUploadUrl[​](#generateuploadurl "Direct link to generateUploadUrl") ▸ **generateUploadUrl**(): `Promise`<`string`> Fetch a short-lived URL for uploading a file into storage. Upon a POST request to this URL, the endpoint will return a JSON object containing a newly allocated `Id<"_storage">`. The POST URL accepts an optional standard HTTP Digest header with a sha256 checksum. #### Returns[​](#returns-4 "Direct link to Returns") `Promise`<`string`> * A url that allows file upload via an HTTP POST. #### Inherited from[​](#inherited-from-4 "Direct link to Inherited from") [StorageWriter](/api/interfaces/server.StorageWriter.md).[generateUploadUrl](/api/interfaces/server.StorageWriter.md#generateuploadurl) #### Defined in[​](#defined-in-4 "Direct link to Defined in") [server/storage.ts:105](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L105) *** ### delete[​](#delete "Direct link to delete") ▸ **delete**(`storageId`): `Promise`<`void`> Delete a file from Convex storage. Once a file is deleted, any URLs previously generated by [getUrl](/api/interfaces/server.StorageReader.md#geturl) will return 404s. #### Parameters[​](#parameters-4 "Direct link to Parameters") | Name | Type | Description | | ----------- | ------------------------------------------------------------- | --------------------------------------------------------------- | | `storageId` | [`GenericId`](/api/modules/values.md#genericid)<`"_storage"`> | The `Id<"_storage">` of the file to delete from Convex storage. | #### Returns[​](#returns-5 "Direct link to Returns") `Promise`<`void`> #### Inherited from[​](#inherited-from-5 "Direct link to Inherited from") [StorageWriter](/api/interfaces/server.StorageWriter.md).[delete](/api/interfaces/server.StorageWriter.md#delete) #### Defined in[​](#defined-in-5 "Direct link to Defined in") [server/storage.ts:113](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L113) ▸ **delete**<`T`>(`storageId`): `Promise`<`void`> **`Deprecated`** Passing a string is deprecated, use `storage.delete(Id<"_storage">)` instead. Delete a file from Convex storage. Once a file is deleted, any URLs previously generated by [getUrl](/api/interfaces/server.StorageReader.md#geturl) will return 404s. #### Type parameters[​](#type-parameters-2 "Direct link to Type parameters") | Name | Type | | ---- | ---------------- | | `T` | extends `string` | #### Parameters[​](#parameters-5 "Direct link to Parameters") | Name | Type | Description | | ----------- | ---------------------------------------------------- | -------------------------------------------------------------------------------------------- | | `storageId` | `T` extends { `__tableName`: `any` } ? `never` : `T` | The [StorageId](/api/modules/server.md#storageid) of the file to delete from Convex storage. | #### Returns[​](#returns-6 "Direct link to Returns") `Promise`<`void`> #### Inherited from[​](#inherited-from-6 "Direct link to Inherited from") [StorageWriter](/api/interfaces/server.StorageWriter.md).[delete](/api/interfaces/server.StorageWriter.md#delete) #### Defined in[​](#defined-in-6 "Direct link to Defined in") [server/storage.ts:124](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L124) *** ### get[​](#get "Direct link to get") ▸ **get**(`storageId`): `Promise`<`null` | `Blob`> Get a Blob containing the file associated with the provided `Id<"_storage">`, or `null` if there is no file. #### Parameters[​](#parameters-6 "Direct link to Parameters") | Name | Type | | ----------- | ------------------------------------------------------------- | | `storageId` | [`GenericId`](/api/modules/values.md#genericid)<`"_storage"`> | #### Returns[​](#returns-7 "Direct link to Returns") `Promise`<`null` | `Blob`> #### Defined in[​](#defined-in-7 "Direct link to Defined in") [server/storage.ts:138](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L138) ▸ **get**<`T`>(`storageId`): `Promise`<`null` | `Blob`> **`Deprecated`** Passing a string is deprecated, use `storage.get(Id<"_storage">)` instead. Get a Blob containing the file associated with the provided [StorageId](/api/modules/server.md#storageid), or `null` if there is no file. #### Type parameters[​](#type-parameters-3 "Direct link to Type parameters") | Name | Type | | ---- | ---------------- | | `T` | extends `string` | #### Parameters[​](#parameters-7 "Direct link to Parameters") | Name | Type | | ----------- | ---------------------------------------------------- | | `storageId` | `T` extends { `__tableName`: `any` } ? `never` : `T` | #### Returns[​](#returns-8 "Direct link to Returns") `Promise`<`null` | `Blob`> #### Defined in[​](#defined-in-8 "Direct link to Defined in") [server/storage.ts:145](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L145) *** ### store[​](#store "Direct link to store") ▸ **store**(`blob`, `options?`): `Promise`<[`GenericId`](/api/modules/values.md#genericid)<`"_storage"`>> Store the file contained in the Blob. If provided, this will verify the sha256 checksum matches the contents of the file. #### Parameters[​](#parameters-8 "Direct link to Parameters") | Name | Type | | ----------------- | -------- | | `blob` | `Blob` | | `options?` | `Object` | | `options.sha256?` | `string` | #### Returns[​](#returns-9 "Direct link to Returns") `Promise`<[`GenericId`](/api/modules/values.md#genericid)<`"_storage"`>> #### Defined in[​](#defined-in-9 "Direct link to Defined in") [server/storage.ts:153](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L153) --- # Interface: StorageReader [server](/api/modules/server.md).StorageReader An interface to read files from storage within Convex query functions. ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * **`StorageReader`** ↳ [`StorageWriter`](/api/interfaces/server.StorageWriter.md) ## Methods[​](#methods "Direct link to Methods") ### getUrl[​](#geturl "Direct link to getUrl") ▸ **getUrl**(`storageId`): `Promise`<`null` | `string`> Get the URL for a file in storage by its `Id<"_storage">`. The GET response includes a standard HTTP Digest header with a sha256 checksum. #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | Description | | ----------- | ------------------------------------------------------------- | -------------------------------------------------------------- | | `storageId` | [`GenericId`](/api/modules/values.md#genericid)<`"_storage"`> | The `Id<"_storage">` of the file to fetch from Convex storage. | #### Returns[​](#returns "Direct link to Returns") `Promise`<`null` | `string`> * A url which fetches the file via an HTTP GET, or `null` if it no longer exists. #### Defined in[​](#defined-in "Direct link to Defined in") [server/storage.ts:51](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L51) ▸ **getUrl**<`T`>(`storageId`): `Promise`<`null` | `string`> **`Deprecated`** Passing a string is deprecated, use `storage.getUrl(Id<"_storage">)` instead. Get the URL for a file in storage by its [StorageId](/api/modules/server.md#storageid). The GET response includes a standard HTTP Digest header with a sha256 checksum. #### Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ---- | ---------------- | | `T` | extends `string` | #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | Description | | ----------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------- | | `storageId` | `T` extends { `__tableName`: `any` } ? `never` : `T` | The [StorageId](/api/modules/server.md#storageid) of the file to fetch from Convex storage. | #### Returns[​](#returns-1 "Direct link to Returns") `Promise`<`null` | `string`> * A url which fetches the file via an HTTP GET, or `null` if it no longer exists. #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/storage.ts:63](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L63) *** ### getMetadata[​](#getmetadata "Direct link to getMetadata") ▸ **getMetadata**(`storageId`): `Promise`<`null` | [`FileMetadata`](/api/modules/server.md#filemetadata)> **`Deprecated`** This function is deprecated, use `db.system.get(Id<"_storage">)` instead. Get metadata for a file. #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | Description | | ----------- | ------------------------------------------------------------- | --------------------------------- | | `storageId` | [`GenericId`](/api/modules/values.md#genericid)<`"_storage"`> | The `Id<"_storage">` of the file. | #### Returns[​](#returns-2 "Direct link to Returns") `Promise`<`null` | [`FileMetadata`](/api/modules/server.md#filemetadata)> * A [FileMetadata](/api/modules/server.md#filemetadata) object if found or `null` if not found. #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/storage.ts:75](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L75) ▸ **getMetadata**<`T`>(`storageId`): `Promise`<`null` | [`FileMetadata`](/api/modules/server.md#filemetadata)> **`Deprecated`** This function is deprecated, use `db.system.get(Id<"_storage">)` instead. Get metadata for a file. #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ---- | ---------------- | | `T` | extends `string` | #### Parameters[​](#parameters-3 "Direct link to Parameters") | Name | Type | Description | | ----------- | ---------------------------------------------------- | -------------------------------------------------------------- | | `storageId` | `T` extends { `__tableName`: `any` } ? `never` : `T` | The [StorageId](/api/modules/server.md#storageid) of the file. | #### Returns[​](#returns-3 "Direct link to Returns") `Promise`<`null` | [`FileMetadata`](/api/modules/server.md#filemetadata)> * A [FileMetadata](/api/modules/server.md#filemetadata) object if found or `null` if not found. #### Defined in[​](#defined-in-3 "Direct link to Defined in") [server/storage.ts:85](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L85) --- # Interface: StorageWriter [server](/api/modules/server.md).StorageWriter An interface to write files to storage within Convex mutation functions. ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * [`StorageReader`](/api/interfaces/server.StorageReader.md) ↳ **`StorageWriter`** ↳↳ [`StorageActionWriter`](/api/interfaces/server.StorageActionWriter.md) ## Methods[​](#methods "Direct link to Methods") ### getUrl[​](#geturl "Direct link to getUrl") ▸ **getUrl**(`storageId`): `Promise`<`null` | `string`> Get the URL for a file in storage by its `Id<"_storage">`. The GET response includes a standard HTTP Digest header with a sha256 checksum. #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | Description | | ----------- | ------------------------------------------------------------- | -------------------------------------------------------------- | | `storageId` | [`GenericId`](/api/modules/values.md#genericid)<`"_storage"`> | The `Id<"_storage">` of the file to fetch from Convex storage. | #### Returns[​](#returns "Direct link to Returns") `Promise`<`null` | `string`> * A url which fetches the file via an HTTP GET, or `null` if it no longer exists. #### Inherited from[​](#inherited-from "Direct link to Inherited from") [StorageReader](/api/interfaces/server.StorageReader.md).[getUrl](/api/interfaces/server.StorageReader.md#geturl) #### Defined in[​](#defined-in "Direct link to Defined in") [server/storage.ts:51](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L51) ▸ **getUrl**<`T`>(`storageId`): `Promise`<`null` | `string`> **`Deprecated`** Passing a string is deprecated, use `storage.getUrl(Id<"_storage">)` instead. Get the URL for a file in storage by its [StorageId](/api/modules/server.md#storageid). The GET response includes a standard HTTP Digest header with a sha256 checksum. #### Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ---- | ---------------- | | `T` | extends `string` | #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | Description | | ----------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------- | | `storageId` | `T` extends { `__tableName`: `any` } ? `never` : `T` | The [StorageId](/api/modules/server.md#storageid) of the file to fetch from Convex storage. | #### Returns[​](#returns-1 "Direct link to Returns") `Promise`<`null` | `string`> * A url which fetches the file via an HTTP GET, or `null` if it no longer exists. #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from") [StorageReader](/api/interfaces/server.StorageReader.md).[getUrl](/api/interfaces/server.StorageReader.md#geturl) #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/storage.ts:63](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L63) *** ### getMetadata[​](#getmetadata "Direct link to getMetadata") ▸ **getMetadata**(`storageId`): `Promise`<`null` | [`FileMetadata`](/api/modules/server.md#filemetadata)> **`Deprecated`** This function is deprecated, use `db.system.get(Id<"_storage">)` instead. Get metadata for a file. #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | Description | | ----------- | ------------------------------------------------------------- | --------------------------------- | | `storageId` | [`GenericId`](/api/modules/values.md#genericid)<`"_storage"`> | The `Id<"_storage">` of the file. | #### Returns[​](#returns-2 "Direct link to Returns") `Promise`<`null` | [`FileMetadata`](/api/modules/server.md#filemetadata)> * A [FileMetadata](/api/modules/server.md#filemetadata) object if found or `null` if not found. #### Inherited from[​](#inherited-from-2 "Direct link to Inherited from") [StorageReader](/api/interfaces/server.StorageReader.md).[getMetadata](/api/interfaces/server.StorageReader.md#getmetadata) #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/storage.ts:75](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L75) ▸ **getMetadata**<`T`>(`storageId`): `Promise`<`null` | [`FileMetadata`](/api/modules/server.md#filemetadata)> **`Deprecated`** This function is deprecated, use `db.system.get(Id<"_storage">)` instead. Get metadata for a file. #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ---- | ---------------- | | `T` | extends `string` | #### Parameters[​](#parameters-3 "Direct link to Parameters") | Name | Type | Description | | ----------- | ---------------------------------------------------- | -------------------------------------------------------------- | | `storageId` | `T` extends { `__tableName`: `any` } ? `never` : `T` | The [StorageId](/api/modules/server.md#storageid) of the file. | #### Returns[​](#returns-3 "Direct link to Returns") `Promise`<`null` | [`FileMetadata`](/api/modules/server.md#filemetadata)> * A [FileMetadata](/api/modules/server.md#filemetadata) object if found or `null` if not found. #### Inherited from[​](#inherited-from-3 "Direct link to Inherited from") [StorageReader](/api/interfaces/server.StorageReader.md).[getMetadata](/api/interfaces/server.StorageReader.md#getmetadata) #### Defined in[​](#defined-in-3 "Direct link to Defined in") [server/storage.ts:85](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L85) *** ### generateUploadUrl[​](#generateuploadurl "Direct link to generateUploadUrl") ▸ **generateUploadUrl**(): `Promise`<`string`> Fetch a short-lived URL for uploading a file into storage. Upon a POST request to this URL, the endpoint will return a JSON object containing a newly allocated `Id<"_storage">`. The POST URL accepts an optional standard HTTP Digest header with a sha256 checksum. #### Returns[​](#returns-4 "Direct link to Returns") `Promise`<`string`> * A url that allows file upload via an HTTP POST. #### Defined in[​](#defined-in-4 "Direct link to Defined in") [server/storage.ts:105](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L105) *** ### delete[​](#delete "Direct link to delete") ▸ **delete**(`storageId`): `Promise`<`void`> Delete a file from Convex storage. Once a file is deleted, any URLs previously generated by [getUrl](/api/interfaces/server.StorageReader.md#geturl) will return 404s. #### Parameters[​](#parameters-4 "Direct link to Parameters") | Name | Type | Description | | ----------- | ------------------------------------------------------------- | --------------------------------------------------------------- | | `storageId` | [`GenericId`](/api/modules/values.md#genericid)<`"_storage"`> | The `Id<"_storage">` of the file to delete from Convex storage. | #### Returns[​](#returns-5 "Direct link to Returns") `Promise`<`void`> #### Defined in[​](#defined-in-5 "Direct link to Defined in") [server/storage.ts:113](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L113) ▸ **delete**<`T`>(`storageId`): `Promise`<`void`> **`Deprecated`** Passing a string is deprecated, use `storage.delete(Id<"_storage">)` instead. Delete a file from Convex storage. Once a file is deleted, any URLs previously generated by [getUrl](/api/interfaces/server.StorageReader.md#geturl) will return 404s. #### Type parameters[​](#type-parameters-2 "Direct link to Type parameters") | Name | Type | | ---- | ---------------- | | `T` | extends `string` | #### Parameters[​](#parameters-5 "Direct link to Parameters") | Name | Type | Description | | ----------- | ---------------------------------------------------- | -------------------------------------------------------------------------------------------- | | `storageId` | `T` extends { `__tableName`: `any` } ? `never` : `T` | The [StorageId](/api/modules/server.md#storageid) of the file to delete from Convex storage. | #### Returns[​](#returns-6 "Direct link to Returns") `Promise`<`void`> #### Defined in[​](#defined-in-6 "Direct link to Defined in") [server/storage.ts:124](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L124) --- # Interface: SystemDataModel [server](/api/modules/server.md).SystemDataModel Internal type used in Convex code generation! Convert a [SchemaDefinition](/api/classes/server.SchemaDefinition.md) into a [GenericDataModel](/api/modules/server.md#genericdatamodel). ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * [`DataModelFromSchemaDefinition`](/api/modules/server.md#datamodelfromschemadefinition)\ ↳ **`SystemDataModel`** ## Properties[​](#properties "Direct link to Properties") ### \_scheduled\_functions[​](#_scheduled_functions "Direct link to _scheduled_functions") • **\_scheduled\_functions**: `Object` #### Type declaration[​](#type-declaration "Direct link to Type declaration") | Name | Type | | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `document` | { `completedTime`: `undefined` \| `number` ; `name`: `string` ; `args`: `any`\[] ; `scheduledTime`: `number` ; `state`: { kind: "pending"; } \| { kind: "inProgress"; } \| { kind: "success"; } \| { kind: "failed"; error: string; } \| { kind: "canceled"; } ; `_creationTime`: `number` ; `_id`: [`GenericId`](/api/modules/values.md#genericid)<`"_scheduled_functions"`> } | | `document.completedTime` | `undefined` \| `number` | | `document.name` | `string` | | `document.args` | `any`\[] | | `document.scheduledTime` | `number` | | `document.state` | { kind: "pending"; } \| { kind: "inProgress"; } \| { kind: "success"; } \| { kind: "failed"; error: string; } \| { kind: "canceled"; } | | `document._creationTime` | `number` | | `document._id` | [`GenericId`](/api/modules/values.md#genericid)<`"_scheduled_functions"`> | | `fieldPaths` | `"_id"` \| `ExtractFieldPaths`<[`VObject`](/api/classes/values.VObject.md)<{ `completedTime`: `undefined` \| `number` ; `name`: `string` ; `args`: `any`\[] ; `scheduledTime`: `number` ; `state`: { kind: "pending"; } \| { kind: "inProgress"; } \| { kind: "success"; } \| { kind: "failed"; error: string; } \| { kind: "canceled"; } }, { `name`: [`VString`](/api/classes/values.VString.md)<`string`, `"required"`> ; `args`: [`VArray`](/api/classes/values.VArray.md)<`any`\[], [`VAny`](/api/classes/values.VAny.md)<`any`, `"required"`, `string`>, `"required"`> ; `scheduledTime`: [`VFloat64`](/api/classes/values.VFloat64.md)<`number`, `"required"`> ; `completedTime`: [`VFloat64`](/api/classes/values.VFloat64.md)<`undefined` \| `number`, `"optional"`> ; `state`: [`VUnion`](/api/classes/values.VUnion.md)<{ `kind`: `"pending"` } \| { `kind`: `"inProgress"` } \| { `kind`: `"success"` } \| { `kind`: `"failed"` ; `error`: `string` } \| { `kind`: `"canceled"` }, \[[`VObject`](/api/classes/values.VObject.md)<{ `kind`: `"pending"` }, { `kind`: [`VLiteral`](/api/classes/values.VLiteral.md)<`"pending"`, `"required"`> }, `"required"`, `"kind"`>, [`VObject`](/api/classes/values.VObject.md)<{ `kind`: `"inProgress"` }, { `kind`: [`VLiteral`](/api/classes/values.VLiteral.md)<`"inProgress"`, `"required"`> }, `"required"`, `"kind"`>, [`VObject`](/api/classes/values.VObject.md)<{ `kind`: `"success"` }, { `kind`: [`VLiteral`](/api/classes/values.VLiteral.md)<`"success"`, `"required"`> }, `"required"`, `"kind"`>, [`VObject`](/api/classes/values.VObject.md)<{ `kind`: `"failed"` ; `error`: `string` }, { `kind`: [`VLiteral`](/api/classes/values.VLiteral.md)<`"failed"`, `"required"`> ; `error`: [`VString`](/api/classes/values.VString.md)<`string`, `"required"`> }, `"required"`, `"kind"` \| `"error"`>, [`VObject`](/api/classes/values.VObject.md)<{ `kind`: `"canceled"` }, { `kind`: [`VLiteral`](/api/classes/values.VLiteral.md)<`"canceled"`, `"required"`> }, `"required"`, `"kind"`>], `"required"`, `"kind"` \| `"error"`> }, `"required"`, `"name"` \| `"args"` \| `"scheduledTime"` \| `"completedTime"` \| `"state"` \| `"state.kind"` \| `"state.error"`>> | | `indexes` | { `by_id`: \[`"_id"`] ; `by_creation_time`: \[`"_creationTime"`] } | | `indexes.by_id` | \[`"_id"`] | | `indexes.by_creation_time` | \[`"_creationTime"`] | | `searchIndexes` | | | `vectorIndexes` | | #### Inherited from[​](#inherited-from "Direct link to Inherited from") DataModelFromSchemaDefinition.\_scheduled\_functions *** ### \_storage[​](#_storage "Direct link to _storage") • **\_storage**: `Object` #### Type declaration[​](#type-declaration-1 "Direct link to Type declaration") | Name | Type | | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `document` | { `contentType`: `undefined` \| `string` ; `sha256`: `string` ; `size`: `number` ; `_creationTime`: `number` ; `_id`: [`GenericId`](/api/modules/values.md#genericid)<`"_storage"`> } | | `document.contentType` | `undefined` \| `string` | | `document.sha256` | `string` | | `document.size` | `number` | | `document._creationTime` | `number` | | `document._id` | [`GenericId`](/api/modules/values.md#genericid)<`"_storage"`> | | `fieldPaths` | `"_id"` \| `ExtractFieldPaths`<[`VObject`](/api/classes/values.VObject.md)<{ `contentType`: `undefined` \| `string` ; `sha256`: `string` ; `size`: `number` }, { `sha256`: [`VString`](/api/classes/values.VString.md)<`string`, `"required"`> ; `size`: [`VFloat64`](/api/classes/values.VFloat64.md)<`number`, `"required"`> ; `contentType`: [`VString`](/api/classes/values.VString.md)<`undefined` \| `string`, `"optional"`> }, `"required"`, `"sha256"` \| `"size"` \| `"contentType"`>> | | `indexes` | { `by_id`: \[`"_id"`] ; `by_creation_time`: \[`"_creationTime"`] } | | `indexes.by_id` | \[`"_id"`] | | `indexes.by_creation_time` | \[`"_creationTime"`] | | `searchIndexes` | | | `vectorIndexes` | | #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from") DataModelFromSchemaDefinition.\_storage --- # Interface: UserIdentity [server](/api/modules/server.md).UserIdentity Information about an authenticated user, derived from a [JWT](https://datatracker.ietf.org/doc/html/rfc7519). The only fields guaranteed to be present are [tokenIdentifier](/api/interfaces/server.UserIdentity.md#tokenidentifier) and [issuer](/api/interfaces/server.UserIdentity.md#issuer). All remaining fields may or may not be present depending on the information given by the identity provider. The explicitly listed fields are derived from the OpenID Connect (OIDC) standard fields, see the [OIDC specification](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims) for more information on these fields. Any additional fields are custom claims that may be present in the JWT, and their type depends on your identity provider configuration. If you know the type of the field, you can assert it in TypeScript like this (for example as a `string`): ``` const identity = await ctx.auth.getUserIdentity(); if (identity === null) { return null; } const customClaim = identity.custom_claim as string; ``` ## Indexable[​](#indexable "Direct link to Indexable") ▪ \[key: `string`]: [`JSONValue`](/api/modules/values.md#jsonvalue) | `undefined` ## Properties[​](#properties "Direct link to Properties") ### tokenIdentifier[​](#tokenidentifier "Direct link to tokenIdentifier") • `Readonly` **tokenIdentifier**: `string` A stable and globally unique string for this identity (i.e. no other user, even from a different identity provider, will have the same string.) JWT claims: `sub` + `iss` #### Defined in[​](#defined-in "Direct link to Defined in") [server/authentication.ts:107](https://github.com/get-convex/convex-js/blob/main/src/server/authentication.ts#L107) *** ### subject[​](#subject "Direct link to subject") • `Readonly` **subject**: `string` Identifier for the end-user from the identity provider, not necessarily unique across different providers. JWT claim: `sub` #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/authentication.ts:115](https://github.com/get-convex/convex-js/blob/main/src/server/authentication.ts#L115) *** ### issuer[​](#issuer "Direct link to issuer") • `Readonly` **issuer**: `string` The hostname of the identity provider used to authenticate this user. JWT claim: `iss` #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/authentication.ts:122](https://github.com/get-convex/convex-js/blob/main/src/server/authentication.ts#L122) *** ### name[​](#name "Direct link to name") • `Optional` `Readonly` **name**: `string` JWT claim: `name` #### Defined in[​](#defined-in-3 "Direct link to Defined in") [server/authentication.ts:127](https://github.com/get-convex/convex-js/blob/main/src/server/authentication.ts#L127) *** ### givenName[​](#givenname "Direct link to givenName") • `Optional` `Readonly` **givenName**: `string` JWT claim: `given_name` #### Defined in[​](#defined-in-4 "Direct link to Defined in") [server/authentication.ts:132](https://github.com/get-convex/convex-js/blob/main/src/server/authentication.ts#L132) *** ### familyName[​](#familyname "Direct link to familyName") • `Optional` `Readonly` **familyName**: `string` JWT claim: `family_name` #### Defined in[​](#defined-in-5 "Direct link to Defined in") [server/authentication.ts:137](https://github.com/get-convex/convex-js/blob/main/src/server/authentication.ts#L137) *** ### nickname[​](#nickname "Direct link to nickname") • `Optional` `Readonly` **nickname**: `string` JWT claim: `nickname` #### Defined in[​](#defined-in-6 "Direct link to Defined in") [server/authentication.ts:142](https://github.com/get-convex/convex-js/blob/main/src/server/authentication.ts#L142) *** ### preferredUsername[​](#preferredusername "Direct link to preferredUsername") • `Optional` `Readonly` **preferredUsername**: `string` JWT claim: `preferred_username` #### Defined in[​](#defined-in-7 "Direct link to Defined in") [server/authentication.ts:147](https://github.com/get-convex/convex-js/blob/main/src/server/authentication.ts#L147) *** ### profileUrl[​](#profileurl "Direct link to profileUrl") • `Optional` `Readonly` **profileUrl**: `string` JWT claim: `profile` #### Defined in[​](#defined-in-8 "Direct link to Defined in") [server/authentication.ts:152](https://github.com/get-convex/convex-js/blob/main/src/server/authentication.ts#L152) *** ### pictureUrl[​](#pictureurl "Direct link to pictureUrl") • `Optional` `Readonly` **pictureUrl**: `string` JWT claim: `picture` #### Defined in[​](#defined-in-9 "Direct link to Defined in") [server/authentication.ts:157](https://github.com/get-convex/convex-js/blob/main/src/server/authentication.ts#L157) *** ### email[​](#email "Direct link to email") • `Optional` `Readonly` **email**: `string` JWT claim: `email` #### Defined in[​](#defined-in-10 "Direct link to Defined in") [server/authentication.ts:162](https://github.com/get-convex/convex-js/blob/main/src/server/authentication.ts#L162) *** ### emailVerified[​](#emailverified "Direct link to emailVerified") • `Optional` `Readonly` **emailVerified**: `boolean` JWT claim: `email_verified` #### Defined in[​](#defined-in-11 "Direct link to Defined in") [server/authentication.ts:167](https://github.com/get-convex/convex-js/blob/main/src/server/authentication.ts#L167) *** ### gender[​](#gender "Direct link to gender") • `Optional` `Readonly` **gender**: `string` JWT claim: `gender` #### Defined in[​](#defined-in-12 "Direct link to Defined in") [server/authentication.ts:172](https://github.com/get-convex/convex-js/blob/main/src/server/authentication.ts#L172) *** ### birthday[​](#birthday "Direct link to birthday") • `Optional` `Readonly` **birthday**: `string` JWT claim: `birthdate` #### Defined in[​](#defined-in-13 "Direct link to Defined in") [server/authentication.ts:177](https://github.com/get-convex/convex-js/blob/main/src/server/authentication.ts#L177) *** ### timezone[​](#timezone "Direct link to timezone") • `Optional` `Readonly` **timezone**: `string` JWT claim: `zoneinfo` #### Defined in[​](#defined-in-14 "Direct link to Defined in") [server/authentication.ts:182](https://github.com/get-convex/convex-js/blob/main/src/server/authentication.ts#L182) *** ### language[​](#language "Direct link to language") • `Optional` `Readonly` **language**: `string` JWT claim: `locale` #### Defined in[​](#defined-in-15 "Direct link to Defined in") [server/authentication.ts:187](https://github.com/get-convex/convex-js/blob/main/src/server/authentication.ts#L187) *** ### phoneNumber[​](#phonenumber "Direct link to phoneNumber") • `Optional` `Readonly` **phoneNumber**: `string` JWT claim: `phone_number` #### Defined in[​](#defined-in-16 "Direct link to Defined in") [server/authentication.ts:192](https://github.com/get-convex/convex-js/blob/main/src/server/authentication.ts#L192) *** ### phoneNumberVerified[​](#phonenumberverified "Direct link to phoneNumberVerified") • `Optional` `Readonly` **phoneNumberVerified**: `boolean` JWT claim: `phone_number_verified` #### Defined in[​](#defined-in-17 "Direct link to Defined in") [server/authentication.ts:197](https://github.com/get-convex/convex-js/blob/main/src/server/authentication.ts#L197) *** ### address[​](#address "Direct link to address") • `Optional` `Readonly` **address**: `string` JWT claim: `address` #### Defined in[​](#defined-in-18 "Direct link to Defined in") [server/authentication.ts:202](https://github.com/get-convex/convex-js/blob/main/src/server/authentication.ts#L202) *** ### updatedAt[​](#updatedat "Direct link to updatedAt") • `Optional` `Readonly` **updatedAt**: `string` JWT claim: `updated_at` #### Defined in[​](#defined-in-19 "Direct link to Defined in") [server/authentication.ts:207](https://github.com/get-convex/convex-js/blob/main/src/server/authentication.ts#L207) --- # Interface: ValidatedFunction\ [server](/api/modules/server.md).ValidatedFunction **`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 with argument validation. Argument validation allows you to assert that the arguments to this function are the expected type. Example: ``` import { query } from "./_generated/server"; import { v } from "convex/values"; export const func = query({ args: { arg: v.string() }, handler: ({ db }, { arg }) => {...}, }); ``` **For security, argument validation should be added to all public functions in production apps.** See [UnvalidatedFunction](/api/modules/server.md#unvalidatedfunction) for functions without argument validation. ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | --------------- | ------------------------------------------------------------------------- | | `Ctx` | `Ctx` | | `ArgsValidator` | extends [`PropertyValidators`](/api/modules/values.md#propertyvalidators) | | `Returns` | `Returns` | ## Properties[​](#properties "Direct link to Properties") ### args[​](#args "Direct link to args") • **args**: `ArgsValidator` A validator for the arguments of this function. This is an object mapping argument names to validators constructed with [v](/api/modules/values.md#v). ``` import { v } from "convex/values"; const args = { stringArg: v.string(), optionalNumberArg: v.optional(v.number()), } ``` #### Defined in[​](#defined-in "Direct link to Defined in") [server/registration.ts:528](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L528) *** ### handler[​](#handler "Direct link to handler") • **handler**: (`ctx`: `Ctx`, `args`: [`ObjectType`](/api/modules/values.md#objecttype)<`ArgsValidator`>) => `Returns` #### Type declaration[​](#type-declaration "Direct link to Type declaration") ▸ (`ctx`, `args`): `Returns` The implementation of this function. This is a function that takes in the appropriate context and arguments and produces some result. ##### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | Description | | ------ | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------ | | `ctx` | `Ctx` | The context object. This is one of QueryCtx, MutationCtx, or ActionCtx depending on the function type. | | `args` | [`ObjectType`](/api/modules/values.md#objecttype)<`ArgsValidator`> | The arguments object for this function. This will match the type defined by the argument validator. | ##### Returns[​](#returns "Direct link to Returns") `Returns` #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/registration.ts:542](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L542) --- # Interface: VectorFilterBuilder\ [server](/api/modules/server.md).VectorFilterBuilder An interface for defining filters for vector searches. This has a similar interface to [FilterBuilder](/api/interfaces/server.FilterBuilder.md), which is used in database queries, but supports only the methods that can be efficiently done in a vector search. ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ------------------- | ------------------------------------------------------------------------------------- | | `Document` | extends [`GenericDocument`](/api/modules/server.md#genericdocument) | | `VectorIndexConfig` | extends [`GenericVectorIndexConfig`](/api/modules/server.md#genericvectorindexconfig) | ## Methods[​](#methods "Direct link to Methods") ### eq[​](#eq "Direct link to eq") ▸ **eq**<`FieldName`>(`fieldName`, `value`): [`FilterExpression`](/api/classes/server.FilterExpression.md)<`boolean`> Is the field at `fieldName` equal to `value` #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------- | | `FieldName` | extends `string` | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | ----------- | -------------------------------------------------------------------------------------------------- | | `fieldName` | `FieldName` | | `value` | [`FieldTypeFromFieldPath`](/api/modules/server.md#fieldtypefromfieldpath)<`Document`, `FieldName`> | #### Returns[​](#returns "Direct link to Returns") [`FilterExpression`](/api/classes/server.FilterExpression.md)<`boolean`> #### Defined in[​](#defined-in "Direct link to Defined in") [server/vector\_search.ts:110](https://github.com/get-convex/convex-js/blob/main/src/server/vector_search.ts#L110) *** ### or[​](#or "Direct link to or") ▸ **or**(`...exprs`): [`FilterExpression`](/api/classes/server.FilterExpression.md)<`boolean`> `exprs[0] || exprs[1] || ... || exprs[n]` #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | | ---------- | --------------------------------------------------------------------------- | | `...exprs` | [`FilterExpression`](/api/classes/server.FilterExpression.md)<`boolean`>\[] | #### Returns[​](#returns-1 "Direct link to Returns") [`FilterExpression`](/api/classes/server.FilterExpression.md)<`boolean`> #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/vector\_search.ts:122](https://github.com/get-convex/convex-js/blob/main/src/server/vector_search.ts#L122) --- # Interface: VectorIndexConfig\ [server](/api/modules/server.md).VectorIndexConfig The configuration for a vector index. ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | -------------- | ---------------- | | `VectorField` | extends `string` | | `FilterFields` | extends `string` | ## Properties[​](#properties "Direct link to Properties") ### vectorField[​](#vectorfield "Direct link to vectorField") • **vectorField**: `VectorField` The field to index for vector search. This must be a field of type `v.array(v.float64())` (or a union) #### Defined in[​](#defined-in "Direct link to Defined in") [server/schema.ts:123](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L123) *** ### dimensions[​](#dimensions "Direct link to dimensions") • **dimensions**: `number` The length of the vectors indexed. This must be between 2 and 2048 inclusive. #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/schema.ts:127](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L127) *** ### filterFields[​](#filterfields "Direct link to filterFields") • `Optional` **filterFields**: `FilterFields`\[] Additional fields to index for fast filtering when running vector searches. #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/schema.ts:131](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L131) --- # Interface: VectorSearchQuery\ [server](/api/modules/server.md).VectorSearchQuery An object with parameters for performing a vector search against a vector index. ## Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ----------- | ---------------------------------------------------------------------------------- | | `TableInfo` | extends [`GenericTableInfo`](/api/modules/server.md#generictableinfo) | | `IndexName` | extends [`VectorIndexNames`](/api/modules/server.md#vectorindexnames)<`TableInfo`> | ## Properties[​](#properties "Direct link to Properties") ### vector[​](#vector "Direct link to vector") • **vector**: `number`\[] The query vector. This must have the same length as the `dimensions` of the index. This vector search will return the IDs of the documents most similar to this vector. #### Defined in[​](#defined-in "Direct link to Defined in") [server/vector\_search.ts:30](https://github.com/get-convex/convex-js/blob/main/src/server/vector_search.ts#L30) *** ### limit[​](#limit "Direct link to limit") • `Optional` **limit**: `number` The number of results to return. If specified, must be between 1 and 256 inclusive. **`Default`** ``` 10 ``` #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/vector\_search.ts:37](https://github.com/get-convex/convex-js/blob/main/src/server/vector_search.ts#L37) *** ### filter[​](#filter "Direct link to filter") • `Optional` **filter**: (`q`: [`VectorFilterBuilder`](/api/interfaces/server.VectorFilterBuilder.md)<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>, [`NamedVectorIndex`](/api/modules/server.md#namedvectorindex)<`TableInfo`, `IndexName`>>) => [`FilterExpression`](/api/classes/server.FilterExpression.md)<`boolean`> #### Type declaration[​](#type-declaration "Direct link to Type declaration") ▸ (`q`): [`FilterExpression`](/api/classes/server.FilterExpression.md)<`boolean`> Optional filter expression made up of `q.or` and `q.eq` operating over the filter fields of the index. e.g. `filter: q => q.or(q.eq("genre", "comedy"), q.eq("genre", "drama"))` ##### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | ---- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `q` | [`VectorFilterBuilder`](/api/interfaces/server.VectorFilterBuilder.md)<[`DocumentByInfo`](/api/modules/server.md#documentbyinfo)<`TableInfo`>, [`NamedVectorIndex`](/api/modules/server.md#namedvectorindex)<`TableInfo`, `IndexName`>> | ##### Returns[​](#returns "Direct link to Returns") [`FilterExpression`](/api/classes/server.FilterExpression.md)<`boolean`> #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/vector\_search.ts:47](https://github.com/get-convex/convex-js/blob/main/src/server/vector_search.ts#L47) --- # convex ## Modules[​](#modules "Direct link to Modules") * [browser](/api/modules/browser.md) * [nextjs](/api/modules/nextjs.md) * [react-auth0](/api/modules/react_auth0.md) * [react-clerk](/api/modules/react_clerk.md) * [react](/api/modules/react.md) * [server](/api/modules/server.md) * [values](/api/modules/values.md) --- # Module: browser Tools for accessing Convex in the browser. **If you are using React, use the [react](/api/modules/react.md) module instead.** ## Usage[​](#usage "Direct link to Usage") Create a [ConvexHttpClient](/api/classes/browser.ConvexHttpClient.md) to connect to the Convex Cloud. ``` 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[​](#classes "Direct link to Classes") * [ConvexHttpClient](/api/classes/browser.ConvexHttpClient.md) * [ConvexClient](/api/classes/browser.ConvexClient.md) * [BaseConvexClient](/api/classes/browser.BaseConvexClient.md) ## Interfaces[​](#interfaces "Direct link to Interfaces") * [BaseConvexClientOptions](/api/interfaces/browser.BaseConvexClientOptions.md) * [SubscribeOptions](/api/interfaces/browser.SubscribeOptions.md) * [MutationOptions](/api/interfaces/browser.MutationOptions.md) * [OptimisticLocalStore](/api/interfaces/browser.OptimisticLocalStore.md) ## Type Aliases[​](#type-aliases "Direct link to Type Aliases") ### HttpMutationOptions[​](#httpmutationoptions "Direct link to HttpMutationOptions") Ƭ **HttpMutationOptions**: `Object` #### Type declaration[​](#type-declaration "Direct link to Type declaration") | Name | Type | Description | | ----------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `skipQueue` | `boolean` | Skip the default queue of mutations and run this immediately. This allows the same HttpConvexClient to be used to request multiple mutations in parallel, something not possible with WebSocket-based clients. | #### Defined in[​](#defined-in "Direct link to Defined in") [browser/http\_client.ts:40](https://github.com/get-convex/convex-js/blob/main/src/browser/http_client.ts#L40) *** ### ConvexClientOptions[​](#convexclientoptions "Direct link to ConvexClientOptions") Ƭ **ConvexClientOptions**: [`BaseConvexClientOptions`](/api/interfaces/browser.BaseConvexClientOptions.md) & { `disabled?`: `boolean` ; `unsavedChangesWarning?`: `boolean` } #### Defined in[​](#defined-in-1 "Direct link to Defined in") [browser/simple\_client.ts:36](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L36) *** ### AuthTokenFetcher[​](#authtokenfetcher "Direct link to AuthTokenFetcher") Ƭ **AuthTokenFetcher**: (`args`: { `forceRefreshToken`: `boolean` }) => `Promise`<`string` | `null` | `undefined`> #### Type declaration[​](#type-declaration-1 "Direct link to Type declaration") ▸ (`args`): `Promise`<`string` | `null` | `undefined`> An async function returning a JWT. Depending on the auth providers configured in convex/auth.config.ts, this may be a JWT-encoded OpenID Connect Identity Token or a traditional JWT. `forceRefreshToken` is `true` if the server rejected a previously returned token or the token is anticipated to expiring soon based on its `exp` time. See ConvexReactClient.setAuth. ##### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | ------------------------ | --------- | | `args` | `Object` | | `args.forceRefreshToken` | `boolean` | ##### Returns[​](#returns "Direct link to Returns") `Promise`<`string` | `null` | `undefined`> #### Defined in[​](#defined-in-2 "Direct link to Defined in") [browser/sync/authentication\_manager.ts:25](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/authentication_manager.ts#L25) *** ### ConnectionState[​](#connectionstate "Direct link to ConnectionState") Ƭ **ConnectionState**: `Object` State describing the client's connection with the Convex backend. #### Type declaration[​](#type-declaration-2 "Direct link to Type declaration") | Name | Type | Description | | ----------------------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `hasInflightRequests` | `boolean` | - | | `isWebSocketConnected` | `boolean` | - | | `timeOfOldestInflightRequest` | `Date` \| `null` | - | | `hasEverConnected` | `boolean` | True if the client has ever opened a WebSocket to the "ready" state. | | `connectionCount` | `number` | The number of times this client has connected to the Convex backend. A number of things can cause the client to reconnect -- server errors, bad internet, auth expiring. But this number being high is an indication that the client is having trouble keeping a stable connection. | | `connectionRetries` | `number` | The number of times this client has tried (and failed) to connect to the Convex backend. | | `inflightMutations` | `number` | The number of mutations currently in flight. | | `inflightActions` | `number` | The number of actions currently in flight. | #### Defined in[​](#defined-in-3 "Direct link to Defined in") [browser/sync/client.ts:147](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L147) *** ### FunctionResult[​](#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[​](#defined-in-4 "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[​](#optimisticupdate "Direct link to OptimisticUpdate") Ƭ **OptimisticUpdate**<`Args`>: (`localQueryStore`: [`OptimisticLocalStore`](/api/interfaces/browser.OptimisticLocalStore.md), `args`: `Args`) => `void` #### Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ------ | ------------------------------------------------------------------- | | `Args` | extends `Record`<`string`, [`Value`](/api/modules/values.md#value)> | #### Type declaration[​](#type-declaration-3 "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[​](#parameters-1 "Direct link to Parameters") | Name | Type | Description | | ----------------- | ------------------------------------------------------------------------- | -------------------------------------------------- | | `localQueryStore` | [`OptimisticLocalStore`](/api/interfaces/browser.OptimisticLocalStore.md) | An interface to read and edit local query results. | | `args` | `Args` | The arguments to the mutation. | ##### Returns[​](#returns-1 "Direct link to Returns") `void` #### Defined in[​](#defined-in-5 "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) *** ### PaginationStatus[​](#paginationstatus "Direct link to PaginationStatus") Ƭ **PaginationStatus**: `"LoadingFirstPage"` | `"CanLoadMore"` | `"LoadingMore"` | `"Exhausted"` #### Defined in[​](#defined-in-6 "Direct link to Defined in") [browser/sync/pagination.ts:5](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/pagination.ts#L5) *** ### QueryJournal[​](#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[​](#defined-in-7 "Direct link to Defined in") [browser/sync/protocol.ts:113](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/protocol.ts#L113) *** ### QueryToken[​](#querytoken "Direct link to QueryToken") Ƭ **QueryToken**: `string` & { `__queryToken`: `true` } A string representing the name and arguments of a query. This is used by the [BaseConvexClient](/api/classes/browser.BaseConvexClient.md). #### Defined in[​](#defined-in-8 "Direct link to Defined in") [browser/sync/udf\_path\_utils.ts:31](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/udf_path_utils.ts#L31) *** ### PaginatedQueryToken[​](#paginatedquerytoken "Direct link to PaginatedQueryToken") Ƭ **PaginatedQueryToken**: [`QueryToken`](/api/modules/browser.md#querytoken) & { `__paginatedQueryToken`: `true` } A string representing the name and arguments of a paginated query. This is a specialized form of QueryToken used for paginated queries. #### Defined in[​](#defined-in-9 "Direct link to Defined in") [browser/sync/udf\_path\_utils.ts:38](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/udf_path_utils.ts#L38) *** ### UserIdentityAttributes[​](#useridentityattributes "Direct link to UserIdentityAttributes") Ƭ **UserIdentityAttributes**: `Omit`<[`UserIdentity`](/api/interfaces/server.UserIdentity.md), `"tokenIdentifier"`> #### Defined in[​](#defined-in-10 "Direct link to Defined in") [server/authentication.ts:215](https://github.com/get-convex/convex-js/blob/main/src/server/authentication.ts#L215) --- # Module: nextjs Helpers for integrating Convex into Next.js applications using server rendering. This module contains: 1. [preloadQuery](/api/modules/nextjs.md#preloadquery), for preloading data for reactive client components. 2. [fetchQuery](/api/modules/nextjs.md#fetchquery), [fetchMutation](/api/modules/nextjs.md#fetchmutation) and [fetchAction](/api/modules/nextjs.md#fetchaction) for loading and mutating Convex data from Next.js Server Components, Server Actions and Route Handlers. ## Usage[​](#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[​](#preloading-data "Direct link to Preloading data") Preload data inside a Server Component: ``` 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: ``` import { Preloaded, usePreloadedQuery } from "convex/react"; import { api } from "@/convex/_generated/api"; export function ClientComponent(props: { preloaded: Preloaded; }) { const data = usePreloadedQuery(props.preloaded); // render `data`... } ``` ## Type Aliases[​](#type-aliases "Direct link to Type Aliases") ### NextjsOptions[​](#nextjsoptions "Direct link to NextjsOptions") Ƭ **NextjsOptions**: `Object` Options to [preloadQuery](/api/modules/nextjs.md#preloadquery), [fetchQuery](/api/modules/nextjs.md#fetchquery), [fetchMutation](/api/modules/nextjs.md#fetchmutation) and [fetchAction](/api/modules/nextjs.md#fetchaction). #### Type declaration[​](#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` if not provided. Explicitly passing undefined here (such as from missing ENV variables) will throw an error in the future. | | `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[​](#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[​](#functions "Direct link to Functions") ### preloadQuery[​](#preloadquery "Direct link to preloadQuery") ▸ **preloadQuery**<`Query`>(`query`, `...args`): `Promise`<[`Preloaded`](/api/modules/react.md#preloaded)<`Query`>> Execute a Convex query function and return a `Preloaded` payload which can be passed to [usePreloadedQuery](/api/modules/react.md#usepreloadedquery) in a Client Component. #### Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"query"`> | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | Description | | --------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | | `query` | `Query` | a [FunctionReference](/api/modules/server.md#functionreference) for the public query to run like `api.dir1.dir2.filename.func`. | | `...args` | [`ArgsAndOptions`](/api/modules/server.md#argsandoptions)<`Query`, [`NextjsOptions`](/api/modules/nextjs.md#nextjsoptions)> | The arguments object for the query. If this is omitted, the arguments will be `{}`. | #### Returns[​](#returns "Direct link to Returns") `Promise`<[`Preloaded`](/api/modules/react.md#preloaded)<`Query`>> A promise of the `Preloaded` payload. #### Defined in[​](#defined-in-1 "Direct link to Defined in") [nextjs/index.ts:101](https://github.com/get-convex/convex-js/blob/main/src/nextjs/index.ts#L101) *** ### preloadedQueryResult[​](#preloadedqueryresult "Direct link to preloadedQueryResult") ▸ **preloadedQueryResult**<`Query`>(`preloaded`): [`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`> Returns the result of executing a query via [preloadQuery](/api/modules/nextjs.md#preloadquery). #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"query"`> | #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | Description | | ----------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------- | | `preloaded` | [`Preloaded`](/api/modules/react.md#preloaded)<`Query`> | The `Preloaded` payload returned by [preloadQuery](/api/modules/nextjs.md#preloadquery). | #### Returns[​](#returns-1 "Direct link to Returns") [`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`> The query result. #### Defined in[​](#defined-in-2 "Direct link to Defined in") [nextjs/index.ts:120](https://github.com/get-convex/convex-js/blob/main/src/nextjs/index.ts#L120) *** ### fetchQuery[​](#fetchquery "Direct link to fetchQuery") ▸ **fetchQuery**<`Query`>(`query`, `...args`): `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`>> Execute a Convex query function. #### Type parameters[​](#type-parameters-2 "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"query"`> | #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | Description | | --------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | | `query` | `Query` | a [FunctionReference](/api/modules/server.md#functionreference) for the public query to run like `api.dir1.dir2.filename.func`. | | `...args` | [`ArgsAndOptions`](/api/modules/server.md#argsandoptions)<`Query`, [`NextjsOptions`](/api/modules/nextjs.md#nextjsoptions)> | The arguments object for the query. If this is omitted, the arguments will be `{}`. | #### Returns[​](#returns-2 "Direct link to Returns") `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`>> A promise of the query's result. #### Defined in[​](#defined-in-3 "Direct link to Defined in") [nextjs/index.ts:136](https://github.com/get-convex/convex-js/blob/main/src/nextjs/index.ts#L136) *** ### fetchMutation[​](#fetchmutation "Direct link to fetchMutation") ▸ **fetchMutation**<`Mutation`>(`mutation`, `...args`): `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Mutation`>> Execute a Convex mutation function. #### Type parameters[​](#type-parameters-3 "Direct link to Type parameters") | Name | Type | | ---------- | ------------------------------------------------------------------------------------- | | `Mutation` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"mutation"`> | #### Parameters[​](#parameters-3 "Direct link to Parameters") | Name | Type | Description | | ---------- | ------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- | | `mutation` | `Mutation` | A [FunctionReference](/api/modules/server.md#functionreference) for the public mutation to run like `api.dir1.dir2.filename.func`. | | `...args` | [`ArgsAndOptions`](/api/modules/server.md#argsandoptions)<`Mutation`, [`NextjsOptions`](/api/modules/nextjs.md#nextjsoptions)> | The arguments object for the mutation. If this is omitted, the arguments will be `{}`. | #### Returns[​](#returns-3 "Direct link to Returns") `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Mutation`>> A promise of the mutation's result. #### Defined in[​](#defined-in-4 "Direct link to Defined in") [nextjs/index.ts:155](https://github.com/get-convex/convex-js/blob/main/src/nextjs/index.ts#L155) *** ### fetchAction[​](#fetchaction "Direct link to fetchAction") ▸ **fetchAction**<`Action`>(`action`, `...args`): `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Action`>> Execute a Convex action function. #### Type parameters[​](#type-parameters-4 "Direct link to Type parameters") | Name | Type | | -------- | ----------------------------------------------------------------------------------- | | `Action` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"action"`> | #### Parameters[​](#parameters-4 "Direct link to Parameters") | Name | Type | Description | | --------- | ---------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | | `action` | `Action` | A [FunctionReference](/api/modules/server.md#functionreference) for the public action to run like `api.dir1.dir2.filename.func`. | | `...args` | [`ArgsAndOptions`](/api/modules/server.md#argsandoptions)<`Action`, [`NextjsOptions`](/api/modules/nextjs.md#nextjsoptions)> | The arguments object for the action. If this is omitted, the arguments will be `{}`. | #### Returns[​](#returns-4 "Direct link to Returns") `Promise`<[`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Action`>> A promise of the action's result. #### Defined in[​](#defined-in-5 "Direct link to Defined in") [nextjs/index.ts:176](https://github.com/get-convex/convex-js/blob/main/src/nextjs/index.ts#L176) --- # Module: react Tools to integrate Convex into React applications. This module contains: 1. [ConvexReactClient](/api/classes/react.ConvexReactClient.md), a client for using Convex in React. 2. [ConvexProvider](/api/modules/react.md#convexprovider), a component that stores this client in React context. 3. [Authenticated](/api/modules/react.md#authenticated), [Unauthenticated](/api/modules/react.md#unauthenticated) and [AuthLoading](/api/modules/react.md#authloading) helper auth components. 4. Hooks [useQuery](/api/modules/react.md#usequery), [useMutation](/api/modules/react.md#usemutation), [useAction](/api/modules/react.md#useaction) and more for accessing this client from your React components. ## Usage[​](#usage "Direct link to Usage") ### Creating the client[​](#creating-the-client "Direct link to Creating the client") ``` 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[​](#storing-the-client-in-react-context "Direct link to Storing the client in React Context") ``` import { ConvexProvider } from "convex/react"; ``` ### Using the auth helpers[​](#using-the-auth-helpers "Direct link to Using the auth helpers") ``` import { Authenticated, Unauthenticated, AuthLoading } from "convex/react"; Logged in Logged out Still loading ``` ### Using React hooks[​](#using-react-hooks "Direct link to Using React hooks") ``` 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[​](#classes "Direct link to Classes") * [ConvexReactClient](/api/classes/react.ConvexReactClient.md) ## Interfaces[​](#interfaces "Direct link to Interfaces") * [ReactMutation](/api/interfaces/react.ReactMutation.md) * [ReactAction](/api/interfaces/react.ReactAction.md) * [Watch](/api/interfaces/react.Watch.md) * [WatchQueryOptions](/api/interfaces/react.WatchQueryOptions.md) * [MutationOptions](/api/interfaces/react.MutationOptions.md) * [ConvexReactClientOptions](/api/interfaces/react.ConvexReactClientOptions.md) ## References[​](#references "Direct link to References") ### AuthTokenFetcher[​](#authtokenfetcher "Direct link to AuthTokenFetcher") Re-exports [AuthTokenFetcher](/api/modules/browser.md#authtokenfetcher) ## Type Aliases[​](#type-aliases "Direct link to Type Aliases") ### ConvexAuthState[​](#convexauthstate "Direct link to ConvexAuthState") Ƭ **ConvexAuthState**: `Object` Type representing the state of an auth integration with Convex. #### Type declaration[​](#type-declaration "Direct link to Type declaration") | Name | Type | | ----------------- | --------- | | `isLoading` | `boolean` | | `isAuthenticated` | `boolean` | #### Defined in[​](#defined-in "Direct link to Defined in") [react/ConvexAuthState.tsx:26](https://github.com/get-convex/convex-js/blob/main/src/react/ConvexAuthState.tsx#L26) *** ### OptionalRestArgsOrSkip[​](#optionalrestargsorskip "Direct link to OptionalRestArgsOrSkip") Ƭ **OptionalRestArgsOrSkip**<`FuncRef`>: `FuncRef`\[`"_args"`] extends `EmptyObject` ? \[args?: EmptyObject | "skip"] : \[args: FuncRef\["\_args"] | "skip"] #### Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | --------- | ------------------------------------------------------------------------------ | | `FuncRef` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`any`> | #### Defined in[​](#defined-in-1 "Direct link to Defined in") [react/client.ts:799](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L799) *** ### Preloaded[​](#preloaded "Direct link to Preloaded") Ƭ **Preloaded**<`Query`>: `Object` The preloaded query payload, which should be passed to a client component and passed to [usePreloadedQuery](/api/modules/react.md#usepreloadedquery). #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"query"`> | #### Type declaration[​](#type-declaration-1 "Direct link to Type declaration") | Name | Type | | ------------ | -------- | | `__type` | `Query` | | `_name` | `string` | | `_argsJSON` | `string` | | `_valueJSON` | `string` | #### Defined in[​](#defined-in-2 "Direct link to Defined in") [react/hydration.tsx:12](https://github.com/get-convex/convex-js/blob/main/src/react/hydration.tsx#L12) *** ### PaginatedQueryReference[​](#paginatedqueryreference "Direct link to PaginatedQueryReference") Ƭ **PaginatedQueryReference**: [`FunctionReference`](/api/modules/server.md#functionreference)<`"query"`, `"public"`, { `paginationOpts`: [`PaginationOptions`](/api/interfaces/server.PaginationOptions.md) }, [`PaginationResult`](/api/interfaces/server.PaginationResult.md)<`any`>> A [FunctionReference](/api/modules/server.md#functionreference) that is usable with [usePaginatedQuery](/api/modules/react.md#usepaginatedquery). This function reference must: * Refer to a public query * Have an argument named "paginationOpts" of type [PaginationOptions](/api/interfaces/server.PaginationOptions.md) * Have a return type of [PaginationResult](/api/interfaces/server.PaginationResult.md). #### Defined in[​](#defined-in-3 "Direct link to Defined in") [react/use\_paginated\_query.ts:31](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L31) *** ### UsePaginatedQueryResult[​](#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](/api/modules/react.md#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[​](#type-parameters-2 "Direct link to Type parameters") | Name | | ------ | | `Item` | #### Defined in[​](#defined-in-4 "Direct link to Defined in") [react/use\_paginated\_query.ts:479](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L479) *** ### PaginationStatus[​](#paginationstatus "Direct link to PaginationStatus") Ƭ **PaginationStatus**: [`UsePaginatedQueryResult`](/api/modules/react.md#usepaginatedqueryresult)<`any`>\[`"status"`] The possible pagination statuses in [UsePaginatedQueryResult](/api/modules/react.md#usepaginatedqueryresult). This is a union of string literal types. #### Defined in[​](#defined-in-5 "Direct link to Defined in") [react/use\_paginated\_query.ts:507](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L507) *** ### PaginatedQueryArgs[​](#paginatedqueryargs "Direct link to PaginatedQueryArgs") Ƭ **PaginatedQueryArgs**<`Query`>: [`Expand`](/api/modules/server.md#expand)<[`BetterOmit`](/api/modules/server.md#betteromit)<[`FunctionArgs`](/api/modules/server.md#functionargs)<`Query`>, `"paginationOpts"`>> Given a [PaginatedQueryReference](/api/modules/react.md#paginatedqueryreference), get the type of the arguments object for the query, excluding the `paginationOpts` argument. #### Type parameters[​](#type-parameters-3 "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`PaginatedQueryReference`](/api/modules/react.md#paginatedqueryreference) | #### Defined in[​](#defined-in-6 "Direct link to Defined in") [react/use\_paginated\_query.ts:515](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L515) *** ### PaginatedQueryItem[​](#paginatedqueryitem "Direct link to PaginatedQueryItem") Ƭ **PaginatedQueryItem**<`Query`>: [`FunctionReturnType`](/api/modules/server.md#functionreturntype)<`Query`>\[`"page"`]\[`number`] Given a [PaginatedQueryReference](/api/modules/react.md#paginatedqueryreference), get the type of the item being paginated over. #### Type parameters[​](#type-parameters-4 "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`PaginatedQueryReference`](/api/modules/react.md#paginatedqueryreference) | #### Defined in[​](#defined-in-7 "Direct link to Defined in") [react/use\_paginated\_query.ts:524](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L524) *** ### UsePaginatedQueryReturnType[​](#usepaginatedqueryreturntype "Direct link to UsePaginatedQueryReturnType") Ƭ **UsePaginatedQueryReturnType**<`Query`>: [`UsePaginatedQueryResult`](/api/modules/react.md#usepaginatedqueryresult)<[`PaginatedQueryItem`](/api/modules/react.md#paginatedqueryitem)<`Query`>> The return type of [usePaginatedQuery](/api/modules/react.md#usepaginatedquery). #### Type parameters[​](#type-parameters-5 "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`PaginatedQueryReference`](/api/modules/react.md#paginatedqueryreference) | #### Defined in[​](#defined-in-8 "Direct link to Defined in") [react/use\_paginated\_query.ts:532](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L532) *** ### RequestForQueries[​](#requestforqueries "Direct link to RequestForQueries") Ƭ **RequestForQueries**: `Record`<`string`, { `query`: [`FunctionReference`](/api/modules/server.md#functionreference)<`"query"`> ; `args`: `Record`<`string`, [`Value`](/api/modules/values.md#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](/api/modules/react.md#usequeries). #### Defined in[​](#defined-in-9 "Direct link to Defined in") [react/use\_queries.ts:137](https://github.com/get-convex/convex-js/blob/main/src/react/use_queries.ts#L137) ## Functions[​](#functions "Direct link to Functions") ### useConvexAuth[​](#useconvexauth "Direct link to useConvexAuth") ▸ **useConvexAuth**(): `Object` Get the [ConvexAuthState](/api/modules/react.md#convexauthstate) within a React component. This relies on a Convex auth integration provider being above in the React component tree. #### Returns[​](#returns "Direct link to Returns") `Object` The current [ConvexAuthState](/api/modules/react.md#convexauthstate). | Name | Type | | ----------------- | --------- | | `isLoading` | `boolean` | | `isAuthenticated` | `boolean` | #### Defined in[​](#defined-in-10 "Direct link to Defined in") [react/ConvexAuthState.tsx:43](https://github.com/get-convex/convex-js/blob/main/src/react/ConvexAuthState.tsx#L43) *** ### ConvexProviderWithAuth[​](#convexproviderwithauth "Direct link to ConvexProviderWithAuth") ▸ **ConvexProviderWithAuth**(`«destructured»`): `Element` A replacement for [ConvexProvider](/api/modules/react.md#convexprovider) which additionally provides [ConvexAuthState](/api/modules/react.md#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 will 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[​](#parameters "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[​](#returns-1 "Direct link to Returns") `Element` #### Defined in[​](#defined-in-11 "Direct link to Defined in") [react/ConvexAuthState.tsx:75](https://github.com/get-convex/convex-js/blob/main/src/react/ConvexAuthState.tsx#L75) *** ### Authenticated[​](#authenticated "Direct link to Authenticated") ▸ **Authenticated**(`«destructured»`): `null` | `Element` Renders children if the client is authenticated. #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | | ---------------- | ----------- | | `«destructured»` | `Object` | | › `children` | `ReactNode` | #### Returns[​](#returns-2 "Direct link to Returns") `null` | `Element` #### Defined in[​](#defined-in-12 "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[​](#unauthenticated "Direct link to Unauthenticated") ▸ **Unauthenticated**(`«destructured»`): `null` | `Element` Renders children if the client is using authentication but is not authenticated. #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | | ---------------- | ----------- | | `«destructured»` | `Object` | | › `children` | `ReactNode` | #### Returns[​](#returns-3 "Direct link to Returns") `null` | `Element` #### Defined in[​](#defined-in-13 "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[​](#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[​](#parameters-3 "Direct link to Parameters") | Name | Type | | ---------------- | ----------- | | `«destructured»` | `Object` | | › `children` | `ReactNode` | #### Returns[​](#returns-4 "Direct link to Returns") `null` | `Element` #### Defined in[​](#defined-in-14 "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[​](#useconvex "Direct link to useConvex") ▸ **useConvex**(): [`ConvexReactClient`](/api/classes/react.ConvexReactClient.md) Get the [ConvexReactClient](/api/classes/react.ConvexReactClient.md) within a React component. This relies on the [ConvexProvider](/api/modules/react.md#convexprovider) being above in the React component tree. #### Returns[​](#returns-5 "Direct link to Returns") [`ConvexReactClient`](/api/classes/react.ConvexReactClient.md) The active [ConvexReactClient](/api/classes/react.ConvexReactClient.md) object, or `undefined`. #### Defined in[​](#defined-in-15 "Direct link to Defined in") [react/client.ts:774](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L774) *** ### ConvexProvider[​](#convexprovider "Direct link to ConvexProvider") ▸ **ConvexProvider**(`props`, `deprecatedLegacyContext?`): `null` | `ReactElement`<`any`, `any`> Provides an active Convex [ConvexReactClient](/api/classes/react.ConvexReactClient.md) to descendants of this component. Wrap your app in this component to use Convex hooks `useQuery`, `useMutation`, and `useConvex`. #### Parameters[​](#parameters-4 "Direct link to Parameters") | Name | Type | Description | | -------------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | `props` | `Object` | an object with a `client` property that refers to a [ConvexReactClient](/api/classes/react.ConvexReactClient.md). | | `props.client` | [`ConvexReactClient`](/api/classes/react.ConvexReactClient.md) | - | | `props.children?` | `ReactNode` | - | | `deprecatedLegacyContext?` | `any` | **`Deprecated`** **`See`** [React Docs](https://legacy.reactjs.org/docs/legacy-context.html#referencing-context-in-lifecycle-methods) | #### Returns[​](#returns-6 "Direct link to Returns") `null` | `ReactElement`<`any`, `any`> #### Defined in[​](#defined-in-16 "Direct link to Defined in") ../../common/temp/node\_modules/.pnpm/@types+react\@18.3.26/node\_modules/@types/react/ts5.0/index.d.ts:1129 *** ### useQuery[​](#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](/api/modules/react.md#convexprovider). #### Type parameters[​](#type-parameters-6 "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"query"`> | #### Parameters[​](#parameters-5 "Direct link to Parameters") | Name | Type | Description | | --------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | | `query` | `Query` | a [FunctionReference](/api/modules/server.md#functionreference) for the public query to run like `api.dir1.dir2.filename.func`. | | `...args` | [`OptionalRestArgsOrSkip`](/api/modules/react.md#optionalrestargsorskip)<`Query`> | The arguments to the query function or the string "skip" if the query should not be loaded. | #### Returns[​](#returns-7 "Direct link to Returns") `Query`\[`"_returnType"`] | `undefined` the result of the query. If the query is loading returns `undefined`. #### Defined in[​](#defined-in-17 "Direct link to Defined in") [react/client.ts:820](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L820) *** ### useMutation[​](#usemutation "Direct link to useMutation") ▸ **useMutation**<`Mutation`>(`mutation`): [`ReactMutation`](/api/interfaces/react.ReactMutation.md)<`Mutation`> Construct a new [ReactMutation](/api/interfaces/react.ReactMutation.md). 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](/api/modules/react.md#convexprovider). #### Type parameters[​](#type-parameters-7 "Direct link to Type parameters") | Name | Type | | ---------- | ------------------------------------------------------------------------------------- | | `Mutation` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"mutation"`> | #### Parameters[​](#parameters-6 "Direct link to Parameters") | Name | Type | Description | | ---------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------- | | `mutation` | `Mutation` | A [FunctionReference](/api/modules/server.md#functionreference) for the public mutation to run like `api.dir1.dir2.filename.func`. | #### Returns[​](#returns-8 "Direct link to Returns") [`ReactMutation`](/api/interfaces/react.ReactMutation.md)<`Mutation`> The [ReactMutation](/api/interfaces/react.ReactMutation.md) object with that name. #### Defined in[​](#defined-in-18 "Direct link to Defined in") [react/client.ts:872](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L872) *** ### useAction[​](#useaction "Direct link to useAction") ▸ **useAction**<`Action`>(`action`): [`ReactAction`](/api/interfaces/react.ReactAction.md)<`Action`> Construct a new [ReactAction](/api/interfaces/react.ReactAction.md). 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](/api/modules/react.md#convexprovider). #### Type parameters[​](#type-parameters-8 "Direct link to Type parameters") | Name | Type | | -------- | ----------------------------------------------------------------------------------- | | `Action` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"action"`> | #### Parameters[​](#parameters-7 "Direct link to Parameters") | Name | Type | Description | | -------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- | | `action` | `Action` | A [FunctionReference](/api/modules/server.md#functionreference) for the public action to run like `api.dir1.dir2.filename.func`. | #### Returns[​](#returns-9 "Direct link to Returns") [`ReactAction`](/api/interfaces/react.ReactAction.md)<`Action`> The [ReactAction](/api/interfaces/react.ReactAction.md) object with that name. #### Defined in[​](#defined-in-19 "Direct link to Defined in") [react/client.ts:913](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L913) *** ### useConvexConnectionState[​](#useconvexconnectionstate "Direct link to useConvexConnectionState") ▸ **useConvexConnectionState**(): [`ConnectionState`](/api/modules/browser.md#connectionstate) React hook to get the current [ConnectionState](/api/modules/browser.md#connectionstate) and subscribe to changes. This hook returns the current connection state and automatically rerenders when any part of the connection state changes (e.g., when going online/offline, when requests start/complete, etc.). The shape of ConnectionState may change in the future which may cause this hook to rerender more frequently. Throws an error if not used under [ConvexProvider](/api/modules/react.md#convexprovider). #### Returns[​](#returns-10 "Direct link to Returns") [`ConnectionState`](/api/modules/browser.md#connectionstate) The current [ConnectionState](/api/modules/browser.md#connectionstate) with the Convex backend. #### Defined in[​](#defined-in-20 "Direct link to Defined in") [react/client.ts:952](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L952) *** ### usePreloadedQuery[​](#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](/api/modules/nextjs.md#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](/api/modules/react.md#convexprovider). #### Type parameters[​](#type-parameters-9 "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"query"`> | #### Parameters[​](#parameters-8 "Direct link to Parameters") | Name | Type | Description | | ---------------- | ------------------------------------------------------- | ------------------------------------------------------ | | `preloadedQuery` | [`Preloaded`](/api/modules/react.md#preloaded)<`Query`> | The `Preloaded` query payload from a Server Component. | #### Returns[​](#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[​](#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[​](#usepaginatedquery "Direct link to usePaginatedQuery") ▸ **usePaginatedQuery**<`Query`>(`query`, `args`, `options`): [`UsePaginatedQueryReturnType`](/api/modules/react.md#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](/api/modules/react.md#paginatedqueryreference). `usePaginatedQuery` concatenates all the pages of results into a single list and manages the continuation cursors when requesting more items. Example usage: ``` 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[​](#type-parameters-10 "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`PaginatedQueryReference`](/api/modules/react.md#paginatedqueryreference) | #### Parameters[​](#parameters-9 "Direct link to Parameters") | Name | Type | Description | | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | | `query` | `Query` | A FunctionReference to the public query function to run. | | `args` | `"skip"` \| [`Expand`](/api/modules/server.md#expand)<[`BetterOmit`](/api/modules/server.md#betteromit)<[`FunctionArgs`](/api/modules/server.md#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[​](#returns-12 "Direct link to Returns") [`UsePaginatedQueryReturnType`](/api/modules/react.md#usepaginatedqueryreturntype)<`Query`> A [UsePaginatedQueryResult](/api/modules/react.md#usepaginatedqueryresult) that includes the currently loaded items, the status of the pagination, and a `loadMore` function. #### Defined in[​](#defined-in-22 "Direct link to Defined in") [react/use\_paginated\_query.ts:162](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L162) *** ### resetPaginationId[​](#resetpaginationid "Direct link to resetPaginationId") ▸ **resetPaginationId**(): `void` Reset pagination id for tests only, so tests know what it is. #### Returns[​](#returns-13 "Direct link to Returns") `void` #### Defined in[​](#defined-in-23 "Direct link to Defined in") [react/use\_paginated\_query.ts:458](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L458) *** ### optimisticallyUpdateValueInPaginatedQuery[​](#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](/api/modules/react.md#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: ``` 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[​](#type-parameters-11 "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`PaginatedQueryReference`](/api/modules/react.md#paginatedqueryreference) | #### Parameters[​](#parameters-10 "Direct link to Parameters") | Name | Type | Description | | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | | `localStore` | [`OptimisticLocalStore`](/api/interfaces/browser.OptimisticLocalStore.md) | An [OptimisticLocalStore](/api/interfaces/browser.OptimisticLocalStore.md) to update. | | `query` | `Query` | A [FunctionReference](/api/modules/server.md#functionreference) for the paginated query to update. | | `args` | [`Expand`](/api/modules/server.md#expand)<[`BetterOmit`](/api/modules/server.md#betteromit)<[`FunctionArgs`](/api/modules/server.md#functionargs)<`Query`>, `"paginationOpts"`>> | The arguments object to the query function, excluding the `paginationOpts` property. | | `updateValue` | (`currentValue`: [`PaginatedQueryItem`](/api/modules/react.md#paginatedqueryitem)<`Query`>) => [`PaginatedQueryItem`](/api/modules/react.md#paginatedqueryitem)<`Query`> | A function to produce the new values. | #### Returns[​](#returns-14 "Direct link to Returns") `void` #### Defined in[​](#defined-in-24 "Direct link to Defined in") [react/use\_paginated\_query.ts:578](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L578) *** ### insertAtTop[​](#insertattop "Direct link to insertAtTop") ▸ **insertAtTop**<`Query`>(`options`): `void` Updates a paginated query to insert an element at the top of the list. This is regardless of the sort order, so if the list is in descending order, the inserted element will be treated as the "biggest" element, but if it's ascending, it'll be treated as the "smallest". Example: ``` const createTask = useMutation(api.tasks.create) .withOptimisticUpdate((localStore, mutationArgs) => { insertAtTop({ paginatedQuery: api.tasks.list, argsToMatch: { listId: mutationArgs.listId }, localQueryStore: localStore, item: { _id: crypto.randomUUID() as Id<"tasks">, title: mutationArgs.title, completed: false }, }); }); ``` #### Type parameters[​](#type-parameters-12 "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`PaginatedQueryReference`](/api/modules/react.md#paginatedqueryreference) | #### Parameters[​](#parameters-11 "Direct link to Parameters") | Name | Type | Description | | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `options` | `Object` | - | | `options.paginatedQuery` | `Query` | A function reference to the paginated query. | | `options.argsToMatch?` | `Partial`<[`Expand`](/api/modules/server.md#expand)<[`BetterOmit`](/api/modules/server.md#betteromit)<[`FunctionArgs`](/api/modules/server.md#functionargs)<`Query`>, `"paginationOpts"`>>> | Optional arguments that must be in each relevant paginated query. This is useful if you use the same query function with different arguments to load different lists. | | `options.localQueryStore` | [`OptimisticLocalStore`](/api/interfaces/browser.OptimisticLocalStore.md) | | | `options.item` | [`PaginatedQueryItem`](/api/modules/react.md#paginatedqueryitem)<`Query`> | The item to insert. | #### Returns[​](#returns-15 "Direct link to Returns") `void` #### Defined in[​](#defined-in-25 "Direct link to Defined in") [react/use\_paginated\_query.ts:640](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L640) *** ### insertAtBottomIfLoaded[​](#insertatbottomifloaded "Direct link to insertAtBottomIfLoaded") ▸ **insertAtBottomIfLoaded**<`Query`>(`options`): `void` Updates a paginated query to insert an element at the bottom of the list. This is regardless of the sort order, so if the list is in descending order, the inserted element will be treated as the "smallest" element, but if it's ascending, it'll be treated as the "biggest". This only has an effect if the last page is loaded, since otherwise it would result in the element being inserted at the end of whatever is loaded (which is the middle of the list) and then popping out once the optimistic update is over. #### Type parameters[​](#type-parameters-13 "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`PaginatedQueryReference`](/api/modules/react.md#paginatedqueryreference) | #### Parameters[​](#parameters-12 "Direct link to Parameters") | Name | Type | Description | | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `options` | `Object` | - | | `options.paginatedQuery` | `Query` | A function reference to the paginated query. | | `options.argsToMatch?` | `Partial`<[`Expand`](/api/modules/server.md#expand)<[`BetterOmit`](/api/modules/server.md#betteromit)<[`FunctionArgs`](/api/modules/server.md#functionargs)<`Query`>, `"paginationOpts"`>>> | Optional arguments that must be in each relevant paginated query. This is useful if you use the same query function with different arguments to load different lists. | | `options.localQueryStore` | [`OptimisticLocalStore`](/api/interfaces/browser.OptimisticLocalStore.md) | | | `options.item` | [`PaginatedQueryItem`](/api/modules/react.md#paginatedqueryitem)<`Query`> | - | #### Returns[​](#returns-16 "Direct link to Returns") `void` #### Defined in[​](#defined-in-26 "Direct link to Defined in") [react/use\_paginated\_query.ts:689](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L689) *** ### insertAtPosition[​](#insertatposition "Direct link to insertAtPosition") ▸ **insertAtPosition**<`Query`>(`options`): `void` This is a helper function for inserting an item at a specific position in a paginated query. You must provide the sortOrder and a function for deriving the sort key (an array of values) from an item in the list. This will only work if the server query uses the same sort order and sort key as the optimistic update. Example: ``` const createTask = useMutation(api.tasks.create) .withOptimisticUpdate((localStore, mutationArgs) => { insertAtPosition({ paginatedQuery: api.tasks.listByPriority, argsToMatch: { listId: mutationArgs.listId }, sortOrder: "asc", sortKeyFromItem: (item) => [item.priority, item._creationTime], localQueryStore: localStore, item: { _id: crypto.randomUUID() as Id<"tasks">, _creationTime: Date.now(), title: mutationArgs.title, completed: false, priority: mutationArgs.priority, }, }); }); ``` #### Type parameters[​](#type-parameters-14 "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`PaginatedQueryReference`](/api/modules/react.md#paginatedqueryreference) | #### Parameters[​](#parameters-13 "Direct link to Parameters") | Name | Type | Description | | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `options` | `Object` | - | | `options.paginatedQuery` | `Query` | A function reference to the paginated query. | | `options.argsToMatch?` | `Partial`<[`Expand`](/api/modules/server.md#expand)<[`BetterOmit`](/api/modules/server.md#betteromit)<[`FunctionArgs`](/api/modules/server.md#functionargs)<`Query`>, `"paginationOpts"`>>> | Optional arguments that must be in each relevant paginated query. This is useful if you use the same query function with different arguments to load different lists. | | `options.sortOrder` | `"asc"` \| `"desc"` | The sort order of the paginated query ("asc" or "desc"). | | `options.sortKeyFromItem` | (`element`: [`PaginatedQueryItem`](/api/modules/react.md#paginatedqueryitem)<`Query`>) => [`Value`](/api/modules/values.md#value) \| [`Value`](/api/modules/values.md#value)\[] | A function for deriving the sort key (an array of values) from an element in the list. Including a tie-breaker field like `_creationTime` is recommended. | | `options.localQueryStore` | [`OptimisticLocalStore`](/api/interfaces/browser.OptimisticLocalStore.md) | | | `options.item` | [`PaginatedQueryItem`](/api/modules/react.md#paginatedqueryitem)<`Query`> | The item to insert. | #### Returns[​](#returns-17 "Direct link to Returns") `void` #### Defined in[​](#defined-in-27 "Direct link to Defined in") [react/use\_paginated\_query.ts:770](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L770) *** ### usePaginatedQuery\_experimental[​](#usepaginatedquery_experimental "Direct link to usePaginatedQuery_experimental") ▸ **usePaginatedQuery\_experimental**<`Query`>(`query`, `args`, `options`): [`UsePaginatedQueryReturnType`](/api/modules/react.md#usepaginatedqueryreturntype)<`Query`> Experimental new usePaginatedQuery implementation that will replace the current one in the future. Load data reactively from a paginated query to a create a growing list. This is an alternate implementation that relies on new client pagination logic. This can be used to power "infinite scroll" UIs. This hook must be used with public query references that match [PaginatedQueryReference](/api/modules/react.md#paginatedqueryreference). `usePaginatedQuery` concatenates all the pages of results into a single list and manages the continuation cursors when requesting more items. Example usage: ``` 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[​](#type-parameters-15 "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`PaginatedQueryReference`](/api/modules/react.md#paginatedqueryreference) | #### Parameters[​](#parameters-14 "Direct link to Parameters") | Name | Type | Description | | ------------------------- | ------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | | `query` | `Query` | A FunctionReference to the public query function to run. | | `args` | `"skip"` \| [`PaginatedQueryArgs`](/api/modules/react.md#paginatedqueryargs)<`Query`> | 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[​](#returns-18 "Direct link to Returns") [`UsePaginatedQueryReturnType`](/api/modules/react.md#usepaginatedqueryreturntype)<`Query`> A [UsePaginatedQueryResult](/api/modules/react.md#usepaginatedqueryresult) that includes the currently loaded items, the status of the pagination, and a `loadMore` function. #### Defined in[​](#defined-in-28 "Direct link to Defined in") [react/use\_paginated\_query2.ts:72](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query2.ts#L72) *** ### useQueries[​](#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](/api/modules/react.md#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: ``` const results = useQueries({ messagesInGeneral: { query: "listMessages", args: { channel: "#general" } } }); ``` then the result would look like: ``` { 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](/api/modules/react.md#convexprovider). #### Parameters[​](#parameters-15 "Direct link to Parameters") | Name | Type | Description | | --------- | -------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | | `queries` | [`RequestForQueries`](/api/modules/react.md#requestforqueries) | An object mapping identifiers to objects of `{query: string, args: Record }` describing which query functions to fetch. | #### Returns[​](#returns-19 "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[​](#defined-in-29 "Direct link to Defined in") [react/use\_queries.ts:61](https://github.com/get-convex/convex-js/blob/main/src/react/use_queries.ts#L61) --- # Module: react-auth0 React login component for use with Auth0. ## Functions[​](#functions "Direct link to Functions") ### ConvexProviderWithAuth0[​](#convexproviderwithauth0 "Direct link to ConvexProviderWithAuth0") ▸ **ConvexProviderWithAuth0**(`«destructured»`): `Element` A wrapper React component which provides a [ConvexReactClient](/api/classes/react.ConvexReactClient.md) 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[​](#parameters "Direct link to Parameters") | Name | Type | | ---------------- | -------------------- | | `«destructured»` | `Object` | | › `children` | `ReactNode` | | › `client` | `IConvexReactClient` | #### Returns[​](#returns "Direct link to Returns") `Element` #### Defined in[​](#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) --- # Module: react-clerk React login component for use with Clerk. ## Functions[​](#functions "Direct link to Functions") ### ConvexProviderWithClerk[​](#convexproviderwithclerk "Direct link to ConvexProviderWithClerk") ▸ **ConvexProviderWithClerk**(`«destructured»`): `Element` A wrapper React component which provides a [ConvexReactClient](/api/classes/react.ConvexReactClient.md) 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[​](#parameters "Direct link to Parameters") | Name | Type | | ---------------- | -------------------- | | `«destructured»` | `Object` | | › `children` | `ReactNode` | | › `client` | `IConvexReactClient` | | › `useAuth` | `UseAuth` | #### Returns[​](#returns "Direct link to Returns") `Element` #### Defined in[​](#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) --- # Module: server Utilities for implementing server-side Convex query and mutation functions. ## Usage[​](#usage "Direct link to Usage") ### Code Generation[​](#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](/api/modules/server.md#querygeneric) * [mutationGeneric](/api/modules/server.md#mutationgeneric) ### Example[​](#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](/api/interfaces/server.GenericDatabaseReader.md) interface. ``` 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](/api/interfaces/server.GenericDatabaseWriter.md) interface. ``` import { mutation } from "./_generated/server"; export default mutation({ handler: async ({ db }, { arg1, arg2 }) => { // Your mutation code here! }, }); ``` ## Classes[​](#classes "Direct link to Classes") * [Crons](/api/classes/server.Crons.md) * [Expression](/api/classes/server.Expression.md) * [IndexRange](/api/classes/server.IndexRange.md) * [HttpRouter](/api/classes/server.HttpRouter.md) * [TableDefinition](/api/classes/server.TableDefinition.md) * [SchemaDefinition](/api/classes/server.SchemaDefinition.md) * [SearchFilter](/api/classes/server.SearchFilter.md) * [FilterExpression](/api/classes/server.FilterExpression.md) ## Interfaces[​](#interfaces "Direct link to Interfaces") * [UserIdentity](/api/interfaces/server.UserIdentity.md) * [Auth](/api/interfaces/server.Auth.md) * [CronJob](/api/interfaces/server.CronJob.md) * [BaseTableReader](/api/interfaces/server.BaseTableReader.md) * [GenericDatabaseReader](/api/interfaces/server.GenericDatabaseReader.md) * [GenericDatabaseReaderWithTable](/api/interfaces/server.GenericDatabaseReaderWithTable.md) * [GenericDatabaseWriter](/api/interfaces/server.GenericDatabaseWriter.md) * [GenericDatabaseWriterWithTable](/api/interfaces/server.GenericDatabaseWriterWithTable.md) * [BaseTableWriter](/api/interfaces/server.BaseTableWriter.md) * [FilterBuilder](/api/interfaces/server.FilterBuilder.md) * [IndexRangeBuilder](/api/interfaces/server.IndexRangeBuilder.md) * [PaginationResult](/api/interfaces/server.PaginationResult.md) * [PaginationOptions](/api/interfaces/server.PaginationOptions.md) * [QueryInitializer](/api/interfaces/server.QueryInitializer.md) * [Query](/api/interfaces/server.Query.md) * [OrderedQuery](/api/interfaces/server.OrderedQuery.md) * [GenericMutationCtx](/api/interfaces/server.GenericMutationCtx.md) * [GenericQueryCtx](/api/interfaces/server.GenericQueryCtx.md) * [GenericActionCtx](/api/interfaces/server.GenericActionCtx.md) * [ValidatedFunction](/api/interfaces/server.ValidatedFunction.md) * [Scheduler](/api/interfaces/server.Scheduler.md) * [SearchIndexConfig](/api/interfaces/server.SearchIndexConfig.md) * [VectorIndexConfig](/api/interfaces/server.VectorIndexConfig.md) * [DefineSchemaOptions](/api/interfaces/server.DefineSchemaOptions.md) * [SystemDataModel](/api/interfaces/server.SystemDataModel.md) * [SearchFilterBuilder](/api/interfaces/server.SearchFilterBuilder.md) * [SearchFilterFinalizer](/api/interfaces/server.SearchFilterFinalizer.md) * [StorageReader](/api/interfaces/server.StorageReader.md) * [StorageWriter](/api/interfaces/server.StorageWriter.md) * [StorageActionWriter](/api/interfaces/server.StorageActionWriter.md) * [VectorSearchQuery](/api/interfaces/server.VectorSearchQuery.md) * [VectorFilterBuilder](/api/interfaces/server.VectorFilterBuilder.md) ## References[​](#references "Direct link to References") ### UserIdentityAttributes[​](#useridentityattributes "Direct link to UserIdentityAttributes") Re-exports [UserIdentityAttributes](/api/modules/browser.md#useridentityattributes) ## Type Aliases[​](#type-aliases "Direct link to Type Aliases") ### FunctionType[​](#functiontype "Direct link to FunctionType") Ƭ **FunctionType**: `"query"` | `"mutation"` | `"action"` The type of a Convex function. #### Defined in[​](#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[​](#functionreference "Direct link to FunctionReference") Ƭ **FunctionReference**<`Type`, `Visibility`, `Args`, `ReturnType`, `ComponentPath`>: `Object` A reference to a registered Convex function. You can create a [FunctionReference](/api/modules/server.md#functionreference) using the generated `api` utility: ``` import { api } from "../convex/_generated/api"; const reference = api.myModule.myFunction; ``` If you aren't using code generation, you can create references using [anyApi](/api/modules/server.md#anyapi-1): ``` 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](/api/modules/react.md#usequery) hook: ``` const result = useQuery(api.myModule.myFunction); ``` #### Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | Description | | --------------- | -------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | | `Type` | extends [`FunctionType`](/api/modules/server.md#functiontype) | The type of the function ("query", "mutation", or "action"). | | `Visibility` | extends [`FunctionVisibility`](/api/modules/server.md#functionvisibility) = `"public"` | The visibility of the function ("public" or "internal"). | | `Args` | extends [`DefaultFunctionArgs`](/api/modules/server.md#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[​](#type-declaration "Direct link to Type declaration") | Name | Type | | ---------------- | --------------- | | `_type` | `Type` | | `_visibility` | `Visibility` | | `_args` | `Args` | | `_returnType` | `ReturnType` | | `_componentPath` | `ComponentPath` | #### Defined in[​](#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[​](#apifrommodules "Direct link to ApiFromModules") Ƭ **ApiFromModules**<`AllModules`>: [`FilterApi`](/api/modules/server.md#filterapi)<`ApiFromModulesAllowEmptyNodes`<`AllModules`>, [`FunctionReference`](/api/modules/server.md#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](/api/modules/server.md#functionreference)s. #### Type parameters[​](#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[​](#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[​](#filterapi "Direct link to FilterApi") Ƭ **FilterApi**<`API`, `Predicate`>: [`Expand`](/api/modules/server.md#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[​](#type-parameters-2 "Direct link to Type parameters") | Name | | ----------- | | `API` | | `Predicate` | #### Defined in[​](#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[​](#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[​](#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[​](#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[​](#type-parameters-3 "Direct link to Type parameters") | Name | | ----- | | `API` | #### Defined in[​](#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[​](#functionargs "Direct link to FunctionArgs") Ƭ **FunctionArgs**<`FuncRef`>: `FuncRef`\[`"_args"`] Given a [FunctionReference](/api/modules/server.md#functionreference), get the return type of the function. This is represented as an object mapping argument names to values. #### Type parameters[​](#type-parameters-4 "Direct link to Type parameters") | Name | Type | | --------- | ------------------------------ | | `FuncRef` | extends `AnyFunctionReference` | #### Defined in[​](#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[​](#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[​](#type-parameters-5 "Direct link to Type parameters") | Name | Type | | --------- | ------------------------------ | | `FuncRef` | extends `AnyFunctionReference` | #### Defined in[​](#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[​](#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[​](#type-parameters-6 "Direct link to Type parameters") | Name | Type | | --------- | ------------------------------ | | `FuncRef` | extends `AnyFunctionReference` | | `Options` | `Options` | #### Defined in[​](#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[​](#functionreturntype "Direct link to FunctionReturnType") Ƭ **FunctionReturnType**<`FuncRef`>: `FuncRef`\[`"_returnType"`] Given a [FunctionReference](/api/modules/server.md#functionreference), get the return type of the function. #### Type parameters[​](#type-parameters-7 "Direct link to Type parameters") | Name | Type | | --------- | ------------------------------ | | `FuncRef` | extends `AnyFunctionReference` | #### Defined in[​](#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) *** ### AuthConfig[​](#authconfig "Direct link to AuthConfig") Ƭ **AuthConfig**: `Object` The value exported by your Convex project in `auth.config.ts`. ``` import { AuthConfig } from "convex/server"; export default { providers: [ { domain: "https://your.issuer.url.com", applicationID: "your-application-id", }, ], } satisfies AuthConfig; ``` #### Type declaration[​](#type-declaration-1 "Direct link to Type declaration") | Name | Type | | ----------- | -------------------------------------------------------- | | `providers` | [`AuthProvider`](/api/modules/server.md#authprovider)\[] | #### Defined in[​](#defined-in-10 "Direct link to Defined in") [server/authentication.ts:19](https://github.com/get-convex/convex-js/blob/main/src/server/authentication.ts#L19) *** ### AuthProvider[​](#authprovider "Direct link to AuthProvider") Ƭ **AuthProvider**: { `applicationID`: `string` ; `domain`: `string` } | { `type`: `"customJwt"` ; `applicationID?`: `string` ; `issuer`: `string` ; `jwks`: `string` ; `algorithm`: `"RS256"` | `"ES256"` } An authentication provider allowed to issue JWTs for your app. See: and #### Defined in[​](#defined-in-11 "Direct link to Defined in") [server/authentication.ts:28](https://github.com/get-convex/convex-js/blob/main/src/server/authentication.ts#L28) *** ### FunctionHandle[​](#functionhandle "Direct link to FunctionHandle") Ƭ **FunctionHandle**<`Type`, `Args`, `ReturnType`>: `string` & [`FunctionReference`](/api/modules/server.md#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[​](#type-parameters-8 "Direct link to Type parameters") | Name | Type | | ------------ | ----------------------------------------------------------------------------------- | | `Type` | extends [`FunctionType`](/api/modules/server.md#functiontype) | | `Args` | extends [`DefaultFunctionArgs`](/api/modules/server.md#defaultfunctionargs) = `any` | | `ReturnType` | `any` | #### Defined in[​](#defined-in-12 "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[​](#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[​](#type-parameters-9 "Direct link to Type parameters") | Name | Type | | --------- | ---------------------------------- | | `Exports` | extends `ComponentExports` = `any` | #### Type declaration[​](#type-declaration-2 "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](/api/modules/server.md#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[​](#defined-in-13 "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) *** ### AnyChildComponents[​](#anychildcomponents "Direct link to AnyChildComponents") Ƭ **AnyChildComponents**: `Record`<`string`, `AnyComponentReference`> #### Defined in[​](#defined-in-14 "Direct link to Defined in") [server/components/index.ts:402](https://github.com/get-convex/convex-js/blob/main/src/server/components/index.ts#L402) *** ### AnyComponents[​](#anycomponents "Direct link to AnyComponents") Ƭ **AnyComponents**: [`AnyChildComponents`](/api/modules/server.md#anychildcomponents) #### Defined in[​](#defined-in-15 "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[​](#genericdocument "Direct link to GenericDocument") Ƭ **GenericDocument**: `Record`<`string`, [`Value`](/api/modules/values.md#value)> A document stored in Convex. #### Defined in[​](#defined-in-16 "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[​](#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[​](#defined-in-17 "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[​](#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[​](#defined-in-18 "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[​](#generictableindexes "Direct link to GenericTableIndexes") Ƭ **GenericTableIndexes**: `Record`<`string`, [`GenericIndexFields`](/api/modules/server.md#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[​](#defined-in-19 "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[​](#genericsearchindexconfig "Direct link to GenericSearchIndexConfig") Ƭ **GenericSearchIndexConfig**: `Object` A type describing the configuration of a search index. #### Type declaration[​](#type-declaration-3 "Direct link to Type declaration") | Name | Type | | -------------- | -------- | | `searchField` | `string` | | `filterFields` | `string` | #### Defined in[​](#defined-in-20 "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[​](#generictablesearchindexes "Direct link to GenericTableSearchIndexes") Ƭ **GenericTableSearchIndexes**: `Record`<`string`, [`GenericSearchIndexConfig`](/api/modules/server.md#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[​](#defined-in-21 "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[​](#genericvectorindexconfig "Direct link to GenericVectorIndexConfig") Ƭ **GenericVectorIndexConfig**: `Object` A type describing the configuration of a vector index. #### Type declaration[​](#type-declaration-4 "Direct link to Type declaration") | Name | Type | | -------------- | -------- | | `vectorField` | `string` | | `dimensions` | `number` | | `filterFields` | `string` | #### Defined in[​](#defined-in-22 "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[​](#generictablevectorindexes "Direct link to GenericTableVectorIndexes") Ƭ **GenericTableVectorIndexes**: `Record`<`string`, [`GenericVectorIndexConfig`](/api/modules/server.md#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[​](#defined-in-23 "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[​](#fieldtypefromfieldpath "Direct link to FieldTypeFromFieldPath") Ƭ **FieldTypeFromFieldPath**<`Document`, `FieldPath`>: [`FieldTypeFromFieldPathInner`](/api/modules/server.md#fieldtypefromfieldpathinner)<`Document`, `FieldPath`> extends [`Value`](/api/modules/values.md#value) | `undefined` ? [`FieldTypeFromFieldPathInner`](/api/modules/server.md#fieldtypefromfieldpathinner)<`Document`, `FieldPath`> : [`Value`](/api/modules/values.md#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[​](#type-parameters-10 "Direct link to Type parameters") | Name | Type | | ----------- | ------------------------------------------------------------------- | | `Document` | extends [`GenericDocument`](/api/modules/server.md#genericdocument) | | `FieldPath` | extends `string` | #### Defined in[​](#defined-in-24 "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[​](#fieldtypefromfieldpathinner "Direct link to FieldTypeFromFieldPathInner") Ƭ **FieldTypeFromFieldPathInner**<`Document`, `FieldPath`>: `FieldPath` extends \`${infer First}.${infer Second}\` ? `ValueFromUnion`<`Document`, `First`, `Record`<`never`, `never`>> extends infer FieldValue ? `FieldValue` extends [`GenericDocument`](/api/modules/server.md#genericdocument) ? [`FieldTypeFromFieldPath`](/api/modules/server.md#fieldtypefromfieldpath)<`FieldValue`, `Second`> : `undefined` : `undefined` : `ValueFromUnion`<`Document`, `FieldPath`, `undefined`> The inner type of [FieldTypeFromFieldPath](/api/modules/server.md#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[​](#type-parameters-11 "Direct link to Type parameters") | Name | Type | | ----------- | ------------------------------------------------------------------- | | `Document` | extends [`GenericDocument`](/api/modules/server.md#genericdocument) | | `FieldPath` | extends `string` | #### Defined in[​](#defined-in-25 "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[​](#generictableinfo "Direct link to GenericTableInfo") Ƭ **GenericTableInfo**: `Object` A type describing the document type and indexes in a table. #### Type declaration[​](#type-declaration-5 "Direct link to Type declaration") | Name | Type | | --------------- | ------------------------------------------------------------------------------- | | `document` | [`GenericDocument`](/api/modules/server.md#genericdocument) | | `fieldPaths` | [`GenericFieldPaths`](/api/modules/server.md#genericfieldpaths) | | `indexes` | [`GenericTableIndexes`](/api/modules/server.md#generictableindexes) | | `searchIndexes` | [`GenericTableSearchIndexes`](/api/modules/server.md#generictablesearchindexes) | | `vectorIndexes` | [`GenericTableVectorIndexes`](/api/modules/server.md#generictablevectorindexes) | #### Defined in[​](#defined-in-26 "Direct link to Defined in") [server/data\_model.ts:145](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L145) *** ### DocumentByInfo[​](#documentbyinfo "Direct link to DocumentByInfo") Ƭ **DocumentByInfo**<`TableInfo`>: `TableInfo`\[`"document"`] The type of a document in a table for a given [GenericTableInfo](/api/modules/server.md#generictableinfo). #### Type parameters[​](#type-parameters-12 "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `TableInfo` | extends [`GenericTableInfo`](/api/modules/server.md#generictableinfo) | #### Defined in[​](#defined-in-27 "Direct link to Defined in") [server/data\_model.ts:157](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L157) *** ### FieldPaths[​](#fieldpaths "Direct link to FieldPaths") Ƭ **FieldPaths**<`TableInfo`>: `TableInfo`\[`"fieldPaths"`] The field paths in a table for a given [GenericTableInfo](/api/modules/server.md#generictableinfo). These can either be field names (like "name") or references to fields on nested objects (like "properties.name"). #### Type parameters[​](#type-parameters-13 "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `TableInfo` | extends [`GenericTableInfo`](/api/modules/server.md#generictableinfo) | #### Defined in[​](#defined-in-28 "Direct link to Defined in") [server/data\_model.ts:167](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L167) *** ### Indexes[​](#indexes "Direct link to Indexes") Ƭ **Indexes**<`TableInfo`>: `TableInfo`\[`"indexes"`] The database indexes in a table for a given [GenericTableInfo](/api/modules/server.md#generictableinfo). This will be an object mapping index names to the fields in the index. #### Type parameters[​](#type-parameters-14 "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `TableInfo` | extends [`GenericTableInfo`](/api/modules/server.md#generictableinfo) | #### Defined in[​](#defined-in-29 "Direct link to Defined in") [server/data\_model.ts:176](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L176) *** ### IndexNames[​](#indexnames "Direct link to IndexNames") Ƭ **IndexNames**<`TableInfo`>: keyof [`Indexes`](/api/modules/server.md#indexes)<`TableInfo`> The names of indexes in a table for a given [GenericTableInfo](/api/modules/server.md#generictableinfo). #### Type parameters[​](#type-parameters-15 "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `TableInfo` | extends [`GenericTableInfo`](/api/modules/server.md#generictableinfo) | #### Defined in[​](#defined-in-30 "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) *** ### NamedIndex[​](#namedindex "Direct link to NamedIndex") Ƭ **NamedIndex**<`TableInfo`, `IndexName`>: [`Indexes`](/api/modules/server.md#indexes)<`TableInfo`>\[`IndexName`] Extract the fields of an index from a [GenericTableInfo](/api/modules/server.md#generictableinfo) by name. #### Type parameters[​](#type-parameters-16 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------------------------------------------------------------- | | `TableInfo` | extends [`GenericTableInfo`](/api/modules/server.md#generictableinfo) | | `IndexName` | extends [`IndexNames`](/api/modules/server.md#indexnames)<`TableInfo`> | #### Defined in[​](#defined-in-31 "Direct link to Defined in") [server/data\_model.ts:189](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L189) *** ### SearchIndexes[​](#searchindexes "Direct link to SearchIndexes") Ƭ **SearchIndexes**<`TableInfo`>: `TableInfo`\[`"searchIndexes"`] The search indexes in a table for a given [GenericTableInfo](/api/modules/server.md#generictableinfo). This will be an object mapping index names to the search index config. #### Type parameters[​](#type-parameters-17 "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `TableInfo` | extends [`GenericTableInfo`](/api/modules/server.md#generictableinfo) | #### Defined in[​](#defined-in-32 "Direct link to Defined in") [server/data\_model.ts:200](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L200) *** ### SearchIndexNames[​](#searchindexnames "Direct link to SearchIndexNames") Ƭ **SearchIndexNames**<`TableInfo`>: keyof [`SearchIndexes`](/api/modules/server.md#searchindexes)<`TableInfo`> The names of search indexes in a table for a given [GenericTableInfo](/api/modules/server.md#generictableinfo). #### Type parameters[​](#type-parameters-18 "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `TableInfo` | extends [`GenericTableInfo`](/api/modules/server.md#generictableinfo) | #### Defined in[​](#defined-in-33 "Direct link to Defined in") [server/data\_model.ts:207](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L207) *** ### NamedSearchIndex[​](#namedsearchindex "Direct link to NamedSearchIndex") Ƭ **NamedSearchIndex**<`TableInfo`, `IndexName`>: [`SearchIndexes`](/api/modules/server.md#searchindexes)<`TableInfo`>\[`IndexName`] Extract the config of a search index from a [GenericTableInfo](/api/modules/server.md#generictableinfo) by name. #### Type parameters[​](#type-parameters-19 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------------------------------------------------------------------------- | | `TableInfo` | extends [`GenericTableInfo`](/api/modules/server.md#generictableinfo) | | `IndexName` | extends [`SearchIndexNames`](/api/modules/server.md#searchindexnames)<`TableInfo`> | #### Defined in[​](#defined-in-34 "Direct link to Defined in") [server/data\_model.ts:214](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L214) *** ### VectorIndexes[​](#vectorindexes "Direct link to VectorIndexes") Ƭ **VectorIndexes**<`TableInfo`>: `TableInfo`\[`"vectorIndexes"`] The vector indexes in a table for a given [GenericTableInfo](/api/modules/server.md#generictableinfo). This will be an object mapping index names to the vector index config. #### Type parameters[​](#type-parameters-20 "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `TableInfo` | extends [`GenericTableInfo`](/api/modules/server.md#generictableinfo) | #### Defined in[​](#defined-in-35 "Direct link to Defined in") [server/data\_model.ts:225](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L225) *** ### VectorIndexNames[​](#vectorindexnames "Direct link to VectorIndexNames") Ƭ **VectorIndexNames**<`TableInfo`>: keyof [`VectorIndexes`](/api/modules/server.md#vectorindexes)<`TableInfo`> The names of vector indexes in a table for a given [GenericTableInfo](/api/modules/server.md#generictableinfo). #### Type parameters[​](#type-parameters-21 "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `TableInfo` | extends [`GenericTableInfo`](/api/modules/server.md#generictableinfo) | #### Defined in[​](#defined-in-36 "Direct link to Defined in") [server/data\_model.ts:232](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L232) *** ### NamedVectorIndex[​](#namedvectorindex "Direct link to NamedVectorIndex") Ƭ **NamedVectorIndex**<`TableInfo`, `IndexName`>: [`VectorIndexes`](/api/modules/server.md#vectorindexes)<`TableInfo`>\[`IndexName`] Extract the config of a vector index from a [GenericTableInfo](/api/modules/server.md#generictableinfo) by name. #### Type parameters[​](#type-parameters-22 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------------------------------------------------------------------------- | | `TableInfo` | extends [`GenericTableInfo`](/api/modules/server.md#generictableinfo) | | `IndexName` | extends [`VectorIndexNames`](/api/modules/server.md#vectorindexnames)<`TableInfo`> | #### Defined in[​](#defined-in-37 "Direct link to Defined in") [server/data\_model.ts:239](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L239) *** ### GenericDataModel[​](#genericdatamodel "Direct link to GenericDataModel") Ƭ **GenericDataModel**: `Record`<`string`, [`GenericTableInfo`](/api/modules/server.md#generictableinfo)> A type describing the tables in a Convex project. This is designed to be code generated with `npx convex dev`. #### Defined in[​](#defined-in-38 "Direct link to Defined in") [server/data\_model.ts:252](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L252) *** ### AnyDataModel[​](#anydatamodel "Direct link to AnyDataModel") Ƭ **AnyDataModel**: `Object` A [GenericDataModel](/api/modules/server.md#genericdatamodel) that considers documents to be `any` and does not support indexes. This is the default before a schema is defined. #### Index signature[​](#index-signature "Direct link to Index signature") ▪ \[tableName: `string`]: { `document`: `any` ; `fieldPaths`: [`GenericFieldPaths`](/api/modules/server.md#genericfieldpaths) ; `indexes`: ; `searchIndexes`: ; `vectorIndexes`: } #### Defined in[​](#defined-in-39 "Direct link to Defined in") [server/data\_model.ts:261](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L261) *** ### TableNamesInDataModel[​](#tablenamesindatamodel "Direct link to TableNamesInDataModel") Ƭ **TableNamesInDataModel**<`DataModel`>: keyof `DataModel` & `string` A type of all of the table names defined in a [GenericDataModel](/api/modules/server.md#genericdatamodel). #### Type parameters[​](#type-parameters-23 "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `DataModel` | extends [`GenericDataModel`](/api/modules/server.md#genericdatamodel) | #### Defined in[​](#defined-in-40 "Direct link to Defined in") [server/data\_model.ts:275](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L275) *** ### NamedTableInfo[​](#namedtableinfo "Direct link to NamedTableInfo") Ƭ **NamedTableInfo**<`DataModel`, `TableName`>: `DataModel`\[`TableName`] Extract the `TableInfo` for a table in a [GenericDataModel](/api/modules/server.md#genericdatamodel) by table name. #### Type parameters[​](#type-parameters-24 "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `DataModel` | extends [`GenericDataModel`](/api/modules/server.md#genericdatamodel) | | `TableName` | extends keyof `DataModel` | #### Defined in[​](#defined-in-41 "Direct link to Defined in") [server/data\_model.ts:284](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L284) *** ### DocumentByName[​](#documentbyname "Direct link to DocumentByName") Ƭ **DocumentByName**<`DataModel`, `TableName`>: `DataModel`\[`TableName`]\[`"document"`] The type of a document in a [GenericDataModel](/api/modules/server.md#genericdatamodel) by table name. #### Type parameters[​](#type-parameters-25 "Direct link to Type parameters") | Name | Type | | ----------- | -------------------------------------------------------------------------------------------- | | `DataModel` | extends [`GenericDataModel`](/api/modules/server.md#genericdatamodel) | | `TableName` | extends [`TableNamesInDataModel`](/api/modules/server.md#tablenamesindatamodel)<`DataModel`> | #### Defined in[​](#defined-in-42 "Direct link to Defined in") [server/data\_model.ts:293](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L293) *** ### ExpressionOrValue[​](#expressionorvalue "Direct link to ExpressionOrValue") Ƭ **ExpressionOrValue**<`T`>: [`Expression`](/api/classes/server.Expression.md)<`T`> | `T` An [Expression](/api/classes/server.Expression.md) or a constant [Value](/api/modules/values.md#value) #### Type parameters[​](#type-parameters-26 "Direct link to Type parameters") | Name | Type | | ---- | -------------------------------------------------------------- | | `T` | extends [`Value`](/api/modules/values.md#value) \| `undefined` | #### Defined in[​](#defined-in-43 "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[​](#cursor "Direct link to Cursor") Ƭ **Cursor**: `string` An opaque identifier used for paginating a database query. Cursors are returned from [paginate](/api/interfaces/server.OrderedQuery.md#paginate) and represent the point of the query where the page of results ended. To continue paginating, pass the cursor back into [paginate](/api/interfaces/server.OrderedQuery.md#paginate) in the [PaginationOptions](/api/interfaces/server.PaginationOptions.md) 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[​](#defined-in-44 "Direct link to Defined in") [server/pagination.ts:21](https://github.com/get-convex/convex-js/blob/main/src/server/pagination.ts#L21) *** ### GenericMutationCtxWithTable[​](#genericmutationctxwithtable "Direct link to GenericMutationCtxWithTable") Ƭ **GenericMutationCtxWithTable**<`DataModel`>: `Omit`<[`GenericMutationCtx`](/api/interfaces/server.GenericMutationCtx.md)<`DataModel`>, `"db"`> & { `db`: [`GenericDatabaseWriterWithTable`](/api/interfaces/server.GenericDatabaseWriterWithTable.md)<`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[​](#type-parameters-27 "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `DataModel` | extends [`GenericDataModel`](/api/modules/server.md#genericdatamodel) | #### Defined in[​](#defined-in-45 "Direct link to Defined in") [server/registration.ts:109](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L109) *** ### GenericQueryCtxWithTable[​](#genericqueryctxwithtable "Direct link to GenericQueryCtxWithTable") Ƭ **GenericQueryCtxWithTable**<`DataModel`>: `Omit`<[`GenericQueryCtx`](/api/interfaces/server.GenericQueryCtx.md)<`DataModel`>, `"db"`> & { `db`: [`GenericDatabaseReaderWithTable`](/api/interfaces/server.GenericDatabaseReaderWithTable.md)<`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[​](#type-parameters-28 "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `DataModel` | extends [`GenericDataModel`](/api/modules/server.md#genericdatamodel) | #### Defined in[​](#defined-in-46 "Direct link to Defined in") [server/registration.ts:167](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L167) *** ### DefaultFunctionArgs[​](#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[​](#defined-in-47 "Direct link to Defined in") [server/registration.ts:278](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L278) *** ### ArgsArray[​](#argsarray "Direct link to ArgsArray") Ƭ **ArgsArray**: `OneArgArray` | `NoArgsArray` An array of arguments to a Convex function. Convex functions can take either a single [DefaultFunctionArgs](/api/modules/server.md#defaultfunctionargs) object or no args at all. #### Defined in[​](#defined-in-48 "Direct link to Defined in") [server/registration.ts:301](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L301) *** ### ArgsArrayToObject[​](#argsarraytoobject "Direct link to ArgsArrayToObject") Ƭ **ArgsArrayToObject**<`Args`>: `Args` extends `OneArgArray`\ ? `ArgsObject` : `EmptyObject` Convert an [ArgsArray](/api/modules/server.md#argsarray) into a single object type. Empty arguments arrays are converted to EmptyObject. #### Type parameters[​](#type-parameters-29 "Direct link to Type parameters") | Name | Type | | ------ | ------------------------------------------------------- | | `Args` | extends [`ArgsArray`](/api/modules/server.md#argsarray) | #### Defined in[​](#defined-in-49 "Direct link to Defined in") [server/registration.ts:316](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L316) *** ### FunctionVisibility[​](#functionvisibility "Direct link to FunctionVisibility") Ƭ **FunctionVisibility**: `"public"` | `"internal"` A type representing the visibility of a Convex function. #### Defined in[​](#defined-in-50 "Direct link to Defined in") [server/registration.ts:324](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L324) *** ### RegisteredMutation[​](#registeredmutation "Direct link to RegisteredMutation") Ƭ **RegisteredMutation**<`Visibility`, `Args`, `Returns`>: { `isConvexFunction`: `true` ; `isMutation`: `true` } & `VisibilityProperties`<`Visibility`> A mutation function that is part of this app. You can create a mutation by wrapping your function in [mutationGeneric](/api/modules/server.md#mutationgeneric) or [internalMutationGeneric](/api/modules/server.md#internalmutationgeneric) and exporting it. #### Type parameters[​](#type-parameters-30 "Direct link to Type parameters") | Name | Type | | ------------ | --------------------------------------------------------------------------- | | `Visibility` | extends [`FunctionVisibility`](/api/modules/server.md#functionvisibility) | | `Args` | extends [`DefaultFunctionArgs`](/api/modules/server.md#defaultfunctionargs) | | `Returns` | `Returns` | #### Defined in[​](#defined-in-51 "Direct link to Defined in") [server/registration.ts:347](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L347) *** ### RegisteredQuery[​](#registeredquery "Direct link to RegisteredQuery") Ƭ **RegisteredQuery**<`Visibility`, `Args`, `Returns`>: { `isConvexFunction`: `true` ; `isQuery`: `true` } & `VisibilityProperties`<`Visibility`> A query function that is part of this app. You can create a query by wrapping your function in [queryGeneric](/api/modules/server.md#querygeneric) or [internalQueryGeneric](/api/modules/server.md#internalquerygeneric) and exporting it. #### Type parameters[​](#type-parameters-31 "Direct link to Type parameters") | Name | Type | | ------------ | --------------------------------------------------------------------------- | | `Visibility` | extends [`FunctionVisibility`](/api/modules/server.md#functionvisibility) | | `Args` | extends [`DefaultFunctionArgs`](/api/modules/server.md#defaultfunctionargs) | | `Returns` | `Returns` | #### Defined in[​](#defined-in-52 "Direct link to Defined in") [server/registration.ts:376](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L376) *** ### RegisteredAction[​](#registeredaction "Direct link to RegisteredAction") Ƭ **RegisteredAction**<`Visibility`, `Args`, `Returns`>: { `isConvexFunction`: `true` ; `isAction`: `true` } & `VisibilityProperties`<`Visibility`> An action that is part of this app. You can create an action by wrapping your function in [actionGeneric](/api/modules/server.md#actiongeneric) or [internalActionGeneric](/api/modules/server.md#internalactiongeneric) and exporting it. #### Type parameters[​](#type-parameters-32 "Direct link to Type parameters") | Name | Type | | ------------ | --------------------------------------------------------------------------- | | `Visibility` | extends [`FunctionVisibility`](/api/modules/server.md#functionvisibility) | | `Args` | extends [`DefaultFunctionArgs`](/api/modules/server.md#defaultfunctionargs) | | `Returns` | `Returns` | #### Defined in[​](#defined-in-53 "Direct link to Defined in") [server/registration.ts:405](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L405) *** ### PublicHttpAction[​](#publichttpaction "Direct link to PublicHttpAction") Ƭ **PublicHttpAction**: `Object` An HTTP action that is part of this app's public API. You can create public HTTP actions by wrapping your function in [httpActionGeneric](/api/modules/server.md#httpactiongeneric) and exporting it. #### Type declaration[​](#type-declaration-6 "Direct link to Type declaration") | Name | Type | | -------- | ------ | | `isHttp` | `true` | #### Defined in[​](#defined-in-54 "Direct link to Defined in") [server/registration.ts:434](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L434) *** ### UnvalidatedFunction[​](#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: ``` import { query } from "./_generated/server"; export const func = query(({ db }, { arg }) => {...}); ``` or as an object like: ``` import { query } from "./_generated/server"; export const func = query({ handler: ({ db }, { arg }) => {...}, }); ``` See [ValidatedFunction](/api/interfaces/server.ValidatedFunction.md) to add argument validation. #### Type parameters[​](#type-parameters-33 "Direct link to Type parameters") | Name | Type | | --------- | ------------------------------------------------------- | | `Ctx` | `Ctx` | | `Args` | extends [`ArgsArray`](/api/modules/server.md#argsarray) | | `Returns` | `Returns` | #### Defined in[​](#defined-in-55 "Direct link to Defined in") [server/registration.ts:472](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L472) *** ### ReturnValueForOptionalValidator[​](#returnvalueforoptionalvalidator "Direct link to ReturnValueForOptionalValidator") Ƭ **ReturnValueForOptionalValidator**<`ReturnsValidator`>: \[`ReturnsValidator`] extends \[[`Validator`](/api/modules/values.md#validator)<`any`, `any`, `any`>] ? `ValidatorTypeToReturnType`<[`Infer`](/api/modules/values.md#infer)<`ReturnsValidator`>> : \[`ReturnsValidator`] extends \[[`PropertyValidators`](/api/modules/values.md#propertyvalidators)] ? `ValidatorTypeToReturnType`<[`ObjectType`](/api/modules/values.md#objecttype)<`ReturnsValidator`>> : `any` There are multiple syntaxes for defining a Convex function: ``` - 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 #### Type parameters[​](#type-parameters-34 "Direct link to Type parameters") | Name | Type | | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | `ReturnsValidator` | extends [`Validator`](/api/modules/values.md#validator)<`any`, `any`, `any`> \| [`PropertyValidators`](/api/modules/values.md#propertyvalidators) \| `void` | #### Defined in[​](#defined-in-56 "Direct link to Defined in") [server/registration.ts:574](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L574) *** ### ArgsArrayForOptionalValidator[​](#argsarrayforoptionalvalidator "Direct link to ArgsArrayForOptionalValidator") Ƭ **ArgsArrayForOptionalValidator**<`ArgsValidator`>: \[`ArgsValidator`] extends \[[`Validator`](/api/modules/values.md#validator)<`any`, `any`, `any`>] ? `OneArgArray`<[`Infer`](/api/modules/values.md#infer)<`ArgsValidator`>> : \[`ArgsValidator`] extends \[[`PropertyValidators`](/api/modules/values.md#propertyvalidators)] ? `OneArgArray`<[`ObjectType`](/api/modules/values.md#objecttype)<`ArgsValidator`>> : [`ArgsArray`](/api/modules/server.md#argsarray) #### Type parameters[​](#type-parameters-35 "Direct link to Type parameters") | Name | Type | | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | `ArgsValidator` | extends [`GenericValidator`](/api/modules/values.md#genericvalidator) \| [`PropertyValidators`](/api/modules/values.md#propertyvalidators) \| `void` | #### Defined in[​](#defined-in-57 "Direct link to Defined in") [server/registration.ts:582](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L582) *** ### DefaultArgsForOptionalValidator[​](#defaultargsforoptionalvalidator "Direct link to DefaultArgsForOptionalValidator") Ƭ **DefaultArgsForOptionalValidator**<`ArgsValidator`>: \[`ArgsValidator`] extends \[[`Validator`](/api/modules/values.md#validator)<`any`, `any`, `any`>] ? \[[`Infer`](/api/modules/values.md#infer)<`ArgsValidator`>] : \[`ArgsValidator`] extends \[[`PropertyValidators`](/api/modules/values.md#propertyvalidators)] ? \[[`ObjectType`](/api/modules/values.md#objecttype)<`ArgsValidator`>] : `OneArgArray` #### Type parameters[​](#type-parameters-36 "Direct link to Type parameters") | Name | Type | | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | `ArgsValidator` | extends [`GenericValidator`](/api/modules/values.md#genericvalidator) \| [`PropertyValidators`](/api/modules/values.md#propertyvalidators) \| `void` | #### Defined in[​](#defined-in-58 "Direct link to Defined in") [server/registration.ts:590](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L590) *** ### MutationBuilder[​](#mutationbuilder "Direct link to MutationBuilder") Ƭ **MutationBuilder**<`DataModel`, `Visibility`>: \(`mutation`: { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: (`ctx`: [`GenericMutationCtx`](/api/interfaces/server.GenericMutationCtx.md)<`DataModel`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue` } | (`ctx`: [`GenericMutationCtx`](/api/interfaces/server.GenericMutationCtx.md)<`DataModel`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue`) => [`RegisteredMutation`](/api/modules/server.md#registeredmutation)<`Visibility`, [`ArgsArrayToObject`](/api/modules/server.md#argsarraytoobject)<`OneOrZeroArgs`>, `ReturnValue`> #### Type parameters[​](#type-parameters-37 "Direct link to Type parameters") | Name | Type | | ------------ | ------------------------------------------------------------------------- | | `DataModel` | extends [`GenericDataModel`](/api/modules/server.md#genericdatamodel) | | `Visibility` | extends [`FunctionVisibility`](/api/modules/server.md#functionvisibility) | #### Type declaration[​](#type-declaration-7 "Direct link to Type declaration") ▸ <`ArgsValidator`, `ReturnsValidator`, `ReturnValue`, `OneOrZeroArgs`>(`mutation`): [`RegisteredMutation`](/api/modules/server.md#registeredmutation)<`Visibility`, [`ArgsArrayToObject`](/api/modules/server.md#argsarraytoobject)<`OneOrZeroArgs`>, `ReturnValue`> Internal type helper used by Convex code generation. Used to give [mutationGeneric](/api/modules/server.md#mutationgeneric) a type specific to your data model. ##### Type parameters[​](#type-parameters-38 "Direct link to Type parameters") | Name | Type | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `ArgsValidator` | extends `void` \| [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`> \| [`PropertyValidators`](/api/modules/values.md#propertyvalidators) | | `ReturnsValidator` | extends `void` \| [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`> \| [`PropertyValidators`](/api/modules/values.md#propertyvalidators) | | `ReturnValue` | extends `any` = `any` | | `OneOrZeroArgs` | extends [`ArgsArray`](/api/modules/server.md#argsarray) \| `OneArgArray`<[`Infer`](/api/modules/values.md#infer)<`ArgsValidator`>> \| `OneArgArray`<[`Expand`](/api/modules/server.md#expand)<{ \[Property in string \| number \| symbol]?: Exclude\, undefined> } & { \[Property in string \| number \| symbol]: Infer\ }>> = [`DefaultArgsForOptionalValidator`](/api/modules/server.md#defaultargsforoptionalvalidator)<`ArgsValidator`> | ##### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `mutation` | { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: (`ctx`: [`GenericMutationCtx`](/api/interfaces/server.GenericMutationCtx.md)<`DataModel`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue` } \| (`ctx`: [`GenericMutationCtx`](/api/interfaces/server.GenericMutationCtx.md)<`DataModel`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue` | ##### Returns[​](#returns "Direct link to Returns") [`RegisteredMutation`](/api/modules/server.md#registeredmutation)<`Visibility`, [`ArgsArrayToObject`](/api/modules/server.md#argsarraytoobject)<`OneOrZeroArgs`>, `ReturnValue`> #### Defined in[​](#defined-in-59 "Direct link to Defined in") [server/registration.ts:604](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L604) *** ### MutationBuilderWithTable[​](#mutationbuilderwithtable "Direct link to MutationBuilderWithTable") Ƭ **MutationBuilderWithTable**<`DataModel`, `Visibility`>: \(`mutation`: { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: (`ctx`: [`GenericMutationCtxWithTable`](/api/modules/server.md#genericmutationctxwithtable)<`DataModel`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue` } | (`ctx`: [`GenericMutationCtxWithTable`](/api/modules/server.md#genericmutationctxwithtable)<`DataModel`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue`) => [`RegisteredMutation`](/api/modules/server.md#registeredmutation)<`Visibility`, [`ArgsArrayToObject`](/api/modules/server.md#argsarraytoobject)<`OneOrZeroArgs`>, `ReturnValue`> #### Type parameters[​](#type-parameters-39 "Direct link to Type parameters") | Name | Type | | ------------ | ------------------------------------------------------------------------- | | `DataModel` | extends [`GenericDataModel`](/api/modules/server.md#genericdatamodel) | | `Visibility` | extends [`FunctionVisibility`](/api/modules/server.md#functionvisibility) | #### Type declaration[​](#type-declaration-8 "Direct link to Type declaration") ▸ <`ArgsValidator`, `ReturnsValidator`, `ReturnValue`, `OneOrZeroArgs`>(`mutation`): [`RegisteredMutation`](/api/modules/server.md#registeredmutation)<`Visibility`, [`ArgsArrayToObject`](/api/modules/server.md#argsarraytoobject)<`OneOrZeroArgs`>, `ReturnValue`> Internal type helper used by Convex code generation. Used to give [mutationGeneric](/api/modules/server.md#mutationgeneric) a type specific to your data model. ##### Type parameters[​](#type-parameters-40 "Direct link to Type parameters") | Name | Type | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `ArgsValidator` | extends `void` \| [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`> \| [`PropertyValidators`](/api/modules/values.md#propertyvalidators) | | `ReturnsValidator` | extends `void` \| [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`> \| [`PropertyValidators`](/api/modules/values.md#propertyvalidators) | | `ReturnValue` | extends `any` = `any` | | `OneOrZeroArgs` | extends [`ArgsArray`](/api/modules/server.md#argsarray) \| `OneArgArray`<[`Infer`](/api/modules/values.md#infer)<`ArgsValidator`>> \| `OneArgArray`<[`Expand`](/api/modules/server.md#expand)<{ \[Property in string \| number \| symbol]?: Exclude\, undefined> } & { \[Property in string \| number \| symbol]: Infer\ }>> = [`DefaultArgsForOptionalValidator`](/api/modules/server.md#defaultargsforoptionalvalidator)<`ArgsValidator`> | ##### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `mutation` | { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: (`ctx`: [`GenericMutationCtxWithTable`](/api/modules/server.md#genericmutationctxwithtable)<`DataModel`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue` } \| (`ctx`: [`GenericMutationCtxWithTable`](/api/modules/server.md#genericmutationctxwithtable)<`DataModel`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue` | ##### Returns[​](#returns-1 "Direct link to Returns") [`RegisteredMutation`](/api/modules/server.md#registeredmutation)<`Visibility`, [`ArgsArrayToObject`](/api/modules/server.md#argsarraytoobject)<`OneOrZeroArgs`>, `ReturnValue`> #### Defined in[​](#defined-in-60 "Direct link to Defined in") [server/registration.ts:697](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L697) *** ### QueryBuilder[​](#querybuilder "Direct link to QueryBuilder") Ƭ **QueryBuilder**<`DataModel`, `Visibility`>: \(`query`: { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: (`ctx`: [`GenericQueryCtx`](/api/interfaces/server.GenericQueryCtx.md)<`DataModel`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue` } | (`ctx`: [`GenericQueryCtx`](/api/interfaces/server.GenericQueryCtx.md)<`DataModel`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue`) => [`RegisteredQuery`](/api/modules/server.md#registeredquery)<`Visibility`, [`ArgsArrayToObject`](/api/modules/server.md#argsarraytoobject)<`OneOrZeroArgs`>, `ReturnValue`> #### Type parameters[​](#type-parameters-41 "Direct link to Type parameters") | Name | Type | | ------------ | ------------------------------------------------------------------------- | | `DataModel` | extends [`GenericDataModel`](/api/modules/server.md#genericdatamodel) | | `Visibility` | extends [`FunctionVisibility`](/api/modules/server.md#functionvisibility) | #### Type declaration[​](#type-declaration-9 "Direct link to Type declaration") ▸ <`ArgsValidator`, `ReturnsValidator`, `ReturnValue`, `OneOrZeroArgs`>(`query`): [`RegisteredQuery`](/api/modules/server.md#registeredquery)<`Visibility`, [`ArgsArrayToObject`](/api/modules/server.md#argsarraytoobject)<`OneOrZeroArgs`>, `ReturnValue`> Internal type helper used by Convex code generation. Used to give [queryGeneric](/api/modules/server.md#querygeneric) a type specific to your data model. ##### Type parameters[​](#type-parameters-42 "Direct link to Type parameters") | Name | Type | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `ArgsValidator` | extends `void` \| [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`> \| [`PropertyValidators`](/api/modules/values.md#propertyvalidators) | | `ReturnsValidator` | extends `void` \| [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`> \| [`PropertyValidators`](/api/modules/values.md#propertyvalidators) | | `ReturnValue` | extends `any` = `any` | | `OneOrZeroArgs` | extends [`ArgsArray`](/api/modules/server.md#argsarray) \| `OneArgArray`<[`Infer`](/api/modules/values.md#infer)<`ArgsValidator`>> \| `OneArgArray`<[`Expand`](/api/modules/server.md#expand)<{ \[Property in string \| number \| symbol]?: Exclude\, undefined> } & { \[Property in string \| number \| symbol]: Infer\ }>> = [`DefaultArgsForOptionalValidator`](/api/modules/server.md#defaultargsforoptionalvalidator)<`ArgsValidator`> | ##### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `query` | { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: (`ctx`: [`GenericQueryCtx`](/api/interfaces/server.GenericQueryCtx.md)<`DataModel`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue` } \| (`ctx`: [`GenericQueryCtx`](/api/interfaces/server.GenericQueryCtx.md)<`DataModel`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue` | ##### Returns[​](#returns-2 "Direct link to Returns") [`RegisteredQuery`](/api/modules/server.md#registeredquery)<`Visibility`, [`ArgsArrayToObject`](/api/modules/server.md#argsarraytoobject)<`OneOrZeroArgs`>, `ReturnValue`> #### Defined in[​](#defined-in-61 "Direct link to Defined in") [server/registration.ts:790](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L790) *** ### QueryBuilderWithTable[​](#querybuilderwithtable "Direct link to QueryBuilderWithTable") Ƭ **QueryBuilderWithTable**<`DataModel`, `Visibility`>: \(`query`: { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: (`ctx`: [`GenericQueryCtxWithTable`](/api/modules/server.md#genericqueryctxwithtable)<`DataModel`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue` } | (`ctx`: [`GenericQueryCtxWithTable`](/api/modules/server.md#genericqueryctxwithtable)<`DataModel`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue`) => [`RegisteredQuery`](/api/modules/server.md#registeredquery)<`Visibility`, [`ArgsArrayToObject`](/api/modules/server.md#argsarraytoobject)<`OneOrZeroArgs`>, `ReturnValue`> #### Type parameters[​](#type-parameters-43 "Direct link to Type parameters") | Name | Type | | ------------ | ------------------------------------------------------------------------- | | `DataModel` | extends [`GenericDataModel`](/api/modules/server.md#genericdatamodel) | | `Visibility` | extends [`FunctionVisibility`](/api/modules/server.md#functionvisibility) | #### Type declaration[​](#type-declaration-10 "Direct link to Type declaration") ▸ <`ArgsValidator`, `ReturnsValidator`, `ReturnValue`, `OneOrZeroArgs`>(`query`): [`RegisteredQuery`](/api/modules/server.md#registeredquery)<`Visibility`, [`ArgsArrayToObject`](/api/modules/server.md#argsarraytoobject)<`OneOrZeroArgs`>, `ReturnValue`> Internal type helper used by Convex code generation. Used to give [queryGeneric](/api/modules/server.md#querygeneric) a type specific to your data model. ##### Type parameters[​](#type-parameters-44 "Direct link to Type parameters") | Name | Type | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `ArgsValidator` | extends `void` \| [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`> \| [`PropertyValidators`](/api/modules/values.md#propertyvalidators) | | `ReturnsValidator` | extends `void` \| [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`> \| [`PropertyValidators`](/api/modules/values.md#propertyvalidators) | | `ReturnValue` | extends `any` = `any` | | `OneOrZeroArgs` | extends [`ArgsArray`](/api/modules/server.md#argsarray) \| `OneArgArray`<[`Infer`](/api/modules/values.md#infer)<`ArgsValidator`>> \| `OneArgArray`<[`Expand`](/api/modules/server.md#expand)<{ \[Property in string \| number \| symbol]?: Exclude\, undefined> } & { \[Property in string \| number \| symbol]: Infer\ }>> = [`DefaultArgsForOptionalValidator`](/api/modules/server.md#defaultargsforoptionalvalidator)<`ArgsValidator`> | ##### Parameters[​](#parameters-3 "Direct link to Parameters") | Name | Type | | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `query` | { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: (`ctx`: [`GenericQueryCtxWithTable`](/api/modules/server.md#genericqueryctxwithtable)<`DataModel`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue` } \| (`ctx`: [`GenericQueryCtxWithTable`](/api/modules/server.md#genericqueryctxwithtable)<`DataModel`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue` | ##### Returns[​](#returns-3 "Direct link to Returns") [`RegisteredQuery`](/api/modules/server.md#registeredquery)<`Visibility`, [`ArgsArrayToObject`](/api/modules/server.md#argsarraytoobject)<`OneOrZeroArgs`>, `ReturnValue`> #### Defined in[​](#defined-in-62 "Direct link to Defined in") [server/registration.ts:879](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L879) *** ### ActionBuilder[​](#actionbuilder "Direct link to ActionBuilder") Ƭ **ActionBuilder**<`DataModel`, `Visibility`>: \(`func`: { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: (`ctx`: [`GenericActionCtx`](/api/interfaces/server.GenericActionCtx.md)<`DataModel`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue` } | (`ctx`: [`GenericActionCtx`](/api/interfaces/server.GenericActionCtx.md)<`DataModel`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue`) => [`RegisteredAction`](/api/modules/server.md#registeredaction)<`Visibility`, [`ArgsArrayToObject`](/api/modules/server.md#argsarraytoobject)<`OneOrZeroArgs`>, `ReturnValue`> #### Type parameters[​](#type-parameters-45 "Direct link to Type parameters") | Name | Type | | ------------ | ------------------------------------------------------------------------- | | `DataModel` | extends [`GenericDataModel`](/api/modules/server.md#genericdatamodel) | | `Visibility` | extends [`FunctionVisibility`](/api/modules/server.md#functionvisibility) | #### Type declaration[​](#type-declaration-11 "Direct link to Type declaration") ▸ <`ArgsValidator`, `ReturnsValidator`, `ReturnValue`, `OneOrZeroArgs`>(`func`): [`RegisteredAction`](/api/modules/server.md#registeredaction)<`Visibility`, [`ArgsArrayToObject`](/api/modules/server.md#argsarraytoobject)<`OneOrZeroArgs`>, `ReturnValue`> Internal type helper used by Convex code generation. Used to give [actionGeneric](/api/modules/server.md#actiongeneric) a type specific to your data model. ##### Type parameters[​](#type-parameters-46 "Direct link to Type parameters") | Name | Type | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `ArgsValidator` | extends `void` \| [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`> \| [`PropertyValidators`](/api/modules/values.md#propertyvalidators) | | `ReturnsValidator` | extends `void` \| [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`> \| [`PropertyValidators`](/api/modules/values.md#propertyvalidators) | | `ReturnValue` | extends `any` = `any` | | `OneOrZeroArgs` | extends [`ArgsArray`](/api/modules/server.md#argsarray) \| `OneArgArray`<[`Infer`](/api/modules/values.md#infer)<`ArgsValidator`>> \| `OneArgArray`<[`Expand`](/api/modules/server.md#expand)<{ \[Property in string \| number \| symbol]?: Exclude\, undefined> } & { \[Property in string \| number \| symbol]: Infer\ }>> = [`DefaultArgsForOptionalValidator`](/api/modules/server.md#defaultargsforoptionalvalidator)<`ArgsValidator`> | ##### Parameters[​](#parameters-4 "Direct link to Parameters") | Name | Type | | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `func` | { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: (`ctx`: [`GenericActionCtx`](/api/interfaces/server.GenericActionCtx.md)<`DataModel`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue` } \| (`ctx`: [`GenericActionCtx`](/api/interfaces/server.GenericActionCtx.md)<`DataModel`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue` | ##### Returns[​](#returns-4 "Direct link to Returns") [`RegisteredAction`](/api/modules/server.md#registeredaction)<`Visibility`, [`ArgsArrayToObject`](/api/modules/server.md#argsarraytoobject)<`OneOrZeroArgs`>, `ReturnValue`> #### Defined in[​](#defined-in-63 "Direct link to Defined in") [server/registration.ts:968](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L968) *** ### HttpActionBuilder[​](#httpactionbuilder "Direct link to HttpActionBuilder") Ƭ **HttpActionBuilder**: (`func`: (`ctx`: [`GenericActionCtx`](/api/interfaces/server.GenericActionCtx.md)<`any`>, `request`: `Request`) => `Promise`<`Response`>) => [`PublicHttpAction`](/api/modules/server.md#publichttpaction) #### Type declaration[​](#type-declaration-12 "Direct link to Type declaration") ▸ (`func`): [`PublicHttpAction`](/api/modules/server.md#publichttpaction) Internal type helper used by Convex code generation. Used to give [httpActionGeneric](/api/modules/server.md#httpactiongeneric) a type specific to your data model and functions. ##### Parameters[​](#parameters-5 "Direct link to Parameters") | Name | Type | | ------ | ------------------------------------------------------------------------------------------------------------------------------- | | `func` | (`ctx`: [`GenericActionCtx`](/api/interfaces/server.GenericActionCtx.md)<`any`>, `request`: `Request`) => `Promise`<`Response`> | ##### Returns[​](#returns-5 "Direct link to Returns") [`PublicHttpAction`](/api/modules/server.md#publichttpaction) #### Defined in[​](#defined-in-64 "Direct link to Defined in") [server/registration.ts:1063](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L1063) *** ### RoutableMethod[​](#routablemethod "Direct link to RoutableMethod") Ƭ **RoutableMethod**: typeof [`ROUTABLE_HTTP_METHODS`](/api/modules/server.md#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[​](#defined-in-65 "Direct link to Defined in") [server/router.ts:31](https://github.com/get-convex/convex-js/blob/main/src/server/router.ts#L31) *** ### RouteSpecWithPath[​](#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](/api/classes/server.HttpRouter.md) to route requests to HTTP actions. #### Type declaration[​](#type-declaration-13 "Direct link to Type declaration") | Name | Type | Description | | --------- | ------------------------------------------------------------- | ------------------------------------------ | | `path` | `string` | Exact HTTP request path to route. | | `method` | [`RoutableMethod`](/api/modules/server.md#routablemethod) | HTTP method ("GET", "POST", ...) to route. | | `handler` | [`PublicHttpAction`](/api/modules/server.md#publichttpaction) | The HTTP action to execute. | #### Defined in[​](#defined-in-66 "Direct link to Defined in") [server/router.ts:56](https://github.com/get-convex/convex-js/blob/main/src/server/router.ts#L56) *** ### RouteSpecWithPathPrefix[​](#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](/api/classes/server.HttpRouter.md) to route requests to HTTP actions. #### Type declaration[​](#type-declaration-14 "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`](/api/modules/server.md#routablemethod) | HTTP method ("GET", "POST", ...) to route. | | `handler` | [`PublicHttpAction`](/api/modules/server.md#publichttpaction) | The HTTP action to execute. | #### Defined in[​](#defined-in-67 "Direct link to Defined in") [server/router.ts:78](https://github.com/get-convex/convex-js/blob/main/src/server/router.ts#L78) *** ### RouteSpec[​](#routespec "Direct link to RouteSpec") Ƭ **RouteSpec**: [`RouteSpecWithPath`](/api/modules/server.md#routespecwithpath) | [`RouteSpecWithPathPrefix`](/api/modules/server.md#routespecwithpathprefix) A type representing a route to an HTTP action. Used by [HttpRouter](/api/classes/server.HttpRouter.md) to route requests to HTTP actions. #### Defined in[​](#defined-in-68 "Direct link to Defined in") [server/router.ts:101](https://github.com/get-convex/convex-js/blob/main/src/server/router.ts#L101) *** ### SchedulableFunctionReference[​](#schedulablefunctionreference "Direct link to SchedulableFunctionReference") Ƭ **SchedulableFunctionReference**: [`FunctionReference`](/api/modules/server.md#functionreference)<`"mutation"` | `"action"`, `"public"` | `"internal"`> A [FunctionReference](/api/modules/server.md#functionreference) that can be scheduled to run in the future. Schedulable functions are mutations and actions that are public or internal. #### Defined in[​](#defined-in-69 "Direct link to Defined in") [server/scheduler.ts:11](https://github.com/get-convex/convex-js/blob/main/src/server/scheduler.ts#L11) *** ### GenericSchema[​](#genericschema "Direct link to GenericSchema") Ƭ **GenericSchema**: `Record`<`string`, [`TableDefinition`](/api/classes/server.TableDefinition.md)> A type describing the schema of a Convex project. This should be constructed using [defineSchema](/api/modules/server.md#defineschema), [defineTable](/api/modules/server.md#definetable), and [v](/api/modules/values.md#v). #### Defined in[​](#defined-in-70 "Direct link to Defined in") [server/schema.ts:645](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L645) *** ### DataModelFromSchemaDefinition[​](#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](/api/classes/server.SchemaDefinition.md) into a [GenericDataModel](/api/modules/server.md#genericdatamodel). #### Type parameters[​](#type-parameters-47 "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------------------------- | | `SchemaDef` | extends [`SchemaDefinition`](/api/classes/server.SchemaDefinition.md)<`any`, `boolean`> | #### Defined in[​](#defined-in-71 "Direct link to Defined in") [server/schema.ts:786](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L786) *** ### SystemTableNames[​](#systemtablenames "Direct link to SystemTableNames") Ƭ **SystemTableNames**: [`TableNamesInDataModel`](/api/modules/server.md#tablenamesindatamodel)<[`SystemDataModel`](/api/interfaces/server.SystemDataModel.md)> #### Defined in[​](#defined-in-72 "Direct link to Defined in") [server/schema.ts:844](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L844) *** ### StorageId[​](#storageid "Direct link to StorageId") Ƭ **StorageId**: `string` A reference to a file in storage. This is used in the [StorageReader](/api/interfaces/server.StorageReader.md) and [StorageWriter](/api/interfaces/server.StorageWriter.md) which are accessible in Convex queries and mutations via QueryCtx and MutationCtx respectively. #### Defined in[​](#defined-in-73 "Direct link to Defined in") [server/storage.ts:11](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L11) *** ### FileStorageId[​](#filestorageid "Direct link to FileStorageId") Ƭ **FileStorageId**: [`GenericId`](/api/modules/values.md#genericid)<`"_storage"`> | [`StorageId`](/api/modules/server.md#storageid) #### Defined in[​](#defined-in-74 "Direct link to Defined in") [server/storage.ts:12](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L12) *** ### FileMetadata[​](#filemetadata "Direct link to FileMetadata") Ƭ **FileMetadata**: `Object` Metadata for a single file as returned by [storage.getMetadata](/api/interfaces/server.StorageReader.md#getmetadata). #### Type declaration[​](#type-declaration-15 "Direct link to Type declaration") | Name | Type | Description | | ------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------ | | `storageId` | [`StorageId`](/api/modules/server.md#storageid) | ID for referencing the file (eg. via [storage.getUrl](/api/interfaces/server.StorageReader.md#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[​](#defined-in-75 "Direct link to Defined in") [server/storage.ts:18](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L18) *** ### SystemFields[​](#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[​](#type-declaration-16 "Direct link to Type declaration") | Name | Type | | --------------- | -------- | | `_creationTime` | `number` | #### Defined in[​](#defined-in-76 "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[​](#idfield "Direct link to IdField") Ƭ **IdField**<`TableName`>: `Object` The `_id` field that Convex automatically adds to documents. #### Type parameters[​](#type-parameters-48 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------- | | `TableName` | extends `string` | #### Type declaration[​](#type-declaration-17 "Direct link to Type declaration") | Name | Type | | ----- | ------------------------------------------------------------ | | `_id` | [`GenericId`](/api/modules/values.md#genericid)<`TableName`> | #### Defined in[​](#defined-in-77 "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[​](#withoutsystemfields "Direct link to WithoutSystemFields") Ƭ **WithoutSystemFields**<`Document`>: [`Expand`](/api/modules/server.md#expand)<[`BetterOmit`](/api/modules/server.md#betteromit)<`Document`, keyof [`SystemFields`](/api/modules/server.md#systemfields) | `"_id"`>> A Convex document with the system fields like `_id` and `_creationTime` omitted. #### Type parameters[​](#type-parameters-49 "Direct link to Type parameters") | Name | Type | | ---------- | ------------------------------------------------------------------- | | `Document` | extends [`GenericDocument`](/api/modules/server.md#genericdocument) | #### Defined in[​](#defined-in-78 "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[​](#withoptionalsystemfields "Direct link to WithOptionalSystemFields") Ƭ **WithOptionalSystemFields**<`Document`>: [`Expand`](/api/modules/server.md#expand)<[`WithoutSystemFields`](/api/modules/server.md#withoutsystemfields)<`Document`> & `Partial`<`Pick`<`Document`, keyof [`SystemFields`](/api/modules/server.md#systemfields) | `"_id"`>>> A Convex document with the system fields like `_id` and `_creationTime` optional. #### Type parameters[​](#type-parameters-50 "Direct link to Type parameters") | Name | Type | | ---------- | ------------------------------------------------------------------- | | `Document` | extends [`GenericDocument`](/api/modules/server.md#genericdocument) | #### Defined in[​](#defined-in-79 "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[​](#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[​](#type-declaration-18 "Direct link to Type declaration") | Name | Type | | ------------------ | -------------------- | | `by_id` | \[`"_id"`] | | `by_creation_time` | \[`"_creationTime"`] | #### Defined in[​](#defined-in-80 "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[​](#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[​](#defined-in-81 "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[​](#vectorsearch "Direct link to VectorSearch") Ƭ **VectorSearch**<`DataModel`, `TableName`, `IndexName`>: (`tableName`: `TableName`, `indexName`: `IndexName`, `query`: [`VectorSearchQuery`](/api/interfaces/server.VectorSearchQuery.md)<[`NamedTableInfo`](/api/modules/server.md#namedtableinfo)<`DataModel`, `TableName`>, `IndexName`>) => `Promise`<{ `_id`: [`GenericId`](/api/modules/values.md#genericid)<`TableName`> ; `_score`: `number` }\[]> #### Type parameters[​](#type-parameters-51 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | `DataModel` | extends [`GenericDataModel`](/api/modules/server.md#genericdatamodel) | | `TableName` | extends [`TableNamesInDataModel`](/api/modules/server.md#tablenamesindatamodel)<`DataModel`> | | `IndexName` | extends [`VectorIndexNames`](/api/modules/server.md#vectorindexnames)<[`NamedTableInfo`](/api/modules/server.md#namedtableinfo)<`DataModel`, `TableName`>> | #### Type declaration[​](#type-declaration-19 "Direct link to Type declaration") ▸ (`tableName`, `indexName`, `query`): `Promise`<{ `_id`: [`GenericId`](/api/modules/values.md#genericid)<`TableName`> ; `_score`: `number` }\[]> ##### Parameters[​](#parameters-6 "Direct link to Parameters") | Name | Type | | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `tableName` | `TableName` | | `indexName` | `IndexName` | | `query` | [`VectorSearchQuery`](/api/interfaces/server.VectorSearchQuery.md)<[`NamedTableInfo`](/api/modules/server.md#namedtableinfo)<`DataModel`, `TableName`>, `IndexName`> | ##### Returns[​](#returns-6 "Direct link to Returns") `Promise`<{ `_id`: [`GenericId`](/api/modules/values.md#genericid)<`TableName`> ; `_score`: `number` }\[]> #### Defined in[​](#defined-in-82 "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[​](#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[​](#type-parameters-52 "Direct link to Type parameters") | Name | Type | | ------------ | ------------------------------ | | `ObjectType` | extends `Record`<`any`, `any`> | #### Defined in[​](#defined-in-83 "Direct link to Defined in") [type\_utils.ts:12](https://github.com/get-convex/convex-js/blob/main/src/type_utils.ts#L12) *** ### BetterOmit[​](#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[​](#type-parameters-53 "Direct link to Type parameters") | Name | Type | | ---- | ----------------- | | `T` | `T` | | `K` | extends keyof `T` | #### Defined in[​](#defined-in-84 "Direct link to Defined in") [type\_utils.ts:24](https://github.com/get-convex/convex-js/blob/main/src/type_utils.ts#L24) ## Variables[​](#variables "Direct link to Variables") ### anyApi[​](#anyapi-1 "Direct link to anyApi") • `Const` **anyApi**: [`AnyApi`](/api/modules/server.md#anyapi) A utility for constructing [FunctionReference](/api/modules/server.md#functionreference)s in projects that are not using code generation. You can create a reference to a function like: ``` 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[​](#defined-in-85 "Direct link to Defined in") [server/api.ts:427](https://github.com/get-convex/convex-js/blob/main/src/server/api.ts#L427) *** ### paginationOptsValidator[​](#paginationoptsvalidator "Direct link to paginationOptsValidator") • `Const` **paginationOptsValidator**: [`VObject`](/api/classes/values.VObject.md)<{ `id`: `undefined` | `number` ; `endCursor`: `undefined` | `null` | `string` ; `maximumRowsRead`: `undefined` | `number` ; `maximumBytesRead`: `undefined` | `number` ; `numItems`: `number` ; `cursor`: `null` | `string` }, { `numItems`: [`VFloat64`](/api/classes/values.VFloat64.md)<`number`, `"required"`> ; `cursor`: [`VUnion`](/api/classes/values.VUnion.md)<`null` | `string`, \[[`VString`](/api/classes/values.VString.md)<`string`, `"required"`>, [`VNull`](/api/classes/values.VNull.md)<`null`, `"required"`>], `"required"`, `never`> ; `endCursor`: [`VUnion`](/api/classes/values.VUnion.md)<`undefined` | `null` | `string`, \[[`VString`](/api/classes/values.VString.md)<`string`, `"required"`>, [`VNull`](/api/classes/values.VNull.md)<`null`, `"required"`>], `"optional"`, `never`> ; `id`: [`VFloat64`](/api/classes/values.VFloat64.md)<`undefined` | `number`, `"optional"`> ; `maximumRowsRead`: [`VFloat64`](/api/classes/values.VFloat64.md)<`undefined` | `number`, `"optional"`> ; `maximumBytesRead`: [`VFloat64`](/api/classes/values.VFloat64.md)<`undefined` | `number`, `"optional"`> }, `"required"`, `"id"` | `"numItems"` | `"cursor"` | `"endCursor"` | `"maximumRowsRead"` | `"maximumBytesRead"`> A [Validator](/api/modules/values.md#validator) for [PaginationOptions](/api/interfaces/server.PaginationOptions.md). This includes the standard [PaginationOptions](/api/interfaces/server.PaginationOptions.md) properties along with an optional cache-busting `id` property used by [usePaginatedQuery](/api/modules/react.md#usepaginatedquery). #### Defined in[​](#defined-in-86 "Direct link to Defined in") [server/pagination.ts:133](https://github.com/get-convex/convex-js/blob/main/src/server/pagination.ts#L133) *** ### ROUTABLE\_HTTP\_METHODS[​](#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[​](#defined-in-87 "Direct link to Defined in") [server/router.ts:14](https://github.com/get-convex/convex-js/blob/main/src/server/router.ts#L14) ## Functions[​](#functions "Direct link to Functions") ### getFunctionName[​](#getfunctionname "Direct link to getFunctionName") ▸ **getFunctionName**(`functionReference`): `string` Get the name of a function from a [FunctionReference](/api/modules/server.md#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[​](#parameters-7 "Direct link to Parameters") | Name | Type | Description | | ------------------- | ---------------------- | ----------------------------------------------------------------------------------- | | `functionReference` | `AnyFunctionReference` | A [FunctionReference](/api/modules/server.md#functionreference) to get the name of. | #### Returns[​](#returns-7 "Direct link to Returns") `string` A string of the function's name. #### Defined in[​](#defined-in-88 "Direct link to Defined in") [server/api.ts:78](https://github.com/get-convex/convex-js/blob/main/src/server/api.ts#L78) *** ### makeFunctionReference[​](#makefunctionreference "Direct link to makeFunctionReference") ▸ **makeFunctionReference**<`type`, `args`, `ret`>(`name`): [`FunctionReference`](/api/modules/server.md#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[​](#type-parameters-54 "Direct link to Type parameters") | Name | Type | | ------ | ----------------------------------------------------------------------------------- | | `type` | extends [`FunctionType`](/api/modules/server.md#functiontype) | | `args` | extends [`DefaultFunctionArgs`](/api/modules/server.md#defaultfunctionargs) = `any` | | `ret` | `any` | #### Parameters[​](#parameters-8 "Direct link to Parameters") | Name | Type | Description | | ------ | -------- | ---------------------------------------------------------------- | | `name` | `string` | The identifier of the function. E.g. `path/to/file:functionName` | #### Returns[​](#returns-8 "Direct link to Returns") [`FunctionReference`](/api/modules/server.md#functionreference)<`type`, `"public"`, `args`, `ret`> #### Defined in[​](#defined-in-89 "Direct link to Defined in") [server/api.ts:122](https://github.com/get-convex/convex-js/blob/main/src/server/api.ts#L122) *** ### filterApi[​](#filterapi-1 "Direct link to filterApi") ▸ **filterApi**<`API`, `Predicate`>(`api`): [`FilterApi`](/api/modules/server.md#filterapi)<`API`, `Predicate`> Given an api of type API and a FunctionReference subtype, return an api object containing only the function references that match. ``` const q = filterApi>(api) ``` #### Type parameters[​](#type-parameters-55 "Direct link to Type parameters") | Name | | ----------- | | `API` | | `Predicate` | #### Parameters[​](#parameters-9 "Direct link to Parameters") | Name | Type | | ----- | ----- | | `api` | `API` | #### Returns[​](#returns-9 "Direct link to Returns") [`FilterApi`](/api/modules/server.md#filterapi)<`API`, `Predicate`> #### Defined in[​](#defined-in-90 "Direct link to Defined in") [server/api.ts:301](https://github.com/get-convex/convex-js/blob/main/src/server/api.ts#L301) *** ### createFunctionHandle[​](#createfunctionhandle "Direct link to createFunctionHandle") ▸ **createFunctionHandle**<`Type`, `Args`, `ReturnType`>(`functionReference`): `Promise`<[`FunctionHandle`](/api/modules/server.md#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[​](#type-parameters-56 "Direct link to Type parameters") | Name | Type | | ------------ | --------------------------------------------------------------------------- | | `Type` | extends [`FunctionType`](/api/modules/server.md#functiontype) | | `Args` | extends [`DefaultFunctionArgs`](/api/modules/server.md#defaultfunctionargs) | | `ReturnType` | `ReturnType` | #### Parameters[​](#parameters-10 "Direct link to Parameters") | Name | Type | | ------------------- | ------------------------------------------------------------------------------------------------------------------------- | | `functionReference` | [`FunctionReference`](/api/modules/server.md#functionreference)<`Type`, `"public"` \| `"internal"`, `Args`, `ReturnType`> | #### Returns[​](#returns-10 "Direct link to Returns") `Promise`<[`FunctionHandle`](/api/modules/server.md#functionhandle)<`Type`, `Args`, `ReturnType`>> #### Defined in[​](#defined-in-91 "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[​](#definecomponent "Direct link to defineComponent") ▸ **defineComponent**<`Exports`>(`name`): [`ComponentDefinition`](/api/modules/server.md#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[​](#type-parameters-57 "Direct link to Type parameters") | Name | Type | | --------- | ---------------------------------- | | `Exports` | extends `ComponentExports` = `any` | #### Parameters[​](#parameters-11 "Direct link to Parameters") | Name | Type | | ------ | -------- | | `name` | `string` | #### Returns[​](#returns-11 "Direct link to Returns") [`ComponentDefinition`](/api/modules/server.md#componentdefinition)<`Exports`> #### Defined in[​](#defined-in-92 "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[​](#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[​](#returns-12 "Direct link to Returns") `AppDefinition` #### Defined in[​](#defined-in-93 "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[​](#componentsgeneric "Direct link to componentsGeneric") ▸ **componentsGeneric**(): [`AnyChildComponents`](/api/modules/server.md#anychildcomponents) #### Returns[​](#returns-13 "Direct link to Returns") [`AnyChildComponents`](/api/modules/server.md#anychildcomponents) #### Defined in[​](#defined-in-94 "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[​](#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[​](#parameters-12 "Direct link to Parameters") | Name | Type | | ------------------- | ----- | | `functionReference` | `any` | #### Returns[​](#returns-14 "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[​](#defined-in-95 "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[​](#cronjobs "Direct link to cronJobs") ▸ **cronJobs**(): [`Crons`](/api/classes/server.Crons.md) Create a CronJobs object to schedule recurring tasks. ``` // 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[​](#returns-15 "Direct link to Returns") [`Crons`](/api/classes/server.Crons.md) #### Defined in[​](#defined-in-96 "Direct link to Defined in") [server/cron.ts:180](https://github.com/get-convex/convex-js/blob/main/src/server/cron.ts#L180) *** ### mutationGeneric[​](#mutationgeneric "Direct link to mutationGeneric") ▸ **mutationGeneric**<`ArgsValidator`, `ReturnsValidator`, `ReturnValue`, `OneOrZeroArgs`>(`mutation`): [`RegisteredMutation`](/api/modules/server.md#registeredmutation)<`"public"`, [`ArgsArrayToObject`](/api/modules/server.md#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[​](#type-parameters-58 "Direct link to Type parameters") | Name | Type | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `ArgsValidator` | extends `void` \| [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`> \| [`PropertyValidators`](/api/modules/values.md#propertyvalidators) | | `ReturnsValidator` | extends `void` \| [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`> \| [`PropertyValidators`](/api/modules/values.md#propertyvalidators) | | `ReturnValue` | extends `any` = `any` | | `OneOrZeroArgs` | extends [`ArgsArray`](/api/modules/server.md#argsarray) \| `OneArgArray`<[`Infer`](/api/modules/values.md#infer)<`ArgsValidator`>> \| `OneArgArray`<[`Expand`](/api/modules/server.md#expand)<{ \[Property in string \| number \| symbol]?: Exclude\, undefined> } & { \[Property in string \| number \| symbol]: Infer\ }>> = [`DefaultArgsForOptionalValidator`](/api/modules/server.md#defaultargsforoptionalvalidator)<`ArgsValidator`> | #### Parameters[​](#parameters-13 "Direct link to Parameters") | Name | Type | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `mutation` | { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: (`ctx`: [`GenericMutationCtx`](/api/interfaces/server.GenericMutationCtx.md)<`any`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue` } \| (`ctx`: [`GenericMutationCtx`](/api/interfaces/server.GenericMutationCtx.md)<`any`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue` | #### Returns[​](#returns-16 "Direct link to Returns") [`RegisteredMutation`](/api/modules/server.md#registeredmutation)<`"public"`, [`ArgsArrayToObject`](/api/modules/server.md#argsarraytoobject)<`OneOrZeroArgs`>, `ReturnValue`> The wrapped mutation. Include this as an `export` to name it and make it accessible. #### Defined in[​](#defined-in-97 "Direct link to Defined in") [server/registration.ts:608](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L608) *** ### internalMutationGeneric[​](#internalmutationgeneric "Direct link to internalMutationGeneric") ▸ **internalMutationGeneric**<`ArgsValidator`, `ReturnsValidator`, `ReturnValue`, `OneOrZeroArgs`>(`mutation`): [`RegisteredMutation`](/api/modules/server.md#registeredmutation)<`"internal"`, [`ArgsArrayToObject`](/api/modules/server.md#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[​](#type-parameters-59 "Direct link to Type parameters") | Name | Type | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `ArgsValidator` | extends `void` \| [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`> \| [`PropertyValidators`](/api/modules/values.md#propertyvalidators) | | `ReturnsValidator` | extends `void` \| [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`> \| [`PropertyValidators`](/api/modules/values.md#propertyvalidators) | | `ReturnValue` | extends `any` = `any` | | `OneOrZeroArgs` | extends [`ArgsArray`](/api/modules/server.md#argsarray) \| `OneArgArray`<[`Infer`](/api/modules/values.md#infer)<`ArgsValidator`>> \| `OneArgArray`<[`Expand`](/api/modules/server.md#expand)<{ \[Property in string \| number \| symbol]?: Exclude\, undefined> } & { \[Property in string \| number \| symbol]: Infer\ }>> = [`DefaultArgsForOptionalValidator`](/api/modules/server.md#defaultargsforoptionalvalidator)<`ArgsValidator`> | #### Parameters[​](#parameters-14 "Direct link to Parameters") | Name | Type | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `mutation` | { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: (`ctx`: [`GenericMutationCtx`](/api/interfaces/server.GenericMutationCtx.md)<`any`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue` } \| (`ctx`: [`GenericMutationCtx`](/api/interfaces/server.GenericMutationCtx.md)<`any`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue` | #### Returns[​](#returns-17 "Direct link to Returns") [`RegisteredMutation`](/api/modules/server.md#registeredmutation)<`"internal"`, [`ArgsArrayToObject`](/api/modules/server.md#argsarraytoobject)<`OneOrZeroArgs`>, `ReturnValue`> The wrapped mutation. Include this as an `export` to name it and make it accessible. #### Defined in[​](#defined-in-98 "Direct link to Defined in") [server/registration.ts:608](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L608) *** ### queryGeneric[​](#querygeneric "Direct link to queryGeneric") ▸ **queryGeneric**<`ArgsValidator`, `ReturnsValidator`, `ReturnValue`, `OneOrZeroArgs`>(`query`): [`RegisteredQuery`](/api/modules/server.md#registeredquery)<`"public"`, [`ArgsArrayToObject`](/api/modules/server.md#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[​](#type-parameters-60 "Direct link to Type parameters") | Name | Type | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `ArgsValidator` | extends `void` \| [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`> \| [`PropertyValidators`](/api/modules/values.md#propertyvalidators) | | `ReturnsValidator` | extends `void` \| [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`> \| [`PropertyValidators`](/api/modules/values.md#propertyvalidators) | | `ReturnValue` | extends `any` = `any` | | `OneOrZeroArgs` | extends [`ArgsArray`](/api/modules/server.md#argsarray) \| `OneArgArray`<[`Infer`](/api/modules/values.md#infer)<`ArgsValidator`>> \| `OneArgArray`<[`Expand`](/api/modules/server.md#expand)<{ \[Property in string \| number \| symbol]?: Exclude\, undefined> } & { \[Property in string \| number \| symbol]: Infer\ }>> = [`DefaultArgsForOptionalValidator`](/api/modules/server.md#defaultargsforoptionalvalidator)<`ArgsValidator`> | #### Parameters[​](#parameters-15 "Direct link to Parameters") | Name | Type | | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `query` | { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: (`ctx`: [`GenericQueryCtx`](/api/interfaces/server.GenericQueryCtx.md)<`any`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue` } \| (`ctx`: [`GenericQueryCtx`](/api/interfaces/server.GenericQueryCtx.md)<`any`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue` | #### Returns[​](#returns-18 "Direct link to Returns") [`RegisteredQuery`](/api/modules/server.md#registeredquery)<`"public"`, [`ArgsArrayToObject`](/api/modules/server.md#argsarraytoobject)<`OneOrZeroArgs`>, `ReturnValue`> The wrapped query. Include this as an `export` to name it and make it accessible. #### Defined in[​](#defined-in-99 "Direct link to Defined in") [server/registration.ts:794](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L794) *** ### internalQueryGeneric[​](#internalquerygeneric "Direct link to internalQueryGeneric") ▸ **internalQueryGeneric**<`ArgsValidator`, `ReturnsValidator`, `ReturnValue`, `OneOrZeroArgs`>(`query`): [`RegisteredQuery`](/api/modules/server.md#registeredquery)<`"internal"`, [`ArgsArrayToObject`](/api/modules/server.md#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[​](#type-parameters-61 "Direct link to Type parameters") | Name | Type | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `ArgsValidator` | extends `void` \| [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`> \| [`PropertyValidators`](/api/modules/values.md#propertyvalidators) | | `ReturnsValidator` | extends `void` \| [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`> \| [`PropertyValidators`](/api/modules/values.md#propertyvalidators) | | `ReturnValue` | extends `any` = `any` | | `OneOrZeroArgs` | extends [`ArgsArray`](/api/modules/server.md#argsarray) \| `OneArgArray`<[`Infer`](/api/modules/values.md#infer)<`ArgsValidator`>> \| `OneArgArray`<[`Expand`](/api/modules/server.md#expand)<{ \[Property in string \| number \| symbol]?: Exclude\, undefined> } & { \[Property in string \| number \| symbol]: Infer\ }>> = [`DefaultArgsForOptionalValidator`](/api/modules/server.md#defaultargsforoptionalvalidator)<`ArgsValidator`> | #### Parameters[​](#parameters-16 "Direct link to Parameters") | Name | Type | | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `query` | { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: (`ctx`: [`GenericQueryCtx`](/api/interfaces/server.GenericQueryCtx.md)<`any`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue` } \| (`ctx`: [`GenericQueryCtx`](/api/interfaces/server.GenericQueryCtx.md)<`any`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue` | #### Returns[​](#returns-19 "Direct link to Returns") [`RegisteredQuery`](/api/modules/server.md#registeredquery)<`"internal"`, [`ArgsArrayToObject`](/api/modules/server.md#argsarraytoobject)<`OneOrZeroArgs`>, `ReturnValue`> The wrapped query. Include this as an `export` to name it and make it accessible. #### Defined in[​](#defined-in-100 "Direct link to Defined in") [server/registration.ts:794](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L794) *** ### actionGeneric[​](#actiongeneric "Direct link to actionGeneric") ▸ **actionGeneric**<`ArgsValidator`, `ReturnsValidator`, `ReturnValue`, `OneOrZeroArgs`>(`func`): [`RegisteredAction`](/api/modules/server.md#registeredaction)<`"public"`, [`ArgsArrayToObject`](/api/modules/server.md#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[​](#type-parameters-62 "Direct link to Type parameters") | Name | Type | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `ArgsValidator` | extends `void` \| [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`> \| [`PropertyValidators`](/api/modules/values.md#propertyvalidators) | | `ReturnsValidator` | extends `void` \| [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`> \| [`PropertyValidators`](/api/modules/values.md#propertyvalidators) | | `ReturnValue` | extends `any` = `any` | | `OneOrZeroArgs` | extends [`ArgsArray`](/api/modules/server.md#argsarray) \| `OneArgArray`<[`Infer`](/api/modules/values.md#infer)<`ArgsValidator`>> \| `OneArgArray`<[`Expand`](/api/modules/server.md#expand)<{ \[Property in string \| number \| symbol]?: Exclude\, undefined> } & { \[Property in string \| number \| symbol]: Infer\ }>> = [`DefaultArgsForOptionalValidator`](/api/modules/server.md#defaultargsforoptionalvalidator)<`ArgsValidator`> | #### Parameters[​](#parameters-17 "Direct link to Parameters") | Name | Type | Description | | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | | `func` | { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: (`ctx`: [`GenericActionCtx`](/api/interfaces/server.GenericActionCtx.md)<`any`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue` } \| (`ctx`: [`GenericActionCtx`](/api/interfaces/server.GenericActionCtx.md)<`any`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue` | The function. It receives a [GenericActionCtx](/api/interfaces/server.GenericActionCtx.md) as its first argument. | #### Returns[​](#returns-20 "Direct link to Returns") [`RegisteredAction`](/api/modules/server.md#registeredaction)<`"public"`, [`ArgsArrayToObject`](/api/modules/server.md#argsarraytoobject)<`OneOrZeroArgs`>, `ReturnValue`> The wrapped function. Include this as an `export` to name it and make it accessible. #### Defined in[​](#defined-in-101 "Direct link to Defined in") [server/registration.ts:972](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L972) *** ### internalActionGeneric[​](#internalactiongeneric "Direct link to internalActionGeneric") ▸ **internalActionGeneric**<`ArgsValidator`, `ReturnsValidator`, `ReturnValue`, `OneOrZeroArgs`>(`func`): [`RegisteredAction`](/api/modules/server.md#registeredaction)<`"internal"`, [`ArgsArrayToObject`](/api/modules/server.md#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[​](#type-parameters-63 "Direct link to Type parameters") | Name | Type | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `ArgsValidator` | extends `void` \| [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`> \| [`PropertyValidators`](/api/modules/values.md#propertyvalidators) | | `ReturnsValidator` | extends `void` \| [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`> \| [`PropertyValidators`](/api/modules/values.md#propertyvalidators) | | `ReturnValue` | extends `any` = `any` | | `OneOrZeroArgs` | extends [`ArgsArray`](/api/modules/server.md#argsarray) \| `OneArgArray`<[`Infer`](/api/modules/values.md#infer)<`ArgsValidator`>> \| `OneArgArray`<[`Expand`](/api/modules/server.md#expand)<{ \[Property in string \| number \| symbol]?: Exclude\, undefined> } & { \[Property in string \| number \| symbol]: Infer\ }>> = [`DefaultArgsForOptionalValidator`](/api/modules/server.md#defaultargsforoptionalvalidator)<`ArgsValidator`> | #### Parameters[​](#parameters-18 "Direct link to Parameters") | Name | Type | Description | | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | | `func` | { `args?`: `ArgsValidator` ; `returns?`: `ReturnsValidator` ; `handler`: (`ctx`: [`GenericActionCtx`](/api/interfaces/server.GenericActionCtx.md)<`any`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue` } \| (`ctx`: [`GenericActionCtx`](/api/interfaces/server.GenericActionCtx.md)<`any`>, ...`args`: `OneOrZeroArgs`) => `ReturnValue` | The function. It receives a [GenericActionCtx](/api/interfaces/server.GenericActionCtx.md) as its first argument. | #### Returns[​](#returns-21 "Direct link to Returns") [`RegisteredAction`](/api/modules/server.md#registeredaction)<`"internal"`, [`ArgsArrayToObject`](/api/modules/server.md#argsarraytoobject)<`OneOrZeroArgs`>, `ReturnValue`> The wrapped function. Include this as an `export` to name it and make it accessible. #### Defined in[​](#defined-in-102 "Direct link to Defined in") [server/registration.ts:972](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L972) *** ### httpActionGeneric[​](#httpactiongeneric "Direct link to httpActionGeneric") ▸ **httpActionGeneric**(`func`): [`PublicHttpAction`](/api/modules/server.md#publichttpaction) Define a Convex HTTP action. #### Parameters[​](#parameters-19 "Direct link to Parameters") | Name | Type | Description | | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | `func` | (`ctx`: [`GenericActionCtx`](/api/interfaces/server.GenericActionCtx.md)<[`GenericDataModel`](/api/modules/server.md#genericdatamodel)>, `request`: `Request`) => `Promise`<`Response`> | The function. It receives an [GenericActionCtx](/api/interfaces/server.GenericActionCtx.md) as its first argument, and a `Request` object as its second. | #### Returns[​](#returns-22 "Direct link to Returns") [`PublicHttpAction`](/api/modules/server.md#publichttpaction) The wrapped function. Route a URL path to this function in `convex/http.js`. #### Defined in[​](#defined-in-103 "Direct link to Defined in") [server/impl/registration\_impl.ts:465](https://github.com/get-convex/convex-js/blob/main/src/server/impl/registration_impl.ts#L465) *** ### paginationResultValidator[​](#paginationresultvalidator "Direct link to paginationResultValidator") ▸ **paginationResultValidator**<`T`>(`itemValidator`): [`VObject`](/api/classes/values.VObject.md)<{ `splitCursor`: `undefined` | `null` | `string` ; `pageStatus`: `undefined` | `null` | `"SplitRecommended"` | `"SplitRequired"` ; `page`: `T`\[`"type"`]\[] ; `continueCursor`: `string` ; `isDone`: `boolean` }, { `page`: [`VArray`](/api/classes/values.VArray.md)<`T`\[`"type"`]\[], `T`, `"required"`> ; `continueCursor`: [`VString`](/api/classes/values.VString.md)<`string`, `"required"`> ; `isDone`: [`VBoolean`](/api/classes/values.VBoolean.md)<`boolean`, `"required"`> ; `splitCursor`: [`VUnion`](/api/classes/values.VUnion.md)<`undefined` | `null` | `string`, \[[`VString`](/api/classes/values.VString.md)<`string`, `"required"`>, [`VNull`](/api/classes/values.VNull.md)<`null`, `"required"`>], `"optional"`, `never`> ; `pageStatus`: [`VUnion`](/api/classes/values.VUnion.md)<`undefined` | `null` | `"SplitRecommended"` | `"SplitRequired"`, \[[`VLiteral`](/api/classes/values.VLiteral.md)<`"SplitRecommended"`, `"required"`>, [`VLiteral`](/api/classes/values.VLiteral.md)<`"SplitRequired"`, `"required"`>, [`VNull`](/api/classes/values.VNull.md)<`null`, `"required"`>], `"optional"`, `never`> }, `"required"`, `"page"` | `"continueCursor"` | `"isDone"` | `"splitCursor"` | `"pageStatus"`> A [Validator](/api/modules/values.md#validator) factory for [PaginationResult](/api/interfaces/server.PaginationResult.md). Create a validator for the result of calling [paginate](/api/interfaces/server.OrderedQuery.md#paginate) with a given item validator. For example: ``` const paginationResultValidator = paginationResultValidator(v.object({ _id: v.id("users"), _creationTime: v.number(), name: v.string(), })); ``` #### Type parameters[​](#type-parameters-64 "Direct link to Type parameters") | Name | Type | | ---- | ------------------------------------------------------------------------------------------------------------------------ | | `T` | extends [`Validator`](/api/modules/values.md#validator)<[`Value`](/api/modules/values.md#value), `"required"`, `string`> | #### Parameters[​](#parameters-20 "Direct link to Parameters") | Name | Type | Description | | --------------- | ---- | ------------------------------------- | | `itemValidator` | `T` | A validator for the items in the page | #### Returns[​](#returns-23 "Direct link to Returns") [`VObject`](/api/classes/values.VObject.md)<{ `splitCursor`: `undefined` | `null` | `string` ; `pageStatus`: `undefined` | `null` | `"SplitRecommended"` | `"SplitRequired"` ; `page`: `T`\[`"type"`]\[] ; `continueCursor`: `string` ; `isDone`: `boolean` }, { `page`: [`VArray`](/api/classes/values.VArray.md)<`T`\[`"type"`]\[], `T`, `"required"`> ; `continueCursor`: [`VString`](/api/classes/values.VString.md)<`string`, `"required"`> ; `isDone`: [`VBoolean`](/api/classes/values.VBoolean.md)<`boolean`, `"required"`> ; `splitCursor`: [`VUnion`](/api/classes/values.VUnion.md)<`undefined` | `null` | `string`, \[[`VString`](/api/classes/values.VString.md)<`string`, `"required"`>, [`VNull`](/api/classes/values.VNull.md)<`null`, `"required"`>], `"optional"`, `never`> ; `pageStatus`: [`VUnion`](/api/classes/values.VUnion.md)<`undefined` | `null` | `"SplitRecommended"` | `"SplitRequired"`, \[[`VLiteral`](/api/classes/values.VLiteral.md)<`"SplitRecommended"`, `"required"`>, [`VLiteral`](/api/classes/values.VLiteral.md)<`"SplitRequired"`, `"required"`>, [`VNull`](/api/classes/values.VNull.md)<`null`, `"required"`>], `"optional"`, `never`> }, `"required"`, `"page"` | `"continueCursor"` | `"isDone"` | `"splitCursor"` | `"pageStatus"`> A validator for the pagination result #### Defined in[​](#defined-in-104 "Direct link to Defined in") [server/pagination.ts:162](https://github.com/get-convex/convex-js/blob/main/src/server/pagination.ts#L162) *** ### httpRouter[​](#httprouter "Direct link to httpRouter") ▸ **httpRouter**(): [`HttpRouter`](/api/classes/server.HttpRouter.md) Return a new [HttpRouter](/api/classes/server.HttpRouter.md) object. #### Returns[​](#returns-24 "Direct link to Returns") [`HttpRouter`](/api/classes/server.HttpRouter.md) #### Defined in[​](#defined-in-105 "Direct link to Defined in") [server/router.ts:47](https://github.com/get-convex/convex-js/blob/main/src/server/router.ts#L47) *** ### defineTable[​](#definetable "Direct link to defineTable") ▸ **defineTable**<`DocumentSchema`>(`documentSchema`): [`TableDefinition`](/api/classes/server.TableDefinition.md)<`DocumentSchema`> Define a table in a schema. You can either specify the schema of your documents as an object like ``` defineTable({ field: v.string() }); ``` or as a schema type like ``` defineTable( v.union( v.object({...}), v.object({...}) ) ); ``` #### Type parameters[​](#type-parameters-65 "Direct link to Type parameters") | Name | Type | | ---------------- | ------------------------------------------------------------------------------------------------------- | | `DocumentSchema` | extends [`Validator`](/api/modules/values.md#validator)<`Record`<`string`, `any`>, `"required"`, `any`> | #### Parameters[​](#parameters-21 "Direct link to Parameters") | Name | Type | Description | | ---------------- | ---------------- | ------------------------------------------- | | `documentSchema` | `DocumentSchema` | The type of documents stored in this table. | #### Returns[​](#returns-25 "Direct link to Returns") [`TableDefinition`](/api/classes/server.TableDefinition.md)<`DocumentSchema`> A [TableDefinition](/api/classes/server.TableDefinition.md) for the table. #### Defined in[​](#defined-in-106 "Direct link to Defined in") [server/schema.ts:593](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L593) ▸ **defineTable**<`DocumentSchema`>(`documentSchema`): [`TableDefinition`](/api/classes/server.TableDefinition.md)<[`VObject`](/api/classes/values.VObject.md)<[`ObjectType`](/api/modules/values.md#objecttype)<`DocumentSchema`>, `DocumentSchema`>> Define a table in a schema. You can either specify the schema of your documents as an object like ``` defineTable({ field: v.string() }); ``` or as a schema type like ``` defineTable( v.union( v.object({...}), v.object({...}) ) ); ``` #### Type parameters[​](#type-parameters-66 "Direct link to Type parameters") | Name | Type | | ---------------- | ----------------------------------------------------------------------------------------- | | `DocumentSchema` | extends `Record`<`string`, [`GenericValidator`](/api/modules/values.md#genericvalidator)> | #### Parameters[​](#parameters-22 "Direct link to Parameters") | Name | Type | Description | | ---------------- | ---------------- | ------------------------------------------- | | `documentSchema` | `DocumentSchema` | The type of documents stored in this table. | #### Returns[​](#returns-26 "Direct link to Returns") [`TableDefinition`](/api/classes/server.TableDefinition.md)<[`VObject`](/api/classes/values.VObject.md)<[`ObjectType`](/api/modules/values.md#objecttype)<`DocumentSchema`>, `DocumentSchema`>> A [TableDefinition](/api/classes/server.TableDefinition.md) for the table. #### Defined in[​](#defined-in-107 "Direct link to Defined in") [server/schema.ts:621](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L621) *** ### defineSchema[​](#defineschema "Direct link to defineSchema") ▸ **defineSchema**<`Schema`, `StrictTableNameTypes`>(`schema`, `options?`): [`SchemaDefinition`](/api/classes/server.SchemaDefinition.md)<`Schema`, `StrictTableNameTypes`> Define the schema of this Convex project. This should be exported from a `schema.ts` file in your `convex/` directory like: ``` export default defineSchema({ ... }); ``` #### Type parameters[​](#type-parameters-67 "Direct link to Type parameters") | Name | Type | | ---------------------- | --------------------------------------------------------------- | | `Schema` | extends [`GenericSchema`](/api/modules/server.md#genericschema) | | `StrictTableNameTypes` | extends `boolean` = `true` | #### Parameters[​](#parameters-23 "Direct link to Parameters") | Name | Type | Description | | ---------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | | `schema` | `Schema` | A map from table name to [TableDefinition](/api/classes/server.TableDefinition.md) for all of the tables in this project. | | `options?` | [`DefineSchemaOptions`](/api/interfaces/server.DefineSchemaOptions.md)<`StrictTableNameTypes`> | Optional configuration. See [DefineSchemaOptions](/api/interfaces/server.DefineSchemaOptions.md) for a full description. | #### Returns[​](#returns-27 "Direct link to Returns") [`SchemaDefinition`](/api/classes/server.SchemaDefinition.md)<`Schema`, `StrictTableNameTypes`> The schema. #### Defined in[​](#defined-in-108 "Direct link to Defined in") [server/schema.ts:769](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L769) --- # Module: values 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[​](#namespaces "Direct link to Namespaces") * [Base64](/api/namespaces/values.Base64.md) ## Classes[​](#classes "Direct link to Classes") * [ConvexError](/api/classes/values.ConvexError.md) * [VId](/api/classes/values.VId.md) * [VFloat64](/api/classes/values.VFloat64.md) * [VInt64](/api/classes/values.VInt64.md) * [VBoolean](/api/classes/values.VBoolean.md) * [VBytes](/api/classes/values.VBytes.md) * [VString](/api/classes/values.VString.md) * [VNull](/api/classes/values.VNull.md) * [VAny](/api/classes/values.VAny.md) * [VObject](/api/classes/values.VObject.md) * [VLiteral](/api/classes/values.VLiteral.md) * [VArray](/api/classes/values.VArray.md) * [VRecord](/api/classes/values.VRecord.md) * [VUnion](/api/classes/values.VUnion.md) ## Type Aliases[​](#type-aliases "Direct link to Type Aliases") ### GenericValidator[​](#genericvalidator "Direct link to GenericValidator") Ƭ **GenericValidator**: [`Validator`](/api/modules/values.md#validator)<`any`, `any`, `any`> The type that all validators must extend. #### Defined in[​](#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[​](#asobjectvalidator "Direct link to AsObjectValidator") Ƭ **AsObjectValidator**<`V`>: `V` extends [`Validator`](/api/modules/values.md#validator)<`any`, `any`, `any`> ? `V` : `V` extends [`PropertyValidators`](/api/modules/values.md#propertyvalidators) ? [`Validator`](/api/modules/values.md#validator)<[`ObjectType`](/api/modules/values.md#objecttype)<`V`>> : `never` Coerce an object with validators as properties to a validator. If a validator is passed, return it. #### Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `V` | extends [`Validator`](/api/modules/values.md#validator)<`any`, `any`, `any`> \| [`PropertyValidators`](/api/modules/values.md#propertyvalidators) | #### Defined in[​](#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[​](#propertyvalidators "Direct link to PropertyValidators") Ƭ **PropertyValidators**: `Record`<`string`, [`Validator`](/api/modules/values.md#validator)<`any`, [`OptionalProperty`](/api/modules/values.md#optionalproperty), `any`>> Validators for each property of an object. This is represented as an object mapping the property name to its [Validator](/api/modules/values.md#validator). #### Defined in[​](#defined-in-2 "Direct link to Defined in") [values/validator.ts:242](https://github.com/get-convex/convex-js/blob/main/src/values/validator.ts#L242) *** ### ObjectType[​](#objecttype "Direct link to ObjectType") Ƭ **ObjectType**<`Fields`>: [`Expand`](/api/modules/server.md#expand)<{ \[Property in OptionalKeys\]?: Exclude\, undefined> } & { \[Property in RequiredKeys\]: Infer\ }> Compute the type of an object from [PropertyValidators](/api/modules/values.md#propertyvalidators). #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | -------- | ------------------------------------------------------------------------- | | `Fields` | extends [`PropertyValidators`](/api/modules/values.md#propertyvalidators) | #### Defined in[​](#defined-in-3 "Direct link to Defined in") [values/validator.ts:252](https://github.com/get-convex/convex-js/blob/main/src/values/validator.ts#L252) *** ### Infer[​](#infer "Direct link to Infer") Ƭ **Infer**<`T`>: `T`\[`"type"`] Extract a TypeScript type from a validator. Example usage: ``` const objectSchema = v.object({ property: v.string(), }); type MyObject = Infer; // { property: string } ``` **`Type Param`** The type of a [Validator](/api/modules/values.md#validator) constructed with [v](/api/modules/values.md#v). #### Type parameters[​](#type-parameters-2 "Direct link to Type parameters") | Name | Type | | ---- | ------------------------------------------------------------------------------------------------------------------------------------ | | `T` | extends [`Validator`](/api/modules/values.md#validator)<`any`, [`OptionalProperty`](/api/modules/values.md#optionalproperty), `any`> | #### Defined in[​](#defined-in-4 "Direct link to Defined in") [values/validator.ts:294](https://github.com/get-convex/convex-js/blob/main/src/values/validator.ts#L294) *** ### VOptional[​](#voptional "Direct link to VOptional") Ƭ **VOptional**<`T`>: `T` extends [`VId`](/api/classes/values.VId.md)\ ? [`VId`](/api/classes/values.VId.md)<`Type` | `undefined`, `"optional"`> : `T` extends [`VString`](/api/classes/values.VString.md)\ ? [`VString`](/api/classes/values.VString.md)<`Type` | `undefined`, `"optional"`> : `T` extends [`VFloat64`](/api/classes/values.VFloat64.md)\ ? [`VFloat64`](/api/classes/values.VFloat64.md)<`Type` | `undefined`, `"optional"`> : `T` extends [`VInt64`](/api/classes/values.VInt64.md)\ ? [`VInt64`](/api/classes/values.VInt64.md)<`Type` | `undefined`, `"optional"`> : `T` extends [`VBoolean`](/api/classes/values.VBoolean.md)\ ? [`VBoolean`](/api/classes/values.VBoolean.md)<`Type` | `undefined`, `"optional"`> : `T` extends [`VNull`](/api/classes/values.VNull.md)\ ? [`VNull`](/api/classes/values.VNull.md)<`Type` | `undefined`, `"optional"`> : `T` extends [`VAny`](/api/classes/values.VAny.md)\ ? [`VAny`](/api/classes/values.VAny.md)<`Type` | `undefined`, `"optional"`> : `T` extends [`VLiteral`](/api/classes/values.VLiteral.md)\ ? [`VLiteral`](/api/classes/values.VLiteral.md)<`Type` | `undefined`, `"optional"`> : `T` extends [`VBytes`](/api/classes/values.VBytes.md)\ ? [`VBytes`](/api/classes/values.VBytes.md)<`Type` | `undefined`, `"optional"`> : `T` extends [`VObject`](/api/classes/values.VObject.md)\ ? [`VObject`](/api/classes/values.VObject.md)<`Type` | `undefined`, `Fields`, `"optional"`, `FieldPaths`> : `T` extends [`VArray`](/api/classes/values.VArray.md)\ ? [`VArray`](/api/classes/values.VArray.md)<`Type` | `undefined`, `Element`, `"optional"`> : `T` extends [`VRecord`](/api/classes/values.VRecord.md)\ ? [`VRecord`](/api/classes/values.VRecord.md)<`Type` | `undefined`, `Key`, `Value`, `"optional"`, `FieldPaths`> : `T` extends [`VUnion`](/api/classes/values.VUnion.md)\ ? [`VUnion`](/api/classes/values.VUnion.md)<`Type` | `undefined`, `Members`, `"optional"`, `FieldPaths`> : `never` #### Type parameters[​](#type-parameters-3 "Direct link to Type parameters") | Name | Type | | ---- | ------------------------------------------------------------------------------------------------------------------------------------ | | `T` | extends [`Validator`](/api/modules/values.md#validator)<`any`, [`OptionalProperty`](/api/modules/values.md#optionalproperty), `any`> | #### Defined in[​](#defined-in-5 "Direct link to Defined in") [values/validators.ts:618](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L618) *** ### OptionalProperty[​](#optionalproperty "Direct link to OptionalProperty") Ƭ **OptionalProperty**: `"optional"` | `"required"` Type representing whether a property in an object is optional or required. #### Defined in[​](#defined-in-6 "Direct link to Defined in") [values/validators.ts:651](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L651) *** ### Validator[​](#validator "Direct link to Validator") Ƭ **Validator**<`Type`, `IsOptional`, `FieldPaths`>: [`VId`](/api/classes/values.VId.md)<`Type`, `IsOptional`> | [`VString`](/api/classes/values.VString.md)<`Type`, `IsOptional`> | [`VFloat64`](/api/classes/values.VFloat64.md)<`Type`, `IsOptional`> | [`VInt64`](/api/classes/values.VInt64.md)<`Type`, `IsOptional`> | [`VBoolean`](/api/classes/values.VBoolean.md)<`Type`, `IsOptional`> | [`VNull`](/api/classes/values.VNull.md)<`Type`, `IsOptional`> | [`VAny`](/api/classes/values.VAny.md)<`Type`, `IsOptional`> | [`VLiteral`](/api/classes/values.VLiteral.md)<`Type`, `IsOptional`> | [`VBytes`](/api/classes/values.VBytes.md)<`Type`, `IsOptional`> | [`VObject`](/api/classes/values.VObject.md)<`Type`, `Record`<`string`, [`Validator`](/api/modules/values.md#validator)<`any`, [`OptionalProperty`](/api/modules/values.md#optionalproperty), `any`>>, `IsOptional`, `FieldPaths`> | [`VArray`](/api/classes/values.VArray.md)<`Type`, [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`>, `IsOptional`> | [`VRecord`](/api/classes/values.VRecord.md)<`Type`, [`Validator`](/api/modules/values.md#validator)<`string`, `"required"`, `any`>, [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`>, `IsOptional`, `FieldPaths`> | [`VUnion`](/api/classes/values.VUnion.md)<`Type`, [`Validator`](/api/modules/values.md#validator)<`any`, `"required"`, `any`>\[], `IsOptional`, `FieldPaths`> A validator for a Convex value. This should be constructed using the validator builder, [v](/api/modules/values.md#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[​](#type-parameters-4 "Direct link to Type parameters") | Name | Type | | ------------ | ------------------------------------------------------------------------------------ | | `Type` | `Type` | | `IsOptional` | extends [`OptionalProperty`](/api/modules/values.md#optionalproperty) = `"required"` | | `FieldPaths` | extends `string` = `never` | #### Defined in[​](#defined-in-7 "Direct link to Defined in") [values/validators.ts:676](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L676) *** ### ObjectFieldType[​](#objectfieldtype "Direct link to ObjectFieldType") Ƭ **ObjectFieldType**: `Object` #### Type declaration[​](#type-declaration "Direct link to Type declaration") | Name | Type | | ----------- | ------------------------------------------------------- | | `fieldType` | [`ValidatorJSON`](/api/modules/values.md#validatorjson) | | `optional` | `boolean` | #### Defined in[​](#defined-in-8 "Direct link to Defined in") [values/validators.ts:717](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L717) *** ### ValidatorJSON[​](#validatorjson "Direct link to ValidatorJSON") Ƭ **ValidatorJSON**: { `type`: `"null"` } | { `type`: `"number"` } | { `type`: `"bigint"` } | { `type`: `"boolean"` } | { `type`: `"string"` } | { `type`: `"bytes"` } | { `type`: `"any"` } | { `type`: `"literal"` ; `value`: [`JSONValue`](/api/modules/values.md#jsonvalue) } | { `type`: `"id"` ; `tableName`: `string` } | { `type`: `"array"` ; `value`: [`ValidatorJSON`](/api/modules/values.md#validatorjson) } | { `type`: `"record"` ; `keys`: [`RecordKeyValidatorJSON`](/api/modules/values.md#recordkeyvalidatorjson) ; `values`: [`RecordValueValidatorJSON`](/api/modules/values.md#recordvaluevalidatorjson) } | { `type`: `"object"` ; `value`: `Record`<`string`, [`ObjectFieldType`](/api/modules/values.md#objectfieldtype)> } | { `type`: `"union"` ; `value`: [`ValidatorJSON`](/api/modules/values.md#validatorjson)\[] } #### Defined in[​](#defined-in-9 "Direct link to Defined in") [values/validators.ts:719](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L719) *** ### RecordKeyValidatorJSON[​](#recordkeyvalidatorjson "Direct link to RecordKeyValidatorJSON") Ƭ **RecordKeyValidatorJSON**: { `type`: `"string"` } | { `type`: `"id"` ; `tableName`: `string` } | { `type`: `"union"` ; `value`: [`RecordKeyValidatorJSON`](/api/modules/values.md#recordkeyvalidatorjson)\[] } #### Defined in[​](#defined-in-10 "Direct link to Defined in") [values/validators.ts:738](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L738) *** ### RecordValueValidatorJSON[​](#recordvaluevalidatorjson "Direct link to RecordValueValidatorJSON") Ƭ **RecordValueValidatorJSON**: [`ObjectFieldType`](/api/modules/values.md#objectfieldtype) & { `optional`: `false` } #### Defined in[​](#defined-in-11 "Direct link to Defined in") [values/validators.ts:743](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L743) *** ### JSONValue[​](#jsonvalue "Direct link to JSONValue") Ƭ **JSONValue**: `null` | `boolean` | `number` | `string` | [`JSONValue`](/api/modules/values.md#jsonvalue)\[] | { `[key: string]`: [`JSONValue`](/api/modules/values.md#jsonvalue); } The type of JavaScript values serializable to JSON. #### Defined in[​](#defined-in-12 "Direct link to Defined in") [values/value.ts:24](https://github.com/get-convex/convex-js/blob/main/src/values/value.ts#L24) *** ### GenericId[​](#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[​](#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[​](#defined-in-13 "Direct link to Defined in") [values/value.ts:52](https://github.com/get-convex/convex-js/blob/main/src/values/value.ts#L52) *** ### Value[​](#value "Direct link to Value") Ƭ **Value**: `null` | `bigint` | `number` | `boolean` | `string` | `ArrayBuffer` | [`Value`](/api/modules/values.md#value)\[] | { `[key: string]`: `undefined` | [`Value`](/api/modules/values.md#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[​](#defined-in-14 "Direct link to Defined in") [values/value.ts:66](https://github.com/get-convex/convex-js/blob/main/src/values/value.ts#L66) *** ### NumericValue[​](#numericvalue "Direct link to NumericValue") Ƭ **NumericValue**: `bigint` | `number` The types of [Value](/api/modules/values.md#value) that can be used to represent numbers. #### Defined in[​](#defined-in-15 "Direct link to Defined in") [values/value.ts:81](https://github.com/get-convex/convex-js/blob/main/src/values/value.ts#L81) ## Variables[​](#variables "Direct link to Variables") ### v[​](#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[​](#type-declaration-1 "Direct link to Type declaration") | Name | Type | | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | \(`tableName`: `TableName`) => [`VId`](/api/classes/values.VId.md)<[`GenericId`](/api/modules/values.md#genericid)<`TableName`>, `"required"`> | | `null` | () => [`VNull`](/api/classes/values.VNull.md)<`null`, `"required"`> | | `number` | () => [`VFloat64`](/api/classes/values.VFloat64.md)<`number`, `"required"`> | | `float64` | () => [`VFloat64`](/api/classes/values.VFloat64.md)<`number`, `"required"`> | | `bigint` | () => [`VInt64`](/api/classes/values.VInt64.md)<`bigint`, `"required"`> | | `int64` | () => [`VInt64`](/api/classes/values.VInt64.md)<`bigint`, `"required"`> | | `boolean` | () => [`VBoolean`](/api/classes/values.VBoolean.md)<`boolean`, `"required"`> | | `string` | () => [`VString`](/api/classes/values.VString.md)<`string`, `"required"`> | | `bytes` | () => [`VBytes`](/api/classes/values.VBytes.md)<`ArrayBuffer`, `"required"`> | | `literal` | \(`literal`: `T`) => [`VLiteral`](/api/classes/values.VLiteral.md)<`T`, `"required"`> | | `array` | \(`element`: `T`) => [`VArray`](/api/classes/values.VArray.md)<`T`\[`"type"`]\[], `T`, `"required"`> | | `object` | \(`fields`: `T`) => [`VObject`](/api/classes/values.VObject.md)<[`Expand`](/api/modules/server.md#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`](/api/classes/values.VRecord.md)<`Record`<[`Infer`](/api/modules/values.md#infer)<`Key`>, `Value`\[`"type"`]>, `Key`, `Value`, `"required"`, `string`> | | `union` | \(...`members`: `T`) => [`VUnion`](/api/classes/values.VUnion.md)<`T`\[`number`]\[`"type"`], `T`, `"required"`, `T`\[`number`]\[`"fieldPaths"`]> | | `any` | () => [`VAny`](/api/classes/values.VAny.md)<`any`, `"required"`, `string`> | | `optional` | \(`value`: `T`) => [`VOptional`](/api/modules/values.md#voptional)<`T`> | | `nullable` | \(`value`: `T`) => [`VUnion`](/api/classes/values.VUnion.md)<`T` \| [`VNull`](/api/classes/values.VNull.md)<`null`, `"required"`>\[`"type"`], \[`T`, [`VNull`](/api/classes/values.VNull.md)<`null`, `"required"`>], `"required"`, `T` \| [`VNull`](/api/classes/values.VNull.md)<`null`, `"required"`>\[`"fieldPaths"`]> | #### Defined in[​](#defined-in-16 "Direct link to Defined in") [values/validator.ts:80](https://github.com/get-convex/convex-js/blob/main/src/values/validator.ts#L80) ## Functions[​](#functions "Direct link to Functions") ### compareValues[​](#comparevalues "Direct link to compareValues") ▸ **compareValues**(`k1`, `k2`): `number` #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | ---- | ------------------------------------------------------ | | `k1` | `undefined` \| [`Value`](/api/modules/values.md#value) | | `k2` | `undefined` \| [`Value`](/api/modules/values.md#value) | #### Returns[​](#returns "Direct link to Returns") `number` #### Defined in[​](#defined-in-17 "Direct link to Defined in") [values/compare.ts:4](https://github.com/get-convex/convex-js/blob/main/src/values/compare.ts#L4) *** ### asObjectValidator[​](#asobjectvalidator-1 "Direct link to asObjectValidator") ▸ **asObjectValidator**<`V`>(`obj`): `V` extends [`Validator`](/api/modules/values.md#validator)<`any`, `any`, `any`> ? `V` : `V` extends [`PropertyValidators`](/api/modules/values.md#propertyvalidators) ? [`Validator`](/api/modules/values.md#validator)<[`ObjectType`](/api/modules/values.md#objecttype)<`V`>> : `never` Coerce an object with validators as properties to a validator. If a validator is passed, return it. #### Type parameters[​](#type-parameters-6 "Direct link to Type parameters") | Name | Type | | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `V` | extends [`PropertyValidators`](/api/modules/values.md#propertyvalidators) \| [`Validator`](/api/modules/values.md#validator)<`any`, `any`, `any`> | #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | | ----- | ---- | | `obj` | `V` | #### Returns[​](#returns-1 "Direct link to Returns") `V` extends [`Validator`](/api/modules/values.md#validator)<`any`, `any`, `any`> ? `V` : `V` extends [`PropertyValidators`](/api/modules/values.md#propertyvalidators) ? [`Validator`](/api/modules/values.md#validator)<[`ObjectType`](/api/modules/values.md#objecttype)<`V`>> : `never` #### Defined in[​](#defined-in-18 "Direct link to Defined in") [values/validator.ts:39](https://github.com/get-convex/convex-js/blob/main/src/values/validator.ts#L39) *** ### jsonToConvex[​](#jsontoconvex "Direct link to jsonToConvex") ▸ **jsonToConvex**(`value`): [`Value`](/api/modules/values.md#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[​](#parameters-2 "Direct link to Parameters") | Name | Type | Description | | ------- | ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | | `value` | [`JSONValue`](/api/modules/values.md#jsonvalue) | The JSON representation of a Convex value previously created with [convexToJson](/api/modules/values.md#convextojson). | #### Returns[​](#returns-2 "Direct link to Returns") [`Value`](/api/modules/values.md#value) The JavaScript representation of the Convex value. #### Defined in[​](#defined-in-19 "Direct link to Defined in") [values/value.ts:187](https://github.com/get-convex/convex-js/blob/main/src/values/value.ts#L187) *** ### convexToJson[​](#convextojson "Direct link to convexToJson") ▸ **convexToJson**(`value`): [`JSONValue`](/api/modules/values.md#jsonvalue) Convert a Convex value to its JSON representation. Use [jsonToConvex](/api/modules/values.md#jsontoconvex) to recreate the original value. To learn more about Convex values, see [Types](https://docs.convex.dev/using/types). #### Parameters[​](#parameters-3 "Direct link to Parameters") | Name | Type | Description | | ------- | --------------------------------------- | ------------------------------------ | | `value` | [`Value`](/api/modules/values.md#value) | A Convex value to convert into JSON. | #### Returns[​](#returns-3 "Direct link to Returns") [`JSONValue`](/api/modules/values.md#jsonvalue) The JSON representation of `value`. #### Defined in[​](#defined-in-20 "Direct link to Defined in") [values/value.ts:429](https://github.com/get-convex/convex-js/blob/main/src/values/value.ts#L429) --- # Namespace: Base64 [values](/api/modules/values.md).Base64 ## Functions[​](#functions "Direct link to Functions") ### byteLength[​](#bytelength "Direct link to byteLength") ▸ **byteLength**(`b64`): `number` #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | | ----- | -------- | | `b64` | `string` | #### Returns[​](#returns "Direct link to Returns") `number` #### Defined in[​](#defined-in "Direct link to Defined in") [values/base64.ts:44](https://github.com/get-convex/convex-js/blob/main/src/values/base64.ts#L44) *** ### toByteArray[​](#tobytearray "Direct link to toByteArray") ▸ **toByteArray**(`b64`): `Uint8Array` #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | | ----- | -------- | | `b64` | `string` | #### Returns[​](#returns-1 "Direct link to Returns") `Uint8Array` #### Defined in[​](#defined-in-1 "Direct link to Defined in") [values/base64.ts:56](https://github.com/get-convex/convex-js/blob/main/src/values/base64.ts#L56) *** ### fromByteArray[​](#frombytearray "Direct link to fromByteArray") ▸ **fromByteArray**(`uint8`): `string` #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | | ------- | ------------ | | `uint8` | `Uint8Array` | #### Returns[​](#returns-2 "Direct link to Returns") `string` #### Defined in[​](#defined-in-2 "Direct link to Defined in") [values/base64.ts:123](https://github.com/get-convex/convex-js/blob/main/src/values/base64.ts#L123) *** ### fromByteArrayUrlSafeNoPadding[​](#frombytearrayurlsafenopadding "Direct link to fromByteArrayUrlSafeNoPadding") ▸ **fromByteArrayUrlSafeNoPadding**(`uint8`): `string` #### Parameters[​](#parameters-3 "Direct link to Parameters") | Name | Type | | ------- | ------------ | | `uint8` | `Uint8Array` | #### Returns[​](#returns-3 "Direct link to Returns") `string` #### Defined in[​](#defined-in-3 "Direct link to Defined in") [values/base64.ts:158](https://github.com/get-convex/convex-js/blob/main/src/values/base64.ts#L158) --- # Authentication Convex deployment endpoints are exposed to the open internet and the claims clients make about who they are must be authenticated 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 (including your own Convex backend) that implement the appropriate OAuth endpoints to verify them. ## Third-party authentication platforms[​](#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](/auth/clerk.md) has great Next.js and React Native support * [WorkOS AuthKit](/auth/authkit/.md) is built for B2B apps and free for up to 1M users * [Auth0](/auth/auth0.md) is more established with more bells and whistles * [Custom Auth Integration](/auth/advanced/custom-auth.md) 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](/auth/functions-auth.md) and storing user information in the [Database](/auth/database-auth.md). ## The Convex Auth Library[​](#the-convex-auth-library "Direct link to The Convex Auth Library") For client-side React and React Native mobile apps you can implement auth directly in Convex with the [Convex Auth](/auth/convex-auth.md) 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 Auth is currently a [beta feature](/production/state/.md#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[​](#debugging "Direct link to Debugging") If you run into issues consult the [Debugging](/auth/debug.md) guide. ## Service Authentication[​](#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. ## Authorization[​](#authorization "Direct link to Authorization") Convex enables a traditional three tier application structure: a client/UI for your app, a backend that handles user requests, and a database for queries. This architecture lets you check every public request against any authorization rules you can define in code. This means Convex doesn't need an opinionated authorization framework like RLS, which is required in client oriented databases like Firebase or Supabase. This flexibility lets you build and use an [authorization framework](https://en.wikipedia.org/wiki/Authorization) for your needs. That said, the most common way is to simply write code that checks if the user is logged in and if they are allowed to do the requested action at the beginning of each public function. For example, the following function enforces that only the currently authenticated user can remove their own user image: ``` export const removeUserImage = mutation({ args: {}, handler: async (ctx) => { const userId = await getAuthUserId(ctx); if (!userId) { return; } ctx.db.patch(userId, { imageId: undefined, image: undefined }); }, }); ``` Related posts from [![Stack](/img/stack-logo-dark.svg)![Stack](/img/stack-logo-light.svg)](https://stack.convex.dev/) --- # Custom OIDC Provider **Note: This is an advanced feature!** We recommend sticking with the [supported third-party authentication providers](/auth.md). Convex can be integrated with any identity provider supporting the [OpenID Connect](https://openid.net/connect/) protocol. At minimum this means that the provider can issue [ID tokens](https://openid.net/specs/openid-connect-core-1_0.html#IDToken) and exposes the corresponding [JWKS](https://auth0.com/docs/secure/tokens/json-web-tokens/json-web-key-sets). The ID token is passed from the client to your Convex backend which ensures that the token is valid and enables you to query the user information embedded in the token, as described in [Auth in Functions](/auth/functions-auth.md). ## Server-side integration[​](#server-side-integration "Direct link to Server-side integration") Just like with [Clerk](/auth/clerk.md) and [Auth0](/auth/auth0.md), the backend needs to be aware of the domain of the Issuer and your application's specific applicationID for a given identity provider. Add these to your `convex/auth.config.ts` file: convex/auth.config.ts TS ``` import { AuthConfig } from "convex/server"; export default { providers: [ { domain: "https://your.issuer.url.com", applicationID: "your-application-id", }, ], } satisfies AuthConfig; ``` The `applicationID` property must exactly match the `aud` field of your JWT and the `domain` property must exactly match the `iss` field of the JWT. Use a tool like [jwt.io](https://jwt.io/) to view an JWT and confirm these fields match exactly. If multiple providers are provided, the first one fulfilling the above criteria will be used. If you're not able to obtain tokens with an `aud` field, you'll need to instead configure a [Custom JWT](/auth/advanced/custom-jwt.md). If you're not sure if your token is an OIDC ID token, check [the spec](https://openid.net/specs/openid-connect-core-1_0-final.html#rfc.section.2) for a list of all required fields. OIDC requires the routes `${domain}/.well-known/jwks.json` and `${domain}/.well-known/openid-configuration`. `domain` may include a path like `https://your.issuer.url.com/api/auth`. This isn't common for third party auth providers but may be useful if you're implementing OIDC on your own server. ## Client-side integration[​](#client-side-integration "Direct link to Client-side integration") ### Integrating a new identity provider[​](#integrating-a-new-identity-provider "Direct link to Integrating a new identity provider") The [`ConvexProviderWithAuth`](/api/modules/react.md#convexproviderwithauth) component provides a convenient abstraction for building an auth integration similar to the ones Convex provides for [Clerk](/auth/clerk.md) and [Auth0](/auth/auth0.md). In the following example we build an integration with an imaginary "ProviderX", whose React integration includes `AuthProviderXReactProvider` and `useProviderXAuth` hook. First we replace `ConvexProvider` with `AuthProviderXReactProvider` wrapping `ConvexProviderWithAuth` at the root of our app: src/index.js ``` import { AuthProviderXReactProvider } from "providerX"; import { ConvexProviderWithAuth } from "convex/react"; root.render( , ); ``` All we really need is to implement the `useAuthFromProviderX` hook which gets passed to the `ConvexProviderWithAuth` component. This `useAuthFromProviderX` hook provides a translation between the auth provider API and the [`ConvexReactClient`](/api/classes/react.ConvexReactClient.md) API, which is ultimately responsible for making sure that the ID token is passed down to your Convex backend. src/ConvexProviderWithProviderX.js ``` function useAuthFromProviderX() { const { isLoading, isAuthenticated, getToken } = useProviderXAuth(); const fetchAccessToken = useCallback( async ({ forceRefreshToken }) => { // Here you can do whatever transformation to get the ID Token // or null // Make sure to fetch a new token when `forceRefreshToken` is true return await getToken({ ignoreCache: forceRefreshToken }); }, // If `getToken` isn't correctly memoized // remove it from this dependency array [getToken], ); return useMemo( () => ({ // Whether the auth provider is in a loading state isLoading: isLoading, // Whether the auth provider has the user signed in isAuthenticated: isAuthenticated ?? false, // The async function to fetch the ID token fetchAccessToken, }), [isLoading, isAuthenticated, fetchAccessToken], ); } ``` ### Using the new provider[​](#using-the-new-provider "Direct link to Using the new provider") If you successfully follow the steps above you can now use the standard Convex utilities for checking the authentication state: the [`useConvexAuth()`](/api/modules/react.md#useconvexauth) hook and the [`Authenticated`](/api/modules/react.md#authenticated), [`Unauthenticated`](/api/modules/react.md#authenticated) and [`AuthLoading`](/api/modules/react.md#authloading) helper components. ### Debugging[​](#debugging "Direct link to Debugging") See [Debugging Authentication](/auth/debug.md). Related posts from [![Stack](/img/stack-logo-dark.svg)![Stack](/img/stack-logo-light.svg)](https://stack.convex.dev/) --- # Custom JWT Provider **Note: This is an advanced feature!** We recommend sticking with the [supported third-party authentication providers](/auth.md). A [JWT](https://en.wikipedia.org/wiki/JSON_Web_Token) is a string combining three base64-encoded JSON objects containing claims about who a user is valid for a limited period of time like an hour. You can create them with a library like [jose](https://github.com/panva/jose) after receiving some evidence (typically a cookie) of a user's identity or get them from a third party authentication service like [Clerk](https://clerk.com). The information in a JWT is signed (the Convex deployment can tell the information is really from the issuer and hasn't been modified) but generally not encrypted (you can read it by base64-decoding the token or pasting it into [jwt.io](https://jwt.io/). If the JWTs issued to your users by an authentication service contain the right fields to implement the OpenID Connect (OIDC) protocol, the easiest way to configure accepting these JWTs is adding an [OIDC Provider](/auth/advanced/custom-auth.md) entry in `convex/auth.config.ts`. If the authentication service or library you're using to issue JWTs doesn't support these fields (for example [OpenAuth](https://openauth.js.org/) JWTs missing an `aud` field because they implement the OAuth 2.0 spec but not OIDC) you'll need to configure a Custom JWT provider in the `convex/auth.config.ts` file. Custom JWTs are required only to have header fields `kid`, `alg` and `typ`, and payload fields `sub`, `iss`, and `exp`. An `iat` field is also expected by Convex clients to implement token refreshing. ## Server-side integration[​](#server-side-integration "Direct link to Server-side integration") Use `type: "customJwt"` to configure a Custom JWT auth provider: convex/auth.config.ts TS ``` import { AuthConfig } from "convex/server"; export default { providers: [ { type: "customJwt", applicationID: "your-application-id", issuer: "https://your.issuer.url.com", jwks: "https://your.issuer.url.com/.well-known/jwks.json", algorithm: "RS256", }, ], }; ``` * `applicationID`: Convex will verify that JWTs have this value in the `aud` claim. See below for important information regarding leaving this field out. The applicationID field is not required, but necessary to use with many authentication providers for security. Read more below before omitting it. * `issuer`: The issuer URL of the JWT. * `jwks`: The URL for fetching the JWKS (JSON Web Key Set) from the auth provider. If you'd like to avoid hitting an external service you may use a data URI, e.g. `"data:text/plain;charset=utf-8;base64,ey..."` * `algorithm`: The algorithm used to sign the JWT. Only RS256 and ES256 are currently supported. See [RFC 7518](https://datatracker.ietf.org/doc/html/rfc7518#section-3.1) for more details. The `issuer` property must exactly match the `iss` field of the JWT used and if specified the `applicationID` property must exactly match the `aud` field. If your JWT doesn't match, use a tool like [jwt.io](https://jwt.io/) to view an JWT and confirm these fields match exactly. ### Warning: omitting `applicationID` is often insecure[​](#warning-omitting-applicationid-is-often-insecure "Direct link to warning-omitting-applicationid-is-often-insecure") Leaving out `applicationID` from an auth configuration means the `aud` (audience) field of your users' JWTs will not be verified. In many cases this is insecure because a JWT intended for another service can be used to impersonate them in your service. Say a user has accounts with `https://todos.com` and `https://banking.com`, two services which use the same third-party authentication service, `accounts.google.com`. A JWT accepted by todos.com could be reused to authenticate with banking.com by either todos.com or an attacker that obtained access to that JWT. The `aud` (audience) field of the JWT prevents this: if the JWT was generated for a specific audience of `https://todos.com` then banking.com can enforce the `aud` field and know not to accept it. If the JWTs issued to your users have an `iss` (issuer) URL like `https://accounts.google.com` that is not specific to your application, it is not secure to trust these tokens without an ApplicationID because that JWT could have been collected by a malicious application. If the JWTs issued to your users have a more specific `iss` field like `https://api.3rd-party-auth.com/client_0123...` then it may be secure to use no `aud` field if you control all the services the issuer url grants then access to and intend for access to any one of these services to grants access to all of them. ### Custom claims[​](#custom-claims "Direct link to Custom claims") In addition to top-level fields like `subject`, `issuer`, and `tokenIdentifier`, subfields of the nested fields of the JWT will be accessible in the auth data returned from `const authInfo = await ctx.auth.getUserIdentity()` like `authInfo["properties.id"]` and `authInfo["properties.favoriteColor"]` for a JWT structured like this: ``` { "properties": { "id": "123", "favoriteColor": "red" }, "iss": "http://localhost:3000", "sub": "user:8fa2be73c2229e85", "exp": 1750968478 } ``` ## Client-side integration[​](#client-side-integration "Direct link to Client-side integration") Your users' browsers need a way to obtain an initial JWT and to request updated JWTs, ideally before the previous one expires. See the instructions for [Custom OIDC Providers](/auth/advanced/custom-auth.md#client-side-integration) for how to do this. --- # Convex & Auth0 [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/nextjs). ## Get started[​](#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](/quickstart/react.md) 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](/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 ``` import { AuthConfig } from "convex/server"; export default { providers: [ { domain: "your-domain.us.auth0.com", applicationID: "yourclientid", }, ] } satisfies AuthConfig; ``` 3. Deploy your changes Run `npx convex dev` to automatically sync your configuration to your backend. ``` 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 ``` 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[​](#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 ``` 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 ``` import { useAuth0 } from "@auth0/auth0-react"; export default function LogoutButton() { const { logout } = useAuth0(); return ( ); } ``` ## Logged-in and logged-out views[​](#logged-in-and-logged-out-views "Direct link to Logged-in and logged-out views") Use the [`useConvexAuth()`](/api/modules/react.md#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 ``` 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 ``` import { Authenticated, Unauthenticated, AuthLoading } from "convex/react"; function App() { return (
Logged in Logged out Still loading
); } ``` ## User information in React[​](#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 ``` import { useAuth0 } from "@auth0/auth0-react"; export default function Badge() { const { user } = useAuth0(); return Logged in as {user.name}; } ``` ## User information in functions[​](#user-information-in-functions "Direct link to User information in functions") See [Auth in Functions](/auth/functions-auth.md) to learn about how to access information about the authenticated user in your queries, mutations and actions. See [Storing Users in the Convex Database](/auth/database-auth.md) to learn about how to store user information in the Convex database. ## Configuring dev and prod tenants[​](#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[​](#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 ``` import { AuthConfig } from "convex/server"; export default { providers: [ { domain: process.env.AUTH0_DOMAIN!, applicationID: process.env.AUTH0_CLIENT_ID!, }, ], } satisfies AuthConfig; ``` **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](/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[​](#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](/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 ``` 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](/quickstarts) or the relevant documentation for the platform you're using: .env.local ``` 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](/production/hosting/.md). ## Debugging authentication[​](#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](/auth/debug.md). ## Under the hood[​](#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. --- # Convex & WorkOS AuthKit [WorkOS AuthKit](https://authkit.com) is an authentication solution that enables sign-in using passwords, social login providers, email one-time codes, two-factor authentication, and user management capabilities. ## Get started[​](#get-started "Direct link to Get started") The quickest way to get started is to create an [associated WorkOS account](/auth/authkit/auto-provision.md) through the Convex CLI. ``` npm create convex@latest -- -t react-vite-authkit cd my-app # or whatever you name the directory npm run dev ``` Follow the prompts to create a WorkOS team that will be associated with your Convex team. After this Convex deployments for projects in this team will be able to automatically provision and configure their own WorkOS environments. That's it! After this you and other members of your Convex team can create and configure development WorkOS environments without visiting [workos.com](https://workos.com). ### Configuring an existing WorkOS account[​](#configuring-an-existing-workos-account "Direct link to Configuring an existing WorkOS account") To use AuthKit with an existing WorkOS account you'll need to configure the account and copy credentials into the Convex deployment and your local `.env.local` file. 1. Sign up for WorkOS Sign up for a free WorkOS account at [workos.com/sign-up](https://signin.workos.com/sign-up). ![Sign up for a WorkOS account](/screenshots/workos-signup.png) 2. Set up AuthKit In the WorkOS Dashboard, navigate to **Authentication** and then to **AuthKit**. From here, click the **Set up AuthKit** button to enable AuthKit in your account. ![Set up AuthKit in your account](/screenshots/workos-setup-authkit.png) 3. Complete AuthKit setup Press the **Begin setup** button with **Use AuthKit's customizable hosted UI** selected. These options can be filled out however you like until you get to step 4, **Add default redirect endpoint URI**. The Redirect URI is the endpoint that WorkOS will return an authorization code to after signing in. This should match your application's domain and port, with `/callback` as the route. For example, if your application is running at `localhost:5173` then the value here should be `http://localhost:5173/callback`. Complete the AuthKit setup. ![Set the redirect URI endpoint](/screenshots/workos-redirect-uri.png) 4. Copy your Client ID and API Key From the [get started](https://dashboard.workos.com/get-started) page under **Quick start**, find your `WORKOS_CLIENT_ID` and copy it. ![Getting your WorkOS Client ID](/screenshots/workos-client-id.png) ## Client configuration[​](#client-configuration "Direct link to Client configuration") Convex offers a provider that is specifically for integrating with WorkOS AuthKit called ``. It works using WorkOS's [authkit-react](https://github.com/workos/authkit-react) SDK. Once you've completed the WorkOS setup above, choose your framework below to continue with the integration. See the following sections for the WorkOS SDK that you're using: * [React](#react) - Use this as a starting point if your SDK is not listed * [Next.js](#nextjs) ### React[​](#react "Direct link to React") **Example:** [React with Convex and AuthKit](https://github.com/workos/template-convex-react-vite-authkit) This guide assumes you have [AuthKit set up](#configuring-an-existing-workos-account) and have a working React app with Convex. If not follow the [Convex React Quickstart](/quickstart/react.md) first. Then: 1. Set up CORS in the WorkOS Dashboard In your WorkOS Dashboard, go to [*Authentication* > *Sessions*](https://dashboard.workos.com/environment/authentication/sessions) > *Cross-Origin Resource Sharing (CORS)* and click on **Manage**. Add your local development domain (e.g., `http://localhost:5173` for Vite) to the list. You'll also need to add your production domain when you deploy. This enables your application to authenticate users through WorkOS AuthKit. ![Setting up CORS](/screenshots/workos-cors-setup.png) 2. Set up your environment variables In your `.env.local` file, add your `WORKOS_CLIENT_ID` and `WORKOS_REDIRECT_URI` environment variables. If you're using Vite, you'll need to prefix it with `VITE_`. **Note:** These values can be found in your [WorkOS Dashboard](https://dashboard.workos.com/). .env.local ``` # WorkOS AuthKit Configuration VITE_WORKOS_CLIENT_ID=your-workos-client-id-here VITE_WORKOS_REDIRECT_URI=http://localhost:5173/callback ``` 3. Configure Convex with the WorkOS Client ID In your app's `convex` folder, create a new file `auth.config.ts` with the following code. This is the server-side configuration for validating access tokens. convex/auth.config.ts TS ``` const clientId = process.env.WORKOS_CLIENT_ID; const authConfig = { providers: [ { type: 'customJwt', issuer: `https://api.workos.com/`, algorithm: 'RS256', jwks: `https://api.workos.com/sso/jwks/${clientId}`, applicationID: clientId, }, { type: 'customJwt', issuer: `https://api.workos.com/user_management/${clientId}`, algorithm: 'RS256', jwks: `https://api.workos.com/sso/jwks/${clientId}`, }, ], }; export default authConfig; ``` 4. Deploy your changes Run `npx convex dev` to automatically sync your configuration to your backend. You'll see an error and a link to click to fill in the WORKOS\_CLIENT\_ID environment variable in your Convex deployment. Follow the link, paste in the WorkOS client ID, save, and you should see the `npx convex dev` command show "Convex functions ready." ``` npx convex dev ``` 5. Install AuthKit In a new terminal window, install the AuthKit React SDK: ``` npm install @workos-inc/authkit-react @convex-dev/workos ``` 6. Configure ConvexProviderWithAuthKit AuthKit and Convex both have provider components that provide authentication and client context to your app. You should already have `` wrapping your app. Replace it with ``, and pass WorkOS's `useAuth()` hook to it. Then, wrap it with ``. `` requires `clientId` and `redirectUri` props, which you can set to `VITE_WORKOS_CLIENT_ID` and `VITE_WORKOS_REDIRECT_URI`, respectively. src/main.tsx TS ``` import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import { AuthKitProvider, useAuth } from "@workos-inc/authkit-react"; import { ConvexReactClient } from "convex/react"; import { ConvexProviderWithAuthKit } from "@convex-dev/workos"; import "./index.css"; import App from "./App.tsx"; const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL); createRoot(document.getElementById("root")!).render( , ); ``` 7. Show UI based on authentication state You can control which UI is shown when the user is signed in or signed out using Convex's ``, `` and `` helper components. It's important to use the [`useConvexAuth()`](/api/modules/react.md#useconvexauth) hook instead of AuthKit'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. In the following example, the `` component is a child of ``, so its content and any of its child components are guaranteed to have an authenticated user, and Convex queries can require authentication. src/App.tsx TS ``` import { Authenticated, Unauthenticated, useQuery } from 'convex/react'; import { api } from '../convex/_generated/api'; import { useAuth } from '@workos-inc/authkit-react'; export default function App() { const { user, signIn, signOut } = useAuth(); return (

Convex + AuthKit

Please sign in to view data

); } function Content() { const data = useQuery(api.myFunctions.listNumbers, { count: 10 }); if (!data) return

Loading...

; return (

Welcome {data.viewer}!

Numbers: {data.numbers?.join(', ') || 'None'}

); } ``` 8. 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 `` from `convex/react`**. Otherwise, it will throw on page load. convex/myFunctions.ts TS ``` import { v } from "convex/values"; import { query } from "./_generated/server"; export const listNumbers = query({ args: { count: v.number(), }, handler: async (ctx, args) => { const numbers = await ctx.db .query("numbers") // Ordered by _creationTime, return most recent .order("desc") .take(args.count); return { viewer: (await ctx.auth.getUserIdentity())?.name ?? null, numbers: numbers.reverse().map((number) => number.value), }; }, }); ``` **Note:** The [React template repository](https://github.com/workos/template-convex-react-vite-authkit) includes additional features and functions for a complete working application. This tutorial covers the core integration steps, but the template provides a more comprehensive implementation. ### Next.js[​](#nextjs "Direct link to Next.js") **Example:** [Next.js with Convex and AuthKit](https://github.com/workos/template-convex-nextjs-authkit) This guide assumes you have [AuthKit set up](#configuring-an-existing-workos-account) and have a working Next.js app with Convex. If not follow the [Convex Next.js Quickstart](/quickstart/nextjs.md) first. Then: 1. Set up your environment variables In your `.env.local` file, add the following environment variables: .env.local ``` # WorkOS AuthKit Configuration WORKOS_CLIENT_ID=client_your_client_id_here WORKOS_API_KEY=sk_test_your_api_key_here WORKOS_COOKIE_PASSWORD=your_secure_password_here_must_be_at_least_32_characters_long NEXT_PUBLIC_WORKOS_REDIRECT_URI=http://localhost:3000/callback # Convex Configuration (you don't have to fill these out, they're generated by Convex) # Deployment used by `npx convex dev` CONVEX_DEPLOY_KEY=your_convex_deploy_key_here NEXT_PUBLIC_CONVEX_URL=https://your-convex-url.convex.cloud ``` 2. Configure Convex with the WorkOS Client ID In your app's `convex` folder, create a new file `auth.config.ts` with the following code. This is the server-side configuration for validating access tokens. convex/auth.config.ts TS ``` const clientId = process.env.WORKOS_CLIENT_ID; const authConfig = { providers: [ { type: 'customJwt', issuer: `https://api.workos.com/`, algorithm: 'RS256', applicationID: clientId, jwks: `https://api.workos.com/sso/jwks/${clientId}`, }, { type: 'customJwt', issuer: `https://api.workos.com/user_management/${clientId}`, algorithm: 'RS256', jwks: `https://api.workos.com/sso/jwks/${clientId}`, }, ], }; export default authConfig; ``` 3. Deploy your changes Run `npx convex dev` to automatically sync your configuration to your backend. You'll see an error and a link to click to fill in the WORKOS\_CLIENT\_ID environment variable in your Convex deployment. Follow the link, paste in the WorkOS client ID, save, and you should see the `npx convex dev` command show "Convex functions ready." ``` npx convex dev ``` 4. Install AuthKit In a new terminal window, install the AuthKit Next.js SDK: ``` npm install @workos-inc/authkit-nextjs @convex-dev/workos ``` 5. Add AuthKit middleware AuthKit's `authkitMiddleware()` helper grants you access to user authentication state throughout your app. Create a `middleware.ts` file. In your `middleware.ts` file, export the `authkitMiddleware()` helper: ``` import { authkitMiddleware } from '@workos-inc/authkit-nextjs'; export default authkitMiddleware({ middlewareAuth: { enabled: true, unauthenticatedPaths: ['/', '/sign-in', '/sign-up'], }, }); export const config = { matcher: [ // Skip Next.js internals and all static files, unless found in search params '/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)', // Always run for API routes '/(api|trpc)(.*)', ], }; ``` 6. Add authentication routes Create the required authentication routes for WorkOS AuthKit to handle sign-in, sign-up, and callback flows. These routes enable the authentication flow by providing endpoints for users to sign in, sign up, and return after authentication. **Create the callback route** to handle OAuth callbacks: app/callback/route.ts TS ``` import { handleAuth } from '@workos-inc/authkit-nextjs'; export const GET = handleAuth(); ``` 7. Create the sign-in route app/sign-in/route.ts TS ``` import { redirect } from 'next/navigation'; import { getSignInUrl } from '@workos-inc/authkit-nextjs'; export async function GET() { const authorizationUrl = await getSignInUrl(); return redirect(authorizationUrl); } ``` 8. Create the sign-up route To redirect users to WorkOS sign-up: app/sign-up/route.ts TS ``` import { redirect } from 'next/navigation'; import { getSignUpUrl } from '@workos-inc/authkit-nextjs'; export async function GET() { const authorizationUrl = await getSignUpUrl(); return redirect(authorizationUrl); } ``` 9. Configure ConvexProviderWithAuthKit Your Next.js app needs to connect AuthKit authentication with Convex for real-time data. We'll create a single provider component that handles both. **Create the Provider Component** This single component handles: * WorkOS authentication setup * Convex client initialization * Token management between WorkOS and Convex * Loading states and error handling Create `components/ConvexClientProvider.tsx`: components/ConvexClientProvider.tsx TS ``` 'use client'; import { ReactNode, useCallback, useRef } from 'react'; import { ConvexReactClient } from 'convex/react'; import { ConvexProviderWithAuth } from 'convex/react'; import { AuthKitProvider, useAuth, useAccessToken } from '@workos-inc/authkit-nextjs/components'; const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!); export function ConvexClientProvider({ children }: { children: ReactNode }) { return ( {children} ); } function useAuthFromAuthKit() { const { user, loading: isLoading } = useAuth(); const { accessToken, loading: tokenLoading, error: tokenError } = useAccessToken(); const loading = (isLoading ?? false) || (tokenLoading ?? false); const authenticated = !!user && !!accessToken && !loading; const stableAccessToken = useRef(null); if (accessToken && !tokenError) { stableAccessToken.current = accessToken; } const fetchAccessToken = useCallback(async () => { if (stableAccessToken.current && !tokenError) { return stableAccessToken.current; } return null; }, [tokenError]); return { isLoading: loading, isAuthenticated: authenticated, fetchAccessToken, }; } ``` 10. Add to your layout Update `app/layout.tsx` to use the provider: app/layout.tsx TS ``` import type { Metadata } from 'next'; import { Geist, Geist_Mono } from 'next/font/google'; import './globals.css'; import { ConvexClientProvider } from '@/components/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', icons: { icon: '/convex.svg', }, }; export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { return ( {children} ); } ``` 11. Show UI based on authentication state You can control which UI is shown when the user is signed in or signed out using Convex's ``, `` and `` helper components. These should be used instead of WorkOS AuthKit's `useAuth()` loading states and manual authentication checks. It's important to use the [`useConvexAuth()`](/api/modules/react.md#useconvexauth) hook instead of WorkOS AuthKit'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. In the following example, the `` component is a child of ``, so its content and any of its child components are guaranteed to have an authenticated user, and Convex queries can require authentication. app/page.tsx TS ``` "use client"; import { Authenticated, Unauthenticated, useQuery } from "convex/react"; import { useAuth } from "@workos-inc/authkit-nextjs/components"; import { api } from "../convex/_generated/api"; import Link from "next/link"; export default function Home() { const { user, signOut } = useAuth(); return (

Convex + AuthKit

{user ? ( ) : ( <> )}

Please sign in to view data

); } function Content() { const data = useQuery(api.myFunctions.listNumbers, { count: 10 }); if (!data) return

Loading...

; return (

Welcome {data.viewer}!

Numbers: {data.numbers?.join(', ') || 'None'}

); } ``` 12. 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 `` from `convex/react`**. Otherwise, it will throw on page load. convex/myFunctions.ts TS ``` import { v } from "convex/values"; import { query } from "./_generated/server"; export const listNumbers = query({ args: { count: v.number(), }, handler: async (ctx, args) => { const numbers = await ctx.db .query("numbers") // Ordered by _creationTime, return most recent .order("desc") .take(args.count); return { viewer: (await ctx.auth.getUserIdentity())?.name ?? null, numbers: numbers.reverse().map((number) => number.value), }; }, }); ``` **Note:** The [Next.js template repository](https://github.com/workos/template-convex-nextjs-authkit) includes additional features and functions for a complete working application. This tutorial covers the core integration steps, but the template provides a more comprehensive implementation. ## Next steps[​](#next-steps "Direct link to Next steps") ### Accessing user information in functions[​](#accessing-user-information-in-functions "Direct link to Accessing user information in functions") See [Auth in Functions](/auth/functions-auth.md) to learn about how to access information about the authenticated user in your queries, mutations and actions. See [Storing Users in the Convex Database](/auth/database-auth.md) to learn about how to store user information in the Convex database. ### Accessing user information client-side[​](#accessing-user-information-client-side "Direct link to Accessing user information client-side") To access the authenticated user's information, use AuthKit's `User` object, which can be accessed using AuthKit's [`useAuth()`](https://github.com/workos/authkit-react?tab=readme-ov-file#useauth) hook. For more information on the `User` object, see the [WorkOS docs](https://workos.com/docs/reference/user-management/user). components/Badge.tsx TS ``` export default function Badge() { const { user } = useAuth(); return Logged in as {user.firstName}; } ``` ## Configuring dev and prod instances[​](#configuring-dev-and-prod-instances "Direct link to Configuring dev and prod instances") To configure a different AuthKit instance between your Convex development and production deployments, you can use environment variables configured on the Convex dashboard. ### Configuring the backend[​](#configuring-the-backend "Direct link to Configuring the backend") In the WorkOS Dashboard, navigate to the [**API keys**](https://dashboard.workos.com/api-keys) page. Copy your WorkOS Client ID. This Client ID is necessary for Convex to validate access tokens from WorkOS AuthKit. In development, its format will be `client_01XXXXXXXXXXXXXXXXXXXXXXXX`. In production, it will follow the same format but represent your production WorkOS application. Paste your WorkOS Client ID into your `.env` file, set it as the `WORKOS_CLIENT_ID` environment variable. Note that this environment variable is used server-side and does not need a `NEXT_PUBLIC_` prefix. .env ``` WORKOS_CLIENT_ID=client_01XXXXXXXXXXXXXXXXXXXXXXXX ``` Then, update your `convex/auth.config.ts` file to use the environment variable: convex/auth.config.ts TS ``` const clientId = process.env.WORKOS_CLIENT_ID; export default { providers: [ { type: "customJwt", issuer: `https://api.workos.com/`, algorithm: "RS256", applicationID: clientId, jwks: `https://api.workos.com/sso/jwks/${clientId}`, }, { type: "customJwt", issuer: `https://api.workos.com/user_management/${clientId}`, algorithm: "RS256", jwks: `https://api.workos.com/sso/jwks/${clientId}`, }, ], }; ``` **Development configuration** In the left sidenav of the Convex [dashboard](https://dashboard.convex.dev), switch to your development deployment and set the `WORKOS_CLIENT_ID` environment variable to your development WorkOS Client ID. Then, to switch your deployment to the new configuration, run `npx convex dev`. **Production configuration** In the left sidenav of the Convex [dashboard](https://dashboard.convex.dev), switch to your production deployment and set the `WORKOS_CLIENT_ID` environment variable to your production WorkOS Client ID. Then, to switch your deployment to the new configuration, run `npx convex deploy`. ### Configuring WorkOS AuthKit's API keys[​](#configuring-workos-authkits-api-keys "Direct link to Configuring WorkOS AuthKit's API keys") WorkOS AuthKit's API keys differ depending on whether they are for development or production. Don't forget to update the environment variables in your `.env` file as well as your hosting platform, such as Vercel or Netlify. **Development configuration** WorkOS API Key for development follows the format `sk_test_...`. WorkOS Client ID for development follows the format `client_01...`. .env.local ``` WORKOS_CLIENT_ID="client_01XXXXXXXXXXXXXXXXXXXXXXXX" WORKOS_API_KEY="sk_test_..." WORKOS_COOKIE_PASSWORD="your_secure_password_here_must_be_at_least_32_characters_long" NEXT_PUBLIC_WORKOS_REDIRECT_URI="http://localhost:3000/callback" ``` **Production configuration** WorkOS API Key for production follows the format `sk_live_...`. WorkOS Client ID for production follows the format `client_01...`. .env ``` WORKOS_CLIENT_ID="client_01XXXXXXXXXXXXXXXXXXXXXXXX" WORKOS_API_KEY="sk_live_..." WORKOS_COOKIE_PASSWORD="your_secure_password_here_must_be_at_least_32_characters_long" NEXT_PUBLIC_WORKOS_REDIRECT_URI="https://your-domain.com/callback" ``` ### Additional WorkOS AuthKit Configuration[​](#additional-workos-authkit-configuration "Direct link to Additional WorkOS AuthKit Configuration") WorkOS AuthKit requires additional configuration: **Cookie Password**: A secure password used to encrypt session cookies. This must be at least 32 characters long. You can generate a random one with `openssl rand -base64 24`. **Redirect URI**: The URL where users are redirected after authentication. This must be configured in both your environment variables and your WorkOS Dashboard application settings. ## Debugging authentication[​](#debugging-authentication "Direct link to Debugging authentication") If a user goes through the WorkOS AuthKit login flow successfully, and after being redirected back to your page, `useConvexAuth()` returns `isAuthenticated: false`, it's possible that your backend isn't correctly configured. The `convex/auth.config.ts` file 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. Common issues with WorkOS AuthKit integration: 1. **Incorrect Client ID**: Ensure the `WORKOS_CLIENT_ID` in your Convex environment matches your WorkOS application 2. **Missing Environment Variables**: Verify all required WorkOS environment variables are set in both your local environment and Convex dashboard 3. **Redirect URI Mismatch**: Ensure the `NEXT_PUBLIC_WORKOS_REDIRECT_URI` matches what's configured in your WorkOS Dashboard 4. **Missing `aud` claim**: WorkOS JWTs may not include the `aud` (audience) claim by default, which Convex requires for token validation. Check your WorkOS Dashboard JWT configuration to ensure the audience claim is properly set to your Client ID For more thorough debugging steps, see the WorkOS AuthKit documentation or [Debugging Authentication](/auth/debug.md). ## Under the hood[​](#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 AuthKit 3. After a successful login AuthKit redirects back to your page, or a different page which you configure via the [`redirectUri`](https://workos.com/docs/user-management/vanilla/nodejs/1-configure-your-project/configure-a-redirect-uri) prop . 4. The `AuthKitProvider` now knows that the user is authenticated. 5. The `ConvexProviderWithAuthKit` fetches an auth token from AuthKit . 6. The `ConvexReactClient` passes this token down to your Convex backend to validate 7. Your Convex backend retrieves the public key from AuthKit to check that the token's signature is valid. 8. The `ConvexReactClient` is notified of successful authentication, and `ConvexProviderWithAuthKit` now knows that the user is authenticated with Convex. `useConvexAuth` returns `isAuthenticated: true` and the `Authenticated` component renders its children. `ConvexProviderWithAuthKit` takes care of refetching the token when needed to make sure the user stays authenticated with your backend. --- # Automatic AuthKit Configuration AuthKit configuration can be automated for cloud dev deployments: each Convex deployment gets its own WorkOS environment configured and has local environment variables added to `.env.local` and Convex deployment environment variables set for it. This integration is in active development and will change as it continues to improve. Today the integration works with the two AuthKit templates offered when running `npm create convex@latest`. ## Creating WorkOS environments on-demand[​](#creating-workos-environments-on-demand "Direct link to Creating WorkOS environments on-demand") Automatically provisioning a WorkOS environment for a Convex deployment is enabled by creating a new WorkOS account and team to associate with a Convex team. Once this account has been created, any member of the Convex team can create a WorkOS environment for their development deployments on each of the team's projects. This happens automatically whenever the `WORKOS_CLIENT_ID` environment variable is read in the `convex/auth.config.ts` file but not set on the deployment during a `convex dev`. The CLI then makes AuthKit-related configuration changes that replace the [manual configuration steps](/auth/authkit/.md#configuring-an-existing-workos-account) required to configure AuthKit for a development Convex deployment. Currently this configures the following with the assumed local development domain: * redirect endpoint URI * CORS origin The following local environment variables may be set in `.env.local`: * `VITE_WORKOS_CLIENT_ID` (Vite only) * `WORKOS_CLIENT_ID` (Next.js only) * `*_WORKOS_REDIRECT_URI` (e.g. `VITE_WORKOS_REDIRECT_URI`) * `WORKOS_API_KEY` (Next.js only) * `WORKOS_COOKIE_PASSWORD` (Next.js only) ### Limitations[​](#limitations "Direct link to Limitations") WorkOS environments can currently only be created for cloud development deployments. Preview and production deployments must be manually configured. To manually configure the production deployment, visit the WorkOS page for the production environment for this project and [follow these steps](/auth/authkit/.md#configuring-an-existing-workos-account). Only one production deployment exists by default per WorkOS team so additional project may need to use separate WorkOS teams. --- # Convex & Clerk [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 user management. ## Get started[​](#get-started "Direct link to Get started") Convex offers a provider that is specifically for integrating with Clerk called ``. It works with any of Clerk's React-based SDKs, such as the Next.js and Expo SDKs. See the following sections for the Clerk SDK that you're using: * [React](#react) - Use this as a starting point if your SDK is not listed * [Next.js](#nextjs) * [TanStack Start](#tanstack-start) ### React[​](#react "Direct link to React") **Example:** [React with Convex and Clerk](https://github.com/get-convex/template-react-vite-clerk) This guide assumes you already have a working React app with Convex. If not follow the [Convex React Quickstart](/quickstart/react.md) first. Then: 1. 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](/screenshots/clerk-signup.png) 2. Create an application in Clerk Choose how you want your users to sign in. ![Create a Clerk application](/screenshots/clerk-createapp.png) 3. Create a JWT Template In the Clerk Dashboard, navigate to the [JWT templates](https://dashboard.clerk.com/last-active?path=jwt-templates) page. Select *New template* and then from the list of templates, select *Convex*. You'll be redirected to the template's settings page. **Do NOT rename the JWT token. It must be called `convex`.** Copy and save the *Issuer* URL somewhere secure. This URL is the issuer domain for Clerk's JWT templates, which is your Clerk app's *Frontend API URL*. In development, it's format will be `https://verb-noun-00.clerk.accounts.dev`. In production, it's format will be `https://clerk..com`. ![Create a JWT template](/screenshots/clerk-createjwt.png) 4. Configure Convex with the Clerk issuer domain In your app's `convex` folder, create a new file `auth.config.ts` with the following code. This is the server-side configuration for validating access tokens. convex/auth.config.ts TS ``` import { AuthConfig } from "convex/server"; export default { providers: [ { // Replace with your own Clerk Issuer URL from your "convex" JWT template // or with `process.env.CLERK_JWT_ISSUER_DOMAIN` // and configure CLERK_JWT_ISSUER_DOMAIN on the Convex Dashboard // See https://docs.convex.dev/auth/clerk#configuring-dev-and-prod-instances domain: process.env.CLERK_JWT_ISSUER_DOMAIN!, applicationID: "convex", }, ] } satisfies AuthConfig; ``` 5. Deploy your changes Run `npx convex dev` to automatically sync your configuration to your backend. ``` npx convex dev ``` 6. Install clerk In a new terminal window, install the Clerk React SDK: ``` npm install @clerk/clerk-react ``` 7. Set your Clerk API keys In the Clerk Dashboard, navigate to the [**API keys**](https://dashboard.clerk.com/last-active?path=api-keys) page. In the **Quick Copy** section, copy your Clerk Publishable Key and set it as the `CLERK_PUBLISHABLE_KEY` environment variable. If you're using Vite, you will need to prefix it with `VITE_`. .env ``` VITE_CLERK_PUBLISHABLE_KEY=YOUR_PUBLISHABLE_KEY ``` 8. Configure ConvexProviderWithClerk Both Clerk and Convex have provider components that are required to provide authentication and client context. You should already have `` wrapping your app. Replace it with ``, and pass Clerk's `useAuth()` hook to it. Then, wrap it with ``. `` requires a `publishableKey` prop, which you can set to the `VITE_CLERK_PUBLISHABLE_KEY` environment variable. src/main.tsx TS ``` 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( , ); ``` 9. Show UI based on authentication state You can control which UI is shown when the user is signed in or signed out using Convex's ``, `` and `` helper components. These should be used instead of Clerk's ``, `` and `` components, respectively. It's important to use the [`useConvexAuth()`](/api/modules/react.md#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. In the following example, the `` component is a child of ``, so its content and any of its child components are guaranteed to have an authenticated user, and Convex queries can require authentication. src/App.tsx TS ``` import { SignInButton, UserButton } from "@clerk/clerk-react"; import { Authenticated, Unauthenticated, AuthLoading, useQuery } from "convex/react"; import { api } from "../convex/_generated/api"; function App() { return (

Still loading

); } 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 `` from `convex/react`**. Otherwise, it will throw on page load. convex/messages.ts TS ``` 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(); }, }); ``` ### Next.js[​](#nextjs "Direct link to Next.js") **Example:** [Next.js with Convex and Clerk](https://github.com/get-convex/template-nextjs-clerk) This guide assumes you already have a working Next.js app with Convex. If not follow the [Convex Next.js Quickstart](/quickstart/nextjs.md) first. Then: 1. 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](/screenshots/clerk-signup.png) 2. Create an application in Clerk Choose how you want your users to sign in. ![Create a Clerk application](/screenshots/clerk-createapp.png) 3. Create a JWT Template In the Clerk Dashboard, navigate to the [JWT templates](https://dashboard.clerk.com/last-active?path=jwt-templates) page. Select *New template* and then from the list of templates, select *Convex*. You'll be redirected to the template's settings page. **Do NOT rename the JWT token. It must be called `convex`.** Copy and save the *Issuer* URL somewhere secure. This URL is the issuer domain for Clerk's JWT templates, which is your Clerk app's *Frontend API URL*. In development, it's format will be `https://verb-noun-00.clerk.accounts.dev`. In production, it's format will be `https://clerk..com`. ![Create a JWT template](/screenshots/clerk-createjwt.png) 4. Configure Convex with the Clerk issuer domain In your app's `convex` folder, create a new file `auth.config.ts` with the following code. This is the server-side configuration for validating access tokens. convex/auth.config.ts TS ``` import { AuthConfig } from "convex/server"; export default { providers: [ { // Replace with your own Clerk Issuer URL from your "convex" JWT template // or with `process.env.CLERK_JWT_ISSUER_DOMAIN` // and configure CLERK_JWT_ISSUER_DOMAIN on the Convex Dashboard // See https://docs.convex.dev/auth/clerk#configuring-dev-and-prod-instances domain: process.env.CLERK_JWT_ISSUER_DOMAIN!, applicationID: "convex", }, ] } satisfies AuthConfig; ``` 5. Deploy your changes Run `npx convex dev` to automatically sync your configuration to your backend. ``` npx convex dev ``` 6. Install clerk In a new terminal window, install the Clerk Next.js SDK: ``` npm install @clerk/nextjs ``` 7. Set your Clerk API keys In the Clerk Dashboard, navigate to the [**API keys**](https://dashboard.clerk.com/last-active?path=api-keys) page. In the **Quick Copy** section, copy your Clerk Publishable and Secret Keys and set them as the `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` and `CLERK_SECRET_KEY` environment variables, respectively. .env ``` NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=YOUR_PUBLISHABLE_KEY CLERK_SECRET_KEY=YOUR_SECRET_KEY ``` 8. Add Clerk middleware Clerk's `clerkMiddleware()` helper grants you access to user authentication state throughout your app. Create a `middleware.ts` file. In your `middleware.ts` file, export the `clerkMiddleware()` helper: ``` import { clerkMiddleware } from '@clerk/nextjs/server' export default clerkMiddleware() export const config = { matcher: [ // Skip Next.js internals and all static files, unless found in search params '/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)', // Always run for API routes '/(api|trpc)(.*)', ], } ``` By default, `clerkMiddleware()` will not protect any routes. All routes are public and you must opt-in to protection for routes.) to learn how to require authentication for specific routes. 9. Configure ConvexProviderWithClerk Both Clerk and Convex have provider components that are required to provide authentication and client context. Typically, you'd replace `` with ``, but with Next.js App Router, things are a bit more complex. `` calls `ConvexReactClient()` to get Convex's client, so it must be used in a Client Component. Your `app/layout.tsx`, where you would use ``, is a Server Component, and a Server Component cannot contain Client Component code. To solve this, you must first create a *wrapper* Client Component around ``. ``` 'use client' import { ReactNode } from 'react' import { ConvexReactClient } from 'convex/react' import { ConvexProviderWithClerk } from 'convex/react-clerk' import { useAuth } from '@clerk/nextjs' if (!process.env.NEXT_PUBLIC_CONVEX_URL) { throw new Error('Missing NEXT_PUBLIC_CONVEX_URL in your .env file') } const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL) export default function ConvexClientProvider({ children }: { children: ReactNode }) { return ( {children} ) } ``` 10. Wrap your app in Clerk and Convex Now, your Server Component, `app/layout.tsx`, can render `` instead of rendering `` directly. It's important that `` wraps ``, and not the other way around, as Convex needs to be able to access the Clerk context. ``` import type { Metadata } from 'next' import { Geist, Geist_Mono } from 'next/font/google' import './globals.css' import { ClerkProvider } from '@clerk/nextjs' import ConvexClientProvider from '@/components/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: 'Clerk Next.js Quickstart', description: 'Generated by create next app', } export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode }>) { return ( {children} ) } ``` 11. Show UI based on authentication state You can control which UI is shown when the user is signed in or signed out using Convex's ``, `` and `` helper components. These should be used instead of Clerk's ``, `` and `` components, respectively. It's important to use the [`useConvexAuth()`](/api/modules/react.md#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. In the following example, the `` component is a child of ``, so its content and any of its child components are guaranteed to have an authenticated user, and Convex queries can require authentication. app/page.tsx TS ``` "use client"; import { Authenticated, Unauthenticated } from "convex/react"; import { SignInButton, UserButton } from "@clerk/nextjs"; import { useQuery } from "convex/react"; import { api } from "../convex/_generated/api"; export default function Home() { return ( <> ); } function Content() { const messages = useQuery(api.messages.getForCurrentUser); return
Authenticated content: {messages?.length}
; } ``` 12. 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 `` from `convex/react`**. Otherwise, it will throw on page load. convex/messages.ts TS ``` 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(); }, }); ``` ### TanStack Start[​](#tanstack-start "Direct link to TanStack Start") **Example:** [TanStack Start with Convex and Clerk](https://github.com/get-convex/templates/tree/main/template-tanstack-start) See the [TanStack Start with Clerk guide](/client/tanstack/tanstack-start/clerk.md) for more information. ## Next steps[​](#next-steps "Direct link to Next steps") ### Accessing user information in functions[​](#accessing-user-information-in-functions "Direct link to Accessing user information in functions") See [Auth in Functions](/auth/functions-auth.md) to learn about how to access information about the authenticated user in your queries, mutations and actions. See [Storing Users in the Convex Database](/auth/database-auth.md) to learn about how to store user information in the Convex database. ### Accessing user information client-side[​](#accessing-user-information-client-side "Direct link to Accessing user information client-side") To access the authenticated user's information, use Clerk's `User` object, which can be accessed using Clerk's [`useUser()`](https://clerk.com/docs/hooks/use-user) hook. For more information on the `User` object, see the [Clerk docs](https://clerk.com/docs/references/javascript/user). components/Badge.tsx TS ``` export default function Badge() { const { user } = useUser(); return Logged in as {user.fullName}; } ``` ## Configuring dev and prod instances[​](#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[​](#configuring-the-backend "Direct link to Configuring the backend") In the Clerk Dashboard, navigate to the [**API keys**](https://dashboard.clerk.com/last-active?path=api-keys) page. Copy your Clerk Frontend API URL. This URL is the issuer domain for Clerk's JWT templates, and is necessary for Convex to validate access tokens. In development, it's format will be `https://verb-noun-00.clerk.accounts.dev`. In production, it's format will be `https://clerk..com`. Paste your Clerk Frontend API URL into your `.env` file, set it as the `CLERK_JWT_ISSUER_DOMAIN` environment variable. .env ``` CLERK_JWT_ISSUER_DOMAIN=https://verb-noun-00.clerk.accounts.dev ``` Then, update your `auth.config.ts` file to use the environment variable. convex/auth.config.ts TS ``` import { AuthConfig } from "convex/server"; export default { providers: [ { domain: process.env.CLERK_JWT_ISSUER_DOMAIN!, applicationID: "convex", }, ], } satisfies AuthConfig; ``` **Development configuration** In the left sidenav of the Convex [dashboard](https://dashboard.convex.dev), switch to your development deployment and set the values for your development Clerk instance. ![Convex dashboard dev deployment settings](/screenshots/clerk-convex-dashboard.png) Then, to switch your deployment to the new configuration, run `npx convex dev`. **Production configuration** In the left sidenav of the Convex [dashboard](https://dashboard.convex.dev), switch to your production deployment and set the values for your production Clerk instance. Then, to switch your deployment to the new configuration, run `npx convex deploy`. ### Configuring Clerk's API keys[​](#configuring-clerks-api-keys "Direct link to Configuring Clerk's API keys") Clerk's API keys differ depending on whether they are for development or production. Don't forget to update the environment variables in your `.env` file as well as your hosting platform, such as Vercel or Netlify. **Development configuration** Clerk's Publishable Key for development follows the format `pk_test_...`. .env.local ``` VITE_CLERK_PUBLISHABLE_KEY="pk_test_..." ``` **Production configuration** Clerk's Publishable Key for production follows the format `pk_live_...`. .env ``` NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="pk_live_..." ``` ## Debugging authentication[​](#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()` returns `isAuthenticated: false`, it's possible that your backend isn't correctly configured. The `auth.config.ts` file 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](/auth/debug.md). ## Under the hood[​](#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. --- # Convex Auth [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 Auth is currently a [beta feature](/production/state/.md#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[​](#get-started "Direct link to Get Started") To start a new project from scratch with Convex and Convex Auth, run: ``` 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[​](#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). --- # Storing Users in the Convex Database *If you're using [Convex Auth](/auth/convex-auth.md) 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](/auth/functions-auth.md) 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](#call-a-mutation-from-the-client) that stores the information from the JWT available on [`ctx.auth`](/api/interfaces/server.Auth.md) 2. [Implement a webhook](#set-up-webhooks) and have your identity provider call it whenever user information changes ## Call a mutation from the client[​](#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[​](#optional-users-table-schema "Direct link to (optional) Users table schema") You can define a `"users"` table, optionally with an [index](/database/reading-data/indexes/.md) 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 ``` users: defineTable({ name: v.string(), tokenIdentifier: v.string(), }).index("by_token", ["tokenIdentifier"]), ``` ### Mutation for storing current user[​](#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 ``` 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[​](#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 ``` 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 ``` 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[​](#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 ``` 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[​](#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 ``` 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[​](#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[​](#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](/dashboard/deployments/deployment-settings.md). 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[​](#optional-users-table-schema-1 "Direct link to (optional) Users table schema") You can define a `"users"` table, optionally with an [index](/database/reading-data/indexes/.md) 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 ``` 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[​](#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 ``` 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[​](#webhook-endpoint-implementation "Direct link to Webhook endpoint implementation") This how the actual HTTP endpoint can be implemented: convex/http.ts TS ``` 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[​](#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 ``` 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[​](#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 ``` 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[​](#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 ``` 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 ``` import { useCurrentUser } from "./useCurrentUser"; export default function App() { const { isLoading, isAuthenticated } = useCurrentUser(); return (
{isLoading ? ( <>Loading... ) : isAuthenticated ? ( ) : ( )}
); } ``` --- # 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[​](#frequently-encountered-issues "Direct link to Frequently encountered issues") ### `ctx.auth.getUserIdentity()` returns `null` in a query[​](#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](/auth/clerk.md#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](/client/nextjs/app-router/server-rendering.md), make sure you are explicitly passing in a JWT token as documented [here](/client/nextjs/app-router/server-rendering.md#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[​](#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): ``` 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](#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[​](#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](/screenshots/auth-ws.png) * For HTTP based clients (`ConvexHTTPClient` and the [HTTP API](/http-api/.md)), 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](/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: ``` // import { useAuth } from "@clerk/nextjs"; // for Next.js import { useAuth } from "@clerk/clerk-react"; const { getToken } = useAuth(); console.log(getToken({ template: "convex" })); ``` * Auth0: ``` 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 , 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](#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[​](#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 . 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 . 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](#step-1-check-whether-authentication-works-on-the-backend) and you should be all set! --- # Auth in Functions *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](/functions.md), you can access information about the currently logged-in user by using the [`auth`](/api/interfaces/server.Auth.md) property of the [`QueryCtx`](/generated-api/server.md#queryctx), [`MutationCtx`](/generated-api/server.md#mutationctx), or [`ActionCtx`](/generated-api/server.md#actionctx) object: convex/myFunctions.ts TS ``` 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[​](#user-identity-fields "Direct link to User identity fields") The [UserIdentity](/api/interfaces/server.UserIdentity.md) 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 ``` 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[​](#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. ### Custom JWT Auth[​](#custom-jwt-auth "Direct link to Custom JWT Auth") If you're using [Custom JWT auth](/auth/advanced/custom-jwt.md) instead of OpenID standard fields you'll find each nested field available at dot-containing-string field names like `identity["properties.email"]`. ## HTTP Actions[​](#http-actions "Direct link to HTTP Actions") You can also access the user identity from an HTTP action [`ctx.auth.getUserIdentity()`](/api/interfaces/server.Auth.md#getuseridentity), by calling your endpoint with an `Authorization` header including a JWT token: myPage.ts TS ``` const jwtToken = "..."; fetch("https://.convex.site/myAction", { headers: { Authorization: `Bearer ${jwtToken}`, }, }); ``` Related posts from [![Stack](/img/stack-logo-dark.svg)![Stack](/img/stack-logo-light.svg)](https://stack.convex.dev/) --- # Chef Chef is an AI app builder that builds complex full-stack apps. It leverages the full power of the Convex platform to one-shot apps like Slack, Instagram, and Notion. This means Chef can: build real-time apps, upload files, do text search and take advantage of Convex Components. ## [Prompt to start an app with Convex Chef](https://chef.convex.dev) ![Chef Screenshot](/assets/images/chef_preview-dfe305b7d7ebb5910c22cf2c22a6842d.png) ## Deploying to production[​](#deploying-to-production "Direct link to Deploying to production") Chef does have a built in ability to deploy your the dev version of your app for you to immediately share with your friends to try. For apps intended to be built and maintained over the long term, we recommend downloading the code and importing it into your preferred IDE. When you download the code from Chef, your project automatically comes with [Cursor rules for Convex](/ai.md), helping you keep coding with confidence. ### Download the code[​](#download-the-code "Direct link to Download the code") ![Chef Screenshot](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAbgAAAAxCAYAAACoArwXAAABXWlDQ1BJQ0MgUHJvZmlsZQAAKJF1kE9LAlEUxc+UZZT9ISIIWsymRWExjGnQzgw0cjFZobUbx2kURn2ME9GuDxHt20TQB7DARUTtWgRCQatoVy2j2ZRM92mlFl24nB+Hex/nXaDDpzJmegDkC7aViC6IqY1N0fuEbgxjAD0YU7USCytKnEbwre3l3ELgWp3mb0n9gZeT1Gns8TJ5uHw1//x3vq16M3pJI/2gljVm2YAgESs7NuO8RzxiUSjifc5Gg485pxtcqc+sJSLEN8RDWlbNED8Q+9MtvtHCeXNb+8rA0/v0wvoq6Sj1OOKIQkQMi0iQJrFSZ/yzM1vfiaAIhl1YyMFAFjZthslhMKETL6EADTPwE8uQqIP81r9v2PSKU0DojeCi6an0p7M5ihlqehPXwGAVqASZaqk/lxUcT2krIDe4rwx0HbjuaxLwTgK1O9d9L7tu7QjovAfOnU+RKmSTCMrFsQAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAABuKADAAQAAAABAAAAMQAAAAB2UVURAAAgCklEQVR4Ae1dB3hcxbX+pV2terfc5YJtXDDyM2AbMM2EXkMLHRJCQhJMCSm0hBpSCKEE00looZgAMb3XUIwM2Lhgy5J7kWXJsupK29/5R2/E9Xp3tXu14tnrOfpW9+7cqf+dmVPmzGxawO8JwZBBwCBgEDAIGARSDIH0FGuPaY5BwCBgEDAIGAQUAobBmY5gEDAIGAQMAimJgGFwKflaTaMMAgYBg4BBwDA40wcMAgYBg4BBICURMAwuJV+raZRBwCBgEDAIGAZn+oBBwCBgEDAIpCQChsGl5Gs1jTIIGAQMAgYBp4HAIGAQMAgYBAwCyULA7fHjy+WN+GZdK1ZuaEF9swftviAQCCEv24FBBZkYMzALE4dmYuK4IcjMzkxW0dvlkxbvRu+W5ha0u9vh8/kQCpm94dshuYsEpKWlISMjA7k5uSgoLLDV6l29LxkMbXWbmIkMpkAyMIgJcg8P19a78fq8Tfjg680IBkNSH0kQ9MMZEkNhhh8ubxAFPjcKWqqQuXkD1vhC8I2ajgMO3hOHTxmKYWU5PZSQ+OMeGZzP50dDQz3S0tNRVFiIrKysxEsxKVIKgc7OTvDT0dGBfv3KhOHFZwgwfenbbmAw/BaLZN31FlMKbnl5ecjMzFTMIln1suazZs0aDB8+3BqU1Hu7GPS2Ek+8vxavVNYKQwshHSFR1oTByZ8TAWQLDxnVVoW89fNR1dAB956HwFM6GkiXpyEH0tN8CAozPH5aOc6eMay3VdkmfY8Mrra2FtnZ2SgqKtomofliEGhqalJMbtCgQXGBYfrS9jAZDLfHpLchdjDNzRWLRIE9i0Qi9e1rBqfrkigGOl2iV2pt97+2Eis2tiqGlpaWjsygF1nBAIo7N2Jx5evo72mBO38wvMPGAsUjhK+5kJ4lWKe7RJAIIo3MUJS8kLDDyQU+nHlyBcrLchOtSsT4MRkcTUnBUNAwt4jQmUAisKmuDjlZ2T2aK01fit5fDIbRsbH7JBFMvT6vWCL62S0qoXTfFYNjpeLFIKEGWCIv29CK25+vQntnQJatgsgKBVDo34L+tVVoWb0YVa0NmLemCgHR6vxiqvSKSdIlypIodCjsNwxDxkzBoHEHwFVQKvZV0fuE0ZV1NCFQVIpLTx2LsUPyLaXZu41pW+KaW3Fxsb2cTapdAgGarbdu3dojgzN9KXp3MBhGx8buE4Mp1JJSPGPTDsZrG9yY9fxy+Ds7MKCjDrntjUjbuAxr61bivbXV2NLWjk6v+GvAL+txQYiLiVqXa/d2iEkSaFjbiIY1i7C88iUMmbAfdpt+ujib5AmjA9weH26bsxzXnT4B5f2y7VSvO03MbQJ0KDFrbt1YmZsICLB/sJ/0RKYvRUfIYBgdG7tPEsGUa26pSPFiYKftT760GPmbqzGu5kPkLnwL1etXYK67Fa8umY9NLU1o62xDlnhM0tMkKJqZM92BDKestwnL43dR12R1zofWljpUf/4iVnzwOBx+MVdKDIf893cE8dRrVXaqtk2amAzOeEtug5X5EgWBePpJPHGiZL9LBMeDTzxxdgmw4mxkPHgxDr0PU5XiwSDRtn/40jton3Mv6uvWoFq8IBvGn4CtDieWVL6JkM8jvCuAoGwJaG1zK+GXGpxXhGA/bZNC1OsCchXLpbAy0fHEvFkz/z101C2R9Ts3BnZuxfhN/4Xn5Ycx+7kPVRq7/2KaKO1matIZBAwCBgGDQOohsGFjPZ5cLLrXjIuEO2XA626Dv6EaNfPeQCeZmN+PkGwHoNe9Q5hXmtgjveJwgoD4VDpEoxPmR62Kvh2BEP0s6VxChc6Nuf++HeP3noqmgf+DTSMmw19+CGo2OLD/lg6Ul9ozVcbU4FLv9ZgW7QwIVFZWYty4ceDVUHIQIJYGz+RguSvn8u5SN/x5hUgXD8h0YWKuTAdqNyxH89ZNCHj9SBdtrSTTiWkDCnHEbgNw4MBCTOmXhzGyubtI1CmXMwNZYq50StoM+VB7TldmzHS0tG7BF44CeCYciFBeARxpYtYU55N3v260DXlSGdysu2fZrsjOkHD27Nn46KOP+qyqLS0tePzxx/HNN9/0WEZrayuqq6uVxNRj5DgifPLJJ3jqqafiiNm3UTgJn3feeaoQXpM5KTc2NqKqqgoej2ebRtClmrjzWarReeedr4SFWbPuAT8UHHakcZrK2KdaX+rwBvDJ0iakh1zi4i+sg9pZextaG2tFWwsiU1z+jxKmdu2Rk3HnOTNw80nTcc3Re+HCSSNxzPB+mFySj6GyLudyCFOTzd/pXaqb8p6kGTMgf6s31IiyF0IozSUfWb+TsE++aQDLtkNJNVHOumcWZl4y0049tklDz5/99ttvm7C99toL++yzD0499VQMG5bczYDbFBTjy6233ooZM2bgoIMOihHL/iMO9j/+8Y/4/e9/jwkTJkTM6NNPP5WJaha++uqr7ucnnXQSrr32WrVJtTswwZtXXnkF//nPf3DWWWclmDK50cnUyGys12XLlvWqkCVLluBXv/oVVq9e3Z3P97//ffzud79TmNXX1yvcb775ZowdK3t1dkJSGtrnlZg6bWp37YnhzItnCp6PdYfxhkyO8aZO/TbuNhHky3HHHYeampru4BEjRqgxecwxx2DKlCnd4b292dGxpzDAeS1emjp12nZ4x5s2nnh8d70dD/GUEynOwlUtXRqXg64iNDPKWpuYJD2yHcDn9+G8PYfjsiMrUDqiHNn5RWhv2IqAPG8XT8sOOb4rz5mOctlv6EvzYBM84mUpHpZ0NhFG5pSPWCzhcbslZ5W7mEBFwyMjFUMmy542NnGP/qQyuEig2AnTC6NkJmRobmk0X+qTTz6pPo888ggqKirsZL1Tp6GW9eMf/1hNwn/7298wdOhQxej+8pe/KK2PDIpmg52ZrIOXE7D1u512se+ccsopCrN//OMfar/T/PnzccMNNyjJkdjt7KS1XjIzammVlZ+rJlFQiMTEOAnHQwMHDlTCFtdVyOxef/11PP3006AgcNppp8WTxU4dh9rvVGHmifRBxRCFKSZD0A8Hj+853ncXnjYZ36tr24XXBJWbPx3/0+QUksxMlzrVKE/2wl6w3wQMHjUSaUUlCLkykO0NobNtlTAtPwpcDniEg9W1i+ekMENlmhQN0Cn7B5QmxwqK5tYpW9PoSZmRniHbCkRr4w5woepNncLg1G1C/3bo2XDUqFH43ve+h+OPPx6/+c1vlGTf3t6uJifdys2bN+O6667DIYccgqOOOkoNPpr6SL/+9a9x8cUX66iKOTLO8uXLVRjT8jsZA82C+v5nP/sZ9t57byXhxzJbxSqbBaxbtw6XXHIJpk+frup31VVXgaZFTTQx/vKXv1RlUXNaunSpfhTxSqbGExceeOABHHvssZg0aRJ+9KMfqUmI9Zw7d65KFwgE8Pe//x0nn3yyKps4hLfj4YcfxoknnqieMy5NBFbSbWPdGe+ee+4B8+0L4qRAyZSfcOKg1s/smNYWL16ssiSTY1uooZ1xxhm4//77MW3athM9LQd8X3z3p59+Or788svu6sR6l7rvcPKn1sT07KfE6+6771b4sX+yn9JMmkzSzI3MjJPqzJld/V0zNz4nbrwmSiUlJWr8HXnkkWocUcAcPXq06m96jDHPF198sbvdl19+OTTmfEYt+ec//7mKc/jhh6tx8Kc//UlNinweiebMmYMf/vCHCsef/vSneOedd1S0r7/+Wo1RPtfEelDbZB9ONlFQSJRRMX4iGl8idabwot9vIumSFXd9fYcwJmpVdA1xwimaXFZhPwwYtjtGFDjhkqO3gsLEOptkjvMH4OnoRFA8J0vzs5CTl40O0dZaZFN9wB+CxyvLBMoEKYxSriRxQYFDuB2FdAbxqj5S5vr6ThUn0X87NIMLb8wee+yBI444QjEjrqNQOiczevbZZ8HBs++++yomdumll6q1KR4h9e6776p4zOvNN99UZirNCDhgaLbabbfd1IDj/dVXX602t1N7fO6553DLLbeEV0N976lsMoyf/OQnoEnxzDPPVGZNDsw//OEPKj0H5i9+8QslFR999NFgXS+77LKIZTGQ+8g4kR544IGgZG0lMkea4dh+EiXse++9V515Ryb3/vvv44ILLsCmTZvUc6613XbbbeqewsPLL7+sJiAVIP94nh0Fg1dffRU/+MEPsOeee6qJ+s4779RRknrlhEApOZKkrLU4Tth2Jg4KSaS77roLxF8zGDIcYmOl22+/HS6XS/Ux9g1OrsS9p3dJvNh3brzxRpUdTcZOp1OZPSkYUBChkMB+OnPmzLj2DVrrFc99pZgnrcxOa24MJ268auLErZ/rsHiuhbKpn32ZpAWmN954A1deeaVq74UXXqj64fnnn4+NGzeqeLyy/910001qDHCsPfbYY6qPqghh/9jnKAjynFMyOaYnZhxH48ePB02aL730Uneqzz77TGmXEydO7A7b2W+0UGJthxZQ9HuzK7RY80z0vrHNh3SHHw5fEBmSOFe2BJQFW3HgqCGoKB+E9GzRyHKz4CgqFs9JBxZu7cBDi1bhwaoGPF5dj4/qW1Eva2kuObs2P0vO+5Q5ssuPUrRC0QiF/6F0wFA4ZOwI95OrAw7ZS+CU+8Z2e8J1r02UBDrcns+XwQGVqPQTD+Ds5G+99RZWrFiBOjkmipM+Bw8nYlL//v2VNKcn/IceekgNOg4A1ovMgYOCkvbChQtVGjJOfc8BfP3116twTlKcFCnZh5/o8vnnn8csm1rHNddcg/LycowcOVLlx0nw448/VvccsNQKuN529tlnq7DBgweD9dUmWhX4f/+YlkQJOpwoATkclH+A5uZmPPPMM0qq1UyMa4bnnnsuXnvtNcXoyCyIAyVyHi5LLZBrK9Q6SBQAFi1apHCkQEGiNsK6UULXZakH39E/PbATLa60tBRcO/3tb3+rJk6mJ4Y0sVEw4AG7mihoUEsmcTJ/9NFHsWrVKiUoxHqXOj0ZG7UTEgUY4nvOOecoLYZh7AecvNlnyfSSQcSFggHNaWRkWnPTeXNsil7XvTbH8UpTpl3afffdVVJaQbgWd9999ymt+MEHH1RMjpYF9hmaM2lO10SNmfHZty+66CI8//zz3e9Dx+GV+XDMkAlyozLxO+yww9S72H///ZU1h/2b+PLsSDJPWjWonacCcY7S68/W9oRrb3yvOp7dsWHNP557jy+AHNnKVupvRHDtUjQ31QNyzFa7owiOnGK8Wt2A4W1L0K8oHwuWrcdHGxrxxao6sVp1qveujl8WppYla3GcQ8TZUvbNeYW10V9FWJ14V6aJFsh1N6dsI3Dw4/DK3jgf8ju75rd46mmN02sGZwWaGUd7QdZCe3PPjk3iBMTOTaJWo+nggw9WEzMH/QknnKCCKY1zHYHECZqTDL+zrjSBkpFpoiOLpsmTJysGR3NdOIPjJEWKVjYnMDJOao1PPPGEGpAsT5NewD/00EN1kBrIZCKRiIyI1NbWFulxd5jWgqiBaqLJjESmpbUNmul0ngMGDFDmIO0hSuGARE2PExVJX1euXIkxY8aosJ3lH/sBNTZq82TeNKmREVGo0QyNbbG+e73GS4GBJ13EepcahwMOOEDfdmuj//rXv7BlyxYVTuxINEUni8GpDOWfMqcJ4wqf7Phdh7H/aW1Zp0v0qvtffn6+6ktak+MSgpWsZkoyIO2YQmGM1hb2NeKRk5PTnYx9k/mxb5K5kTjuWH89dshAyeAoIDKft99+GxRMUuU0EsXIIrzHLq37sW6siIlec3388ejOQt0JknBTXP0Ocr1erJM1taxxU+AdMw2NngAWvzwLjWtXwet1Y/+KcSjJdeObRVWoaWyRE008Yq2UzdwBmiLFsCmMjet3DvGidImJ0+PnfrkAijJzxMQZQj9xPhnZUoNiMW0OdYjW1t6M5vp1CMlZlsCUhFvx7cyecNKuBASaUiOlCVJfSxVkVhww1Ha0u7dVCtfMis/4Kwg029GpgCZFSoDaA/KLL74A8+K6iJV0eoZZ761xeN9T2ZzUOLHyyrW9IUOGbJOFTk+TmCbdDm2T1uG8UuNiuzUDsz6jOWf9+vUgo9L56rwYj3ZspvVK5+SHZH0e/p0TDYnmJKYjUSon5nriUYF9+C/Zi+mU9qlh8UMzNCdRmsO0WZFNifQuGN7Tu2QckrW/aAypjdAZiMQDfanF9cXPpegxGG5NUQXLPzIIPTZ1mJ2rFn5oSbEe0abbyDwpXFm9oMP7jMaZfdHK4HR+VhyZH5kXrQs0FdObmlo5hVviyXBaH1KFuMbG92R9j3x34eNBCyt8798VeSceIudEivNHhheeYKZoZWmor3oPG1d+LXvgOpQn5TufLBDzI3Do6HIsXF8rJk06i3TVkCZIfpxikKTZMV1MkBwn2TIHpguTyxQNrqO2GmWL5yDHIz/H1dKMPF8QQwJucVwpsNXMXjM4lqqZnFaj+b0viCYfusdzsiUT0K70CxYsUNoPy+Q9iQOQRNMFzSPUwjgQuHDOdHSyINmta09l04TJiZFOBpQ0SWSqWnPTWhDDuIhP0lJqJBMl20sp+IMPPlDSK5m1Jq63UfObPXt2t6OGxolxWCYnAmohnOjJLFkWzY40FfCZxo3xNXaUjLXkTTMtMYz3p3GYT28o3LXdbl50ICI+XD9k+0n86SearGn2JfPviXp6l5HS6+0GXOejkwWJg5mnyScbw64JMLrHKZ+rSTNO78lI7WEYNV5uUaHQQ+GHfYcMnMIbt2FoYn+jhqeJ44BLCno9VK+BMw+9Jsq4TMP85s2b1903iRm/c5zqd0UhhQ491O5Yl3BnIV3uznjVcymXePTcpOdVa3v4PNwcbX3eF/dlRSVY1SSHJcv6miNNTiwRLaxh1VJxGGlVbv5+mhsDHhw8ZjzOrxiKFZu2YGG9nEnpkrMlxSMyKGdNFmVlSFynMlmS2+VnZUtVQyJ4tyM3Mx/Bzha0ymHN8+sasWRLKzb7OzGypEwcVDLwto1G2WZwtPlbJ6GuF7M9YwuPl0gdOUlz4qZZkoOUGteIESO6pW5OvpTmuGbGQUSzIx0sGEcvOrPz0wxF85yW1mnG5NoB0+pBl0i9GLensrWk+8ILLyhtiWtvWvtkemqWHJxc2+FCOqVXOjnEIsblYKenH9ftOIly8qXzAh1BtNmLzI/rR2Rm1Lo0M+daBokOD/TEpAcnNVrugSN+mogZsaHZ6YorrlCayR133KG0YJr5wiVsnW5HvPI9ca2TTjNkNNRyiSHbTJOiVYOIVn+u65KivctI6VgO3wOdW2hJYJ+kuZL9gPloASlS2kTDyLwiafbMRzM3ToacKBMhrnFz/FHTYt/VJux//vOfirkxL65lst9qJxIyL/Y969oy4xF/Op+QwVPoYP9nH7MyOGt+7Ovsm1w3Zt+kJ7AmCl7s0yyHefbVmrAyAXLNUjwj4yXlk9BLQYJzqWZufH8k/V3XI5E66TS9vfJk/83CdJxyrFZxSDSvoByhNWUP3DF/Dvzi4p8hJkeXnHBy2uj+aFhfh/2LXOIVWYjivCx0eoKYPq5c3v8GfLqhCa1isuTGN3piyvHLcjBzDnwS1i6nl6zo8OG1jQ1oFdkzIOtwg+VTUTHZVvVtMzjahOOheONZ89ImOjI4fkg0TdCrjU4gej2MA4SDjWZGMjkSOwLXVzipkCi1azOblqo5uMjgOIB0WeFXpo0UxnBST2Vz/Y6OHVx/ozmFZXK9T0uvnDQpDZPpci+WZnbc6K3L7Srp2//c4M4Jh84jXIzXRDfpG264QX9VkyonCO06zXYznXYQIIOkNsaJhg471DA5aeh1NraNe8aIKZ0zSJyQOVmHm5u6C+3jGz3QEy2GpjNO7myH7iPMg2Y0vQcuGt6Mx2c9vUudXl+ZjkStkRvw//znP6vvxJXCVjKZGzNm+4iPduzSTE1N0OJ4wmvXBCl75CyagapUjH9kLHqNkgyaTjn0utWCFJPSU5hbX8i09Uk4epzqrJmW/UsLmBwLOt9wzJgf1/nohMK1UmJG5katTRPHNDU9Ci40//cVkYmcJ4J8pO0rLFNrUNbnxNoq+Pe2bpG0t97maTd9RXYdPAuehkN+AQCBTjhb3OIoEsL1E0bj1qrlyvvxuPGjUCjHcj362UY0Cg9b39CEvQaNwT6jC7Bo/UbU1DfBHZDjlkX7k63iMr6Ez4mnZEjW6URSQbMcxfxqzQYcPqocb6xag1YxXmbKvrnjZxxkq9ppAb9Hco5MsX6cjy+emyBjSRLKlVWk5WS+8Mg1hXIr5mD5/5iAuQYWrWxKv1wXs5pswttADZUMLhFJlJMA3f7J9PSaRni+1Gi59khNLhKxbowTS4th2xgnVv1j9RNdbqw47CfxbAHg5BGrv+myol05YVNj4ORop5/E8y4jlU38yAS0YBYpTix8dPxocTRD44RLIjNjGCdHjtFKGYN6bUdPyjrPZF1pVie2NP9a+zG3p9BCwe0EHAdcR9PCZ6yymR8dfJhfONGkzmUK9klqeNp0GR4vGl7WePHEscbX91bMY2nQOr6+JloemWc07VznGeuaaHmx8vLLXPLfU07EirZW0cD8aBKN65DiQjmhBCiZNglrGzfj33MXyPoaMG9jEzZ7xAMyIwP5sm+uLE/W7CR+zdZ2eGWeTpODmmW3G4Jy7wt4RftzqjW4WikjIHkXuzJx3KjheKdmDY4aUIK/Vn6BzNwuR7tYdQx/ZluD44DhALJKL+GZc2H0u9qYGM+gCa9fsr7HKpvMJxoD0uVHY0D6eaQrPSAjbRmwxqUpMVbe8dQtVtusZfXmnkyrN4wr3rKpDfBjl+LBK1LefA+xmFukNImEWddj9IRIJqe96yiMchLuK+bGulLA6wnbRDwdmV8k5sZ1eFojKKxQI4zG3BLBz07cLny/da6zk0c8aXrD3OLJP5E4TvF4razYC/c/9CjcaQFMKivEgsY2ZLrScc6gHLw4dzGy5de4j5ooGvu+2Zi3bC1WyL7F1Y1u1Ld7cOq+e8A3X37tm2t3bZ1ifnSoX/p2i8ekx90hR3bx9+K4uduJZtko/vrKtbh9vz0x/dgTbDE3ts02g7MOoERAMnENAgaB5CJgFQ60FmctoUvIvHi7dRxrnL66p7cqrQjJIjI9Ht9HM6d1W0ey8k8kn++KySVSp76Oe7Jo5LMeeRS7yTaOQmTgK9Gyy/Mz8WRlDX1FUJyZgRfmfoPh5SUIpAfR3OqT47naMX5wGQbk5ch6XC7yxGOyQfbGeUVT6xRzpVucU7gJgPvjnMrrMiBmS/lJHhFy6vr3Q+DI42w3yzaDs12iSWgQMAj0GQKcdMMpUlh4nL76TlNiMon74HYkIrY7kpbV19iMkfX8G6+4HPNnP4s5a9YiJzML2eIoUl3XiquOmqQ0tbxxw3DQ/hVoXFmL6lVvYerAUkwfPwzzV6xCuzjTbXJ70CHmyg6/HLgs++icYsbMla0gITFf8wDnHDnpJMuRLXvoOrFx6FgMGjnKdrNiMjiaCQwZBHpCIJ5+Ek+cnspJ5efx4BNPnFTGKNG2GbwSRSy++BdcdTUu++AjjKivw8SyMnHjz0G+UxhdhgO7DS1Fx9ZWvPT8e2hs6cCAwiyUFeVgzdZmLGtwY504pjS4fegQRufl2psrW9bDs9VG7hyXE2ViBnXJ/rgtovVN/p9JuOnGm+KrVJRYdGWJStwMrDesRo1kHuzSCLB/hG8ajwSI6UuRUOkKMxhGx8buk3gxJROMtO/Ubrk7Wrq+YvLX3DcLR0+pQIYwty+3uvHM2tV4fvFa+Wkcj6yX5WDMkDKMLi/FcHEQqe/woHKd7GurbxHtTUySXmFwsr8tU7S0bOEx/B25kiwXSrOzlMNJi8wpxcWluOueu3sNZ0wGl5uTiyaxsRoyCERDgBMJ+0lPZPpSdIQMhtGxsfskXkwpeOnTf+yWtaOmi5fJ26n/ADEbHn3dLVjpzERbaQn6jZuEzfmDsKhJHEbEWeTD6lo8Oq8Kb6ypx9urG/B1bQOaxasyKKZJOgblZeWjMD8bucLYyIRbhAmuE8ehhvZOuHLycO/DD2H8uPF2qrZNmpgMrqCwQNlF+UOchgwC4QiwX3AbAftJT2T6UmSEDIaRcelNaCKYUvDS52v2pswdMW28TN5u3SdP3hu3z3oQA4aPxcTDzpIjgsZhfkc+rnrxMzzw2VLMXbcFC9Y3oMUbVM4jOa4slMrpM1niWc71tgwxaXbK1pFOj0+2IgXEVJmDiokVeEp+xWXvKduvJdupZ8x9cMzQJy6cDQ31au8K9w7Z2T9kp2ImzY6LAAcONXt20n79yqSjxlzK7W6I6UvdUCjTv8HwWzyScWe3X9bW1qp9qLG21CSjfswjmfvSYtVJM/lkHwsXrcy//vVW3Cn7WdtaWrtNvtTM+OFZJf3lcHyP8JLWDjc6hZkF5XQSV4Zob+JU0r8gDyXiiXnGuRfgsiuvjVaErfAeGZzOtaW5Be3ya6s8UiqVbda6veYaGQF2WJp1KPnGo7lFymVX70sGw0i9ondhvcFUC17s19xfyv16zK8vqK8ZnF0mn4y2LpFfWLnvvvvV6U3kETxBhD+D4xQoh8r+061yOIVPfvomQ34/QA6zRIlsGaBTybHyY8QnnnUORo4ek4xqbJNH3Axum1Tmi0HAIGAQSDEEdnbBqzdMPpmvsrW1RU6YeR0ff/KpOsN0vRyp5hJNrbmtHcMG98ewIcOw77S9sdc+0zDt4Bnya9+Jn1ASb30Ng4sXKRPPIGAQMAgYBHYqBGI6mexULTGVNQgYBAwCBgGDgAUBw+AsYJhbg4BBwCBgEEgdBAyDS513aVpiEDAIGAQMAhYEDIOzgGFuDQIGAYOAQSB1EDAMLnXepWmJQcAgYBAwCFgQMAzOAoa5NQgYBAwCBoHUQcAwuNR5l6YlBgGDgEHAIGBBwDA4Cxjm1iBgEDAIGARSB4H/BcSYac9JP+PcAAAAAElFTkSuQmCC) At the top right of the Chef UI there is a download code button. Download the code and you’ll get a zip file. Unzip the file and put the folder in your desired location. We recommend renaming the folder to the name of your app for convenience. For the rest of the setup, open up the terminal and `cd` into your app: ``` cd ~/ ``` ### Install dependencies[​](#install-dependencies "Direct link to Install dependencies") Run the following command to install all dependencies for your project ``` npm i ``` ### Run your app[​](#run-your-app "Direct link to Run your app") Run the following command run your app, and setup Convex if you haven’t already. ``` npm run dev ``` Follow any instructions to login to Convex from your machine. caution You have now taken over from Chef for development of this app. Chef doesn't have the ability to re-import a project or track any progress from outside it. Going back to this project on Chef will cause conflicts in your project. ### Set up the frontend build script[​](#set-up-the-frontend-build-script "Direct link to Set up the frontend build script") Chef projects don’t come with a build script. So make sure to add the following to your `package.json` file: ``` "scripts": { //... other scripts "build": "vite build" }, ``` ### Recommended: Setup Git[​](#recommended-setup-git "Direct link to Recommended: Setup Git") In the terminal run the following three commands setup git for your app. The downloaded code comes with a `.gitignore` file. ``` git init git add --all git commit -m "Initial commit" ``` It's also recommended you setup a remote git repository with [GitHub](https://github.com/) if you're going to use the production hosting guides below. ### Set up production frontend hosting[​](#set-up-production-frontend-hosting "Direct link to Set up production frontend hosting") Follow one of the Convex [hosting guides](/production/hosting/.md) to set up frontend hosting and continuous deployment of your frontend and backend code. ### Initialize Convex Auth for Prod[​](#initialize-convex-auth-for-prod "Direct link to Initialize Convex Auth for Prod") Once you have a production deployment. You need to [set up Convex Auth for production](https://labs.convex.dev/auth/production). ## Integrations[​](#integrations "Direct link to Integrations") ### OpenAI[​](#openai "Direct link to OpenAI") If you ask Chef to use AI, by default it will try to use the built in OpenAI proxy with a limited number of calls. This helps you prototype your AI app idea quickly. However, at some point the built in number of calls will run out and you'll need to provide your own OpenAI API Key and remove the proxy URL. So that means you'll have to find the code that looks like this: ``` const openai = new OpenAI({ baseURL: process.env.CONVEX_OPENAI_BASE_URL, apiKey: process.env.CONVEX_OPENAI_API_KEY, }); ``` And remove the baseURL parameter: ``` const openai = new OpenAI({ apiKey: process.env.CONVEX_OPENAI_API_KEY, }); ``` Chef may automatically prompt you to change the environment variable. But if it doesn't, you can change it by going to the "Database" tab. Then click on Settings > Environment Variables and change `CONVEX_OPENAI_API_KEY` to your [personal OpenAI key](https://platform.openai.com). We plan on making this transition better over time. ### Resend[​](#resend "Direct link to Resend") Chef comes with a built in way to send emails to yourself via Resend. You can only send emails to the account you used to log into Chef. To send emails to anyone, you have to setup your app for production with a domain name. This is a limitation of how email providers work to combat spam. ## FAQs[​](#faqs "Direct link to FAQs") ### What browsers does Chef support?[​](#what-browsers-does-chef-support "Direct link to What browsers does Chef support?") Chef is best used on desktop/laptop browsers. It may work on some tablet or mobile browsers. Chef does not work in Safari on any platform. ### How does the pricing for Chef work?[​](#how-does-the-pricing-for-chef-work "Direct link to How does the pricing for Chef work?") Chef pricing is primarily based on AI token usage. The free plan gives you enough tokens to build the first version of your app in a small number of prompts. After that you can upgrade to the Starter plan that where you can pay for tokens as you go. ### What’s the difference between Chef and Convex?[​](#whats-the-difference-between-chef-and-convex "Direct link to What’s the difference between Chef and Convex?") Chef is an AI app builder that builds full-stack apps. Convex is the backend and database that powers Chef. ### Can I import my existing app to Chef?[​](#can-i-import-my-existing-app-to-chef "Direct link to Can I import my existing app to Chef?") Chef currently doesn’t have import and GitHub integration. But you can get most of the value by setting up the [Convex AI Rules and MCP server](/ai.md) in your Agentic IDE like Cursor. ### Are there any best practices for Chef?[​](#are-there-any-best-practices-for-chef "Direct link to Are there any best practices for Chef?") Yes! Check out this [tips post written by one of our engineers](https://stack.convex.dev/chef-cookbook-tips-working-with-ai-app-builders). ### What Convex Components can Chef use?[​](#what-convex-components-can-chef-use "Direct link to What Convex Components can Chef use?") Chef can use the [collaborative text editor](https://www.convex.dev/components/prosemirror-sync) component and the [presence](https://www.convex.dev/components/presence) component. We will support more components soon. Chef supports all other Convex features like text search, file storage, etc. ## Limitations[​](#limitations "Direct link to Limitations") Chef works off a singular template with Convex, Convex Auth and React powered by Vite. Switching these technologies is not supported by Chef. --- # CLI The Convex command-line interface (CLI) is your interface for managing Convex projects and Convex functions. To install the CLI, run: ``` npm install convex ``` You can view the full list of commands with: ``` npx convex ``` ## Configure[​](#configure "Direct link to Configure") ### Create a new project[​](#create-a-new-project "Direct link to Create a new project") The first time you run ``` 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[​](#recreate-project-configuration "Direct link to Recreate project configuration") Run ``` npx convex dev ``` in a project directory without a set `CONVEX_DEPLOYMENT` to configure a new or existing project. ### Log out[​](#log-out "Direct link to Log out") ``` 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[​](#develop "Direct link to Develop") ### Run the Convex dev server[​](#run-the-convex-dev-server "Direct link to Run the Convex dev server") ``` npx convex dev ``` Watches the local filesystem. When you change a [function](/functions.md) or the [schema](/database/schemas.md), the new versions are pushed to your dev deployment and the [generated types](/generated-api/.md) in `convex/_generated` are updated. By default, logs from your dev deployment are displayed in the terminal. It's also possible to [run a Convex deployment locally](/cli/local-deployments.md) for development. ### Open the dashboard[​](#open-the-dashboard "Direct link to Open the dashboard") ``` npx convex dashboard ``` Open the [Convex dashboard](/dashboard.md). ### Open the docs[​](#open-the-docs "Direct link to Open the docs") ``` npx convex docs ``` Get back to these docs! ### Run Convex functions[​](#run-convex-functions "Direct link to Run Convex functions") ``` 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. ``` 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[​](#tail-deployment-logs "Direct link to Tail deployment logs") You can choose how to pipe logs from your dev deployment to your console: ``` # Show all logs continuously npx convex dev --tail-logs always # Pause logs during deploys to see sync issues (default) npx convex dev # Don't display logs while developing npx convex dev --tail-logs disable # Tail logs without deploying npx convex logs ``` Use `--prod` with `npx convex logs` to tail the prod deployment logs instead. ### Import data from a file[​](#import-data-from-a-file "Direct link to Import data from a file") ``` npx convex import --table npx convex import .zip ``` See description and use-cases: [data import](/database/import-export/import.md). ### Export data to a file[​](#export-data-to-a-file "Direct link to Export data to a file") ``` npx convex export --path npx convex export --path .zip npx convex export --include-file-storage --path ``` See description and use-cases: [data export](/database/import-export/export.md). ### Display data from tables[​](#display-data-from-tables "Direct link to Display data from tables") ``` npx convex data # lists tables npx convex data ``` Display a simple view of the [dashboard data page](/dashboard/deployments/data.md) 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](/database/reading-data/.md). The `npx convex data
` command works with [system tables](/database/advanced/system-tables.md), such as `_storage`, in addition to your own tables. ### Read and write environment variables[​](#read-and-write-environment-variables "Direct link to Read and write environment variables") ``` 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](/dashboard/deployments/deployment-settings.md#environment-variables). ## Deploy[​](#deploy "Direct link to Deploy") ### Deploy Convex functions to production[​](#deploy-convex-functions-to-production "Direct link to Deploy Convex functions to production") ``` 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: ``` npx convex deploy --cmd "npm run build" ``` You can customize the URL environment variable name with `--cmd-url-env-var-name`: ``` 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](/generated-api/.md) in the `convex/_generated` directory. 4. Bundle your Convex functions and their dependencies. 5. Push your functions, [indexes](/database/reading-data/indexes/.md), and [schema](/database/schemas.md) to production. Once this command succeeds the new functions will be available immediately. ### Deploy Convex functions to a [preview deployment](/production/hosting/preview-deployments.md)[​](#deploy-convex-functions-to-a-preview-deployment "Direct link to deploy-convex-functions-to-a-preview-deployment") ``` npx convex deploy ``` When run with the `CONVEX_DEPLOY_KEY` environment variable containing a [Preview Deploy Key](/cli/deploy-key-types.md#deploying-to-preview-deployments), this command will: 1. Create a new Convex deployment. `npx convex deploy` will infer the Git branch name for Vercel, Netlify, GitHub, and GitLab environments, or the `--preview-create` option can be used to customize the name associated with the newly created deployment. ``` 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: ``` npx convex deploy --cmd "npm run build" ``` You can customize the URL environment variable name with `--cmd-url-env-var-name`: ``` 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](/generated-api/.md) in the `convex/_generated` directory. 5. Bundle your Convex functions and their dependencies. 6. Push your functions, [indexes](/database/reading-data/indexes/.md), and [schema](/database/schemas.md) to the deployment. 7. Run a function specified by `--preview-run` (similar to the `--run` option for `npx convex dev`). ``` npx convex deploy --preview-run myFunction ``` See the [Vercel](/production/hosting/vercel.md#preview-deployments) or [Netlify](/production/hosting/netlify.md#deploy-previews) hosting guide for setting up frontend and backend previews together. ### Update generated code[​](#update-generated-code "Direct link to Update generated code") ``` npx convex codegen ``` The [generated code](/generated-api/.md) in the `convex/_generated` directory includes types required for a TypeScript typecheck. This code is generated whenever necessary while running `npx convex dev` and this code should be committed to the repo (your code won't typecheck without it!). In the rare cases it's useful to regenerate code (e.g. in CI to ensure that the correct code was checked it) you can use this command. Generating code can require communicating with a convex deployment in order to evaluate configuration files in the Convex JavaScript runtime. This doesn't modify the code running on the deployment. --- # Agent Mode When logged in on your own machine, agents like Cursor and Claude Code can run CLI commands like `npx convex env list` that use your logged-in credentials run commands against your personal dev environment as if you ran the commands yourself. This works well when you're collaborating with an agent; just like when the agent runs `git commit -am "Fix."`, the commit will use your local git credentials. But when cloud-based coding agents like Jules, Devin, Codex, or Cursor background agents run Convex CLI commands, they can't log in. And if you do log in for them, the agent will use your default dev deployment to develop, conflicting with your own changes! Instead, set `CONVEX_AGENT_MODE=anonymous` in this environment, causing the agent to use [anonymous development](/cli/local-deployments.md) to run a separate Convex backend on the VM where the agent is working. Convex Agent Mode is in beta Convex Agent Mode is currently a [beta feature](/production/state/.md#beta-features). If you have feedback or feature requests, [let us know on Discord](https://convex.dev/community)! You can set this variable in .env.local or set it in the agent's environment. ``` CONVEX_AGENT_MODE=anonymous npx convex dev ``` In the future `CONVEX_AGENT_MODE` may support other behaviors like allowing agents to provision their own short-lived cloud deployments. --- # Deploy keys When you can't log in or use the CLI interactively to specify a project or deployment, for example in a production build environment, the environment variable `CONVEX_DEPLOY_KEY` can be set to a deploy key to make convex CLI commands run non-interactively. Deploy keys identify a deployment, project, or team; confer permission to take certain actions with those resources; and can change the behavior of the convex CLI. ### Developing locally does not require a deploy key[​](#developing-locally-does-not-require-a-deploy-key "Direct link to Developing locally does not require a deploy key") Running `npx convex dev` on a new machine offers the choice to log in or run Convex locally without an account. Logging in stores a *user token* at `~/.convex/config.json` which is used automatically for all CLI use going forward on that machine. This token grants permission to push code to and read/write data from any deployment this user has access to. Using Convex locally without logging in ([anonymous development](/cli/local-deployments.md#anonymous-development)) creates a deployment locally and records this preference for this project in the `.env.local` file in the project directory. The *admin key* for this anonymous backend is stored in `~/.convex/anonymous-convex-backend-state/` along with its serialized data. In either of these cases, there's no reason to set `CONVEX_DEPLOY_KEY`. ### How to set a deploy key[​](#how-to-set-a-deploy-key "Direct link to How to set a deploy key") Generally deploys keys are set in a dashboard of the service that needs the key but in most shells you can set it right before the command, like ``` CONVEX_DEPLOY_KEY='key goes here' npx convex dev ``` or export it before you run the command ``` export CONVEX_DEPLOY_KEY='key goes here' npx convex dev ``` or add it to your `.env.local` file where it will be found by `npx convex` when run in that directory. # Common uses of deploy keys ### Deploying from build pipelines[​](#deploying-from-build-pipelines "Direct link to Deploying from build pipelines") A *production deploy key* specifies the production deployment of a project and grants permissions to deploy code to it. > `prod:qualified-jaguar-123|eyJ2...0=` You can deploying code from a build pipeline where you can't log in (e.g. Vercel, Netlify, Cloudflare build pipelines) Read more about [deploying to production](https://docs.convex.dev/production/hosting/). ### Deploying to preview deployments[​](#deploying-to-preview-deployments "Direct link to Deploying to preview deployments") A *preview deploy key* looks like this: > `preview:team-slug:project-slug|eyJ2...0=` Use a preview deploy key to change the behavior of a normal `npx convex deploy` command to deploy to a preview branch. Read more about [preview deployments](/production/hosting/preview-deployments.md). ### Admin keys[​](#admin-keys "Direct link to Admin keys") An admin key provides complete control over a deployment. An admin key might look like > `bold-hyena-681|01c2...c09c` Unlike other types of deploy key, an admin key does not require a network connection to to be used since it's a irrevocable secret baked into the deployment when created. These keys are used to control [anonymous](/cli/local-deployments.md#anonymous-development) Convex deployments locally without logging in, but rarely need to be set explicitly. Setting `CONVEX_DEPLOY_KEY` to one will cause the Convex CLI to run against that deployment instead of offering a choice. ## Rarer types of deploy keys[​](#rarer-types-of-deploy-keys "Direct link to Rarer types of deploy keys") ### Project tokens[​](#project-tokens "Direct link to Project tokens") A *project token* grants total control over a project to a convex CLI and carries with it the permission to create and use development and production deployments in that project. > `project:team-slug:project-slug|eyJ2...0=` Project tokens are obtained when a user grants an permission to use a project to an organization via an Convex OAuth application. Actions made with the token are on behalf of the user so if a user loses access to a project the token no longer grant access to it. ### Development deploy keys[​](#development-deploy-keys "Direct link to Development deploy keys") A *dev deploy key* might be used to provide an agent full access to a single deployment for development. > `dev:joyful-jaguar-123|eyJ2...0=` This can help limit the blast radius when developing with an agent. To give an agent exclusive access to its own dev deployment, see [Agent Mode](/cli/agent-mode.md). --- # Local Deployments for Development Instead of syncing code to a Convex dev deployment hosted in the cloud, you can develop against a deployment running on your own computer. You can even use the Convex dashboard with local deployments! ## Background on deployments in Convex[​](#background-on-deployments-in-convex "Direct link to Background on deployments in Convex") Each Convex deployment contains its own data, functions, scheduled functions, etc. A project has one production deployment, up to one cloud deployment for development per team member, and potentially many transient [preview deployments](/production/hosting/preview-deployments.md). You can also develop with Convex using a deployment running on your own machine. Since the deployment is running locally, code sync is faster and means resources like functions calls and database bandwidth don't count against [the quotas for your Convex plan](https://www.convex.dev/pricing). You can use local deployments with an existing Convex project, and view your deployment in the Convex dashboard under your project. You can also use local deployments without a Convex account and debug and inspect them with a locally running version of the Convex dashboard. ## Using local deployments[​](#using-local-deployments "Direct link to Using local deployments") Local deployments are in beta Local deployments are currently a [beta feature](/production/state/.md#beta-features). If you have feedback or feature requests, [let us know on Discord](https://convex.dev/community)! While using local deployments, the local Convex backend runs as a subprocess of the `npx convex dev` command and exits when that command is stopped. This means a `convex dev` command must be running in order to run other commands like `npx convex run` against this local deployment or for your frontend to connect to this deployment. State for local backends is stored the `~/.convex/` directory. ### Anonymous development[​](#anonymous-development "Direct link to Anonymous development") You can use local deployments to develop with Convex without having to create an account. Whenever you want to create an account to deploy your app to production or to use more Convex features, you can use `npx convex login` to link your local deployments with your account. ### Local deployments for an existing project[​](#local-deployments-for-an-existing-project "Direct link to Local deployments for an existing project") To use a local deployment for an existing project, run: ``` npx convex dev --local --once ``` You'll also always be given the option for a local deployment if you run `npx convex dev --configure`. Other flows may assume you want a cloud deployment in some situations, for example when connecting to a project for which you already have a cloud development deployment. ## Local deployments vs. production[​](#local-deployments-vs-production "Direct link to Local deployments vs. production") Local deployments are not recommended for production use: they're development deployments, i.e. logs for function results and full stack traces for error responses are sent to connected clients. For running a production application, you can use a production deployment hosted on the Convex cloud. Learn more about deploying to production [here](/production.md). Alternatively, you can self-host a production deployment using the [open source convex-backend repo](https://github.com/get-convex/convex-backend). ### Disabling[​](#disabling "Direct link to Disabling") To stop using local developments for a project, run the following: ``` npx convex disable-local-deployments ``` Remember your cloud dev deployment and each local dev deployment are completely separate, so contain different data. When switching between deployments you may wish to [export and re-import](/database/import-export/.md) the data to keep using it. ## Limitations[​](#limitations "Direct link to Limitations") * **No Public URL** - Cloud deployments have public URL to receive incoming HTTP requests from services like Twilio, but local deployments listen for HTTP requests on your own computer. Similarly, you can't power websites with Convex WebSocket connections unless your users browsers know how to reach your computer. Set up a proxy like ngrok or use a cloud deployment for these uses cases. * **Node actions require specific Node.js versions** - Running Node.js actions (actions defined in files with `"use node;"`) requires having Node.js 18 installed, since this is the version of Node.js used in production when Node.js actions run in AWS Lambda functions. To resolve this you can install and set up [nvm](https://github.com/nvm-sh/nvm) and then install Node.js version 18. You don't need to use Node.js 18 for the rest of your project. * **Node.js actions run directly on your computer** - Like a normal Node.js server, code running in Node.js actions has unrestricted filesystem access. Queries, mutations, and Convex runtime actions still run in isolated environments. * Logs get cleared out every time a `npx convex dev` command is restarted. * []()**Using the dashboard with Safari**: Safari [blocks requests to localhost](https://bugs.webkit.org/show_bug.cgi?id=171934), which prevents the dashboard from working with local deployments. We recommend using another browser if you’re using local deployments. * []()**Using the dashboard with Brave**: Brave [blocks requests to localhost by default](https://brave.com/privacy-updates/27-localhost-permission/), which prevents the dashboard from working with local deployments. You can use the following workaround: * Go to `brave://flags/` * Enable the `#brave-localhost-access-permission` flag * Go back to the Convex dashboard * Click on **View Site Information** (![View Site Information icon](/screenshots/brave-site-information.png)) in the URL bar, then on **Site settings** * Change the setting for **Localhost access** to **Allow** --- # Android Kotlin Convex Android client library enables your Android application to interact with your Convex backend. It allows your frontend code to: 1. Call your [queries](/functions/query-functions.md), [mutations](/functions/mutation-functions.md) and [actions](/functions/actions.md) 2. Authenticate users using [Auth0](/auth/auth0.md) The library is open source and [available on GitHub](https://github.com/get-convex/convex-mobile/tree/main/android). Follow the [Android Quickstart](/quickstart/android.md) to get started. ## Installation[​](#installation "Direct link to Installation") You'll need to make the following changes to your app's `build.gradle[.kts]` file. ``` 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[​](#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: ``` 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: ``` 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: ``` val convex = (application as MyApplication).convex ``` ## Fetching data[​](#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`: ``` 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[​](#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. ``` 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](/client/android/data-types.md#custom-data-types) to automatically convert Convex objects to Kotlin model classes. caution * There are important gotchas when [sending and receiving numbers](/client/android/data-types.md#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](/client/android/data-types.md#field-name-conversion). * Depending on your backend functions, you may need to deal with [reserved Kotlin keywords](/client/android/data-types.md#field-name-conversion). ### Subscription lifetime[​](#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[​](#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: ``` 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[​](#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[​](#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[​](#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: ``` // 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. ``` 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[​](#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[​](#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[​](#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. --- # Kotlin and Convex type conversion ## Custom data types[​](#custom-data-types "Direct link to Custom data types") When receiving values from Convex, you aren't limited to primitive values. You can create custom `@Serializable` classes that will be automatically decoded from response data. Consider a Convex query function that returns results like this JavaScript object: ``` { name: "Guardians", uniformColors: ["blue", "white", "red"], wins: 80n, losses: 60n } ``` That can be represented in Kotlin using: ``` @Serializable data class BaseballTeam( val name: String, val uniformColors: List, val wins: @ConvexNum Int, val losses: @ConvexNum Int) ``` Then you can pass it as the type argument in your `subscribe` call: ``` convex.subscribe("mlb:first_place_team", args = mapOf("division" to "AL Central")) ``` The data from the remote function will be deserialized to your custom class. ## Numerical types[​](#numerical-types "Direct link to Numerical types") Your Convex backend code is written in JavaScript, which has two relatively common types for numerical data: `number` and `BigInt`. `number` is used whenever a value is assigned a literal numeric value, whether `42` or `3.14`. `BigInt` can be used by adding a trailing `n`, like `42n`. Despite the two types, is very common to use `number` for holding either integer or floating point values in JavaScript. Because of this, Convex takes extra care to encode values so they won't lose precision. Since technically the `number` type is an IEEE 754 floating point value, anytime you get a plain `number` from Convex it will be represented as floating point in Kotlin. You can choose to use `Double` or `Float`, depending on your needs but be aware that `Float` might lose precision from the original. It also means that Kotlin's `Long` type (64 bit) can't be safely stored in a `number` (only 53 bits are available to encode integers) and requires a `BigInt`. That's a long lead up to explain that in order to represent numerical values in responses from Convex, you need to hint to Kotlin that they should use custom decoding. You can do this in three ways. Use whichever seems most useful to your project. 1. Annotate the plain Kotlin type (`Int`, `Long`, `Float`, `Double`) with `@ConvexNum` 2. Use a provided type alias for those types (`Int32`, `Int64`, `Float32`, `Float64`) 3. Include a special annotation at the top of any file that defines `@Serializable` classes and just use the plain types with no annotation ``` @file:UseSerializers( Int64ToIntDecoder::class, Int64ToLongDecoder::class, Float64ToFloatDecoder::class, Float64ToDoubleDecoder::class ) package com.example.convexapp import kotlinx.serialization.UseSerializers // @Serializable classes and things. ``` In the example, JavaScript's `BigInt` type is used by adding a trailing `n` to the `wins` and `losses` values which lets the Kotlin code use `Int`. If instead the code used regular JavaScript `number` types, on the Kotlin side those would be received as floating point values and deserialization would fail. If you have a situation like that where `number` is used but by convention only contains integer values, you can handle that in your `@Serializable` class. ``` @Serializable data class BaseballTeam( val name: String, val uniformColors: List, @SerialName("wins") private val internalWins: Double, @SerialName("losses") private val internalLosses: Double) { // Expose the JavaScript number values as Ints. val wins get() = internalWins.toInt() val losses get() = internalLosses.toInt() } ``` The pattern is to store the `Double` values privately and with different names that the value from the backend. Then add accessors to provide the `Int` values. ## Field name conversion[​](#field-name-conversion "Direct link to Field name conversion") This pattern was used above, but it bears describing on its own. Sometimes a value will be produced on the backend with a key that matches a Kotlin keyword (`{fun: true}`) or doesn't conform to Kotlin naming conventions (e.g. starts with an underscore). You can use `@SerialName` to handle those cases. For example, here's how you can ingest the Convex [document ID](https://docs.convex.dev/database/document-ids) from a backend response and convert it to a field name that won't trigger Kotlin lint warnings: ``` @Serializable data class ConvexDocument(@SerialName("_id") val id: String) ``` --- # 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](/api/classes/browser.ConvexClient.md) allows web applications and long-running Node.js servers to subscribe to updates on Convex queries, while the [Convex HTTP client](/api/classes/browser.ConvexHttpClient.md) 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`](/api/classes/browser.ConvexClient.md) described in [React](/client/react.md). ## Convex Client[​](#convex-client "Direct link to Convex Client") The [`ConvexClient`](/api/classes/browser.ConvexClient.md) provides subscriptions to queries in Node.js and any JavaScript environment that supports WebSockets. script.ts TS ``` 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](/quickstart/script-tag.md) to get started. ## HTTP client[​](#http-client "Direct link to HTTP client") The [`ConvexHttpClient`](/api/classes/browser.ConvexHttpClient.md) works in the browser, Node.js, and any JavaScript environment with `fetch`. See the [Node.js Quickstart](/quickstart/nodejs.md). script.ts TS ``` 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`[​](#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 ``` 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, ); ``` --- # Bun [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](/api/classes/browser.ConvexHttpClient.md)) and those plus query subscriptions (see [ConvexClient](/api/classes/browser.ConvexClient.md)) in Bun. ``` 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[​](#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"`. --- # Node.js Convex supports point-in-time queries (see [HTTP client](/api/classes/browser.ConvexHttpClient.md)) and query subscriptions (see [ConvexClient](/api/classes/browser.ConvexClient.md)) in Node.js. If your JavaScript code uses import/export syntax, calling Convex functions works just like in a browser. ``` 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[​](#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[​](#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)[​](#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`](/production/project-configuration.md#convexjson): ``` { "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. ``` 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[​](#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[​](#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"`. --- # Script Tag Sometimes you just want to get your data on a web page: no installing packages, no build steps, no TypeScript. Subscribing to queries deployed to an existing Convex deployment from a script tag is simple. index.html ``` ``` VS Code doesn't support TypeScript autocompletion in HTML files so for types and better autocompletion you can split your code out into a script file: index.html ```
``` script.js ``` const CONVEX_URL = "CONVEX_URL_GOES_HERE"; // These JSDoc type annotations help VS Code find types. /** @type {import("convex/browser")["ConvexClient"]} */ const ConvexClient = convex.ConvexClient; const client = new ConvexClient(CONVEX_URL); /** @type {import("./convex/_generated/api")["api"]} */ const api = convex.anyApi; client.onUpdate(api.messages.list, {}, (messages) => { console.log(messages); const container = document.querySelector(".messages"); container.innerHTML = ""; for (const message of messages.reverse()) { const li = document.createElement("li"); li.textContent = `${message.author}: ${message.body}`; container.appendChild(li); } }); document.querySelector("form").addEventListener("submit", (e) => { e.preventDefault(); const inp = e.target.querySelector("input"); client.mutation(api.messages.send, { body: inp.value, author: "me", }); inp.value = ""; }); ``` See the [Script Tag Quickstart](/quickstart/script-tag.md) for instructions for setting up a new Convex project. --- # Next.js [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](/client/nextjs/pages-router/.md) version of this page. ## Getting started[​](#getting-started "Direct link to Getting started") Follow the [Next.js Quickstart](/quickstart/nextjs.md) to add Convex to a new or existing Next.js project. ## Calling Convex functions from client code[​](#calling-convex-functions-from-client-code "Direct link to Calling Convex functions from client code") To fetch and edit the data in your database from client code, use hooks of the [Convex React library](/client/react.md). ## [Convex React library documentation](/client/react.md) ## Server rendering (SSR)[​](#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](/functions/query-functions.md#caching--reactivity--consistency) 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](/client/nextjs/app-router/server-rendering.md) page for more details about preloading data for Client Components, fetching data and authentication in Server Components, and implementing Route Handlers. ## Adding authentication[​](#adding-authentication "Direct link to Adding authentication") ### Client-side only[​](#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](/auth/clerk.md) or [Auth0](/auth/auth0.md), inside your `app/ConvexClientProvider.tsx` file. For example this is what the file would look like for Auth0: app/ConvexClientProvider.tsx TS ``` "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](/api/classes/react.ConvexReactClient.md) instance between pages to avoid needing to reconnect to Convex on client-side page navigation. ### Server and client side[​](#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[​](#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[​](#auth0 "Direct link to Auth0") See the [Auth0 Next.js](https://auth0.com/docs/quickstart/webapp/nextjs/01-login) guide. #### Other providers[​](#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. --- # Next.js Server Rendering Next.js automatically renders both Client and Server Components on the server during the initial page load. By default Client Components will not wait for Convex data to be loaded, and your UI will render in a "loading" state. Read on to learn how to preload data during server rendering and how to interact with the Convex deployment from Next.js server-side. **Example:** [Next.js App Router](https://github.com/get-convex/convex-demos/tree/main/nextjs-app-router) This pages covers the App Router variant of Next.js. Next.js Server Rendering support is in beta Next.js Server Rendering support is currently a [beta feature](/production/state/.md#beta-features). If you have feedback or feature requests, [let us know on Discord](https://convex.dev/community)! ## Preloading data for Client Components[​](#preloading-data-for-client-components "Direct link to Preloading data for Client Components") If you want to preload data from Convex and leverage Next.js [server rendering](https://nextjs.org/docs/app/building-your-application/rendering/server-components#server-rendering-strategies), but still retain reactivity after the initial page load, use [`preloadQuery`](/api/modules/nextjs.md#preloadquery) from [`convex/nextjs`](/api/modules/nextjs.md). In a [Server Component](https://nextjs.org/docs/app/building-your-application/rendering/server-components) call `preloadQuery`: app/TasksWrapper.tsx TS ``` import { preloadQuery } from "convex/nextjs"; import { api } from "@/convex/_generated/api"; import { Tasks } from "./Tasks"; export async function TasksWrapper() { const preloadedTasks = await preloadQuery(api.tasks.list, { list: "default", }); return ; } ``` In a [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components) call [`usePreloadedQuery`](/api/modules/react.md#usepreloadedquery): app/TasksWrapper.tsx TS ``` "use client"; import { Preloaded, usePreloadedQuery } from "convex/react"; import { api } from "@/convex/_generated/api"; export function Tasks(props: { preloadedTasks: Preloaded; }) { const tasks = usePreloadedQuery(props.preloadedTasks); // render `tasks`... return
...
; } ``` [`preloadQuery`](/api/modules/nextjs.md#preloadquery) takes three arguments: 1. The query reference 2. Optionally the arguments object passed to the query 3. Optionally a [NextjsOptions](/api/modules/nextjs.md#nextjsoptions) object `preloadQuery` uses the [`cache: 'no-store'` policy](https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating#opting-out-of-data-caching) so any Server Components using it will not be eligible for [static rendering](https://nextjs.org/docs/app/building-your-application/rendering/server-components#server-rendering-strategies). ### Using the query result[​](#using-the-query-result "Direct link to Using the query result") [`preloadQuery`](/api/modules/nextjs.md#preloadquery) returns an opaque `Preloaded` payload that should be passed through to `usePreloadedQuery`. If you want to use the return value of the query, perhaps to decide whether to even render the Client Component, you can pass the `Preloaded` payload to the [`preloadedQueryResult`](/api/modules/nextjs.md#preloadedqueryresult) function. ## Using Convex to render Server Components[​](#using-convex-to-render-server-components "Direct link to Using Convex to render Server Components") If you need Convex data on the server, you can load data from Convex in your [Server Components](https://nextjs.org/docs/app/building-your-application/data-fetching/fetching), but it will be non-reactive. To do this, use the [`fetchQuery`](/api/modules/nextjs.md#fetchquery) function from `convex/nextjs`: app/StaticTasks.tsx TS ``` import { fetchQuery } from "convex/nextjs"; import { api } from "@/convex/_generated/api"; export async function StaticTasks() { const tasks = await fetchQuery(api.tasks.list, { list: "default" }); // render `tasks`... return
...
; } ``` ## Server Actions and Route Handlers[​](#server-actions-and-route-handlers "Direct link to Server Actions and Route Handlers") Next.js supports building HTTP request handling routes, similar to Convex [HTTP Actions](/functions/http-actions.md). You can use Convex from a [Server Action](https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations) or a [Route Handler](https://nextjs.org/docs/app/building-your-application/routing/route-handlers) as you would any other database service. To load and edit Convex data in your Server Action or Route Handler, you can use the `fetchQuery`, `fetchMutation` and `fetchAction` functions. Here's an example inline Server Action calling a Convex mutation: app/example/page.tsx TS ``` import { api } from "@/convex/_generated/api"; import { fetchMutation, fetchQuery } from "convex/nextjs"; import { revalidatePath } from "next/cache"; export default async function PureServerPage() { const tasks = await fetchQuery(api.tasks.list, { list: "default" }); async function createTask(formData: FormData) { "use server"; await fetchMutation(api.tasks.create, { text: formData.get("text") as string, }); revalidatePath("/example"); } // render tasks and task creation form return
...; } ``` Here's an example Route Handler calling a Convex mutation: app/api/route.ts TS ``` import { NextResponse } from "next/server"; // Hack for TypeScript before 5.2 const Response = NextResponse; import { api } from "@/convex/_generated/api"; import { fetchMutation } from "convex/nextjs"; export async function POST(request: Request) { const args = await request.json(); await fetchMutation(api.tasks.create, { text: args.text }); return Response.json({ success: true }); } ``` ## Server-side authentication[​](#server-side-authentication "Direct link to Server-side authentication") To make authenticated requests to Convex during server rendering, pass a JWT token to [`preloadQuery`](/api/modules/nextjs.md#preloadquery) or [`fetchQuery`](/api/modules/nextjs.md#fetchquery) in the third options argument: app/TasksWrapper.tsx TS ``` import { preloadQuery } from "convex/nextjs"; import { api } from "@/convex/_generated/api"; import { Tasks } from "./Tasks"; export async function TasksWrapper() { const token = await getAuthToken(); const preloadedTasks = await preloadQuery( api.tasks.list, { list: "default" }, { token }, ); return ; } ``` The implementation of `getAuthToken` depends on your authentication provider. * Clerk * Auth0 app/auth.ts TS ``` import { auth } from "@clerk/nextjs/server"; export async function getAuthToken() { return (await (await auth()).getToken({ template: "convex" })) ?? undefined; } ``` app/auth.ts TS ``` // You'll need v4.3 or later of @auth0/nextjs-auth0 import { getSession } from '@auth0/nextjs-auth0'; export async function getAuthToken() { const session = await getSession(); const idToken = session.tokenSet.idToken; return idToken; } ``` ## Configuring Convex deployment URL[​](#configuring-convex-deployment-url "Direct link to Configuring Convex deployment URL") Convex hooks used by Client Components are configured via the `ConvexReactClient` constructor, as shown in the [Next.js Quickstart](/quickstart/nextjs.md). To use `preloadQuery`, `fetchQuery`, `fetchMutation` and `fetchAction` in Server Components, Server Actions and Route Handlers you must either: 1. have `NEXT_PUBLIC_CONVEX_URL` environment variable set to the Convex deployment URL 2. or pass the [`url` option](/api/modules/nextjs.md#nextjsoptions) in the third argument to `preloadQuery`, `fetchQuery`, `fetchMutation` or `fetchAction` ## Consistency[​](#consistency "Direct link to Consistency") [`preloadQuery`](/api/modules/nextjs.md#preloadquery) and [`fetchQuery`](/api/modules/nextjs.md#fetchquery) use the `ConvexHTTPClient` under the hood. This client is stateless. This means that two calls to `preloadQuery` are not guaranteed to return consistent data based on the same database state. This is similar to more traditional databases, but is different from the [guaranteed consistency](/client/react.md#consistency) provided by the `ConvexReactClient`. To prevent rendering an inconsistent UI avoid using multiple `preloadQuery` calls on the same page. --- # Next.js Pages Router This pages covers the Pages Router variant of Next.js. Alternatively see the [App Router](/client/nextjs/app-router/.md) version of this page. ## Getting started[​](#getting-started "Direct link to Getting started") Follow the [Next.js Pages Router Quickstart](/client/nextjs/pages-router/quickstart.md) to add Convex to a new or existing Next.js project. ## Adding client-side authentication[​](#adding-client-side-authentication "Direct link to Adding client-side authentication") The simplest approach to authentication in Next.js is to keep it client-side. For example Auth0 describes this approach in [Next.js Authentication with Auth0 guide](https://auth0.com/blog/ultimate-guide-nextjs-authentication-auth0), describing it in "[Next.js Static Site Approach](https://auth0.com/blog/ultimate-guide-nextjs-authentication-auth0/#Next-js-Static-Site-Approach)" and "Serverless with the user on the frontend". To require login on every page of your application you can add logic to `_app.jsx` to conditionally render page content, blocking it until the user is logged in. If you're using Auth0, the helper component `ConvexProviderWithAuth0` can be imported from `convex/react-auth0`. pages/\_app.jsx ``` import { ConvexReactClient } from "convex/react"; import { ConvexProviderWithAuth0 } from "convex/react-auth0"; import { Auth0Provider } from "@auth0/auth0-react"; import { AppProps } from "next/app"; const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!); export default function MyApp({ Component, pageProps }: AppProps) { return ( ); } ``` 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.jsx) 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 `pages/_app.jsx`. Share a single [ConvexReactClient](/api/classes/react.ConvexReactClient.md) instance between pages to avoid needing to reconnect to Convex on client-side page navigation. Read more about authenticating users with Convex in [Authentication](/auth.md). ## API routes[​](#api-routes "Direct link to API routes") Next.js supports building HTTP request handling routes, similar to Convex [HTTP Actions](/functions/http-actions.md). Using Next.js routes might be helpful if you need to use a dependency not supported by the Convex default runtime. To build an [API route](https://nextjs.org/docs/api-routes/introduction) add a file to the `pages/api` directory. To load and edit Convex data in your endpoints, use the [`fetchQuery`](/api/modules/nextjs.md#fetchquery) function from `convex/nextjs`: pages/api/clicks.js ``` import type { NextApiRequest, NextApiResponse } from "next"; import { fetchQuery } from "convex/nextjs"; import { api } from "../../convex/_generated/api"; export const count = async function handler( _req: NextApiRequest, res: NextApiResponse, ) { const clicks = await fetchQuery(api.counter.get, { counterName: "clicks" }); res.status(200).json({ clicks }); }; ``` ## Server-side rendering[​](#server-side-rendering "Direct link to Server-side rendering") **Consider client-side rendering Convex data when using Next.js.** Data from Convex is [fully reactive](/functions/query-functions.md#caching--reactivity--consistency) so Convex needs a connection from your deployment to the browser in order to push updates as data changes. You can of course load data from Convex in [`getStaticProps`](https://nextjs.org/docs/basic-features/data-fetching/get-static-props) or [`getServerSideProps`](https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props), but it will be non-reactive. To do this, use the [`fetchQuery`](/api/modules/nextjs.md#fetchquery) function to call query functions just like you would in [API routes](#api-routes). To make authenticated requests to Convex during server-side rendering, you need authentication info present server-side. Auth0 describes this approach in [Serverless with the user on the backend](https://auth0.com/blog/ultimate-guide-nextjs-authentication-auth0/#Serverless-with-the-user-on-the-backend). When server-side rendering, pass the authentication token as `token` to the third argument of `fetchQuery`. To preload data on server side before rendering a reactive query on the client side use [`preloadQuery`](/api/modules/nextjs.md#preloadquery). Check out the [App Router version of these docs](/client/nextjs/app-router/server-rendering.md) for more details. --- # Next.js Pages Quickstart Learn how to query data from Convex in a Next.js app using the Pages Router. Alternatively see the [App Router](/quickstart/nextjs.md) version of this quickstart. 1. 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). ``` npx create-next-app@latest my-app --no-app --js ``` 2. 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`. ``` cd my-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. ``` 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 ``` {"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. ``` 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 ``` import { query } from "./_generated/server"; export const get = query({ args: {}, handler: async (ctx) => { return await ctx.db.query("tasks").collect(); }, }); ``` 7. Connect the app to your backend In `pages/_app.js`, create a `ConvexReactClient` and pass it to a `ConvexProvider` wrapping your app. pages/\_app.js ``` import "@/styles/globals.css"; import { ConvexProvider, ConvexReactClient } from "convex/react"; const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL); export default function App({ Component, pageProps }) { return ( ); } ``` 8. Display the data in your app In `pages/index.js`, use the `useQuery` hook to fetch from your `api.tasks.get` API function. pages/index.js ``` 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}
))}
); } ``` 9. Start the app Start the app, open in a browser, and see the list of tasks. ``` npm run dev ``` --- # OpenAPI & Other Languages 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](/http-api/.md). This means that your queries will not be reactive/real-time. OAS generation is in beta OAS generation is currently a [beta feature](/production/state/.md#beta-features). If you have feedback or feature requests, [let us know on Discord](https://convex.dev/community)! ## Setup[​](#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. ``` 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. ``` 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/). ``` # 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[​](#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 ``` 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 ``` 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[​](#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`. --- # Python See the [Python Quickstart](/quickstart/python.md) 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). --- # Convex React 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](/functions/query-functions.md), [mutations](/functions/mutation-functions.md) and [actions](/functions/actions.md) 2. Upload and display files from [File Storage](/file-storage.md) 3. Authenticate users using [Authentication](/auth.md) 4. Implement full text [Search](/search.md) 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](/quickstart/react.md) to get started with React using [Vite](https://vitejs.dev/). ## Installation[​](#installation "Direct link to Installation") Convex React is part of the `convex` npm package: ``` npm install convex ``` ## Connecting to a backend[​](#connecting-to-a-backend "Direct link to Connecting to a backend") The [`ConvexReactClient`](/api/classes/react.ConvexReactClient.md) 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](/client/react/deployment-urls.md) on how to pass in the right value: ``` 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`](/api/modules/react.md#convexprovider) wrapping your component tree: ``` reactDOMRoot.render( , ); ``` ## Fetching data[​](#fetching-data "Direct link to Fetching data") Your React app fetches data using the [`useQuery`](/api/modules/react.md#usequery) React hook by calling your [queries](/functions/query-functions.md) via an [`api`](/generated-api/api.md#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](/understanding/best-practices/typescript.md): src/App.tsx TS ``` 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[​](#query-arguments "Direct link to Query arguments") Arguments to your query follow the query name: src/App.tsx TS ``` export function App() { const a = "Hello world"; const b = 4; const data = useQuery(api.functions.myQuery, { a, b }); //... } ``` ### Reactivity[​](#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[​](#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[​](#paginating-queries "Direct link to Paginating queries") See [Paginating within React Components](/database/pagination.md#paginating-within-react-components). ### Skipping queries[​](#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 ``` 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 ``` 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[​](#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`](/api/classes/react.ConvexReactClient.md#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()`](/api/modules/react.md#useconvex) hook. src/App.tsx TS ``` import { useConvex } from "convex/react"; import { api } from "../convex/_generated/api"; export function App() { const convex = useConvex(); return ( ); } ``` ## Editing data[​](#editing-data "Direct link to Editing data") Your React app edits data using the [`useMutation`](/api/modules/react.md#usemutation) React hook by calling your [mutations](/functions/mutation-functions.md). 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](/understanding/best-practices/typescript.md): src/App.tsx TS ``` 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[​](#mutation-arguments "Direct link to Mutation arguments") Arguments to your mutation are passed to the `async` function returned from `useMutation`: src/App.tsx TS ``` export function App() { const a = "Hello world"; const b = 4; const doSomething = useMutation(api.functions.doSomething); return ; } ``` ### Mutation response and error handling[​](#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 ``` 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 ``` 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](/functions/error-handling/.md) in functions. ### Retries[​](#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[​](#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](/client/react/optimistic-updates.md) on how to configure them. ## Calling third-party APIs[​](#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`](/api/modules/react.md#useaction) React hook by calling your [actions](/functions/actions.md). 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](/understanding/best-practices/typescript.md): src/App.tsx TS ``` 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[​](#action-arguments "Direct link to Action arguments") Action arguments work exactly the same as [mutation arguments](#mutation-arguments). ### Action response and error handling[​](#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](#mutation-response-and-error-handling). Actions do not support automatic retries or optimistic updates. ## Under the hood[​](#under-the-hood "Direct link to Under the hood") The [`ConvexReactClient`](/api/classes/react.ConvexReactClient.md) 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. --- # Convex React Native To use Convex in [React Native](https://reactnative.dev/) use the [Convex React client library](/client/react.md). Follow the [React Native Quickstart](/quickstart/react-native.md) 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). --- # Configuring Deployment URL When [connecting to your backend](/client/react.md#connecting-to-a-backend) it's important to correctly configure the deployment URL. ### Create a Convex project[​](#create-a-convex-project "Direct link to Create a Convex project") The first time you run ``` npx convex dev ``` in your project directory you will create a new Convex project. Your new project includes two deployments: *production* and *development*. The *development* deployment's URL will be saved in `.env.local` or `.env` file, depending on the frontend framework or bundler you're using. You can find the URLs of all deployments in a project by visiting the [deployment settings](/dashboard/deployments/deployment-settings.md) on your Convex [dashboard](https://dashboard.convex.dev). ### Configure the client[​](#configure-the-client "Direct link to Configure the client") Construct a Convex React client by passing in the URL of the Convex deployment. There should generally be a single Convex client in a frontend application. src/index.js ``` import { ConvexProvider, ConvexReactClient } from "convex/react"; const deploymentURL = import.meta.env.VITE_CONVEX_URL; const convex = new ConvexReactClient(deploymentURL); ``` While this URL can be hardcoded, it's convenient to use an environment variable to determine which deployment the client should connect to. Use an environment variable name accessible from your client code according to the frontend framework or bundler you're using. ### Choosing environment variable names[​](#choosing-environment-variable-names "Direct link to Choosing environment variable names") To avoid unintentionally exposing secret environment variables in frontend code, many bundlers require environment variables referenced in frontend code to use a specific prefix. [Vite](https://vitejs.dev/guide/env-and-mode.html) requires environment variables used in frontend code start with `VITE_`, so `VITE_CONVEX_URL` is a good name. [Create React App](https://create-react-app.dev/docs/adding-custom-environment-variables/) requires environment variables used in frontend code to begin with `REACT_APP_`, so the code above uses `REACT_APP_CONVEX_URL`. [Next.js](https://nextjs.org/docs/basic-features/environment-variables#exposing-environment-variables-to-the-browser) requires them to begin with `NEXT_PUBLIC_`, so `NEXT_PUBLIC_CONVEX_URL` is a good name. Bundlers provide different ways to access these variables too: while [Vite uses `import.meta.env.VARIABLE_NAME`](https://vitejs.dev/guide/env-and-mode.html), many other tools like Next.js use the Node.js-like [`process.env.VARIABLE_NAME`](https://nextjs.org/docs/basic-features/environment-variables) ``` import { ConvexProvider, ConvexReactClient } from "convex/react"; const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL); ``` [`.env` files](https://www.npmjs.com/package/dotenv) are a common way to wire up different environment variable values in development and production environments. `npx convex dev` will save the deployment URL to the corresponding `.env` file, while trying to infer which bundler your project uses. .env.local ``` NEXT_PUBLIC_CONVEX_URL=https://guiltless-dog-960.convex.cloud # examples of other environment variables that might be passed to the frontend NEXT_PUBLIC_SENTRY_DSN=https://123abc@o123.ingest.sentry.io/1234 NEXT_PUBLIC_LAUNCHDARKLY_SDK_CLIENT_SIDE_ID=01234567890abcdef ``` Your backend functions can use [environment variables](/production/environment-variables.md) configured on your dashboard. They do not source values from `.env` files. --- # Optimistic Updates Even though Convex queries are completely reactive, sometimes you'll want to update your 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. These updates are made by functions registered on a mutation invocation with the [`.withOptimisticUpdate`](/api/interfaces/react.ReactMutation.md#withoptimisticupdate) configuration option. Optimistic updates are run when a mutation is initiated, rerun if the local query results change, and rolled back when a mutation completes. ## Simple example[​](#simple-example "Direct link to Simple example") Here is how an optimistic update could be added to an `increment` mutation in a simple counter app: src/IncrementCounter.tsx TS ``` import { api } from "../convex/_generated/api"; import { useMutation } from "convex/react"; export function IncrementCounter() { const increment = useMutation(api.counter.increment).withOptimisticUpdate( (localStore, args) => { const { increment } = args; const currentValue = localStore.getQuery(api.counter.get); if (currentValue !== undefined) { localStore.setQuery(api.counter.get, {}, currentValue + increment); } }, ); const incrementCounter = () => { increment({ increment: 1 }); }; return ; } ``` Optimistic updates receive a [`localStore`](/api/interfaces/browser.OptimisticLocalStore.md), a view of the Convex client's internal state, followed by the arguments to the mutation. This optimistic update updates the `api.counter.get` query to be `increment` higher if it's loaded. ## Complex example[​](#complex-example "Direct link to Complex example") If we want to add an optimistic update to a multi-channel chat app, that might look like: src/MessageSender.tsx TS ``` import { api } from "../convex/_generated/api"; import { useMutation } from "convex/react"; import { Id } from "../convex/_generated/dataModel"; export function MessageSender(props: { channel: Id<"channels"> }) { const sendMessage = useMutation(api.messages.send).withOptimisticUpdate( (localStore, args) => { const { channel, body } = args; const existingMessages = localStore.getQuery(api.messages.list, { channel, }); // If we've loaded the api.messages.list query, push an optimistic message // onto the list. if (existingMessages !== undefined) { const now = Date.now(); const newMessage = { _id: crypto.randomUUID() as Id<"messages">, _creationTime: now, channel, body, }; localStore.setQuery(api.messages.list, { channel }, [ ...existingMessages, newMessage, ]); } }, ); async function handleSendMessage( channelId: Id<"channels">, newMessageText: string, ) { await sendMessage({ channel: channelId, body: newMessageText }); } return ( ); } ``` This optimistic update changes the `api.messages.list` query for the current channel to include a new message. The newly created message object should match the structure of the real messages generated by the `api.messages.list` query on the server. Because this message includes the client's current time (not the server's), it will inevitably not match the `api.messages.list` query after the mutation runs. That's okay! The Convex client will handle rolling back this update after the mutation completes and the queries are updated. If there are small mistakes in optimistic updates, the UI will always eventually render the correct values. Similarly, the update creates a temporary `Id` with `new Id("messages", crypto.randomUUID())`. This will also be rolled back and replaced with the true ID once the server assigns it. Lastly, note that this update creates a new array of messages instead of using `existingMessages.push(newMessage)`. This is important! Mutating objects inside of optimistic updates will corrupt the client's internal state and lead to surprising results. Always create new objects inside of optimistic updates. ## Learning more[​](#learning-more "Direct link to Learning more") To learn more, check out our API documentation: * [`.withOptimisticUpdate`](/api/interfaces/react.ReactMutation.md#withoptimisticupdate) * [`OptimisticUpdate`](/api/modules/browser.md#optimisticupdate) * [`OptimisticLocalStore`](/api/interfaces/browser.OptimisticLocalStore.md) If you'd like some hands on experience, try adding optimistic updates to the [tutorial app](https://github.com/get-convex/convex-tutorial)! If you do, you should notice the app feels snappier — just a little, Convex is pretty fast already! — but otherwise works the same. To explore even further, try inserting a mistake into this update! You should see a flicker as the optimistic update is applied and then rolled back. --- # Rust See the [Rust Quickstart](/quickstart/rust.md) and [`convex` on docs.rs docs](https://docs.rs/convex/latest/convex/). The Rust client is open source and available on [GitHub](https://github.com/get-convex/convex-rs). --- # Svelte 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](/api/classes/browser.ConvexClient.md) with declarative subscriptions in Svelte 5. See the [Svelte Quickstart](/quickstart/svelte.md) to get started. The Svelte client is open source and available on [GitHub](https://github.com/get-convex/convex-svelte). --- # iOS & macOS Swift 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](/functions/query-functions.md), [mutations](/functions/mutation-functions.md) and [actions](/functions/actions.md) 2. Authenticate users using [Auth0](/auth/auth0.md) The library is open source and [available on GitHub](https://github.com/get-convex/convex-swift). Follow the [Swift Quickstart](/quickstart/swift.md) to get started. ## Installation[​](#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](/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[​](#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: ``` 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[​](#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`: ``` 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[​](#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. ``` 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](/client/swift/data-types.md#custom-data-types) to automatically convert Convex objects to Swift structs. caution * There are important gotchas when [sending and receiving numbers](/client/swift/data-types.md#numerical-types) between Swift and Convex. * Depending on your backend functions, you may need to deal with [reserved Swift keywords](/client/swift/data-types.md#field-name-conversion). ### Subscription lifetime[​](#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[​](#editing-data "Direct link to Editing Data") You can use the `mutation` method on `ConvexClient` to trigger a backend [mutation](/functions/mutation-functions.md). `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: ``` let isColorAdded: Bool = try await convex.mutation("colors:put", with: ["color": newColor]) ``` ### Handling errors[​](#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`](/functions/error-handling/application-errors.md) 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. ``` 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](/functions/error-handling/.md) for more details. ## Calling third-party APIs[​](#calling-third-party-apis "Direct link to Calling third-party APIs") You can use the `action` method on `ConvexClient` to trigger a backend [action](/functions/actions.md). 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](/functions/actions.md#calling-actions-from-clients). ## Authentication with Auth0[​](#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](/auth.md) 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[​](#production-and-dev-deployments "Direct link to Production and dev deployments") When you're ready to move toward [production](/production.md) 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: ``` 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](/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[​](#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`. ``` 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 . ## Under the hood[​](#under-the-hood "Direct link to Under the hood") The Swift Convex library is built on top of the official [Convex Rust client](/client/rust.md). 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. --- # Swift and Convex type conversion ## Custom data types[​](#custom-data-types "Direct link to Custom data types") Convex lets you easily express your data in the backend as TypeScript objects, and can return those objects from queries, mutations and actions. To handle objects on the Swift side, create `struct` definitions that conform to the `Decodable` protocol. Usually that’s fairly trivial to do, as any `struct` with all `Decodable` members can automatically conform. Consider a Convex query function that returns results like this JavaScript object: ``` { name: "Guardians", uniformColors: ["blue", "white", "red"], wins: 80n, losses: 60n } ``` That can be represented in Swift using: ``` struct BaseballTeam: Decodable { let name: String let uniformColors: [String] @ConvexInt var wins: Int @ConvexInt var losses: Int } ``` Then you can pass that type as the yielding argument in your subscribe call: ``` convex.subscribe(to: "mlb:first_place_team", with: ["division": "AL Central"], yielding: BaseballTeam.self) ``` The data from the remote function will be deserialized to your custom struct. Often your use of the type can be inferred from the calling context, and you can skip the yielding argument. ## Numerical types[​](#numerical-types "Direct link to Numerical types") Numeric types like `Int` and `Double` are encoded in a special format to ensure proper interoperation with your TypeScript backend functions. To safely use them on the Swift side, ensure that you use one of the following property wrappers. | Type | Wrapper | | ------------------------------ | ---------------------- | | `Float` or `Double` | `@ConvexFloat` | | `Float?` or `Double?` | `@OptionalConvexFloat` | | `Int` or `Int32` or `Int64` | `@ConvexInt` | | `Int?` or `Int32?` or `Int64?` | `@OptionalConvexInt` | Note that `struct` properties with wrappers must be declared as `var`. ## Field name conversion[​](#field-name-conversion "Direct link to Field name conversion") If your code receives objects with names that you need to or want to translate to different names, you can use a `CodingKeys` `enum` to specify a mapping of remote names to names on your struct. For example, imagine a backend function or API that returns log entries like the following representing when someone came in and went out: ``` {name: "Bob", in: "2024-10-03 08:00:00", out: "2024-10-03 11:00:00"} ``` That data can’t decode directly into a `struct` because `in` is a keyword in Swift. We can use `CodingKeys` to give it an alternate name while still ingesting the data from the original name. ``` struct Log: Decodable { let name: String let inTime: String let outTime: String enum CodingKeys: String, CodingKey { case name case inTime = "in" case outTime = "out" } } ``` ## Putting it all together[​](#putting-it-all-together "Direct link to Putting it all together") In the custom data type example above, JavaScript's `BigInt` type is used in the backend data by adding a trailing `n` to the `wins` and `losses` values which lets the Swift code use `Int`. If instead the code used regular JavaScript `number` types, on the Swift side those would be received as floating point values and deserialization to `Int` would fail. If you have a situation like that where `number` is used but by convention it only contains integer values, you can handle that in your `struct` by using field name conversion and custom properties to hide the floating point representation. ``` struct BaseballTeam: Decodable { let name: String let uniformColors: [String] @ConvexFloat private var internalWins: Double @ConvexFloat private var internalLosses: Double enum CodingKeys: String, CodingKey { case name case uniformColors case internalWins = "wins" case internalLosses = "losses" } // Expose the Double values as Ints var wins: Int { Int(internalWins) } var losses: Int { Int(internalLosses) } } ``` The pattern is to store the `Double` values privately and with different names than the value from the backend. Then add custom properties to provide the `Int` values. --- # Convex with TanStack Query [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](/client/react.md) 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 adapter is currently a [beta feature](/production/state/.md#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: ``` 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[​](#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 ``` npm i @convex-dev/react-query ``` wire up Convex to TanStack Query like this: src/main.tsx ``` 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`](/api/modules/react.md#convexprovider) so you can also use normal [Convex React](/client/react.md) hooks ## Queries[​](#queries "Direct link to Queries") A live-updating subscription to a Convex [query](/functions/query-functions.md) is as simple as calling TanStack [`useQuery`](https://tanstack.com/query/latest/docs/framework/react/reference/useQuery) with `convexQuery`: ``` 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). ``` 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[​](#mutations "Direct link to Mutations") Your app can call Convex [mutations](/functions/mutation-functions.md) 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`: ``` 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`](/client/react.md#editing-data) hook from [Convex React](/client/react.md). ## Differences from using `fetch` with 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. --- # TanStack Start [TanStack Start](https://tanstack.com/start/latest) is a new React web framework with best-in-class typesafe routing. When used with Convex, TanStack Start provides * Live-updating queries with React Query (the React client for TanStack Query) * Subscription session resumption, from SSR to live on the client * Loader-based preloading and prefetching * Consistent logical query timestamp during SSR * Opt-in component-local SSR and more! This page describes the recommended way to use Convex with TanStack Start, via React Query. The standard Convex React hooks work also with TanStack Start without React Query, as do the [React Query hooks](/client/tanstack/tanstack-query/.md) without TanStack Start! But using all three is a sweet spot. TanStack Start is in Beta TanStack Start is a new React framework currently in beta. You can use it today but there may be breaking changes made to it before a stable release. ## Getting started[​](#getting-started "Direct link to Getting started") Follow the [TanStack Start Quickstart](/quickstart/tanstack-start.md) to add Convex to a new TanStack Start project. ## Using Convex with React Query[​](#using-convex-with-react-query "Direct link to Using Convex with React Query") You can read more about [React Query hooks](/client/tanstack/tanstack-query/.md), but a few highlights relevant to TanStack Start. ### Staying subscribed to queries[​](#staying-subscribed-to-queries "Direct link to Staying subscribed to queries") Convex queries in React Query continue to receive updates after the last component subscribed to the query unmounts. The default for this behavior is 5 minutes and this value is configured with [`gcTime`](https://tanstack.com/query/latest/docs/framework/react/guides/caching). This is useful to know when debugging why a query result is already loaded: for client side navigations, whether a subscription is already active can depend on what pages were previously visited in a session. ### Using Convex React hooks[​](#using-convex-react-hooks "Direct link to Using Convex React hooks") [Convex React](/client/react.md) hooks like [`usePaginatedQuery`](/api/modules/react.md#usepaginatedquery) can be used alongside TanStack hooks. These hooks reference the same Convex Client so there's still just one set of consistent query results in your app when these are combined. ## Server-side Rendering[​](#server-side-rendering "Direct link to Server-side Rendering") Using TanStack Start and Query with Convex makes it particularly easy to live-update Convex queries on the client while also [server-rendering](https://tanstack.com/query/v5/docs/framework/react/guides/ssr) them. [`useSuspenseQuery()`](https://tanstack.com/query/latest/docs/framework/react/reference/useSuspenseQuery) is the simplest way to do this: ``` const { data } = useSuspenseQuery(convexQuery(api.messages.list, {})); ``` ### Consistent client views[​](#consistent-client-views "Direct link to Consistent client views") In the browser all Convex query subscriptions present a consistent, at-the-same-logical-timestamp view of the database: if one query result reflects a given mutation transaction, every other query result will too. Server-side rendering is usually a special case: instead of a stateful WebSocket session, on the server it's simpler to fetch query results ad-hoc. This can lead to inconsistencies analogous to one REST endpoint returning results before a mutation ran and another endpoint returning results after that change. In TanStack Start, this issue is avoided by sending in a timestamp along with each query: Convex uses the same timestamp for all queries. ### Loaders[​](#loaders "Direct link to Loaders") To make client-side navigations faster you can add a [loader](https://tanstack.com/router/latest/docs/framework/react/guide/external-data-loading#using-loaders-to-ensure-data-is-loaded) to a route. By default, loaders will run when mousing over a link to that page. ``` export const Route = createFileRoute('/posts')({ loader: async (opts) => { await opts.context.queryClient.ensureQueryData( convexQuery(api.messages.list, {}), ); }; component: () => { const { data } = useSuspenseQuery(convexQuery(api.messages.list, {})); return (
{data.map((message) => ( ))}
); }, }) ``` ## Authentication[​](#authentication "Direct link to Authentication") Client-side authentication in Start works the way [client-side authentication with Convex](https://docs.convex.dev/auth) generally works in React because TanStack Start works well as a client-side framework. To use Clerk auth to make authenticated Convex calls on the server as well see the [TanStack Start + Clerk guide](/client/tanstack/tanstack-start/clerk.md). Clerk is an official partner of TanStack, see our setup guide. --- # TanStack Start with Clerk Using Clerk with Convex looks like following the [Clerk TanStack Quickstart](https://clerk.com/docs/quickstarts/tanstack-start) and adding Convex like the [Convex TanStack Quickstart](/quickstart/tanstack-start.md) shows. Then to make Clerk identity tokens available everywhere you might make authenticated calls to Convex in TanStack Start, you'll want to 1. Get an ID token from Clerk in addition to the `getAuth()` call with `const token = await auth.getToken({ template: "convex" })`. 2. Set the token in beforeLoad with `ctx.context.convexQueryClient.serverHttpClient?.setAuth(token)` so the token will be available in loaders. 3. Add `` to the root component to keep refreshing Clerk tokens while the app is in use. Making these changes looks like modifying `app/router.tsx` like this: app/router.tsx ``` import { createRouter as createTanStackRouter } from '@tanstack/react-router' import { routeTree } from './routeTree.gen' import { DefaultCatchBoundary } from './components/DefaultCatchBoundary' import { NotFound } from './components/NotFound' import { routerWithQueryClient } from '@tanstack/react-router-with-query' import { ConvexProvider, ConvexReactClient } from 'convex/react' import { ConvexQueryClient } from '@convex-dev/react-query' import { QueryClient } from '@tanstack/react-query' export function createRouter() { const CONVEX_URL = (import.meta as any).env.VITE_CONVEX_URL! if (!CONVEX_URL) { throw new Error('missing VITE_CONVEX_URL envar') } const convex = new ConvexReactClient(CONVEX_URL, { unsavedChangesWarning: false, }) const convexQueryClient = new ConvexQueryClient(convex) const queryClient: QueryClient = new QueryClient({ defaultOptions: { queries: { queryKeyHashFn: convexQueryClient.hashFn(), queryFn: convexQueryClient.queryFn(), }, }, }) convexQueryClient.connect(queryClient) const router = routerWithQueryClient( createTanStackRouter({ routeTree, defaultPreload: 'intent', defaultErrorComponent: DefaultCatchBoundary, defaultNotFoundComponent: () => , context: { queryClient, convexClient: convex, convexQueryClient }, scrollRestoration: true, Wrap: ({ children }) => ( {children} ), }), queryClient, ) return router } declare module '@tanstack/react-router' { interface Register { router: ReturnType } } ``` and modifying `app/routes/__root.tsx` like this: app/routes/\_\_root.tsx ``` import { Link, Outlet, createRootRouteWithContext, useRouteContext, } from '@tanstack/react-router' import { ClerkProvider, SignInButton, SignedIn, SignedOut, UserButton, useAuth, } from '@clerk/tanstack-start' import { TanStackRouterDevtools } from '@tanstack/router-devtools' import { Meta, Scripts, createServerFn } from '@tanstack/start' import { QueryClient } from '@tanstack/react-query' import * as React from 'react' import { getAuth } from '@clerk/tanstack-start/server' import { getWebRequest } from 'vinxi/http' import { DefaultCatchBoundary } from '~/components/DefaultCatchBoundary.js' import { NotFound } from '~/components/NotFound.js' import appCss from '~/styles/app.css?url' import { ConvexQueryClient } from '@convex-dev/react-query' import { ConvexReactClient } from 'convex/react' import { ConvexProviderWithClerk } from 'convex/react-clerk' const fetchClerkAuth = createServerFn({ method: 'GET' }).handler(async () => { const auth = await getAuth(getWebRequest()) const token = await auth.getToken({ template: 'convex' }) return { userId: auth.userId, token, } }) export const Route = createRootRouteWithContext<{ queryClient: QueryClient convexClient: ConvexReactClient convexQueryClient: ConvexQueryClient }>()({ head: () => ({ meta: [ { charSet: 'utf-8', }, { name: 'viewport', content: 'width=device-width, initial-scale=1', }, ], links: [ { rel: 'stylesheet', href: appCss }, { rel: 'apple-touch-icon', sizes: '180x180', href: '/apple-touch-icon.png', }, { rel: 'icon', type: 'image/png', sizes: '32x32', href: '/favicon-32x32.png', }, { rel: 'icon', type: 'image/png', sizes: '16x16', href: '/favicon-16x16.png', }, { rel: 'manifest', href: '/site.webmanifest', color: '#fffff' }, { rel: 'icon', href: '/favicon.ico' }, ], }), beforeLoad: async (ctx) => { const auth = await fetchClerkAuth() const { userId, token } = auth // During SSR only (the only time serverHttpClient exists), // set the Clerk auth token to make HTTP queries with. if (token) { ctx.context.convexQueryClient.serverHttpClient?.setAuth(token) } return { userId, token, } }, errorComponent: (props) => { return ( ) }, notFoundComponent: () => , component: RootComponent, }) function RootComponent() { const context = useRouteContext({ from: Route.id }) return ( ) } function RootDocument({ children }: { children: React.ReactNode }) { return (
Home {' '} Posts

{children} ) } ``` Now all queries, mutations and action made with [TanStack Query](/client/tanstack/tanstack-query/.md) will be authenticated by a Clerk identity token. --- # Vue [Vue](https://vuejs.org/) is an "approachable, performant and versatile framework for building web user interfaces." The community-maintained [`convex-vue`](https://www.npmjs.com/package/convex-vue) npm package is a Vue.js integration library for Convex. It also powers [convex-nuxt](/client/vue/nuxt.md). See the [Vue Quickstart](/quickstart/vue.md) to get started or the [convex-vue GitHub page](https://github.com/chris-visser/convex-vue) for more documentation. info The [`convex-vue` library](https://github.com/chris-visser/convex-vue) is community-maintained. Thank you to the maintainer [Chris Visser](https://github.com/chris-visser) for his work on this project! You're welcome to ask questions about the library on the [Convex Discord](https://convex.dev/community) but opening a [convex-vue GitHub](https://github.com/chris-visser/convex-vue) issue is a better way to request a new feature or report a bug. --- # Nuxt [Nuxt](https://nuxt.com/) is a powerful web framework powered by Vue. The community-maintained [`convex-nuxt` npm package](https://www.npmjs.com/package/convex-nuxt) provides deep integration of Convex with the Nuxt 3 ecosystem. It uses [convex-vue](/client/vue.md) under the hood. See the [Nuxt Quickstart](/quickstart/nuxt.md) to get started or the [convex-nuxt GitHub page](https://github.com/chris-visser/convex-nuxt) for more documentation. info The [`convex-nuxt` library](https://github.com/chris-visser/convex-nuxt/tree/main) is community-maintained. Thank you to the maintainer [Chris Visser](https://github.com/chris-visser) for his work on this project! You're welcome to ask questions about the library on the [Convex Discord](https://convex.dev/community) but opening a [convex-nuxt GitHub](https://github.com/chris-visser/convex-nuxt) issue is a better way to request a new feature or report a bug. --- # Components 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). Components can be installed from NPM or from a local folder. Once installed, they have their own database tables and isolated function execution environment. Check out the full directory of components on the [Convex website](https://convex.dev/components). ## [Understanding components](/components/understanding.md) [Explore the concepts behind and build a mental model for how components work.](/components/understanding.md) ## [Using components](/components/using.md) [Learn about useful components and how to use them in your application.](/components/using.md) ## [Authoring components](/components/authoring.md) [Learn how to write and publish a component.](/components/authoring.md) ## [Components Directory](https://convex.dev/components) [List of all components.](https://convex.dev/components) --- # Authoring Components Building a Convex Component lets you package up Convex functions, schemas, and persistent state into a reusable module that you or other developers can drop into their projects. They differ from regular libraries in that they have their own database tables, sub-transactions, and can define functions that run in an isolated environment. Trying to decide between writing a library or a component? Building it as a component allows you to: * Persist data to tables where you control the schema. * Isolate access to data behind an API boundary. * Define queries, mutations, and actions that can run asynchronously to manage complex workflows. * Share functionality between apps in a predictable way. ## Anatomy of a component[​](#anatomy-of-a-component "Direct link to Anatomy of a component") Practically speaking, a component is defined in a folder containing a `convex.config.ts`. The component's folder has the same structure as a normal `convex/` folder: ``` component/ ├── _generated/ # Generated code for the component's API and data model. ├── convex.config.ts # Defines the component and its child components. ├── schema.ts # Defines a schema only accessible by the component └-- …folders/files.ts # Queries, mutations, and actions for the component. ``` The component's `convex.config.ts` file configures the component's default name and child components. component/convex.config.ts TS ``` import { defineComponent } from "convex/server"; // import workpool from "@convex-dev/workpool/convex.config.js"; // import localComponent from "../localComponent/convex.config.js"; const component = defineComponent("myComponent"); // component.use(workpool); // component.use(localComponent, { name: "customName" }); export default component; ``` Instances of the component are configured when used by the main app or other components in their `convex.config.ts` files, forming a tree of components, with the main app at the root. ## Getting started[​](#getting-started "Direct link to Getting started") The source code for components can be a local folder or bundled into an NPM package. ### Local components[​](#local-components "Direct link to Local components") The easiest way to get started is by creating a new folder for your component and adding a `convex.config.ts` file to it (like the one above). Then import it in your app's `convex/convex.config.ts` file: convex/convex.config.ts TS ``` import { defineApp } from "convex/server"; import myComponent from "./components/myComponent/convex.config.js"; const app = defineApp(); app.use(myComponent); export default app; ``` Once installed, `npx convex dev` will generate code in `./components/myComponent/_generated/` and re-generate it whenever you make changes to the component's code. Tip: The recommended pattern for local components is to organize them in a `convex/components` folder, but they can be stored anywhere in your project. ### Packaged components[​](#packaged-components "Direct link to Packaged components") Components can be distributed and installed as NPM packages, enabling you to share solutions to common problems with the broader developer community via the [Convex Components directory](https://convex.dev/components). Get started with a new project using the [component template](https://github.com/get-convex/templates/tree/main/template-component): ``` npm create convex@latest -- --component ``` Follow the CLI's instructions to get started and keep the component's generated code up-to-date. [See below for more information on building and publishing NPM package components.](#building-and-publishing-npm-package-components) ### Hybrid components[​](#hybrid-components "Direct link to Hybrid components") Hybrid components define a local component, but use shared library code for some of the functionality. This allows you to provide a extra flexibility when users need to override or extend the schema or functions. An example of a hybrid component is the [Better Auth Component](https://convex-better-auth.netlify.app/features/local-install). Note: in general, components should be composed or designed to be extended explicitly, as hybrid components introduce a lot of complexity for maintaining and updating the component in backwards-compatible ways. ## Hello world[​](#hello-world "Direct link to Hello world") To try adding a new function, create a file `helloWorld.ts` in your component's folder (e.g. `src/component/helloWorld.ts` in the template): ./path/to/component/hello.ts TS ``` import { v } from "convex/values"; import { query } from "./_generated/server.js"; export const world = query({ args: {}, returns: v.string(), handler: async () => { return "hello world"; }, }); ``` After it deploys, you can run `npx convex run --component myComponent hello:world`. You can now also run it from a function in your app: convex/sayHi.ts TS ``` import { components } from "./_generated/api"; import { query } from "./_generated/server"; export default query({ handler: async (ctx) => { return await ctx.runQuery(components.myComponent.hello.world); }, }); ``` Try it out: `npx convex run sayHi`. ## Key differences from regular Convex development[​](#key-differences-from-regular-convex-development "Direct link to Key differences from regular Convex development") Developing a component is similar to developing the rest of your Convex backend. This section is a guide to the key concepts and differences. ### The Component API[​](#the-component-api "Direct link to The Component API") When you access a component reference like `components.foo`, you're working with the `ComponentApi` type which has some key differences from the regular `api` object: * **Only public functions are accessible**: Internal functions are not exposed to the parent app. * **Functions become internal references**: The component's "public" queries, mutations, and actions are turned into references with "internal" visibility. They can be called with `ctx.runQuery`, `ctx.runMutation`, etc. but **not** directly accessible from clients via HTTP or WebSockets. See below for patterns to re-export functions from the component. * **IDs become strings**: Any `Id<"tableName">` arguments or return values become plain strings in the `ComponentApi`. See next section for details. Similar to regular Convex functions, you can call both public and internal functions via `npx convex run` and the Convex dashboard. ### `Id` types and validation[​](#id-types-and-validation "Direct link to id-types-and-validation") All `Id<"table_name">` types within a component become simple string types outside of the component (in the `ComponentApi` type). In addition, you cannot currently have a `v.id("table_name")` validator that represents a table in another component / app. Why? In Convex, a `v.id("table_name")` validator will check that an ID in an argument, return value, or database document matches the named table's format. Under the hood, this is currently encoded as a number assigned to each table in your schema. Within a component’s implementation, the same applies to the component's tables. However, a `v.id("users")` within the component is not the same as `v.id("users")` in another component or in the main app, as each "users" table can have a different table number representation. For this reason, all `Id` types in the `ComponentApi` become simple strings. ### Generated code[​](#generated-code "Direct link to Generated code") Each component has its own `_generated` directory in addition to the `convex/_generated` directory. They are similar, but its contents are specific to the component and its schema. In general, code outside of the component should not import from this directory with the exception of `_generated/component`. * `component.ts` is only generated for components, and contains the component's `ComponentApi` type. * `server.ts` contains function builders like `query` and `mutation` to define your component's API. It's important that you import these when defining your component's functions, and not from `convex/_generated/server`. See below for more information on function visibility. * `api.ts` contains the component's `api` and `internal` objects to reference the component's functions. It also includes the `components` object with references to its child components, if any. In general, no code outside of the component should import from this file. Instead, they should use their own `components` object which includes this component keyed by whatever name they chose to install it with. * `dataModel.ts` contains the types for the component's data model. Note that the `Id` and `Doc` types here are not useful outside of the component, since the API turns all ID types into strings at the boundary. ### Environment variables[​](#environment-variables "Direct link to Environment variables") The component's functions are isolated from the app's environment variables, so they cannot access `process.env`. Instead, you can pass environment variables as arguments to the component's functions. ``` return await ctx.runAction(components.sampleComponent.lib.translate, { baseUrl: process.env.BASE_URL, ...otherArgs, }); ``` See below for other strategies for static configuration. ### HTTP Actions[​](#http-actions "Direct link to HTTP Actions") A component cannot expose HTTP actions itself because the routes could conflict with the main app's routes. Similar to other functions (queries, mutations, and actions), a component can define HTTP action handlers which the app can choose to mount. There’s an example in the [Twilio component](https://github.com/get-convex/twilio/blob/0bdf7fd4ee7dd46d442be3693280564eea597b68/src/client/index.ts#L71). All HTTP actions need to be mounted in the main app’s `convex/http.ts` file. ### Authentication via ctx.auth[​](#authentication-via-ctxauth "Direct link to Authentication via ctx.auth") Within a component, `ctx.auth` is not available. You typically will do authentication in the app, then pass around identifiers like `userId` or other identifying information to the component. This explicit passing makes it clear what data flows between the app and component, making your component easier to understand and test. convex/myFunctions.ts TS ``` import { getAuthUserId } from "@convex-dev/auth/server"; export const someMutation = mutation({ args: {}, handler: async (ctx) => { const userId = await getAuthUserId(ctx); await ctx.runMutation(components.myComponent.foo.bar, { userId, ...otherArgs, }); }, }); ``` ### Function Handles[​](#function-handles "Direct link to Function Handles") Sometimes you want the app to call a component and the component should call back into the app. For example, when using the Migrations component, the app defines a function that modifies a document, and the component runs this function on every document. As another example, an app using the Twilio component gives it a function to run whenever the phone number receives a text message. These features are implemented using function handles. A function reference is something like api.foo.bar or `internal.foo.bar` or `components.counter.foo.bar`. Function references are restricted as described above (a component can only use references to its own functions or the public functions of its children). If you have a valid function reference, you can turn it into something that can be called from anywhere: ``` const handle = await createFunctionHandle(api.foo.bar); ``` This handle is a string. Since it’s a string, you can pass it between functions and even store it in a table. You would use `v.string()` in args/schema validators. When you want to use it, cast it back to FunctionHandle and use it as you would use a function reference. Note argument and return value validation still run at runtime, so don't worry about losing guarantees. ``` const handle = handleString as FunctionHandle<"mutation">; const result = await ctx.runMutation(handle, args); // or run it asynchronously via the scheduler: await ctx.scheduler.runAfter(0, handle, args); ``` [Here](https://github.com/get-convex/workpool/blob/aebe2db49fc3ec50ded6892ed27f464450b3d31e/src/component/worker.ts#L26-L28) is an example of using function handles in the [Workpool](https://www.convex.dev/components/workpool) component. ### Pagination[​](#pagination "Direct link to Pagination") The built-in `.paginate()` doesn't work in components, because of how Convex keeps track of reactive pagination. Therefore we recommend you use `paginator` from [`convex-helpers`](https://npmjs.com/package/convex-helpers) if you need pagination within your component. If you expose a pagination API that wants to be used with `usePaginatedQuery`, in a React context, use the `usePaginatedQuery` from `convex-helpers` instead of the default one from `convex/react`. It will have a fixed first page size until you hit “load more,” at which point the first page will grow if anything before the second page is added. [Here](https://github.com/get-convex/rag/blob/23fb22d593682e23d9134304e823f7532cbc7e67/src/component/chunks.ts#L437-L462) is an example of pagination in the [RAG](https://www.convex.dev/components/rag) component. ## Tips and best practices[​](#tips-and-best-practices "Direct link to Tips and best practices") ### Validation[​](#validation "Direct link to Validation") All public component functions should have argument and return validators. Otherwise, the argument and return values will be typed as `any`. Below is an example of using validators. ``` import schema from "./schema"; const messageDoc = schema.tables.messages.validator.extend({ _id: v.id("messages), _creationTime: v.number(), }); export const getLatestMessage = query({ args: {}, returns: v.nullable(messageDoc), handler: async (ctx) => { return await ctx.db.query("messages").order("desc).first(); }, }); ``` Find out more information about function validation [here](/functions/validation.md). ### Static configuration[​](#static-configuration "Direct link to Static configuration") A common pattern to track configuration in a component is to have a "globals" table with a single document that contains the configuration. You can then define functions to update this document from the CLI or from the app. To read the values, you can query them with `ctx.db.query("globals").first();`. ## Wrapping the component with client code[​](#wrapping-the-component-with-client-code "Direct link to Wrapping the component with client code") When building a component, sometimes you want to provide a simpler API than directly calling `ctx.runMutation(components.foo.bar, ...)`, add more type safety, or provide functionality that spans the component's boundary. You can hide calls to the component's functions behind a more ergonomic client API that runs within the app's environment and calls into the component. This section covers conventions and approaches to writing client code. These aren't hard and fast rules; choose the pattern that best fits your component's needs. Note: An important aspect of this pattern is that the code running in the app has access to `ctx.auth`, `process.env`, and other app-level resources. For many use-cases, this is important, such as running code to define migrations in the app, which are then run from the Migrations Component. On the other hand, apps that want really tight control over what code runs in their app may prefer to call the component's functions directly. ### Simple Function Wrappers[​](#simple-function-wrappers "Direct link to Simple Function Wrappers") The simplest approach is to define standalone functions that wrap calls to the component. This works well for straightforward operations and utilities. ``` import type { GenericActionCtx, GenericDataModel, GenericMutationCtx, } from "convex/server"; import type { ComponentApi } from "../component/_generated/component.js"; export async function callMyFunction( ctx: MutationCtx | ActionCtx, component: ComponentApi, args: ... ) { // You can create function handles, add shared utilities, // or do any processing that needs to run in the app's environment. const functionHandle = await createFunctionHandle(args.someFn); const someArg = process.env.SOME_ARG; await ctx.runMutation(component.call.fn, { ...args, someArg, functionHandle, }); } // Useful types for functions that only need certain capabilities. type MutationCtx = Pick, "runMutation">; type ActionCtx = Pick< GenericActionCtx, "runQuery" | "runMutation" | "runAction" >; ``` Note: we only use `ctx.runMutation`, so we can use `Pick` to select a type that only includes that function. This allows users to call it even if their `ctx` is not exactly the standard MutationCtx. It also means it can be called from an Action, as ActionCtx also includes `ctx.runMutation`. If your function also needs auth or storage, you can adjust what you `Pick`. ### Re-exporting component functions[​](#re-exporting-component-functions "Direct link to Re-exporting component functions") Sometimes you want to provide ready-made functions that apps can directly re-export to their public API. This is useful when you want to give apps the ability to expose your component's functionality to React clients or the public internet. The most straightforward way to do this is have the user define their own functions that call into the component. This allows the app to choose to add auth, rate limiting, etc. convex/counter.ts TS ``` export const add = mutation({ args: { value: v.number() }, returns: v.null(), handler: async (ctx, args) => { // The app can authenticate the user here if needed await ctx.runMutation(components.counter.add, args); }, }); ``` This is the recommended pattern, as it makes it clear to the user how the request is being authenticated. However, if you need to re-export a lot of functions, you can use the next pattern. #### Re-mounting an API[​](#re-mounting-an-api "Direct link to Re-mounting an API") Code in your `src/client/index.ts` can export these functions: ``` import type { Auth } from "convex/server"; // In your component's src/client/index.ts export function makeCounterAPI( component: ComponentApi, options: { // Important: provide a way for the user to authenticate these requests auth: (ctx: { auth: Auth }, operation: "read" | "write") => Promise; }, ) { return { add: mutation({ args: { value: v.number() }, handler: async (ctx, args) => { await options.auth(ctx, "write"); return await ctx.runMutation(component.public.add, args); }, }), get: query({ args: {}, handler: async (ctx) => { await options.auth(ctx, "read"); return await ctx.runQuery(component.public.get, {}); }, }), }; } ``` Then apps can mount these in their own API: ``` // In the app's convex/counter.ts import { makeCounterAPI } from "@convex-dev/counter"; import { components } from "./_generated/server.js"; export const { add, get } = makeCounterAPI(components.counter, { auth: async (ctx, operation) => { const userId = await getAuthUserId(ctx); // Check if the user has permission to perform the operation if (operation === "write" && !userId) { throw new Error("User not authenticated"); } return userId; }, }); ``` This pattern is also useful for components that need to provide functions with specific signatures for integration purposes. Here's a real-world [example](https://github.com/get-convex/prosemirror-sync/blob/91e19d5e5a2a272d44f3a31c9171e111dc98676c/src/client/index.ts#L171C4-L173C6) from the [ProseMirror component](https://www.convex.dev/components/prosemirror-sync) that exports ready-made functions. ### Class-Based Clients[​](#class-based-clients "Direct link to Class-Based Clients") For more complex components, a class-based client provides a stateful interface that can hold configuration and provide multiple methods. **Basic class pattern:** ``` import Foo from "@convex-dev/foo"; import { components } from "./_generated/server.js"; const foo = new Foo(components.foo, { maxShards: 10, }); ``` **With configuration options:** Classes typically accept the component reference as their first argument, with optional configuration as the second: ``` export class Foo { private apiKey: string; constructor( public component: ComponentApi, options?: { maxShards?: number; // Named after the environment variable it overrides, for clarity. FOO_AUTH_KEY?: string; }, ) { this.apiKey = options?.FOO_AUTH_KEY ?? process.env.FOO_AUTH_KEY!; } async count(ctx: GenericQueryCtx) { return await ctx.runQuery(this.component.public.count, { API_KEY: this.apiKey, }); } } ``` **Dynamic instantiation:** Note that clients don't need to be instantiated statically. If you need runtime values, you can create instances dynamically: ``` export const myQuery = query({ handler: async (ctx, args) => { const foo = new Foo(components.foo, { apiKey: args.customApiKey, }); await foo.count(ctx); }, }); ``` ## Building and publishing NPM package components[​](#building-and-publishing-npm-package-components "Direct link to Building and publishing NPM package components") ### Build process[​](#build-process "Direct link to Build process") While developing a component that will be bundled, the example app that installs and exercises it will import the bundled version of the component. This helps ensure that the code you are testing matches the code that will be published. However, that means `npx convex dev` cannot detect where the original source code is located for the component, and will not automatically generate the code for the component. When developing a component that will be bundled, you need to run a separate build process to generate the component's `_generated` directory. The component authoring template will automatically generate the code for the component when running `npm run dev`. You can see the setup in the [template's `package.json` scripts](https://github.com/get-convex/templates/blob/main/template-component/package.json). If you're setting up your own build process, you'll need to run the following commands with their own file watchers: 1. **Component codegen**: Generate code for the component itself ``` npx convex codegen --component-dir ./path/to/component ``` 2. **Build the package**: Build the NPM package ``` npm run build # Your build command (e.g., tsc, esbuild, etc.) ``` 3. **Example app codegen & deploy**: Generate code for the example app and deploy it app ``` npx convex dev --typecheck-components # optionally type-check the components ``` **Note on ordering:** The ideal ordering is: component codegen → build the package → example app `convex dev` runs. This is a recommended convention followed by the template to avoid builds racing with each other, but the key requirement is that the component must be built and available before the example app tries to import it. ### Entry points[​](#entry-points "Direct link to Entry points") When publishing a component on NPM, you will need to expose all the relevant entry points to be used in your project: * `@your/package` exports types, classes, and constants used to interact with the component from within their app's code. This is optional, but common. * `@your/package/convex.config.js` exposes the component's config. * `@your/package/_generated/component.js` exports the `ComponentApi` type, which describes the component's types from the point of view of app it's used in. * `@your/package/test` for utilities to use the component with `convex-test`. [The template’s package.json](https://github.com/get-convex/templates/blob/main/template-component/package.json) does this for you, but if you're setting up your own build process, you'll need to set this up in your package.json. ### Local package resolution for development[​](#local-package-resolution-for-development "Direct link to Local package resolution for development") When developing a component, you generally want to be importing the component's code in the same way that apps will import it, e.g. `import {} from "@your/package"`. To achieve this without having to install the package from NPM in the example app, follow the template's project structure: 1. In the root of the project, have the `package.json` with the package name matching the `@your/package` name. This causes imports for that name to resolve to the `package.json`’s `exports`. 2. In the `exports` section of the `package.json`, map the aforementioned entry points to the bundled files, generally in the `dist` directory. This means imports from the package name will resolve to the bundled files. 3. Have a single package.json file and node\_modules directory in the root of the project, so the example app will resolve to the package name by default. This will also avoid having multiple versions of `convex` referenced by the library vs. the example app. To add dependencies used only by the example app, add them as `devDependencies` in the `package.json`. ### Publishing to NPM[​](#publishing-to-npm "Direct link to Publishing to NPM") To publish a component on NPM, check out [PUBLISHING.md](https://github.com/get-convex/templates/blob/main/template-component/PUBLISHING.md). ## Testing[​](#testing "Direct link to Testing") ### Testing implementations[​](#testing-implementations "Direct link to Testing implementations") To test components, you can use the [`convex-test` library](/testing/convex-test.md). The main difference is that you must provide the schema and modules to the test instance. component/some.test.ts TS ``` import { test } from "vitest"; import { convexTest } from "convex-test"; import schema from "./schema.ts"; const modules = import.meta.glob("./**/*.ts"); export function initConvexTest() { const t = convexTest(schema, modules); return t; } test("Test something with a local component", async () => { const t = initConvexTest(); // Test like you would normally. await t.run(async (ctx) => { await ctx.db.insert("myComponentTable", { name: "test" }); }); }); ``` If your component has child components, see the [Testing components](/components/using.md#testing-components) section in the Using Components documentation. ### Testing the API and client code[​](#testing-the-api-and-client-code "Direct link to Testing the API and client code") To test the functions that are exported from the component to run in the app's environment, you can follow the same approach as in [Using Components](/components/using.md#testing-components) and test it from an app that uses the component. The template component includes an example app in part for this purpose: to exercise the component's bundled code as it will be used by apps installing it. ### Exporting test helpers[​](#exporting-test-helpers "Direct link to Exporting test helpers") Most components export testing helpers to make it easy to register the component with the test instance. Here is an example from the [template component’s `/test` entrypoint](https://github.com/get-convex/templates/blob/main/template-component/src/test.ts): ``` /// import type { TestConvex } from "convex-test"; import type { GenericSchema, SchemaDefinition } from "convex/server"; import schema from "./component/schema.js"; const modules = import.meta.glob("./component/**/*.ts"); /** * Register the component with the test convex instance. * @param t - The test convex instance, e.g. from calling `convexTest`. * @param name - The name of the component, as registered in convex.config.ts. */ export function register( t: TestConvex>, name: string = "sampleComponent", ) { t.registerComponent(name, schema, modules); } export default { register, schema, modules }; ``` For NPM packages, this is exposed as `@your/package/test` in the package's `package.json`: ``` { ... "exports": { ... "./test": "./src/test.ts", ... } } ``` --- # Understanding Components Convex Components are self-contained backend modules that bundle functions, schemas, and data together. They let you add complex functionality to your app—like authentication, rate limiting, or document collaboration—without implementing everything from scratch. If you've worked with modern web development, you've likely encountered similar ideas in different forms. Components draw inspiration from frontend components, third-party APIs, and service-oriented architectures. The key difference is that Convex Components run within your backend, giving you composability combined with the persistence and reliability of backend services. The following diagram shows how data and function access works in the component ecosystem. Arrows from one element to another represent that an element has access to the functions or data of the other element. ![Screenshot of the component dropdown](/img/components-diagram.png) ### Data[​](#data "Direct link to Data") Similar to frontend components, Convex Components encapsulate state and behavior and allow exposing a clean interface. However, instead of 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 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[​](#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 an external service, code inside a component can't read data that is not explicitly provided to it. This includes database tables, file storage, environment variables, scheduled functions, etc. Conversely, the component's data cannot be directly mutated by the main app, allowing full separation of concerns. * Similar to a service-oriented architecture, functions in components are run in an isolated environment, so writes to global variables and patches to system behavior are not shared between components. * Similar to a monolithic 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-transaction isolated from other calls, allowing you to safely catch errors thrown by components. This 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-transaction. [Read more](/components/using.md#transactions). ### Encapsulation[​](#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. --- # Using Components Convex Components add new features to your backend in their own sandbox with their own functions, schema and data, scheduled functions and all other fundamental Convex features. You can see the full list of components in the [directory](https://convex.dev/components). ## Installation[​](#installation "Direct link to Installation") We'll use the [Agent](https://www.npmjs.com/package/@convex-dev/agent) component as an example. 1. Install from \`npm\` ``` npm i @convex-dev/agent ``` 2. Add the component to your app Create or update the `convex.config.ts` file in your app's `convex/` folder and install the component by calling `use`. Multiple instances of the same component can be installed by calling `use` multiple times with different names. Each will have their own tables and functions. convex/convex.config.ts TS ``` import { defineApp } from "convex/server"; import agent from "@convex-dev/agent/convex.config.js"; const app = defineApp(); app.use(agent); app.use(agent, { name: "agent2" }); //... Add other components here export default app; ``` 3. Run convex dev The `convex dev` CLI command will generate code necessary for using the component. ``` npx convex dev ``` 4. Access the component through its API Each instance of a component has its API listed under the `components` object by its name. Some components wrap this API with classes or functions. Check out each component's documentation for more details on its usage. ``` import { components } from "./_generated/api.js"; const agent = new Agent(components.agent, { ... }); ``` ## Using the component's API directly[​](#using-the-components-api-directly "Direct link to Using the component's API directly") Though components may expose higher level TypeScript APIs, under the hood they are called via normal Convex functions over the component sandbox boundary. Queries, mutations, and action rules still apply - queries can only call component queries, mutations can also call component mutations, and actions can also call component actions. As a result, queries into components are reactive by default, and mutations have the same transaction guarantees. Component functions can be called from your application using the following syntax: ``` import { internalAction } from "./_generated/server"; import { components } from "./_generated/api"; export const myAction = internalAction({ args: { threadId: v.string() }, handler: async (ctx, args) => { // Call the component's API to get the thread status. const { status } = await ctx.runQuery(components.agent.threads.getThread, { threadId: args.threadId, }); //... }, }); ``` Some components abstract away the component's API. For instance, the `Agent` class from `@convex-dev/agent` is initialized with `components.agent`, and its methods take in `ctx` so they can call the component's API internally. [Learn more about the Agent Component here](/agents.md). ## Transactions[​](#transactions "Direct link to Transactions") Remember that mutation functions in Convex are [transactions](/functions/mutation-functions.md#transactions). Either all the changes in the mutation get written at once or none are written at all. All writes for a top-level mutation call, including writes performed by calls into other components' mutations, are committed at the same time. If the top-level mutation throws an error, all of the writes are rolled back, and the mutation doesn't change the database at all. However, if a component mutation call throws an exception, only its writes are rolled back. Then, if the caller catches the exception, it can continue, perform more writes, and return successfully. If the caller doesn't catch the exception, then it's treated as failed and all the writes associated with the caller mutation are rolled back. This means your code can choose a different code path depending on the semantics of your component. As an example, take the [Rate Limiter](https://www.npmjs.com/package/@convex-dev/ratelimiter) component. One API of the Rate Limiter throws an error if a rate limit is hit: ``` // Automatically throw an error if the rate limit is hit. await rateLimiter.limit(ctx, "failedLogins", { key: userId, throws: true }); ``` If the call to `rateLimiter.limit` throws an exception, we're over the rate limit. Then, if the calling mutation doesn't catch this exception, the whole transaction is rolled back. The calling mutation, on the other hand, could also decide to ignore the rate limit by catching the exception and proceeding. For example, an app may want to ignore rate limits if there is a development environment override. In this case, only the component mutation will be rolled back, and the rest of the mutation will continue. ## Dashboard[​](#dashboard "Direct link to Dashboard") You can see your component’s data, functions, files, logs, and other info using the dropdown in the Dashboard. You can also use the dropdown to exclude info from certain components. ![Screenshot of the component dropdown](/screenshots/component_dropdown.png) ## Testing components[​](#testing-components "Direct link to Testing components") When writing tests with [`convex-test`](/testing/convex-test.md), that use components, you must register the component with the test instance. This tells it what schema to validate and where to find the component source code. Most components export convenient helper functions on `/test` to make this easy: convex/some.test.ts TS ``` import agentTest from "@convex-dev/agent/test"; import { expect, test } from "vitest"; import { convexTest } from "convex-test"; import { components } from "./_generated/api"; import { createThread } from "@convex-dev/agent"; // Define this once, often in a shared test helper file. export function initConvexTest() { const t = convexTest(); agentTest.register(t); return t; } test("Agent createThread", async () => { const t = initConvexTest(); const threadId = await t.run(async (ctx) => { // Calling functions that use ctx and components.agent return await createThread(ctx, components.agent, { title: "Hello, world!", }); }); // Calling functions directly on the component's API const thread = await t.query(components.agent.threads.getThread, { threadId, }); expect(thread).toMatchObject({ title: "Hello, world!", }); }); ``` If you need to register the component yourself, you can do so by passing the component's schema and modules to the test instance. convex/manual.test.ts TS ``` /// import { test } from "vitest"; import { convexTest } from "convex-test"; import schema from "./path/to/component/schema.ts"; const modules = import.meta.glob("./path/to/component/**/*.ts"); test("Test something with a local component", async () => { const t = convexTest(); t.registerComponent("componentName", schema, modules); await t.run(async (ctx) => { await ctx.runQuery(components.componentName.someQuery, { arg: "value", }); }); }); ``` ## Log Streams[​](#log-streams "Direct link to Log Streams") You can use the `data.function.component_path` field in [log streams](/production/integrations/log-streams/.md) to separate log lines based on the component they came from. --- # Dashboard ![Dashboard Projects View](/assets/images/projects-ea1be7a1deec4ee628278d2badc15e2f.png) [The dashboard](https://dashboard.convex.dev/) is the central hub for managing your Convex projects. Here you can create and manage your Convex teams, projects, and deployments. --- # Deployments 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](/production/hosting/preview-deployments.md) 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](/assets/images/deployment_menu-b2e23e5c7d44f8defdad7685df75ef29.png) --- # Data ![Data Dashboard Page](/assets/images/data-8f3dc6a4eb6c62497429e58ad703367b.png) The [data page](https://dashboard.convex.dev/deployment/data) allows you to view and manage all of your tables and documents. On the left side of the page is a list of your tables. Clicking on a table will allows you to create, view, update, and delete documents in that table. You may drag-and-drop the column headers in each table to visually re-order the data. A readonly view of the data page is available in the [command line](/cli.md#display-data-from-tables). ``` npx convex data [table] ``` ## Filtering documents[​](#filtering-documents "Direct link to Filtering documents") You may filters documents on the data page by clicking the "Filter" button on the top of the page. ![Data filters](/assets/images/data_filters-1d3e550f86642506f0507d143a070ab8.png) All fields in a document are filterable by the operations supported in Convex query syntax. [Equality](/database/reading-data/filters.md#equality-conditions) and [comparisons](/database/reading-data/filters.md#comparisons) share the same rules when filtering in the dashboard as a query using the Convex client. You may also filter based on the type of the field. To add a filter, click the `+` next to an existing filter. If you add more than one condition, they will be evaluated using the `and` operation. For each filter, you must select a field to filter by, operation, and comparison value. In the third input box (selecting a value), you may enter a valid Convex value, such as `"a string"`, `123`, or even a complex object, such as `{ a: { b: 2 } }` note When filtering by `_creationTime`, a date picker will be displayed instead of the normal JavaScript syntax input box. Comparisons for `_creationTime` are made at the nanosecond granularity, so if you'd like to filter to an exact time, try adding two filter conditions for `creationTime >= $time` and `creationTime <= $time + 1 minute`. ## Writing custom queries[​](#writing-custom-queries "Direct link to Writing custom queries") You can write a [query](/database/reading-data/.md) directly in the dashboard. This allows you to perform arbitrary filtering and transformation of the data, including sorting, joins, grouping and aggregations. In the `⋮` overflow menu at the top of the data page click on the “Custom query” option. ![Custom query button](/screenshots/data_custom_query.png) This opens the same UI used for [running your deployed functions](/dashboard/deployments/functions.md#running-functions), but with the “Custom test query” option selected, which lets you edit the source code for the query. This source code will be sent to your deployment and executed when you click on the “Run Custom Query“ button. ![Running a custom test query](/assets/images/data_custom_query_runner-3ed1f45c917689a4d0109d8759690e24.png) If you're not on the data page, you can still open this UI via the persistent *fn* button shown on the bottom right of all deployment pages. The keyboard shortcut to open the function runner is Ctrl + \` (backtick). ## Creating tables[​](#creating-tables "Direct link to Creating tables") You may create a table from the dashboard by clicking the "Create Table" button and entering a new name for the table. ## Creating documents[​](#creating-documents "Direct link to Creating documents") You may add individual documents to the table using the “Add Documents” button located in the data table's toolbar. Once you click “Add Documents” a side panel will open, allowing you to add new documents to your table using JavaScript syntax. To add more than one document add a time, add new objects to the array in the editor. ![Add document](/assets/images/data_add_document-f81e3b7952d2685f6d797773bb4c5b6d.png) ## Quick actions (context menu)[​](#quick-actions-context-menu "Direct link to Quick actions (context menu)") You can right-click on a document or value to open a context menu with quick actions, like copying values, quickly filtering by the selected value, and deleting documents. ![Quick actions context menu](/assets/images/data_context_menu-dc17e11f1df2733cdcf9170af0baf0b1.png) ## Editing a cell[​](#editing-a-cell "Direct link to Editing a cell") To edit a cell's value, double-click on the cell in the data table, or press the Enter key while it’s selected. You can change the selected cell by using the arrow keys. You can change the value by editing inline, and pressing enter to save. note You can even edit the type of your value here, as long as it satisfies your [schema](/database/schemas.md) — try replacing a string with an object! ![Inline value editor](/assets/images/data_edit_inline-eb2c461a2f3395ec975e6829eb70d66d.png) ## Editing a document[​](#editing-a-document "Direct link to Editing a document") To edit multiple fields in a document at the same time, hover over the document and right-click to open the context menu. From there you can click on "Edit Document". ![Edit entire document](/assets/images/data_edit_document-23e314be7901f2892a2136350798afc6.png) ## Adding references to other documents[​](#adding-references-to-other-documents "Direct link to Adding references to other documents") To reference another document, use the string ID of the document you want to reference. You can copy the ID by clicking on its cell and pressing CTRL/CMD+C. ## Bulk editing documents[​](#bulk-editing-documents "Direct link to Bulk editing documents") You can edit multiple or all documents at once. To select all documents click on the checkbox in the table header row. To select individual documents hover over the left-most cell and click the checkbox that appears. To select multiple adjacent documents at once, press the Shift key when clicking on the checkbox. When at least one document is selected, the “(Bulk) Edit Document(s)” button will be visible in the table toolbar. Click the button and an editor will appear on the right hand side. ![Bulk edit documents](/assets/images/data_bulk_edit-77eab4f33e91c212d74c2b3664adea8d.png) ## Deleting documents[​](#deleting-documents "Direct link to Deleting documents") When at least one document is selected (see above), the “Delete Document(s)” button will be visible in the table toolbar. Click the button to delete documents. If you're editing data in a production deployment a confirmation dialog will appear before the documents are deleted. ## Clear a table[​](#clear-a-table "Direct link to Clear a table") You can also delete all documents by clicking on the `⋮` overflow menu at the top of the data page and clicking "Clear Table". This action will delete all documents in the table, without deleting the table itself. In production environments, the Convex dashboard will have you type in the name of the table before deletion. ## Delete a table[​](#delete-a-table "Direct link to Delete a table") This is a permanent action Deleting a table is irreversible. In production environments, the Convex dashboard will have you type in the name of the table before deletion. The "Delete table" button can be found by clicking on the `⋮` overflow menu at the top of the data page. This action will delete all documents this table, and remove the table from your list of tables. If this table had indexes, you will need to redeploy your convex functions (by running `npx convex deploy` or `npx convex dev` for production or development, respectively) to recreate the indexes. ## Generating a schema[​](#generating-a-schema "Direct link to Generating a schema") At the bottom-left of the page is a "Generate Schema" button which you can click to have Convex generate a [schema](/database/schemas.md) of all your documents within this table. ![Generate Schema button](/assets/images/data_generate_schema-83edb92d597e55d5fc1f7c7fed701d47.png) ## View the schema of a table[​](#view-the-schema-of-a-table "Direct link to View the schema of a table") The "Schema" button can be found by clicking on the `⋮` overflow menu at the top of the data page. This button will open a panel showing the saved and generated [schemas](/database/schemas.md) associated with the selected table. ## View the indexes of a table[​](#view-the-indexes-of-a-table "Direct link to View the indexes of a table") The "Indexes" button can be found by clicking on the `⋮` overflow menu at the top of the data page. This button will open a panel showing the [indexes](/database/reading-data/indexes/.md) associated with the selected table. Indexes that have not completed backfilling will be accompanied by a loading spinner next to their name. --- # Settings The [deployment settings page](https://dashboard.convex.dev/deployment/settings) gives you access to information and configuration options related to a specific deployment (**production**, your personal **development** deployment, or a **preview** deployment). ## URL and Deploy Key[​](#url-and-deploy-key "Direct link to URL and Deploy Key") The [URL and deploy key page](https://dashboard.convex.dev/deployment/settings) shows: * The URL this deployment is hosted at. Some Convex integrations may require the deployment URL for configuration. * The URL that HTTP Actions for this deployment should be sent to. * The deployment's deploy key, used to [integrate with build tools such as Netlify and Vercel](/production/hosting/.md) and [syncing data with Fivetran and Airbyte](/production/integrations/streaming-import-export.md). ![Deployment Settings Dashboard Page](/assets/images/deployment_settings-58661797d5cadbc484d3d36dde845c04.png) ## Environment Variables[​](#environment-variables "Direct link to Environment Variables") The [environment variables page](https://dashboard.convex.dev/deployment/settings/environment-variables) lets you add, change, remove and copy the deployment's [environment variables](/production/environment-variables.md). ![deployment settings environment variables page](/assets/images/deployment_settings_env_vars-e148766325f85db3409292b10f202bba.png) ## Authentication[​](#authentication "Direct link to Authentication") The [authentication page](https://dashboard.convex.dev/deployment/settings/authentication) shows the values configured in your `auth.config.js` for user [authentication](/auth.md) implementation. ## Backup & Restore[​](#backup--restore "Direct link to Backup & Restore") The [backup & restore page](https://dashboard.convex.dev/deployment/settings/backups) lets you [backup](/database/backup-restore.md) the data stored in your deployment's database and file storage. On this page, you can schedule periodic backups. ![deployment settings export page](/assets/images/backups-7e17da1541fc3eb26194a96ab33414ea.png) ## Integrations[​](#integrations "Direct link to Integrations") The integrations page allows you to configure [log streaming](/production/integrations/.md), [exception reporting](/production/integrations/.md), and [streaming export](/production/integrations/streaming-import-export.md) integrations. ## Pause Deployment[​](#pause-deployment "Direct link to Pause Deployment") On the [pause deployment page](https://dashboard.convex.dev/deployment/settings/pause-deployment) you can [pause your deployment](/production/pause-deployment.md) with the pause button. ![deployment settings pause deployment page](/assets/images/deployment_settings_pause-4e036413269bccced2d58a99d2bb6f98.png) --- # File Storage The [file storage page](https://dashboard.convex.dev/deployment/files) displays [files stored in your deployment](/file-storage.md). The page also shows the files' storage IDs, size, and content type. You can upload new files and download or delete existing files. Storage IDs might be referenced by documents in your database. tip When new files are uploaded, the UI will reference the name of the recently uploaded file. However, these names are not persisted and will no longer appear when the page is reloaded. ![File Storage button](/assets/images/file_storage-6eed790b85399ae0dbe0996f8db411b3.png) --- # Functions ![Functions Dashboard View](/assets/images/functions-0c27a5b23883cc955c799abe6442f280.png) The [functions page](https://dashboard.convex.dev/deployment/functions) shows all currently deployed Convex functions. For dev deployments, these are updated continuously by [`npx convex dev`](/cli.md#run-the-convex-dev-server). The functions for production deployments are registered with [`npx convex deploy`](/cli.md#deploy-convex-functions-to-production). ## Running functions[​](#running-functions "Direct link to Running functions") To run a Convex function in the dashboard, select a function from the list on the left-hand side of the page, and click the "Run Function" button that appears next to the function's name. If you're not on the functions page, you can still open this UI via the persistent *fn* button shown on the bottom right of all deployment pages. The keyboard shortcut to open the function runner is Ctrl + \` (backtick). This view allows you to fill out the arguments for your function and run it. Query results will update automatically as you modify function arguments and data changes. Mutation and action results will be visible once you click the "Run" button. Note that these results will show the logs and value returned from the function. To see what changed when you ran your function, see the [data page](/dashboard/deployments/data.md). ![Running a function](/assets/images/run_function-00e5055078a6800d2c85de13f677df51.png) You can also [write a custom query function](/dashboard/deployments/data.md#writing-custom-queries) by choosing the “Custom test query“ option instead of one of your deployed functions. ### Querying a paginated function[​](#querying-a-paginated-function "Direct link to Querying a paginated function") When querying a paginated function in the dashboard, the UI will expect the arguments to include [`PaginationOptions`](/api/interfaces/server.PaginationOptions.md) -- i.e. an object containing the `numItems` field, and optionally the `cursor` field. The name of this argument should be the same as the name defined in your query function. * `numItems` should be the number of items to include in a page * `cursor` can be left blank to begin pagination. Once you receive results, you may set `cursor` to the result's `continueCursor` field to proceed to the next page. ### Assuming a user identity[​](#assuming-a-user-identity "Direct link to Assuming a user identity") tip Assuming a user identity in the Convex dashboard does not give you access to a real user identity. Instead, this concept can be thought of as "mocking" a user identity into your function. If you're building an authenticated application, you may want to run a Convex function while acting as an authenticated user identity. To do so, check the "Act as a user" box. From there, you can type in the box that appears to fill out the user identity object. ![Acting as a user](/assets/images/acting_as_a_user-abda4bbcb55710a7a9973381cfb0a4f6.png) The valid user attributes are: | Attribute | Type | | ------------------- | ---------------------------------------- | | subject\* | string | | issuer\* | string | | name | string | | givenName | string | | familyName | string | | nickname | string | | preferredUsername | string | | profileUrl | string | | email | string | | emailVerified | boolean | | gender | string | | birthday | string | | timezone | string | | language | string | | phoneNumber | string | | phoneNumberVerified | boolean | | address | string | | updatedAt | string (in the form of an RFC 3339 date) | | customClaims | object | \*These attributes are required. ## Metrics[​](#metrics "Direct link to Metrics") There are four basic charts for each function. For overall team usage metrics, see [team settings](/dashboard/teams.md#usage). ### Invocations[​](#invocations "Direct link to Invocations") This chart plots the number of times your function was called per minute. As your app's usage increases, you should see this chart trend upward as well. ### Errors[​](#errors "Direct link to Errors") A plot of any exceptions that occur while running your function. Want to know what's going wrong? Check out the logs page, detailed below. ### Cache Hit Rate[​](#cache-hit-rate "Direct link to Cache Hit Rate") tip Cache hit rate only applies to query functions A percentage rate of how often this function is simply reusing a cached value vs. being rerun. Your application will run best and your response times will be fastest with high cache hit rates. ### Execution Time[​](#execution-time "Direct link to Execution Time") How long, in milliseconds, this function is taking to run. There are four individual lines plotted on this chart, p50, p90, p95, and p99. Each of these lines represents the response time for that percentile in the distribution of hits over time. So, only 1% of requests took longer to run than the time shown by the p99 line. Typically, keeping an eye on these *tail latencies* is a good way to make sure your application is getting data services quickly. Consider the relationship of the execution time to the cache hit rate. As a rule, a cache hit takes well under 1 ms, so the higher your cache hit rate, the better your response times will be. Clicking on any of the charts will give you a larger, detailed view where you can customize the time ranges you're inspecting. --- # Health The [health page](https://dashboard.convex.dev/deployment/) is the landing page for your deployment. On this page, you can see some important information about the health of your deployment. ## Failure Rate[​](#failure-rate "Direct link to Failure Rate") ![Failure Rate Card](/assets/images/health_failure_rate-96b5cc94c00dc12c789240f58c7e4ab2.png) The failure rate card shows the percentage of failed request by minute ove the last hour. The failure rate is calculated as the number of failed requests divided by the total number of requests. ## Cache Hit Rate[​](#cache-hit-rate "Direct link to Cache Hit Rate") ![Cache Hit Rate Card](/assets/images/health_cache_hit_rate-81841697e2ba3432148ac37633aaad6e.png) The cache hit rate card shows the percentage of cache hits by minute over the last hour. The cache hit rate is calculated as the number of cache hits divided by the total number of requests. Cache hit rate only applies to query functions. ## Scheduler Status[​](#scheduler-status "Direct link to Scheduler Status") ![Scheduler Status Card](/assets/images/scheduler_overdue-d79a8e0d353fdaee48ed6ec968444f98.png) The scheduler status card shows the status of the [scheduler](/scheduling/scheduled-functions.md). If the scheduler falls behind due to too many scheduled tasks, the status will show as "Overdue", displaying the lag time in minutes. You may click the button in the top right corner of the card to view a chart showing the scheduler status over the last hour. ![Scheduler Status Chart](/assets/images/scheduler_status-feaf42e465eb0ff0516cd033b658c662.png) ## Last Deployed[​](#last-deployed "Direct link to Last Deployed") ![Last Deployed Card](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAXgAAAA/CAYAAADqt9PGAAABXWlDQ1BJQ0MgUHJvZmlsZQAAKJF1kM1KQmEQhp9jhVRCQREtIlz1AxZiQm3tBzFciCX9LIrT0TRQ+zga1a4raBXRFUR34CairqAgqGhVtHEbhYtKTnO0UosGhvfhZWa++QYcLl2pdDOQyebNaHDSvbi07HYWcdFFK+MM6kZOBSKRsJTwrY1RukGz9XrEnrWjXV5Fgo6359jo0OvTyu7f+oZoiydyhuiHpN9QZh40r3BkO69s3hPuNmUp4QObk1U+sXmtyqeVmvnolPCVcKeR0uPCD8KetTo/WceZ9JbxtYO9vSuRjc2J9kr2ESaIm5joPFECLBBimpl/evyVnik2UexiskGSFHmZEBBHkSYhHCKLwSgeYR9eSb996983rHmqByaO5KnHmrd6B4V+6NiveQNF+c4sXJwp3dR/LquVmnPrY74qtxeg5dCyXhbAOQzlW8t6L1hW+Ria7uG89AkQvWUZ5yFI3gAAAFZlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA5KGAAcAAAASAAAARKACAAQAAAABAAABeKADAAQAAAABAAAAPwAAAABBU0NJSQAAAFNjcmVlbnNob3RntW2aAAAB1WlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNi4wLjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczpleGlmPSJodHRwOi8vbnMuYWRvYmUuY29tL2V4aWYvMS4wLyI+CiAgICAgICAgIDxleGlmOlBpeGVsWURpbWVuc2lvbj42MzwvZXhpZjpQaXhlbFlEaW1lbnNpb24+CiAgICAgICAgIDxleGlmOlBpeGVsWERpbWVuc2lvbj4zNzY8L2V4aWY6UGl4ZWxYRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpVc2VyQ29tbWVudD5TY3JlZW5zaG90PC9leGlmOlVzZXJDb21tZW50PgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4Kr7XQLQAAE25JREFUeAHtnQdcFNf2x48RTYy9d2ONsSBYMLFEFCsWrIAaxRZ9n2c0MVY0kjxb8kwkin81saBREwUVnxWNBUSN+p5d7NifsaAiYG+Z//0dM+OyLmF3Dexbcu7ns8zce8+de+c7M2fOPecumyUpIV4jSUJACAgBIZDpCLyW6c5ITkgICAEhIASYgCh4uRGEgBAQApmUgCj4THph5bSEgBAQAqLg5R4QAkJACGRSAqLgM+mFldMSAkJACIiCl3tACAgBIZBJCYiCz6QXVk5LCAgBISAKXu4BISAEhEAmJeDyKuf19OkzevDwIT158pQ0Tb4v9Sospa0QEAJCwJxAlixZKFs2F8rxxhvk4pLVvDrNvN0KHso9+c5dypM3DxXPmy/NjkRACAgBISAEbCeQmJRIyUnJlCd3LpuVvN0KHpY7lHs+Ue62XzFpIQSEgBCwkoCuYx/cv0+5c+W0stVzMbt98HDL6B3b1KMICwEhIASEgE0EoGuhc21Ndit48bnbilrkhYAQEAL2E7BH59qt4O0fprQUAkJACAiBjCAgCj4jKEsfQkAICAEHEBAF7wDo0qUQEAJCICMIiILPCMrShxAQAkLAAQREwTsAunQpBISAEMgIAqLgM4Ky9CEEhIAQcAABUfAOgC5dCgEhIAQygoAo+IygLH0IASEgBBxAQBS8A6BLl0JACAiBjCAgCj4jKEsfQkAICAEHEBAF7wDo0qUQEAKZj0BMzHbyatacsmZ7PcV23PgJDjvZdFfwR2Jj6dTp0w47wevX4wlj0D+3bt1Kt7EkJSVxP/HxN9Ktj7QOfF/9xzmc65UrV9MSlXohQA8ePKC9e/fSpUuX7KIRFxdHD9V/lv2rJyj2cRMm0BdBQfTsySOK2rKZt56NGlHM9u3kKCWf7gq+Zq061KFDp3S7/j8sXEhTgr9N9fiz58whjEH/FC1ekqq7utGIkaPo6VPb/ztbqh2piq1bo7if+QsW/JFYutYdOnyYxzD566/TtR85uPMTWLt2LdWrX48mTppIfv5+1LtPb4KBYEvq4tuFoOT/ygnKG4ocSt3TsxGjgDWP9MXnQVyOfbwEMjqlu4JP7xMKCfk/+mxsUJrd9Ondm2bOmE7Dhn5KOXLkoG+nTqNeffrSb7/9lmZbERACmY3AjRs3KHB0IP2w4AdavWo1xWyL4V9lmz1ndmY71XQ9Hyh3WOhQ5HrSXTW6kke5Xm9apsun59buH/z4swb17NkzCp0/n7bv2MnTxfr16tHfBvSnXLlycRewKGbMnEX7DxygYkWLUovmzcnbuxW99tpr9MmQT9kdAUEo684dO5KPTzuLQ2vW1Iu6dvXnOvTZ2dePwsLCybtlS+rR4wMuh/tm2fLl6oLtoLx58lJAQA9qUL8+1929e5c+Gvwx1apZkzw86tD3s+dQrpy5yN/fl9/eFjtVhXBPrVz5Lzpw8CDVdHenTp060juVK9O9e/do4KDBVKpkSZo08YWPbtKXX9FpZRFN+XoyFS5cmNtHRKzk8y9frhx9PHgwlS5dyugObqHQ+Qto95495FajBjVs0MCokx0hkBqBK1evqOehK7mrexLp9ddfp5bqWdi0aVNqTXjGu2r1Ktq9azflL5CfBvQf8JIsrPmlS5cqF+EVKqXu014BvdT9WprwQpkyZQqNGTOG8ubNa7SbFjJNPVO1qJGygDGjXrx4MR06fIjKlC6jnnNvqlq1qiFrvhOzPYYi10dSUnISubq6Up/efejNN980xLYrxbtl6xZ6/Pgx+fv509GjR6nMW2XU8+rJMvj3uxs2bqCdO3eqn8TLQU2aNKGGDRsa7a3ZgXKH9W6aYMWbWvN6Hdw3cONEeW7Wi9J963ALvtsHPejvAwdR3Ok4uqr8xiNHBZKvf1fjxL2aNmcLHQr28OEj5NOhI82ZO5frL//6qyF36eIlgrKzJmXNmtV4o+7avYeb3Llzh1q2ak1Dh42geOW334zpVmMvCg9fxvWPHj2iH3/8iebOnUet27Sj2COxNC80lFq09GbXjKV+4Quv3+B9mjBxEp8blDfyh48coZw5c9KZuDP09TdT+OZHe5wjZPbv28/K/eixYyyP2QbGN19ZW65u7nTm7FnuDg9EF3Xjwt20Ryn4ufPm0ZBPh1oaipQJgRQE3Gq4UZDZzPfQoUNUvlz5FHKmmXHjxrHF7+bmxgbQYGVswFjS04mTJwguGyjUVq1a8X3dM6An++hhrEBxb9r84gVy/fp1mqNcqGXKlOFDjBg5gjb+vJG8vLwob7689GH/D+ny5cv64VNsw8LCaNiwYVS8RHGWj4qK4hmJLoQX0chRI6lwocJUtUpVGj9+PC0NW8rPnC4THBxMISEhVLFCRX5hYUazfMVyvdqqLSxy3TrXGyDICkVunqD4M9qCp6SEeM2ez7kzpzUVTEjzo05Se7tSJYty9+4kaV9OmqiFTJtq1L/37rv49W7txvWr2oVzZ3m/efNmRn3wlG+0BaHzjHwNV1fNxcXFyJuPScHnY/y0eFEKmft3k7mdsqq5fHTgKJaLXLeW83eTEzXX6tW1YsWKcj7+2hWuz5Ytm/aff+/msl92btfUy0JTVj3nl4eHsYyyyDlf7733NMjv3/cfzh88sI/zdT08OD89ZBrLzw+dy/kVy8I5P2H8OM6r2YxWsGBB7eL5c5yPO31Sy549u+bv78f5VSsjWL5du7ba08cPuax9ex8uG/TRQM6b85B82vfsX5HR1s0/a+5u1bVf/3vR4n0Te+SgVsO1qnb5vxeM+lUrV2iVKpbTDqn7GszwjMREbzXq8Yy51aim7d/7by6bMX2a1rNHN6M+dN5szbdLRyNfu6abtn1blJE/fHC/dvvWDSNvel1OnzyuoV4v26ueSdfqVbTHD+/zs1DT3VXbtDHSqL94/qxWrWplbc73s7js1IljLH/+bJwhs2fXTq3KO5U06CX9uGltldK2KAsdZqltavKWZM3LoHNt1dUOddG8oX4pfPiwoRQVFc2B0jhl0R47fpxffDdu3qTKb79N6uXAFnLrtu3IS02hunTpTGXfeotlXuUPrAxYH7CkkaKjt/E2Kjqaorc931cvDrp27TpdvXqNsmfPxvXqhUK1a9XiffUyIvUSIFjaT5484TL9D44PtwxcOu7K4kFCW486dWjvvn1s1fgpa2fosOG0Zu06NZUNoNUq6IXUrVtXtoJ27d7N+RkzZ/IWf3Lnzk0HDxzkPI6P1K9PH8KvryP1VbGG1avX8L78EQLWEIDrYviI4RQ8JZiKFStmsQlkqlerTsWLFTfqGzdubOxjRxkjVLt2bdoWs43OnztP586d4/sc7hkkHx8f5W6dQTfVs12oUCFav349denchevwBy6isUFj2Z0Cl0119WyllipUqMAzhA0bNtDFixeVC3M/94VZcEJCAu97enoazUuVKkUVK1Y08ofVYoRq1aoZswdUeHh4sPvomHqecR7WJFstclvlrRnDH8k41EWTmJhItWp7kHebtrRiRQQHPKHQTdP2mGgapaZuuGECR4+htytXoaDPvzAVsWsfbhL44OrW9eD2165d4+258+fprLox8SlXvhz7zB88fGD0kTtPbmMfO3ny5GFljBvLNCUnJxPcOvhhctOEPF4GSepX0jFtbdasKW3evIV98pGRG9jnX65s2RTuJn082GKa5/H7mHEjI2EMejIfn14uWyFgicCFCxdowN8G0NChQ8lcYZvKw/2ZK/fzuJhejsUKcHfqCW7C9xu9T6HKdRkfH8/+/aIqbqankireVEsZR1DKWJZ5WsWnvFt769U0Qbk14DY6dvwYr+jp1bsXpbasee68uco92oIiIyPp4aOH1NxkhQriW2rmnGJs6ATj1VPC7YQUsQC9HPEB1FmbbHG78Gob9fxmZHKoBb9x489s/U7+51dsyePE27TzMc4fAdZ49fb/aOBAmjhhvHpTXyJPZcXDJ61cKkZABYoaH92KNQ6Qyg5eLIMGfcy1zZo25S1uzAuLL9KM6dOpaNEiXAZl75LVhYOaujKNjT3KvnIEgaHE4WcvU6Y05c+fP0VvsFAw04ClgPNA8AdrjuHnRJBU7+ODbt0IHCZO+pJv5u7dn8cfoPxxXARylynfoX5umC0ULfJ8fO7uz2cGO3/5xVietUsFwCQJAWsIQAn37deXevboSd27df/DJlXeqUJLlizhWa+u1OPOxKXwwS9ctJB8fX2VQTaKj4Vn8psp36Q4bof2HdRChmVs0CComSf3C+MEhg/87/hgbX1ArwCKiIigAQNSBnNx3NmzZ9PUb6caL6VTp04Z/VRWixgQnzquvAGw0pGg9PFC8WrixXnMDszPB3EuzAYwU7E2WQqcwgePhK1ysxiHshSQNSrTaSdDLHi4WxAINP1AMRb5XVFti4khKKlgdcGwllxPt28nUoOGjaiVd2taq9wY0dui1fTuFpUsUcJQ7mXLleWbbMxnYw33jt7edBuq1qYjmNuilTeVq1CJYtWU86svJ6lpYQsW69WzJ7/1O3bqTMuWLedAbh2Pd6mteuHghtITLHUEemd99z35tO9IeFn4dnkxzdTlsB2gVgPhS08IhC5atJiDx3D5DOjf3xBTPnM+F7y0YHWYHqtf3750/MQJXiGE88fMxc29Fn3xj/HcvlnTZvxi+eqfk+kf48bT+AkT+eVnHFx2hEAqBGCc9Puwn3IZerBShtsEn9Qs5prK1YiVa1OnTmVDBW6XyZMnp7CSYZRgpg3lDGUNJYznwzQh+AplvGTpEvX9mA5GFZRr4yaNlas0mstuJ95mF0zOXM9dqIag2oGxAwPq5MmTPOtH25DpIYYInqMePXoo9+dQWh+5nlfJfDLkE+VmzW7IuKvFCrDog78NZuUPAy5ILXWs61GXihd/4YYyGqSyAwseCda5nqDU9Y9exta7cjuZB2T1+nTb2uq01+VtCbKqwUNDpviEL12iPXpwT1Pr0zlQiXoEWLt378Zyx4/FcpAibMlPWp3atTV1c/EH+4cPHTACGHt2/6IpS5fbIFBqHpjQg6x6/8qq5j5+XLTwJVllKWtVq1TR1A3Efaklh5o+Dj3IqlwqmlLQXK+sci0goCefB/o1D7KiLGjsZ1rJkiV4fCVKFNc+GzP6pX6Vz53r27Zt81LdmNGBRnu1lI37S7gZb8ht2fSzpmIV3L5UqZLanNnf8b4EWSWYav4smObnh87hACmCpKYfBBlN5Uz3Tx4/qvm0ba1Vr/YOBygjloerZ9PdCLJeunBOa9O6JQczEfD8PGiM1qxpY21j5LoUx/x0yGD1rNfhgKjp8deu+ZfW1MtTQ4AUAdHAUcNTDXjuiInWPOrU5MAwgr+zZkzn89CfDSw6QEC1m7+v5ufbSVuzaqXWt0+AEWRFvxivv19nPhcco/+HfbTEhJspxmo6vj/a/zxorIYAKramcmq5JJejzrTcnn17gqxZoLCV8rM53UpIpLf+hGAnOoYL486du4bbwtJg4ANE0FMPiprLwFJAAFKfPprX25LH2xwBYNM1tbBsihQrQWpFD21UVgEseVgKWD9sTYIlX6RIYYuiH38yhGbO+o6W/vQj+fn5WpSB5V+oUEFmYEkAYy5QoIClKikTAn8qgdu3b/OzhufRUoLrB9YxnkdLKTAwkGeeo0Y9d+WYy+BZgy88tePr8viS4tWrVzmWZWqdox4zCLTXXZuQbdmqpXL3fpRi5gBZPMuQxTP/KglWOtwwCKTqvnls4cbB9lUT3EcFC+Sz6TCWr5BNh3h1YShSU2Vq6YimX46wVJ8vn20nbukYepk1ilL/IpbeJq2tJeWOVTJwS61bt54qqQh/x44vpqzmx1PLNc2LUuStGXOKBpIRAnYSMI83mR9Gd72alyOge1Ct/MJa97Vrnq8YM5dBHqtxrElwGSFwaykhaIwFBwP/PpCNvoiVEfzlq/q/f3HRtI2tz7JpW9P9DHe/mHaeyn6G+OBT6dupinEzVShf3ib/XFonGKviEPiCV4cO7dXKgvU8I0irjdQLAWclEB4eTmHhYfyNVny7NT0TZgfwzeOLV63btKYdO3bQYhUHS+3lk55jceSx/ydcNI4EIH0LASEgBJyBgD0uGrHgneHKyhiFgBAQAnYQEAVvBzRpIgSEgBBwBgKi4J3hKskYhYAQEAJ2EBAFbwc0aSIEhIAQcAYCouCd4SrJGIWAEBACdhAQBW8HNGkiBISAEHAGAqLgneEqyRiFgBAQAnYQEAVvBzRpIgSEgBBwBgJ2K3j9fzw4w0nKGIWAEBACzk7AHp1rt4LPls2FEpMSnZ2ZjF8ICAEh8D9PALoWOtfWZLeCz6H+81qy+lUiUfK2Ihd5ISAEhID1BKBjoWuhc21Ndv8vGnT09OkzesD/3P9pih/FsHUQIi8EhIAQEAIvE4BbBpY7lLuLy4ufR3xZ0nKJ7Ta/yXHQYW4Lv7hiIiK7QkAICAEh4CACdrtoHDRe6VYICAEhIASsJCAK3kpQIiYEhIAQcDYCouCd7YrJeIWAEBACVhIQBW8lKBETAkJACDgbAVHwznbFZLxCQAgIASsJiIK3EpSICQEhIAScjYAoeGe7YjJeISAEhICVBETBWwlKxISAEBACzkZAFLyzXTEZrxAQAkLASgKi4K0EJWJCQAgIAWcj8P/bl5hNUzqt1gAAAABJRU5ErkJggg==) The last deployed card shows the time of the last time your functions were deployed. ## Integrations[​](#integrations "Direct link to Integrations") info Integrations are only available on Convex Professional. ![Last Deployed Card](/assets/images/health_integrations-d276b1aa3d1f8706b3a9d3104d4a7cb2.png) The integrations card shows the status of your [Exception Reporting](/production/integrations/exception-reporting.md) and [Log Streams](/production/integrations/log-streams/.md) integrations, with quick links to view and configure your integrations. ## Insights[​](#insights "Direct link to Insights") ![Insights Card](/assets/images/insights-15ec1ad7e37db8c689c0abb030b1fa17.png) The Health page also surfaces insights about your deployment, with suggestions on how to improve performance and reliability. Each Insight contains a description of the issue, the impact on your deployment (via a chart and event log), and a link to learn more about the issue and how to resolve it. Clicking on an Insight will open a breakdown of the issue, including a larger chart and a list of events that triggered the Insight. ![Insight Breakdown](/assets/images/insights_breakdown-9f58d14e058976c361b23a1cac9f8a37.png) Available insights include: * Functions that are [reading too many bytes](/production/state/limits.md#transactions) in a single transaction. * Functions that are [reading too many documents](/production/state/limits.md#transactions) in a single transaction. * Functions that are experiencing [write conflicts](/error.md#1). --- # History ![History Dashboard Page](/assets/images/history-9d8ba9365e0f53531de2ddef5cd4cfd0.png) info The history page is only available on Convex Professional. This [history page](https://dashboard.convex.dev/deployment/history) is an audit log of configuration-related events that have occurred in the selected deployment, such as function deployments, changes to indexes, and changes to environment variables. You may also view an audit log of team-related events in the [team audit log](/dashboard/teams.md#audit-log). --- # Logs ![Logs Dashboard Page](/assets/images/logs-ed208103a42edfb005e9089a8edad58e.png) The [logs page](https://dashboard.convex.dev/deployment/logs) is a realtime view of all activity that occurs within your deployment. The logs page provides a short history of recent function logs, and will display new logs as they are generated. To store a longer history of logs, you may configure a [log stream](/production/integrations/log-streams/.md). Function activity includes: * The time of function execution. * The request ID of the function execution. * The outcome of the function execution (success or failure). * The name of the invoked function. * The output of the function, including any log lines logged by the function (ex `console.log`) and exceptions. * The duration of function execution, in milliseconds (does not include network latency). In addition to function activity, [deployment events](/dashboard/deployments/history.md) describing configuration changes will be present here. Clicking on log will open a view for all logs associated with the same Request ID as the selected log. This can be useful for debugging errors and understanding the context of a function execution. ![Request ID Logs](/assets/images/request_logs-dd39b47c480a5c133a89f7ef87420b4e.png) You can use controls on the top of this page to filter logs by text, function name, execution status, and log severity. ### Filter logs[​](#filter-logs "Direct link to Filter logs") Use the "Filter logs..." text box on the top of the page to filter log text. You can use the “Functions” drop-down list to include or exclude functions from the results. You can also find logs for a particular error using "Filter logs" and the [Convex request id](/functions/error-handling/.md#debugging-errors). For example if you see this `Error` in your browser console: ![Browser Error](/assets/images/console_error_requestid-27707a2afed9232acb56746eaa59248c.png) You can view the logs for that function in your dashboard by pasting that Request ID into the 'Search logs...' search bar on the [Logs](/dashboard/deployments/logs.md) page of your Convex dashboard. Note that because this page is not a complete historical view of logs, you may not find logs for older requests. Most error reporting services and log sinks should also be searchable by Request ID. ### Log Types[​](#log-types "Direct link to Log Types") Logs can also be filtered by type. Types include function outcomes (success or failure) and severity levels (info, warn, debug, error). All failed executions will include a reason, which will usually be a JavaScript exception. --- # Schedules The [schedules page](https://dashboard.convex.dev/deployment/schedules) displays all [scheduled functions](/scheduling/scheduled-functions.md) and [cron jobs](/scheduling/cron-jobs.md) in your deployment. Use the tabs at the top of this page to switch between scheduled functions and cron jobs. ## Scheduled functions UI[​](#scheduled-functions-ui "Direct link to Scheduled functions UI") The scheduled functions UI shows a list of all upcoming function invocation. From here, you can filter to scheduled runs for a specific function, and cancel scheduled functions runs. ![Scheduled functions](/assets/images/scheduled_functions-8dad14a0426380104964b52c68dbdc31.png) ## Cron jobs UI[​](#cron-jobs-ui "Direct link to Cron jobs UI") The cron jobs UI lists all of your cron jobs, including their run frequency and scheduled run time. ![Cron jobs](/assets/images/cron_jobs-9986c12428ea362a4dc2b012249a4611.png) Expanding a specific cron job will open the execution history for the selected job. ![Cron job history](/assets/images/cron_job_history-1be17ce3db8bb6772c2f8102f74436cd.png) --- # Projects ![Project settings](/assets/images/projects-ea1be7a1deec4ee628278d2badc15e2f.png) A project corresponds to a codebase that uses Convex, which contains a production deployment and one personal deployment for each team member. Clicking on a project in the [landing page](https://dashboard.convex.dev) will redirect you to project details. ## Creating a project[​](#creating-a-project "Direct link to Creating a project") Projects can be created from the dashboard or from the [CLI](/cli.md#create-a-new-project). To create a project from the dashboard click on the Create Project button. ## Project Settings[​](#project-settings "Direct link to Project Settings") You can access project-level settings by clicking on the triple-dot `⋮` button on each Project card on the Projects page. ![Project card menu](/assets/images/project_menu-374924ad6539365422c2fe033a860807.png) On the [Project Settings page](https://dashboard.convex.dev/project/settings), you can: * Update your project's name and slug. * Manage the project's Admins. See [Roles and Permissions](/dashboard/teams.md#roles-and-permissions) for more details. * View the amount of [usage metrics](/dashboard/teams.md#usage) your project has consumed. * Add [custom domains](/production/hosting/custom.md#custom-domains) for your production deployment * Generate deploy keys for your production and preview deployments. * Create and edit [default environment variables](/production/environment-variables.md#project-environment-variable-defaults). * View instructions to regain access to your project, should you lose track of your `CONVEX_DEPLOYMENT` config. * Permanently delete the project. ![Project settings](/assets/images/project_settings-1f0b5c77c97069e4f609965071ca2759.png) ## Deleting projects[​](#deleting-projects "Direct link to Deleting projects") To delete a project, click on the triple-dot `⋮` button on the Project card and select "Delete". You may also delete your project from the Project Settings page. Once a project is deleted, it cannot be recovered. All deployments and data associated with the project will be permanently removed. When deleting a project from the dashboard, you will be asked to confirm the deletion. Projects with activity in the production deployment will have additional confirmation steps to prevent accidental deletion. ![Delete project](/assets/images/project_delete-6db8dd21ba528b6c7ce4063a54e2d7f0.png) --- # Teams 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](/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[​](#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](/assets/images/teams_general-be57d90397e8c7890730dfd5d52f29a3.png) ## Team Members[​](#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](/assets/images/teams_members-a49899c63f9a183cb0b684f0353bc678.png) ### Roles and permissions[​](#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[​](#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](#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](#project-admins) for more information. #### Project Admins[​](#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](/dashboard/projects.md#project-settings) page instead. ## Billing[​](#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/pricing). ![Team billing page](/assets/images/teams_billing-52fb5e7787443bac74030153c75f3a80.png) ### Spending limits[​](#spending-limits "Direct link to Spending limits") When you have an active Convex subscription, you can set the spending limits for your team on the [billing page](https://dashboard.convex.dev/team/settings/billing): * The **warning threshold** is only a soft limit: if it is exceeded, the team will be notified by email, but no other action will be taken. * The **disable threshold** is a hard limit: if it is exceeded, all projects in the team will be disabled. This will cause errors to be thrown when attempting to run functions in your projects. You can re-enable projects by increasing or removing the limit. Spending limits only apply to the resources used by your team’s projects beyond the amounts included in your plan. The seat fees (the amount paid for each developer in your team) are not counted towards the limits. For instance, if you send the spending limit to $0/month, you will be billed for the seat fees only and the projects will be disabled if you exceed the built-in resources included in your plan. ![The team billing page with some spending limits set.](/assets/images/teams_billing_spending_limits-3288d9eefd1e795c3e73baa05fcecb9e.png) ## Usage[​](#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/pricing). ![Team usage page](/assets/images/teams_usage-714de6c9b025dd8a5724545347f16ff7.png) All metrics are available in daily breakdowns: ![Team usage page graphs](/assets/images/teams_usage_2-be702e62f3542f613dceeb4464d8a724.png) ## Audit Log[​](#audit-log "Direct link to Audit Log") info The Audit Log is only available on Convex Professional. 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](/assets/images/teams_audit_log-c22793879705a616a42ab4f72274358a.png) You may also view a history of deployment-related events on the [deployment history page](/dashboard/deployments/history.md). --- # Database 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](/functions.md) 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](#tables), [documents](#documents) and [schemas](#schemas) below, then move on to [Reading Data](/database/reading-data/.md) and [Writing Data](/database/writing-data.md). As your app grows more complex you'll need more from your database: * Relational data modeling with [Document IDs](/database/document-ids.md) * Fast querying with [Indexes](/database/reading-data/indexes/.md) * Exposing large datasets with [Paginated Queries](/database/pagination.md) * Type safety by [Defining a Schema](/database/schemas.md) * Interoperability with data [Import & Export](/database/import-export/.md) ## Tables[​](#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. ``` // `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[​](#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: ``` {} {"name": "Jamie"} {"name": {"first": "Ari", "second": "Cole"}, "age": 60} ``` They can also contain references to other documents in other tables. See [Data Types](/database/types.md) to learn more about the types supported in Convex and [Document IDs](/database/document-ids.md) to learn about how to use those types to model your data. ## Schemas[​](#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: ``` 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](/database/schemas.md) to learn more about schemas. ## [Next: Reading Data](/database/reading-data/.md) [Query and read data from Convex database tables](/database/reading-data/.md) Related posts from [![Stack](/img/stack-logo-dark.svg)![Stack](/img/stack-logo-light.svg)](https://stack.convex.dev/) --- # OCC and Atomicity In [Queries](/functions/query-functions.md), we mentioned that determinism was 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.[​](#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: ``` $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! ``` $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. ``` $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: ``` $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[​](#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[​](#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[​](#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. --- # Schema Philosophy With Convex there is no need to write any `CREATE TABLE` statements, or think through your stored table structure ahead of time so you can name your field and types. You simply put your objects into Convex and keep building your app! However, moving fast early can be problematic later. "Was that field a number or a string? I think I changed it when I fixed that one bug?" Storage systems which are too permissive can sometimes become liabilities as your system matures and you want to be able to reason assuredly about exactly what data is in your system. The good news is Convex is always typed. It's just implicitly typed! When you submit a document to Convex, tracks all the types of all the fields in your document. You can go to your [dashboard](/dashboard.md) and view the inferred schema of any table to understand what you've ended up with. "What about that field I changed from a string to a number?" Convex can handle this too. Convex will track those changes, in this case the field is a union like `v.union(v.number(), v.string())`. That way even when you change your mind about your documents fields and types, Convex has your back. Once you are ready to formalize your schema, you can define it using our [schema builder](/database/schemas.md) to enable schema validation and generate types based on it. --- # System Tables System tables enable read-only access to metadata for built-in Convex features. Currently there are two system tables exposed: * `"_scheduled_functions"` table contains metadata for [scheduled functions](/scheduling/scheduled-functions.md#retrieving-scheduled-function-status) * `"_storage"` table contains metadata for [stored files](/file-storage/file-metadata.md) 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. Queries reading from system tables are reactive and realtime just like queries reading from all other tables, and pagination can be used to enumerate all documents even when there are too many to read in a single query. --- Convex supports Backup & Restore of data via the [dashboard](https://dashboard.convex.dev/deployment/settings/backups). ![Backups Page](/assets/images/backups-7e17da1541fc3eb26194a96ab33414ea.png) # Backups A backup is a consistent snapshot of your table data made at the time of your request. Backups can be configured to include file storage. Take a manual 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. Manual 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[​](#periodic-backups "Direct link to Periodic Backups") Schedule a periodic daily or weekly backup by checking the "Backup automatically" box. You can select what time of day / day of week to have the backup occur and whether to include file storage or not. Daily backups are stored for 7 days. Weekly backups are stored for 14 days. Periodic backups require a Convex Pro plan. Periodic backups require 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[​](#restoring-from-backup "Direct link to Restoring from backup") Restore from a backup by selecting "Restore" from the submenu of an individual backup. 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. Existing files in the deployment will not be deleted when restoring from a backup, but any files in the backup that do not currently exist in the deployment will be uploaded to the deployment. ### Restoring in an emergency[​](#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](/cli.md#export-data-to-a-file): ``` 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 that include [file storage](/file-storage.md) will contain storage data in a `_storage` folder, with metadata like IDs and checksums in `_storage/documents.jsonl` and each file as `_storage/`. ### Using the downloaded backup.[​](#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](/database/import-export/import.md#restore-data-from-a-backup-zip-file). ## FAQ[​](#faq "Direct link to FAQ") ### Are there any limitations?[​](#are-there-any-limitations "Direct link to Are there any limitations?") Each backup is accessible for up to 7 days. On the Free/Starter plan, up to two backups can stored per deployment at a time. Deployments on Convex Professional plan can have many backups with standard usage based pricing. ### How are they priced?[​](#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](/production/state/limits.md#database) for pricing details. ### What does the backup not contain?[​](#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`](/database/advanced/system-tables.md) system table. 3. Environment variables. Environment variables can be copied from Settings in the Convex dashboard. --- # Document IDs **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. ``` 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: ``` const retrievedUser = await ctx.db.get(userId); ``` You can access the ID of a document in the [`_id` field](/database/types.md#system-fields): ``` const userId = retrievedUser._id; ``` Also, this same ID can be used to update that document in place: ``` await ctx.db.patch(userId, { name: "Steph Curry" }); ``` Convex generates an [`Id`](/generated-api/data-model.md#id) TypeScript type based on your [schema](/database/schemas.md) that is parameterized over your table names: ``` import { Id } from "./_generated/dataModel"; const userId: Id<"users"> = user._id; ``` IDs are strings at runtime, but the [`Id`](/generated-api/data-model.md#id) type can be used to distinguish IDs from other strings at compile time. ## References and relationships[​](#references-and-relationships "Direct link to References and relationships") In Convex, you can reference a document simply by embedding its `Id` in another document: ``` await ctx.db.insert("books", { title, ownerId: user._id, }); ``` You can follow references with `ctx.db.get`: ``` const user = await ctx.db.get(book.ownerId); ``` And [query for documents](/database/reading-data/.md) with a reference: ``` 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[​](#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[​](#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 ``` 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`](/api/interfaces/server.GenericDatabaseReader.md#normalizeid) to confirm that the ID belongs to the expected table before returning the object. convex/tasks.ts TS ``` 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](/img/stack-logo-dark.svg)![Stack](/img/stack-logo-light.svg)](https://stack.convex.dev/) --- # Data Import & Export If you're bootstrapping your app from existing data, Convex provides three ways to get the data in: * Import from csv/json into a single table via the [CLI](/database/import-export/import.md#single-table-import). * Restore from a backup via the [dashboard](/database/backup-restore.md) or [CLI](/database/import-export/import.md#restore-data-from-a-backup-zip-file). * [Streaming import](/production/integrations/streaming-import-export.md) from any existing database via Airbyte destination connector. You can export data from Convex in two ways. * Download a backup as a zip from the [dashboard](/database/backup-restore.md). * Set up [streaming export](/production/integrations/streaming-import-export.md) to any external database via Fivetran or Airbyte. Great for connecting to a custom BI setup (eg [Snowflake](https://www.snowflake.com/), [Databricks](https://www.databricks.com), or [BigQuery](https://cloud.google.com/bigquery)): Data Import & Export is in beta Data Import & Export is currently a [beta feature](/production/state/.md#beta-features). If you have feedback or feature requests, [let us know on Discord](https://convex.dev/community)! --- # Data Export You can export your data from Convex by [taking a backup](/database/backup-restore.md) and downloading it as a zip file. Alternatively, you can export the same data with the [command line](/cli.md#export-data-to-a-file): ``` npx convex export --path ~/Downloads ``` --- # Data Import You can import data into Convex from a local file using the command line. ``` npx convex import ``` Data import is in beta Data import is currently a [beta feature](/production/state/.md#beta-features). If you have feedback or feature requests, [let us know on Discord](https://convex.dev/community)! Use `--help` to see all options. The most common flows are described here. ## Single table import[​](#single-table-import "Direct link to Single table import") ``` npx convex import --table ``` Import a CSV, JSON, or JSONLines file into a Convex table. * `.csv` files must have a header, and each row's entries are interpreted either as a (floating point) number or a string. * `.jsonl` files must have a JSON object per line. * `.json` files must be an array of JSON objects. * JSON arrays have a size limit of 8MiB. To import more data, use CSV or JSONLines. You can convert json to jsonl with a command like `jq -c '.[]' data.json > data.jsonl` Imports into a table with existing data will fail by default, but you can specify `--append` to append the imported rows to the table or `--replace` to replace existing data in the table with your import. The default is to import into your dev deployment. Use `--prod` to import to your production deployment or `--preview-name` to import into a preview deployment. ## Restore data from a backup ZIP file[​](#restore-data-from-a-backup-zip-file "Direct link to Restore data from a backup ZIP file") ``` npx convex import .zip ``` Import from a [Backup](/database/backup-restore.md) into a Convex deployment, where the backup is a ZIP file that has been downloaded on the dashboard. Documents will retain their `_id` and `_creationTime` fields so references between tables are maintained. Imports where tables have existing data will fail by default, but you can specify `--replace` to replace existing data in tables mentioned in the ZIP file. ## Use cases[​](#use-cases "Direct link to Use cases") 1. Seed dev deployments with sample data. ``` # full backup - exported from prod or another dev deployment. npx convex import seed_data.zip # Import single table from jsonl/csv npx convex import --table
data.jsonl ``` 2. Restore a deployment from a [backup](/database/backup-restore.md) programmatically. Download a backup, and restore from this backup if needed. ``` npx convex import --prod --replace backup.zip ``` 3. Seed preview deployments with sample data, exported from prod, dev, or another preview deployment. Example for Vercel, seeding data from `seed_data.zip` committed in the root of the repo. ``` npx convex deploy --cmd 'npm run build' && if [ "$VERCEL_ENV" == "preview" ]; then npx convex import --preview-name "$VERCEL_GIT_COMMIT_REF" seed_data.zip; fi ``` 4. Clear a table efficiently with an empty import. ``` touch empty_file.jsonl npx convex import --replace --table empty_file.jsonl ``` ## Features[​](#features "Direct link to Features") * Data import is the only way to create documents with pre-existing `_id` and `_creationTime` fields. * The `_id` field must match Convex's ID format. * If `_id` or `_creationTime` are not provided, new values are chosen during import. * Data import creates and replaces tables atomically (except when using `--append`). * Queries and mutations will not view intermediate states where partial data is imported. * Indexes and schemas will work on the new data without needing time for re-backfilling or re-validating. * Data import only affects tables that are mentioned in the import, either by `--table` or as entries in the ZIP file. * While JSON and JSONLines can import arbitrary JSON values, ZIP imports can additionally import other Convex values: Int64, Bytes, etc. Types are preserved in the ZIP file through the `generated_schema.jsonl` file. * Data import of ZIP files that include [file storage](/file-storage.md) import the files and preserve [`_storage`](/database/advanced/system-tables.md) documents, including their `_id`, `_creationTime`, and `contentType` fields. ## Warnings[​](#warnings "Direct link to Warnings") * [Streaming Export](/production/integrations/streaming-import-export.md) (Fivetran or Airbyte) does not handle data imports or backup restorations, similar to table deletion and creation and some schema changes. We recommend resetting streaming export sync after a restore or a data import. * Avoid changing the ZIP file between downloading it from Data Export and importing it with `npx convex import`. Some manual changes of the ZIP file may be possible, but remain undocumented. Please share your use case and check with the Convex team in [Discord](https://convex.dev/community). * Data import is not always supported when importing into a deployment that was created before Convex version 1.7. * The import may work, especially when importing a ZIP backup from a deployment created around the same time as the target deployment. As a special case, you can always restore from backups from its own deployment. * Reach out in [Discord](https://convex.dev/community) if you encounter issues, as there may be a workaround. Data import uses database bandwidth to write all documents, and file bandwidth if the export includes file storage. You can observe this bandwidth in the [usage dashboard](https://dashboard.convex.dev/team/settings/usage) as function name `_cli/import` and associated cost in the [limits docs](/production/state/limits.md#database). --- # Paginated Queries Paginated queries are [queries](/functions/query-functions.md) that return a list of results in incremental pages. This can be used to build components with "Load More" buttons or "infinite scroll" UIs where more results are loaded as the user scrolls. **Example:** [Paginated Messaging App](https://github.com/get-convex/convex-demos/tree/main/pagination) Using pagination in Convex is as simple as: 1. Writing a paginated query function that calls [`.paginate(paginationOpts)`](/api/interfaces/server.OrderedQuery.md#paginate). 2. Using the [`usePaginatedQuery`](/api/modules/react.md#usepaginatedquery) React hook. Like other Convex queries, paginated queries are completely reactive. ## Writing paginated query functions[​](#writing-paginated-query-functions "Direct link to Writing paginated query functions") Convex uses cursor-based pagination. This means that paginated queries return a string called a [`Cursor`](/api/modules/server.md#cursor) that represents the point in the results that the current page ended. To load more results, you simply call the query function again, passing in the cursor. To build this in Convex, define a query function that: 1. Takes in a single arguments object with a `paginationOpts` property of type [`PaginationOptions`](/api/interfaces/server.PaginationOptions.md). * `PaginationOptions` is an object with `numItems` and `cursor` fields. * Use `paginationOptsValidator` exported from `"convex/server"` to [validate](/functions/validation.md) this argument * The arguments object may include properties as well. 2. Calls [`.paginate(paginationOpts)`](/api/interfaces/server.OrderedQuery.md#paginate) on a [database query](/database/reading-data/.md), passing in the `PaginationOptions` and returning its result. * The returned `page` in the [`PaginationResult`](/api/interfaces/server.PaginationResult.md) is an array of documents. You may [`map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) or [`filter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) it before returning it. convex/messages.ts TS ``` import { v } from "convex/values"; import { query, mutation } from "./_generated/server"; import { paginationOptsValidator } from "convex/server"; export const list = query({ args: { paginationOpts: paginationOptsValidator }, handler: async (ctx, args) => { const foo = await ctx.db .query("messages") .order("desc") .paginate(args.paginationOpts); return foo; }, }); ``` ### Additional arguments[​](#additional-arguments "Direct link to Additional arguments") You can define paginated query functions that take arguments in addition to `paginationOpts`: convex/messages.ts TS ``` export const listWithExtraArg = query({ args: { paginationOpts: paginationOptsValidator, author: v.string() }, handler: async (ctx, args) => { return await ctx.db .query("messages") .filter((q) => q.eq(q.field("author"), args.author)) .order("desc") .paginate(args.paginationOpts); }, }); ``` ### Transforming results[​](#transforming-results "Direct link to Transforming results") You can apply arbitrary [transformations](/database/reading-data/.md#more-complex-queries) to the `page` property of the object returned by `paginate`, which contains the array of documents: convex/messages.ts TS ``` export const listWithTransformation = query({ args: { paginationOpts: paginationOptsValidator }, handler: async (ctx, args) => { const results = await ctx.db .query("messages") .order("desc") .paginate(args.paginationOpts); return { ...results, page: results.page.map((message) => ({ author: message.author.slice(0, 1), body: message.body.toUpperCase(), })), }; }, }); ``` ## Paginating within React Components[​](#paginating-within-react-components "Direct link to Paginating within React Components") To paginate within a React component, use the [`usePaginatedQuery`](/api/modules/react.md#usepaginatedquery) hook. This hook gives you a simple interface for rendering the current items and requesting more. Internally, this hook manages the continuation cursors. The arguments to this hook are: * The name of the paginated query function. * The arguments object to pass to the query function, excluding the `paginationOpts` (that's injected by the hook). * An options object with the `initialNumItems` to load on the first page. The hook returns an object with: * `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"`. src/App.tsx TS ``` import { usePaginatedQuery } from "convex/react"; import { api } from "../convex/_generated/api"; export function App() { const { results, status, loadMore } = usePaginatedQuery( api.messages.list, {}, { initialNumItems: 5 }, ); return (
{results?.map(({ _id, body }) =>
{body}
)}
); } ``` You can also pass additional arguments in the arguments object if your function expects them: src/App.tsx TS ``` import { usePaginatedQuery } from "convex/react"; import { api } from "../convex/_generated/api"; export function App() { const { results, status, loadMore } = usePaginatedQuery( api.messages.listWithExtraArg, { author: "Alex" }, { initialNumItems: 5 }, ); return (
{results?.map(({ _id, body }) =>
{body}
)}
); } ``` ### Reactivity[​](#reactivity "Direct link to Reactivity") Like any other Convex query functions, paginated queries are **completely reactive**. Your React components will automatically rerender if items in your paginated list are added, removed or changed. One consequence of this is that **page sizes in Convex may change!** If you request a page of 10 items and then one item is removed, this page may "shrink" to only have 9 items. Similarly if new items are added, a page may "grow" beyond its initial size. ## Paginating manually[​](#paginating-manually "Direct link to Paginating manually") If you're paginating outside of React, you can manually call your paginated function multiple times to collect the items: download.ts TS ``` import { ConvexHttpClient } from "convex/browser"; import { api } from "../convex/_generated/api"; import * as dotenv from "dotenv"; dotenv.config(); const client = new ConvexHttpClient(process.env.VITE_CONVEX_URL!); /** * Logs an array containing all messages from the paginated query "listMessages" * by combining pages of results into a single array. */ async function getAllMessages() { let continueCursor = null; let isDone = false; let page; const results = []; while (!isDone) { ({ continueCursor, isDone, page } = await client.query(api.messages.list, { paginationOpts: { numItems: 5, cursor: continueCursor }, })); console.log("got", page.length); results.push(...page); } console.log(results); } getAllMessages(); ``` --- # Reading Data [Query](/functions/query-functions.md) and [mutation](/functions/mutation-functions.md) functions can read data from database tables using *document ids* and *document queries*. ## Reading a single document[​](#reading-a-single-document "Direct link to Reading a single document") Given a single document's id you can read its data with the [`db.get`](/api/interfaces/server.GenericDatabaseReader.md#get) method: convex/tasks.ts TS ``` 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); // do something with `task` }, }); ``` **Note**: You should use the `v.id` validator like in the example above to make sure you are not exposing data from tables other than the ones you intended. ## Querying documents[​](#querying-documents "Direct link to Querying documents") Document queries always begin by choosing the table to query with the [`db.query`](/api/interfaces/server.GenericDatabaseReader.md#query) method: convex/tasks.ts TS ``` import { query } from "./_generated/server"; export const listTasks = query({ args: {}, handler: async (ctx) => { const tasks = await ctx.db.query("tasks").collect(); // do something with `tasks` }, }); ``` Then you can: 1. filter 2. order 3. and `await` the results We'll see how this works in the examples below. ## Filtering your query[​](#filtering-your-query "Direct link to Filtering your query") The best way to filter in Convex is to use indexes. Indexes build a special internal structure in your database to speed up lookups. There are two steps to using indexes: 1. Define the index in your `convex/schema.ts` file. 2. Query via the `withIndex()` syntax. ### 1. Define the index[​](#1-define-the-index "Direct link to 1. Define the index") If you aren't familiar with how to create a Convex schema, read the [schema doc](/database/schemas.md). Let’s assume you’re building a chat app and want to get all messages in a particular channel. You can define a new index called `by_channel` on the `messages` table by using the `.index()` method in your schema. convex/schema.ts ``` import { defineSchema, defineTable } from "convex/server"; import { v } from "convex/values"; // Define a messages table with an index. export default defineSchema({ messages: defineTable({ channel: v.id("channels"), body: v.string(), user: v.id("users"), }).index("by_channel", ["channel"]), }); ``` ### 2. Filter a query with an index[​](#2-filter-a-query-with-an-index "Direct link to 2. Filter a query with an index") In your query function, you can now filter your `messages` table by using the `by_channel` index. ``` const messages = await ctx.db .query("messages") .withIndex("by_channel", (q) => q.eq("channel", channel)) .collect(); ``` In Convex, you must explicitly use the `withIndex()` syntax to ensure your database uses the index. This differs from a more traditional SQL database, where the database implicitly chooses to use an index based on heuristics. The Convex approach leads to fewer surprises in the long run. You can create an index across multiple fields at once, query a specific range of data, and change the order of your query result. [Read the complete index documentation](/database/reading-data/indexes/.md) to learn more. Convex also supports a slower filtering mechanism that effectively loops through the table to match the filter. This can be useful if you know your table will be small (low thousands of rows), you're prototyping, or you want to filter an index query further. You can read more about filters [here](/database/reading-data/filters.md). ## Ordering[​](#ordering "Direct link to Ordering") By default Convex always returns documents ordered by [`_creationTime`](/database/types.md#system-fields). You can use [`.order("asc" | "desc")`](/api/interfaces/server.Query.md#order) to pick whether the order is ascending or descending. If the order isn't specified, it defaults to ascending. ``` // Get all messages, oldest to newest. const messages = await ctx.db.query("messages").order("asc").collect(); ``` ``` // Get all messages, newest to oldest. const messages = await ctx.db.query("messages").order("desc").collect(); ``` If you need to sort on a field other than `_creationTime` and your document query returns a small number of documents (on the order of hundreds rather than thousands of documents), consider sorting in JavaScript: ``` // Get top 10 most liked messages, assuming messages is a fairly small table: const messages = await ctx.db.query("messages").collect(); const topTenMostLikedMessages = recentMessages .sort((a, b) => b.likes - a.likes) .slice(0, 10); ``` For document queries that return larger numbers of documents, you'll want to use an [index](/database/reading-data/indexes/.md) to improve the performance. Document queries that use indexes will be [ordered based on the columns in the index](/database/reading-data/indexes/.md#sorting-with-indexes) and can avoid slow table scans. ``` // Get the top 20 most liked messages of all time, using the "by_likes" index. const messages = await ctx.db .query("messages") .withIndex("by_likes") .order("desc") .take(20); ``` See [Limits](/database/reading-data/indexes/.md#limits) for details. ### Ordering of different types of values[​](#ordering-of-different-types-of-values "Direct link to Ordering of different types of values") A single field can have values of any [Convex type](/database/types.md). When there are values of different types in an indexed field, their ascending order is as follows: No value set (`undefined`) < Null (`null`) < Int64 (`bigint`) < Float64 (`number`) < Boolean (`boolean`) < String (`string`) < Bytes (`ArrayBuffer`) < Array (`Array`) < Object (`Object`) The same ordering is used by the filtering comparison operators `q.lt()`, `q.lte()`, `q.gt()` and `q.gte()`. ## Retrieving results[​](#retrieving-results "Direct link to Retrieving results") Most of our previous examples have ended the document query with the [`.collect()`](/api/interfaces/server.Query.md#collect) method, which returns all the documents that match your filters. Here are the other options for retrieving results. ### Taking `n` results[​](#taking-n-results "Direct link to taking-n-results") [`.take(n)`](/api/interfaces/server.Query.md#take) selects only the first `n` results that match your query. ``` const users = await ctx.db.query("users").take(5); ``` ### Finding the first result[​](#finding-the-first-result "Direct link to Finding the first result") [`.first()`](/api/interfaces/server.Query.md#first) selects the first document that matches your query and returns `null` if no documents were found. ``` // We expect only one user with that email address. const userOrNull = await ctx.db .query("users") .withIndex("by_email", (q) => q.eq("email", "test@example.com")) .first(); ``` ### Using a unique result[​](#using-a-unique-result "Direct link to Using a unique result") [`.unique()`](/api/interfaces/server.Query.md#unique) selects the single document from your query or returns `null` if no documents were found. If there are multiple results it will throw an exception. ``` // Our counter table only has one document. const counterOrNull = await ctx.db.query("counter").unique(); ``` ### Loading a page of results[​](#loading-a-page-of-results "Direct link to Loading a page of results") [`.paginate(opts)`](/api/interfaces/server.OrderedQuery.md#paginate) loads a page of results and returns a [`Cursor`](/api/modules/server.md#cursor) for loading additional results. See [Paginated Queries](/database/pagination.md) to learn more. ## More complex queries[​](#more-complex-queries "Direct link to More complex queries") Convex prefers to have a few, simple ways to walk through and select documents from tables. In Convex, there is no specific query language for complex logic like a join, an aggregation, or a group by. Instead, you can write the complex logic in JavaScript! Convex guarantees that the results will be consistent. ### Join[​](#join "Direct link to Join") Table join might look like: convex/events.ts TS ``` import { query } from "./_generated/server"; import { v } from "convex/values"; export const eventAttendees = query({ args: { eventId: v.id("events") }, handler: async (ctx, args) => { const event = await ctx.db.get(args.eventId); return Promise.all( (event?.attendeeIds ?? []).map((userId) => ctx.db.get(userId)), ); }, }); ``` ### Aggregation[​](#aggregation "Direct link to Aggregation") Here's an example of computing an average: convex/purchases.ts TS ``` import { query } from "./_generated/server"; import { v } from "convex/values"; export const averagePurchasePrice = query({ args: { email: v.string() }, handler: async (ctx, args) => { const userPurchases = await ctx.db .query("purchases") .withIndex("by_buyer", (q) => q.eq("buyer", args.email)) .collect(); const sum = userPurchases.reduce((a, { value: b }) => a + b, 0); return sum / userPurchases.length; }, }); ``` > If you need more scalable aggregate options (for example to handle frequent updates or large tables), consider using the [Sharded Counter](https://www.convex.dev/components/sharded-counter) or [Aggregate](https://www.convex.dev/components/aggregate) components. These components can help you handle high-throughput counters, sums, or computations without looping through the whole table. ### Group by[​](#group-by "Direct link to Group by") Here's an example of grouping and counting: convex/purchases.ts TS ``` import { query } from "./_generated/server"; import { v } from "convex/values"; export const numPurchasesPerBuyer = query({ args: { email: v.string() }, handler: async (ctx, args) => { const userPurchases = await ctx.db.query("purchases").collect(); return userPurchases.reduce( (counts, { buyer }) => ({ ...counts, [buyer]: counts[buyer] ?? 0 + 1, }), {} as Record, ); }, }); ``` ## Explore the syntax on the dashboard[​](#explore-the-syntax-on-the-dashboard "Direct link to Explore the syntax on the dashboard") You can try out the syntax described above directly from the dashboard by [writing a custom test query](/dashboard/deployments/data.md#writing-custom-queries). --- # Filtering The [`filter`](/api/interfaces/server.Query.md#filter) method allows you to restrict the documents that your document query returns. This method takes a filter constructed by [`FilterBuilder`](/api/interfaces/server.FilterBuilder.md) and will only select documents that match. The examples below demonstrate some of the common uses of `filter`. You can see the full list of available filtering methods [in the reference docs](/api/interfaces/server.FilterBuilder.md). If you need to filter to documents containing some keywords, use a [search query](/search/text-search.md). Use indexes instead Filters effectively loop over your table looking for documents that match. This can be slow or cause your function to hit a [limit](/production/state/limits.md) when your table has thousands of rows. For faster more database efficient queries use [indexes instead](/database/reading-data/indexes/.md). ### Equality conditions[​](#equality-conditions "Direct link to Equality conditions") This document query finds documents in the `users` table where `doc.name === "Alex"`: ``` // Get all users named "Alex". const usersNamedAlex = await ctx.db .query("users") .filter((q) => q.eq(q.field("name"), "Alex")) .collect(); ``` Here `q` is the [`FilterBuilder`](/api/interfaces/server.FilterBuilder.md) utility object. It contains methods for all of our supported filter operators. This filter will run on all documents in the table. For each document, `q.field("name")` evaluates to the `name` property. Then `q.eq` checks if this property is equal to `"Alex"`. If your query references a field that is missing from a given document then that field will be considered to have the value `undefined`. ### Comparisons[​](#comparisons "Direct link to Comparisons") Filters can also be used to compare fields against values. This document query finds documents where `doc.age >= 18`: ``` // Get all users with an age of 18 or higher. const adults = await ctx.db .query("users") .filter((q) => q.gte(q.field("age"), 18)) .collect(); ``` Here the `q.gte` operator checks if the first argument (`doc.age`) is greater than or equal to the second (`18`). Here's the full list of comparisons: | Operator | Equivalent TypeScript | | ------------- | --------------------- | | `q.eq(l, r)` | `l === r` | | `q.neq(l, r)` | `l !== r` | | `q.lt(l, r)` | `l < r` | | `q.lte(l, r)` | `l <= r` | | `q.gt(l, r)` | `l > r` | | `q.gte(l, r)` | `l >= r` | ### Arithmetic[​](#arithmetic "Direct link to Arithmetic") You can also include basic arithmetic in your queries. This document query finds documents in the `carpets` table where `doc.height * doc.width > 100`: ``` // Get all carpets that have an area of over 100. const largeCarpets = await ctx.db .query("carpets") .filter((q) => q.gt(q.mul(q.field("height"), q.field("width")), 100)) .collect(); ``` Here's the full list of arithmetic operators: | Operator | Equivalent TypeScript | | ------------- | --------------------- | | `q.add(l, r)` | `l + r` | | `q.sub(l, r)` | `l - r` | | `q.mul(l, r)` | `l * r` | | `q.div(l, r)` | `l / r` | | `q.mod(l, r)` | `l % r` | | `q.neg(x)` | `-x` | ### Combining operators[​](#combining-operators "Direct link to Combining operators") You can construct more complex filters using methods like `q.and`, `q.or`, and `q.not`. This document query finds documents where `doc.name === "Alex" && doc.age >= 18`: ``` // Get all users named "Alex" whose age is at least 18. const adultAlexes = await ctx.db .query("users") .filter((q) => q.and(q.eq(q.field("name"), "Alex"), q.gte(q.field("age"), 18)), ) .collect(); ``` Here is a query that finds all users where `doc.name === "Alex" || doc.name === "Emma"`: ``` // Get all users named "Alex" or "Emma". const usersNamedAlexOrEmma = await ctx.db .query("users") .filter((q) => q.or(q.eq(q.field("name"), "Alex"), q.eq(q.field("name"), "Emma")), ) .collect(); ``` ## Advanced filtering techniques[​](#advanced-filtering-techniques "Direct link to Advanced filtering techniques") Sometimes the filter syntax is is not expressive enough. For example you may want to collect all posts that have a tag. Your schema for the posts looks like this: ``` export default defineSchema({ posts: defineTable({ body: v.string(), tags: v.array(v.string()), }), }); ``` One way to solve is by applying the filter on the result of the `collect()` call. This is just filtering a JavaScript array: ``` export const postsWithTag = query({ args: { tag: v.string() }, handler: async (ctx, args) => { const allPosts = await ctx.db.query("posts").collect(); return allPosts.filter((post) => post.tags.includes(args.tag)); }, }); ``` But this requires reading the whole table first. If you want to just get the first result that matches, reading the whole table could be very inefficient. Instead you may want to use the JavaScript [`for await...of`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of) syntax to loop through the table one document at a time: ``` export const firstPostWithTag = query({ args: { tag: v.string() }, handler: (ctx, args) => { for await (const post of db.query("posts")) { if (post.tags.includes(args.tag)) { return post; } } }, }); ``` This works because Convex queries are [JavaScript iterables](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols). Even with this optimization you are still just looping over the table to find the first post that matches and may hit your function limits. Using indexes is still the way to go. You can read a [detailed discussion of how to handle tags with indexes](https://stack.convex.dev/complex-filters-in-convex#optimize-with-indexes). ## Querying performance and limits[​](#querying-performance-and-limits "Direct link to Querying performance and limits") Most of the example document queries above can lead to a *full table scan*. That is, for the document query to return the requested results, it might need to walk over every single document in the table. Take this simple example: ``` const tasks = await ctx.db.query("tasks").take(5); ``` This document query will not scan more than 5 documents. On the other hand, this document query: ``` const tasks = await ctx.db .query("tasks") .filter((q) => q.eq(q.field("isCompleted"), true)) .first(); ``` might need to walk over every single document in the `"tasks"` table just to find the first one with `isCompleted: true`. If a table has more than a few thousand documents, you should use [indexes](/database/reading-data/indexes/.md) to improve your document query performance. Otherwise, you may run into our enforced limits, detailed in [Read/write limit errors](/functions/error-handling/.md#readwrite-limit-errors). For information on other limits, see [Limits](/production/state/limits.md). --- # Indexes Indexes are a data structure that allow you to speed up your [document queries](/database/reading-data/.md#querying-documents) by telling Convex how to organize your documents. Indexes also allow you to change the order of documents in query results. For a more in-depth introduction to indexing see [Indexes and Query Performance](/database/reading-data/indexes/indexes-and-query-perf.md). ## Defining indexes[​](#defining-indexes "Direct link to Defining indexes") Indexes are defined as part of your Convex [schema](/database/schemas.md). Each index consists of: 1. A name. * Must be unique per table. 2. An ordered list of fields to index. * To specify a field on a nested document, use a dot-separated path like `properties.name`. To add an index onto a table, use the [`index`](/api/classes/server.TableDefinition.md#index) method on your table's schema: convex/schema.ts ``` import { defineSchema, defineTable } from "convex/server"; import { v } from "convex/values"; // Define a messages table with two indexes. export default defineSchema({ messages: defineTable({ channel: v.id("channels"), body: v.string(), user: v.id("users"), }) .index("by_channel", ["channel"]) .index("by_channel_user", ["channel", "user"]), }); ``` The `by_channel` index is ordered by the `channel` field defined in the schema. For messages in the same channel, they are ordered by the [system-generated `_creationTime` field](/database/types.md#system-fields) which is added to all indexes automatically. By contrast, the `by_channel_user` index orders messages in the same `channel` by the `user` who sent them, and only then by `_creationTime`. Indexes are created in [`npx convex dev`](/cli.md#run-the-convex-dev-server) and [`npx convex deploy`](/cli.md#deploy-convex-functions-to-production). You may notice that the first deploy that defines an index is a bit slower than normal. This is because Convex needs to *backfill* your index. The more data in your table, the longer it will take Convex to organize it in index order. If you need to add indexes to large tables, use a [staged index](#staged-indexes). You can feel free to query an index in the same deploy that defines it. Convex will ensure that the index is backfilled before the new query and mutation functions are registered. Be careful when removing indexes In addition to adding new indexes, `npx convex deploy` will delete indexes that are no longer present in your schema. Make sure that your indexes are completely unused before removing them from your schema! ## Querying documents using indexes[​](#querying-documents-using-indexes "Direct link to Querying documents using indexes") A query for "messages in `channel` created 1-2 minutes ago" over the `by_channel` index would look like: ``` const messages = await ctx.db .query("messages") .withIndex("by_channel", (q) => q .eq("channel", channel) .gt("_creationTime", Date.now() - 2 * 60000) .lt("_creationTime", Date.now() - 60000), ) .collect(); ``` The [`.withIndex`](/api/interfaces/server.QueryInitializer.md#withindex) method defines which index to query and how Convex will use that index to select documents. The first argument is the name of the index and the second is an *index range expression*. An index range expression is a description of which documents Convex should consider when running the query. The choice of index both affects how you write the index range expression and what order the results are returned in. For instance, by making both a `by_channel` and `by_channel_user` index, we can get results within a channel ordered by `_creationTime` or by `user`, respectively. If you were to use the `by_channel_user` index like this: ``` const messages = await ctx.db .query("messages") .withIndex("by_channel_user", (q) => q.eq("channel", channel)) .collect(); ``` The results would be all of the messages in a `channel` ordered by `user`, then by `_creationTime`. If you were to use `by_channel_user` like this: ``` const messages = await ctx.db .query("messages") .withIndex("by_channel_user", (q) => q.eq("channel", channel).eq("user", user), ) .collect(); ``` The results would be the messages in the given `channel` sent by `user`, ordered by `_creationTime`. An index range expression is always a chained list of: 1. 0 or more equality expressions defined with [`.eq`](/api/interfaces/server.IndexRangeBuilder.md#eq). 2. \[Optionally] A lower bound expression defined with [`.gt`](/api/interfaces/server.IndexRangeBuilder.md#gt) or [`.gte`](/api/interfaces/server.IndexRangeBuilder.md#gte). 3. \[Optionally] An upper bound expression defined with [`.lt`](/api/interfaces/server.IndexRangeBuilder.md#lt) or [`.lte`](/api/interfaces/server.IndexRangeBuilder.md#lte). **You must step through fields in index order.** Each equality expression must compare a different index field, starting from the beginning and in order. The upper and lower bounds must follow the equality expressions and compare the next field. For example, it is not possible to write a query like: ``` // DOES NOT COMPILE! const messages = await ctx.db .query("messages") .withIndex("by_channel", (q) => q .gt("_creationTime", Date.now() - 2 * 60000) .lt("_creationTime", Date.now() - 60000), ) .collect(); ``` This query is invalid because the `by_channel` index is ordered by `(channel, _creationTime)` and this query range has a comparison on `_creationTime` without first restricting the range to a single `channel`. Because the index is sorted first by `channel` and then by `_creationTime`, it isn't a useful index for finding messages in all channels created 1-2 minutes ago. The TypeScript types within `withIndex` will guide you through this. To better understand what queries can be run over which indexes, see [Introduction to Indexes and Query Performance](/database/reading-data/indexes/indexes-and-query-perf.md). **The performance of your query is based on the specificity of the range.** For example, if the query is ``` const messages = await ctx.db .query("messages") .withIndex("by_channel", (q) => q .eq("channel", channel) .gt("_creationTime", Date.now() - 2 * 60000) .lt("_creationTime", Date.now() - 60000), ) .collect(); ``` then query's performance would be based on the number of messages in `channel` created 1-2 minutes ago. If the index range is not specified, all documents in the index will be considered in the query. Picking a good index range For performance, define index ranges that are as specific as possible! If you are querying a large table and you're unable to add any equality conditions with `.eq`, you should consider defining a new index. `.withIndex` is designed to only allow you to specify ranges that Convex can efficiently use your index to find. For all other filtering you can use the [`.filter`](/api/interfaces/server.Query.md#filter) method. For example to query for "messages in `channel` **not** created by me" you could do: ``` const messages = await ctx.db .query("messages") .withIndex("by_channel", q => q.eq("channel", channel)) .filter(q => q.neq(q.field("user"), myUserId) .collect(); ``` In this case the performance of this query will be based on how many messages are in the channel. Convex will consider each message in the channel and only return the messages where the `user` field matches `myUserId`. ## Sorting with indexes[​](#sorting-with-indexes "Direct link to Sorting with indexes") Queries that use `withIndex` are ordered by the columns specified in the index. The order of the columns in the index dictates the priority for sorting. The values of the columns listed first in the index are compared first. Subsequent columns are only compared as tie breakers only if all earlier columns match. Since Convex automatically includes `_creationTime` as the last column in all indexes, `_creationTime` will always be the final tie breaker if all other columns in the index are equal. For example, `by_channel_user` includes `channel`, `user`, and `\_creationTime`. So queries on `messages` that use `.withIndex("by_channel_user")` will be sorted first by channel, then by user within each channel, and finally by the creation time. Sorting with indexes allows you to satisfy use cases like displaying the top `N` scoring users, the most recent `N` transactions, or the most `N` liked messages. For example, to get the top 10 highest scoring players in your game, you might define an index on the player's highest score: ``` export default defineSchema({ players: defineTable({ username: v.string(), highestScore: v.number(), }).index("by_highest_score", ["highestScore"]), }); ``` You can then efficiently find the top 10 highest scoring players using your index and [`take(10)`](/api/interfaces/server.Query.md#take): ``` const topScoringPlayers = await ctx.db .query("users") .withIndex("by_highest_score") .order("desc") .take(10); ``` In this example, the range expression is omitted because we're looking for the highest scoring players of all time. This particular query is reasonably efficient for large data sets only because we're using `take()`. If you use an index without a range expression, you should always use one of the following in conjunction with `withIndex`: 1. [`.first()`](/api/interfaces/server.Query.md#first) 2. [`.unique()`](/api/interfaces/server.Query.md#unique) 3. [`.take(n)`](/api/interfaces/server.Query.md#take) 4. [`.paginate(ops)`](/database/pagination.md) These APIs allow you to efficiently limit your query to a reasonable size without performing a full table scan. Full Table Scans When your query fetches documents from the database, it will scan the rows in the range you specify. If you are using `.collect()`, for instance, it will scan all of the rows in the range. So if you use `withIndex` without a range expression, you will be [scanning the whole table](https://docs.convex.dev/database/indexes/indexes-and-query-perf#full-table-scans), which can be slow when your table has thousands of rows. `.filter()` doesn't affect which documents are scanned. Using `.first()` or `.unique()` or `.take(n)` will only scan rows until it has enough documents. You can include a range expression to satisfy more targeted queries. For example, to get the top scoring players in Canada, you might use both `take()` and a range expression: ``` // query the top 10 highest scoring players in Canada. const topScoringPlayers = await ctx.db .query("users") .withIndex("by_country_highest_score", (q) => q.eq("country", "CA")) .order("desc") .take(10); ``` ## Staged indexes[​](#staged-indexes "Direct link to Staged indexes") By default, index creation happens synchronously when you deploy code. For large tables, the process of [backfilling the index](/database/reading-data/indexes/indexes-and-query-perf.md#backfilling-and-maintaining-indexes) for the existing table can be slow. Staged indexes are a way to create an index on a large table asynchronously without blocking deploy. This can be useful if you are working on multiple features at once. To create a staged index, use the following syntax in your `schema.ts`. ``` export default defineSchema({ messages: defineTable({ channel: v.id("channels"), }).index("by_channel", { fields: ["channel"], staged: true }), }); ``` Staged indexes cannot be used until enabled Staged indexes cannot be used in queries until you enable them. To enable them, they must first finish backfilling. You can check the backfill progress via the [*Indexes* pane](/dashboard/deployments/data.md#view-the-indexes-of-a-table) on the dashboard data page. Once it is complete, you can enable the index and use it by removing the `staged` option. ``` export default defineSchema({ messages: defineTable({ channel: v.id("channels"), }).index("by_channel", { fields: ["channel"] }), }); ``` ## Limits[​](#limits "Direct link to Limits") Convex supports indexes containing up to 16 fields. You can define 32 indexes on each table. Indexes can't contain duplicate fields. No reserved fields (starting with `_`) are allowed in indexes. The `_creationTime` field is automatically added to the end of every index to ensure a stable ordering. It should not be added explicitly in the index definition, and it's counted towards the index fields limit. The `by_creation_time` index is created automatically (and is what is used in database queries that don't specify an index). The `by_id` index is reserved. --- # Introduction to Indexes and Query Performance How do I ensure my Convex [database queries](/database/reading-data/.md) are fast and efficient? When should I define an [index](/database/reading-data/indexes/.md)? What is an index? This document explains how you should think about query performance in Convex by describing a simplified model of how queries and indexes function. If you already have a strong understanding of database queries and indexes you can jump straight to the reference documentation instead: * [Reading Data](/database/reading-data/.md) * [Indexes](/database/reading-data/indexes/.md) ## A Library of Documents[​](#a-library-of-documents "Direct link to A Library of Documents") You can imagine that Convex is a physical library storing documents as physical books. In this world, every time you add a document to Convex with [`db.insert("books", {...})`](/api/interfaces/server.GenericDatabaseWriter.md#insert) a librarian places the book on a shelf. By default, Convex organizes your documents in the order they were inserted. You can imagine the librarian inserting documents left to right on a shelf. If you run a query to find the first book like: ``` const firstBook = await ctx.db.query("books").first(); ``` then the librarian could start at the left edge of the shelf and find the first book. This is an extremely fast query because the librarian only has to look at a single book to get the result. Similarly, if we want to retrieve the last book that was inserted we could instead do: ``` const lastBook = await ctx.db.query("books").order("desc").first(); ``` This is the same query but we've swapped the order to descending. In the library, this means that the librarian will start on the right edge of the shelf and scan right-to-left. The librarian still only needs to look at a single book to determine the result so this query is also extremely fast. ## Full Table Scans[​](#full-table-scans "Direct link to Full Table Scans") Now imagine that someone shows up at the library and asks "what books do you have by Jane Austen?" This could be expressed as: ``` const books = await ctx.db .query("books") .filter((q) => q.eq(q.field("author"), "Jane Austen")) .collect(); ``` This query is saying "look through all of the books, left-to-right, and collect the ones where the `author` field is Jane Austen." To do this the librarian will need to look through the entire shelf and check the author of every book. This query is a *full table scan* because it requires Convex to look at every document in the table. The performance of this query is based on the number of books in the library. If your Convex table has a small number of documents, this is fine! Full table scans should still be fast if there are a few hundred documents, but if the table has many thousands of documents these queries will become slow. In the library analogy, this kind of query is fine if the library has a single shelf. As the library expands into a bookcase with many shelves or many bookcases, this approach becomes infeasible. ## Card Catalogs[​](#card-catalogs "Direct link to Card Catalogs") How can we more efficiently find books given an author? One option is to re-sort the entire library by `author`. This will solve our immediate problem but now our original queries for `firstBook` and `lastBook` would become full table scans because we'd need to examine every book to see which was inserted first/last. Another option is to duplicate the entire library. We could purchase 2 copies of every book and put them on 2 separate shelves: one shelf sorted by insertion time and another sorted by author. This would work, but it's expensive. We now need twice as much space for our library. A better option is to build an *index* on `author`. In the library, we could use an old-school [card catalog](https://en.wikipedia.org/wiki/Library_catalog) to organize the books by author. The idea here is that the librarian will write an index card for each book that contains: * The book's author * The location of the book on the shelves These index cards will be sorted by author and live in a separate organizer from the shelves that hold the books. The card catalog should stay small because it only has an index card per book (not the entire text of the book). ![Card Catalog](/assets/images/card-catalog-7ca883b19c630085876ee5d2f59b672a.jpg) When a patron asks for "books by Jane Austen", the librarian can now: 1. Go to the card catalog and quickly find all of the cards for "Jane Austen". 2. For each card, go and find the book on the shelf. This is quite fast because the librarian can quickly find the index cards for Jane Austen. It's still a little bit of work to find the book for each card but the number of index cards is small so this is quite fast. ## Indexes[​](#indexes "Direct link to Indexes") Database indexes work based on the same concept! With Convex you can define an *index* with: convex/schema.ts ``` import { defineSchema, defineTable } from "convex/server"; import { v } from "convex/values"; export default defineSchema({ books: defineTable({ author: v.string(), title: v.string(), text: v.string(), }).index("by_author", ["author"]), }); ``` then Convex will create a new index called `by_author` on `author`. This means that your `books` table will now have an additional data structure that is sorted by the `author` field. You can query this index with: ``` const austenBooks = await ctx.db .query("books") .withIndex("by_author", (q) => q.eq("author", "Jane Austen")) .collect(); ``` This query instructs Convex to go to the `by_author` index and find all the entries where `doc.author === "Jane Austen"`. Because the index is sorted by `author`, this is a very efficient operation. This means that Convex can execute this query in the same manner that the librarian can: 1. Find the range of the index with entries for Jane Austen. 2. For each entry in that range, get the corresponding document. The performance of this query is based on the number of documents where `doc.author === "Jane Austen"` which should be quite small. We've dramatically sped up the query! ## Backfilling and Maintaining Indexes[​](#backfilling-and-maintaining-indexes "Direct link to Backfilling and Maintaining Indexes") One interesting detail to think about is the work needed to create this new structure. In the library, the librarian must go through every book on the shelf and put a new index card for each one in the card catalog sorted by author. Only after that can the librarian trust that the card catalog will give it correct results. The same is true for Convex indexes! When you define a new index, the first time you run `npx convex deploy` Convex will need to loop through all of your documents and index each one. This is why the first deploy after the creation of a new index will be slightly slower than normal; Convex has to do a bit of work for each document in your table. If the table is particularly large, consider using a [staged index](/database/reading-data/indexes/.md#staged-indexes) to complete the backfill asynchronously from the deploy. Similarly, even after an index is defined, Convex will have to do a bit of extra work to keep this index up to date as the data changes. Every time a document is inserted, updated, or deleted in an indexed table, Convex will also update its index entry. This is analogous to a librarian creating new index cards for new books as they add them to the library. If you are defining a few indexes there is no need to worry about the maintenance cost. As you define more indexes, the cost to maintain them grows because every `insert` needs to update every index. This is why Convex has a limit of 32 indexes per table. In practice most applications define a handful of indexes per table to make their important queries efficient. ## Indexing Multiple Fields[​](#indexing-multiple-fields "Direct link to Indexing Multiple Fields") Now imagine that a patron shows up at the library and would like to check out *Foundation* by Isaac Asimov. Given our index on `author`, we can write a query that uses the index to find all the books by Isaac Asimov and then examines the title of each book to see if it's *Foundation*. ``` const foundation = await ctx.db .query("books") .withIndex("by_author", (q) => q.eq("author", "Isaac Asimov")) .filter((q) => q.eq(q.field("title"), "Foundation")) .unique(); ``` This query describes how a librarian might execute the query. The librarian will use the card catalog to find all of the index cards for Isaac Asimov's books. The cards themselves don't have the title of the book so the librarian will need to find every Asimov book on the shelves and look at its title to find the one named *Foundation*. Lastly, this query ends with [`.unique`](/api/interfaces/server.Query.md#unique) because we expect there to be at most one result. This query demonstrates the difference between filtering using [`withIndex`](/api/interfaces/server.QueryInitializer.md#withindex) and [`filter`](/api/interfaces/server.Query.md#filter). `withIndex` only allows you to restrict your query based on the index. You can only do operations that the index can do efficiently like finding all documents with a given author. `filter` on the other hand allows you to write arbitrary, complex expressions but it won't be run using the index. Instead, `filter` expressions will be evaluated on every document in the range. Given all of this, we can conclude that **the performance of indexed queries is based on how many documents are in the index range**. In this case, the performance is based on the number of Isaac Asimov books because the librarian will need to look at each one to examine its title. Unfortunately, Isaac Asimov wrote [a lot of books](https://en.wikipedia.org/wiki/Isaac_Asimov_bibliography_\(alphabetical\)). Realistically even with 500+ books, this will be fast enough on Convex with the existing index, but let's consider how we could improve it anyway. One approach is to build a separate `by_title` index on `title`. This could let us swap the work we do in `.filter` and `.withIndex` to instead be: ``` const foundation = await ctx.db .query("books") .withIndex("by_title", (q) => q.eq("title", "Foundation")) .filter((q) => q.eq(q.field("author"), "Isaac Asimov")) .unique(); ``` In this query, we're efficiently using the index to find all the books called *Foundation* and then filtering through to find the one by Isaac Asimov. This is okay, but we're still at risk of having a slow query because too many books have a title of *Foundation*. An even better approach could be to build a *compound* index that indexes both `author` and `title`. Compound indexes are indexes on an ordered list of fields. convex/schema.ts ``` import { defineSchema, defineTable } from "convex/server"; import { v } from "convex/values"; export default defineSchema({ books: defineTable({ author: v.string(), title: v.string(), text: v.string(), }).index("by_author_title", ["author", "title"]), }); ``` In this index, books are sorted first by the author and then within each author by title. This means that a librarian can use the index to jump to the Isaac Asimov section and quickly find *Foundation* within it. Expressing this as a Convex query this looks like: ``` const foundation = await ctx.db .query("books") .withIndex("by_author_title", (q) => q.eq("author", "Isaac Asimov").eq("title", "Foundation"), ) .unique(); ``` Here the index range expression tells Convex to only consider documents where the author is Isaac Asimov and the title is *Foundation*. This is only a single document so this query will be quite fast! Because this index sorts by `author` and then by `title`, it also efficiently supports queries like "All books by Isaac Asimov that start with F." We could express this as: ``` const asimovBooksStartingWithF = await ctx.db .query("books") .withIndex("by_author_title", (q) => q.eq("author", "Isaac Asimov").gte("title", "F").lt("title", "G"), ) .collect(); ``` This query uses the index to find books where `author === "Isaac Asimov" && "F" <= title < "G"`. Once again, the performance of this query is based on how many documents are in the index range. In this case, that's just the Asimov books that begin with "F" which is quite small. Also note that this index also supports our original query for "books by Jane Austen." It's okay to only use the `author` field in an index range expression and not restrict by title at all. Lastly, imagine that a library patron asks for the book *The Three-Body Problem* but they don't know the author's name. Our `by_author_title` index won't help us here because it's sorted first by `author`, and then by `title`. The title, *The Three-Body Problem*, could appear anywhere in the index! The Convex TypeScript types in the `withIndex` make this clear because they require that you compare index fields in order. Because the index is defined on `["author", "title"]`, you must first compare the `author` with `.eq` before the `title`. In this case, the best option is probably to create the separate `by_title` index to facilitate this query. ## Conclusions[​](#conclusions "Direct link to Conclusions") Congrats! You now understand how queries and indexes work within Convex! Here are the main points we've covered: 1. By default Convex queries are *full table scans*. This is appropriate for prototyping and querying small tables. 2. As your tables grow larger, you can improve your query performance by adding *indexes*. Indexes are separate data structures that order your documents for fast querying. 3. In Convex, queries use the *`withIndex`* method to express the portion of the query that uses the index. The performance of a query is based on how many documents are in the index range expression. 4. Convex also supports *compound indexes* that index multiple fields. To learn more about queries and indexes, check out our reference documentation: * [Reading Data](/database/reading-data/.md) * [Indexes](/database/reading-data/indexes/.md) --- # Schemas 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](/understanding/best-practices/typescript.md), 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](/database/advanced/schema-philosophy.md). **Example:** [TypeScript and Schemas](https://github.com/get-convex/convex-demos/tree/main/typescript) ## Writing 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 ``` 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`](/api/modules/server.md#definetable) function. Within each table, the document type is defined using the validator builder, [`v`](/api/modules/values.md#v). In addition to the fields listed, Convex will also automatically add `_id` and `_creationTime` fields. To learn more, see [System Fields](/database/types.md#system-fields). Generating a Schema While writing your schema, it can be helpful to consult the [Convex Dashboard](/dashboard/deployments/data.md#generating-a-schema). The "Generate Schema" button in the "Data" view suggests a schema declaration based on the data in your tables. ### Validators[​](#validators "Direct link to Validators") The validator builder, [`v`](/api/modules/values.md#v) is used to define the type of documents in each table. It has methods for each of [Convex's types](/database/types.md): convex/schema.ts ``` 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](/functions/validation.md) and schemas both use the same validator builder, `v`. #### Optional fields[​](#optional-fields "Direct link to Optional fields") You can describe optional fields by wrapping their type with `v.optional(...)`: ``` defineTable({ optionalString: v.optional(v.string()), optionalNumber: v.optional(v.number()), }); ``` This corresponds to marking fields as optional with `?` in TypeScript. #### Unions[​](#unions "Direct link to Unions") You can describe fields that could be one of multiple types using `v.union`: ``` 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: ``` 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`: ``` { "kind": "StringDocument", "value": "abc" } ``` or they have a `kind` of `"NumberDocument"` and a number for their `value`: ``` { "kind": "NumberDocument", "value": 123 } ``` #### Literals[​](#literals "Direct link to Literals") Fields that are a constant can be expressed with `v.literal`: ``` defineTable({ oneTwoOrThree: v.union( v.literal("one"), v.literal("two"), v.literal("three"), ), }); ``` #### Record objects[​](#record-objects "Direct link to Record objects") You can describe objects that map arbitrary keys to values with `v.record`: ``` defineTable({ simpleMapping: v.record(v.string(), v.boolean()), }); ``` You can use other types of string validators for the keys: ``` 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[​](#any "Direct link to Any") Fields or documents that could take on any value can be represented with `v.any()`: ``` defineTable({ anyValue: v.any(), }); ``` This corresponds to the `any` type in TypeScript. ### Options[​](#options "Direct link to Options") These options are passed as part of the [options](/api/interfaces/server.DefineSchemaOptions.md) argument to [`defineSchema`](/api/modules/server.md#defineschema). #### `schemaValidation: boolean`[​](#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`: ``` 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`[​](#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`: ``` 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[​](#schema-validation "Direct link to Schema validation") Schemas are pushed automatically in [`npx convex dev`](/cli.md#run-the-convex-dev-server) and [`npx convex deploy`](/cli.md#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`](#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[​](#circular-references "Direct link to Circular references") You might want to define a schema with circular ID references like: convex/schema.ts ``` 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 ``` 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 ``` 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](/production/contact.md) if you need better support for circular references. ## TypeScript types[​](#typescript-types "Direct link to TypeScript types") Once you've defined a schema, [`npx convex dev`](/cli.md#run-the-convex-dev-server) will produce new versions of [`dataModel.d.ts`](/generated-api/data-model.md) and [`server.d.ts`](/generated-api/server.md) with types based on your schema. ### `Doc`[​](#doctablename "Direct link to doctablename") The [`Doc`](/generated-api/data-model.md#doc) TypeScript type from [`dataModel.d.ts`](/generated-api/data-model.md) provides document types for all of your tables. You can use these both when writing Convex functions and in your React components: MessageView\.tsx ``` 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](/functions/validation.md#extracting-typescript-types). ### `query` and `mutation`[​](#query-and-mutation "Direct link to query-and-mutation") The [`query`](/generated-api/server.md#query) and [`mutation`](/generated-api/server.md#mutation) functions in [`server.js`](/generated-api/server.md) have the same API as before but now provide a `db` with more precise types. Functions like [`db.insert(table, document)`](/api/interfaces/server.GenericDatabaseWriter.md#insert) now understand your schema. Additionally [database queries](/database/reading-data/.md) will now return the correct document type (not `any`). Related posts from [![Stack](/img/stack-logo-dark.svg)![Stack](/img/stack-logo-light.svg)](https://stack.convex.dev/) --- # Data Types 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](/database/schemas.md). ## Convex values[​](#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](/functions/validation.md) and [Schemas](/database/schemas.md) | `json` Format for [Export](/database/import-export/.md) | Notes | | ----------- | ------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Id | [Id](/database/document-ids.md) ([string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#string_type)) | `doc._id` | `v.id(tableName)` | string | See [Document IDs](/database/document-ids.md). | | 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[​](#system-fields "Direct link to System fields") Every document in Convex has two automatically-generated system fields: * `_id`: The [document ID](/database/document-ids.md) of the document. * `_creationTime`: The time this document was created, in milliseconds since the Unix epoch. ## Limits[​](#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](/production/state/limits.md). If any of these limits don't work for you, [let us know](https://convex.dev/community)! ## Working with `undefined`[​](#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)` or `q.gt("a", undefined)`. 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](/database/writing-data.md#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 ``` 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[​](#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/). --- # Writing Data [Mutations](/functions/mutation-functions.md) can insert, update, and remove data from database tables. ## Inserting new documents[​](#inserting-new-documents "Direct link to Inserting new documents") You can create new documents in the database with the [`db.insert`](/api/interfaces/server.GenericDatabaseWriter.md#insert) method: convex/tasks.ts TS ``` 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](/functions/query-functions.md) and [mutations](/functions/mutation-functions.md) can be written into the database. See [Data Types](/database/types.md) for the full list of supported types. The `insert` method returns a globally unique ID for the newly inserted document. ## Updating existing documents[​](#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`](/api/interfaces/server.GenericDatabaseWriter.md#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 ``` 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`](/api/interfaces/server.GenericDatabaseWriter.md#replace) method will replace the existing document entirely, potentially removing existing fields: convex/tasks.ts TS ``` 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[​](#deleting-documents "Direct link to Deleting documents") Given an existing document ID the document can be removed from the table with the [`db.delete`](/api/interfaces/server.GenericDatabaseWriter.md#delete) method. convex/tasks.ts TS ``` 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); }, }); ``` ## Bulk inserts or updates[​](#bulk-inserts-or-updates "Direct link to Bulk inserts or updates") If you are used to SQL you might be looking for some sort of bulk insert or bulk update statement. In Convex the entire `mutation` function is automatically a single transaction. You can just insert or update in a loop in the mutation function. Convex queues up all database changes in the function and executes them all in a single transaction when the function ends, leading to a single efficient change to the database. ```` /** * Bulk insert multiple products into the database. * * Equivalent to the SQL: * ```sql * INSERT INTO products (product_id, product_name, category, price, in_stock) * VALUES * ('Laptop Pro', 'Electronics', 1299.99, true), * ('Wireless Mouse', 'Electronics', 24.95, true), * ('Ergonomic Keyboard', 'Electronics', 89.50, true), * ('Ultra HD Monitor', 'Electronics', 349.99, false), * ('Wireless Headphones', 'Audio', 179.99, true); * ``` */ export const bulkInsertProducts = mutation({ args: { products: v.array( v.object({ product_name: v.string(), category: v.string(), price: v.number(), in_stock: v.boolean(), }), ), }, handler: async (ctx, args) => { const { products } = args; // Insert in a loop. This is efficient because Convex queues all the changes // to be executed in a single transaction when the mutation ends. for (const product of products) { const id = await ctx.db.insert("products", { product_name: product.product_name, category: product.category, price: product.price, in_stock: product.in_stock, }); } }, }); ```` ## Migrations[​](#migrations "Direct link to Migrations") Database migrations are done through the migration component. The component is designed to run online migrations to safely evolve your database schema over time. It allows you to resume from failures, and validate changes with dry runs. [Convex Component](https://www.convex.dev/components/migrations) ### [Migrations](https://www.convex.dev/components/migrations) [Framework for long running data migrations of live data.](https://www.convex.dev/components/migrations) ## Write performance and limits[​](#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](/production/state/limits.md#transactions). --- # Deployment API The public interface of a Convex deployment is defined by the functions defined in files in a convex folder. The public HTTP endpoints of every Convex deployment consist of custom HTTP endpoints defined by [HTTP Actions](/functions/http-actions.md) and a static [public HTTP API](/http-api/.md). Deployments also provide private endpoints only for the administrators of that deployment: * [Streaming export API](/streaming-export-api.md) * [Streaming import API](/streaming-import-api.md) * [Platform APIs](/deployment-platform-api.md) --- Version: 1.0.0 # Convex Deployment API Admin API for interacting with deployments. ## Authentication[​](#authentication "Direct link to Authentication") * API Key: Deploy Key * API Key: OAuth Project Token * API Key: OAuth Team Token * API Key: Team Token Deploy keys are used for deployment operations. See [deploy key types](https://docs.convex.dev/cli/deploy-key-types) for more information. Use the `Convex `prefix (e.g., `Convex `). | Security Scheme Type: | apiKey | | ---------------------- | ------------- | | Header parameter name: | Authorization | Obtained through a [Convex OAuth application](https://docs.convex.dev/management-api) with project scope. Use the `Convex `prefix (e.g., `Convex `). | Security Scheme Type: | apiKey | | ---------------------- | ------------- | | Header parameter name: | Authorization | Obtained through a [Convex OAuth application](https://docs.convex.dev/management-api). Use the `Convex `prefix (e.g., `Convex `). | Security Scheme Type: | apiKey | | ---------------------- | ------------- | | Header parameter name: | Authorization | Created in the dashboard under team settings for any team you can manage. Use the `Convex `prefix (e.g., `Convex `). | Security Scheme Type: | apiKey | | ---------------------- | ------------- | | Header parameter name: | Authorization | ### License --- # Get canonical URLs ``` GET /get_canonical_urls ``` Get the canonical URLs for a deployment. ## Responses[​](#responses "Direct link to Responses") * 200 --- # List environment variables ``` GET /list_environment_variables ``` Get all environment variables in a deployment. In the future this might not include "secret" environment variables. ## Responses[​](#responses "Direct link to Responses") * 200 --- # Update canonical URL ``` POST /update_canonical_url ``` Set or unset the canonical URL for a deployment's convex.cloud or convex.site domain. This allows you to customize the CONVEX\_SITE\_URL and CONVEX\_CLOUD\_URL environment variables in your deployment. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 --- # Update environment variables ``` POST /update_environment_variables ``` Update one or many environment variables in a deployment. This will invalidate all subscriptions, since environment variables are accessible in queries but are not part of the cache key of a query result. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 --- # Deployment Platform API info The Convex Deployment API is openly available in Beta. Please contact if your use case requires additional capabilities. Unlike HTTP endpoints which expose application-specific functionality to clients, management API endpoints configure deployments (e.g. modifying environment variables). ## Authorization[​](#authorization "Direct link to Authorization") The Deployment Management API requires a Authorization header with a key that grants admin access to that deployment. [Deployment keys](https://docs.convex.dev/cli/deploy-key-types#development-deploy-keys) created in the [dashboard](https://docs.convex.dev/dashboard/deployments/deployment-settings#url-and-deploy-key) or by API calls can be used for these APIs. [Team Access Tokens](/platform-apis.md#managing-your-own-projects) and [OAuth Application Tokens](/platform-apis/oauth-applications.md) can also be used in depending on whether you are using the Management API on behalf of your own team or on behalf of the team of a user of a Convex integration you've built. Whatever type of key, add the string `"Convex "` to the front. ``` const token = "ey...0="; const response = await fetch( "https://happy-otter-123.convex.cloud/api/v1/list_environment_variables { headers: { Authorization: `Convex ${token}`, }, }, ); console.log(await response.json()); ``` --- # Errors and Warnings This page explains specific errors thrown by Convex. See [Error Handling](/functions/error-handling/.md) to learn about handling errors in general. ## Write conflict: Optimistic concurrency control[​](#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[​](#example-a "Direct link to Example A") A mutation `updateCounter` always updates the same document: ``` 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[​](#example-b "Direct link to Example B") Mutation `writeCount` depends on the entire `tasks` table: ``` 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[​](#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[​](#resources "Direct link to Resources") * Learn more about [optimistic concurrency control](/database/advanced/occ.md). * See this [Stack post](https://stack.convex.dev/waitlist) for an example of designing an app to avoid mutation conflicts. ### Related Components[​](#related-components "Direct link to Related Components") [Convex Component](https://www.convex.dev/components/workpool) ### [Workpool](https://www.convex.dev/components/workpool) [Workpool give critical tasks priority by organizing async operations into separate, customizable queues.](https://www.convex.dev/components/workpool) [Convex Component](https://www.convex.dev/components/sharded-counter) ### [Sharded Counter](https://www.convex.dev/components/sharded-counter) [High-throughput counter enables denormalized counts without write conflicts by spreading writes over multiple documents.](https://www.convex.dev/components/sharded-counter) [Convex Component](https://www.convex.dev/components/action-cache) ### [Action Cache](https://www.convex.dev/components/action-cache) [Cache frequently run actions. By leveraging the \`force\` parameter to keep the cache populated, you can ensure that the cache is always up to date and avoid data races.](https://www.convex.dev/components/action-cache) --- # ESLint rules ESLint rules for Convex functions enforce best practices. Let us know if there's a rule you would find helpful! ## Setup[​](#setup "Direct link to Setup") For ESLint 9 (flat config, using `eslint.config.js`), install the rules with: ``` npm i @convex-dev/eslint-plugin --save-dev ``` and add this to your `eslint.config.js` file: ``` import convexPlugin from "@convex-dev/eslint-plugin"; import { defineConfig } from "eslint/config"; export default defineConfig([ // Other configurations ...convexPlugin.configs.recommended, ]); ``` If you’re using the deprecated `.eslintrc.js` format Install these two libraries: ``` npm i @typescript-eslint/eslint-plugin @convex-dev/eslint-plugin --save-dev ``` In `.eslintrc.js`, add: ``` module.exports = extends: [ // Other configurations "plugin:@typescript-eslint/recommended", "plugin:@convex-dev/recommended", ], ignorePatterns: ["node_modules/", "dist/", "build/"], }; ``` If your Convex functions are in a directory other than `convex` By default, the Convex ESLint plugin will only apply rules in the `convex` directory. If you’re [customizing the Convex directory location](/production/project-configuration.md#changing-the-convex-folder-name-or-location), here’s how to adapt your ESLint configuration: ``` // eslint.config.js import convexPlugin from "@convex-dev/eslint-plugin"; const recommendedConfig = convexPlugin.configs.recommended[0]; const recommendedRules = recommendedConfig.rules; export default [ // Other configurations go here... // Custom configuration with modified directory pattern { files: ["**/src/convex/**/*.ts"], plugins: { "@convex-dev": convexPlugin, }, rules: recommendedRules, }, ]; ``` If you’re using the `next lint` command from Next.js For `next lint` to run ESLint on your `convex` directory you need to add that directory to the default set of directories. Add this section to your `next.config.ts`: ``` const nextConfig: NextConfig = { /* other options here */ eslint: { dirs: ["pages", "app", "components", "lib", "src", "convex"], }, }; ``` ## Rules[​](#rules "Direct link to Rules") | Rule | Recommended | Auto-fixable | | ---------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ------------ | | [`@convex-dev/no-old-registered-function-syntax`](#no-old-registered-function-syntax)
Prefer object syntax for registered functions | ✅ | 🔧 | | [`@convex-dev/require-argument-validators`](#require-argument-validators)
Require argument validators for Convex functions | ✅ | 🔧 | | [`@convex-dev/import-wrong-runtime`](#import-wrong-runtime)
Prevent Convex runtime files from importing from Node runtime files | | | ### no-old-registered-function-syntax[​](#no-old-registered-function-syntax "Direct link to no-old-registered-function-syntax") Prefer object syntax for registered functions. Convex queries, mutations, and actions can be defined with a single function or with an object containing a handler property. Using the objects makes it possible to add argument and return value validators, so is always preferable. ``` // ✅ Allowed by this rule: export const list = query({ handler: async (ctx) => { const data = await ctx.db.query("messages").collect(); ... }, }); // ❌ Not allowed by this rule: export const list = query(async (ctx) => { const data = await ctx.db.query("messages").collect(); ... }); ``` ### require-argument-validators[​](#require-argument-validators "Direct link to require-argument-validators") Require argument validators for Convex functions. Convex queries, mutations, and actions can validate their arguments before beginning to run the handler function. Besides being a concise way to validate, the types of arguments, using argument validators enables generating more descriptive function specs and therefore OpenAPI bindings. ``` // ✅ Allowed by this rule: export const list = query({ args: {}, handler: async (ctx) => { ... }, }); // ✅ Allowed by this rule: export const list = query({ args: { channel: v.id('channel') }, handler: async (ctx, { channel }) => { ... }, }); // ❌ Not allowed with option { ignoreUnusedArguments: false } (default) // ✅ Allowed with option { ignoreUnusedArguments: true } export const list = query({ handler: async (ctx) => { ... }, }); // ❌ Not allowed by this rule: export const list = query({ handler: async (ctx, { channel }: { channel: Id<"channel"> }) => { ... }, }); ``` This rule can be customized to tolerate functions that don’t define an argument validator but don’t use their arguments. Here’s how you can set up the rule to work this way: ``` // eslint.config.js export default defineConfig([ // Your other rules… { files: ["**/convex/**/*.ts"], rules: { "@convex-dev/require-args-validator": [ "error", { ignoreUnusedArguments: true, }, ], }, }, ]); ``` ### import-wrong-runtime[​](#import-wrong-runtime "Direct link to import-wrong-runtime") Prevent Convex runtime files from importing from Node runtime files (files with a `"use node"` directive). This rule is experimental. Please let us know if you find it helpful! ``` // In a file that doesn’t use `"use node"`: // ✅ Allowed by this rule: import { someFunction } from "./someOtherFile"; // where someOtherFile doesn't use `"use node"` // ❌ Not allowed by this rule: import { someFunction } from "./someNodeFile"; // where someNodeFile uses `"use node"` ``` --- # File Storage 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](/file-storage/upload-files.md) files to store them in Convex and reference them in your database documents * [Store](/file-storage/store-files.md) files generated or fetched from third-party APIs * [Serve](/file-storage/serve-files.md) files via URL * [Delete](/file-storage/delete-files.md) files stored in Convex * Access file [metadata](/file-storage/file-metadata.md) You can manage your stored files on the [dashboard](/dashboard/deployments/file-storage.md). **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) --- # Deleting Files Files stored in Convex can be deleted from [mutations](/functions/mutation-functions.md), [actions](/functions/actions.md), and [HTTP actions](/functions/http-actions.md) via the [`storage.delete()`](/api/interfaces/server.StorageWriter.md#delete) function, which accepts a storage ID. Storage IDs correspond to documents in the `"_storage"` system table (see [Metadata](/file-storage/file-metadata.md)), so they can be validated using the `v.id("_storage")`. convex/images.ts TS ``` import { v } from "convex/values"; import { Id } from "./_generated/dataModel"; import { mutation } from "./_generated/server"; export const deleteById = mutation({ args: { storageId: v.id("_storage"), }, handler: async (ctx, args) => { return await ctx.storage.delete(args.storageId); }, }); ``` --- # Accessing File Metadata Every stored file is reflected as a document in the `"_storage"` system table. File metadata of a file can be accessed from [queries](/functions/query-functions.md) and [mutations](/functions/mutation-functions.md) via `db.system.get` and `db.system.query`: convex/images.ts TS ``` import { v } from "convex/values"; import { query } from "./_generated/server"; export const getMetadata = query({ args: { storageId: v.id("_storage"), }, handler: async (ctx, args) => { return await ctx.db.system.get(args.storageId); }, }); export const listAllFiles = query({ args: {}, handler: async (ctx) => { // You can use .paginate() as well return await ctx.db.system.query("_storage").collect(); }, }); ``` This is an example of the returned document: ``` { "_creationTime": 1700697415295.742, "_id": "3k7ty84apk2zy00ay4st1n5p9kh7tf8", "contentType": "image/jpeg", "sha256": "cb58f529b2ed5a1b8b6681d91126265e919ac61fff6a367b8341c0f46b06a5bd", "size": 125338 } ``` The returned document has the following fields: * `sha256`: a base16 encoded sha256 checksum of the file contents * `size`: the size of the file in bytes * `contentType`: the `ContentType` of the file if it was provided on upload You can check the metadata manually on your [dashboard](/dashboard/deployments/file-storage.md). ## Accessing metadata from actions (deprecated)[​](#accessing-metadata-from-actions-deprecated "Direct link to Accessing metadata from actions (deprecated)") Alternatively, a [`storage.getMetadata()`](/api/interfaces/server.StorageReader.md#getmetadata) function is available to access individual file metadata from [actions](/functions/actions.md) and [HTTP actions](/functions/http-actions.md): convex/images.ts TS ``` import { v } from "convex/values"; import { action } from "./_generated/server"; export const getMetadata = action({ args: { storageId: v.id("_storage") }, handler: async (ctx, args) => { return await ctx.storage.getMetadata(args.storageId); }, }); ``` Note that [`storage.getMetadata()`](/api/interfaces/server.StorageReader.md#getmetadata) returns a [`FileMetadata`](/api/modules/server.md#filemetadata), which has a slightly different shape than the result from `db.system.get`. --- # Serving Files Files stored in Convex can be served to your users by generating a URL pointing to a given file. ## Generating file URLs in queries[​](#generating-file-urls-in-queries "Direct link to Generating file URLs in queries") The simplest way to serve files is to return URLs along with other data required by your app from [queries](/functions/query-functions.md) and [mutations](/functions/mutation-functions.md). A file URL can be generated from a storage ID by the [`storage.getUrl`](/api/interfaces/server.StorageReader.md#geturl) function of the [`QueryCtx`](/api/interfaces/server.GenericQueryCtx.md), [`MutationCtx`](/api/interfaces/server.GenericMutationCtx.md), or [`ActionCtx`](/api/interfaces/server.GenericActionCtx.md) object: convex/listMessages.ts TS ``` 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) => ({ ...message, // If the message is an "image" its `body` is an `Id<"_storage">` ...(message.format === "image" ? { url: await ctx.storage.getUrl(message.body) } : {}), })), ); }, }); ``` File URLs can be used in `img` elements to render images: src/App.tsx TS ``` function Image({ message }: { message: { url: string } }) { return ; } ``` In your query you can control who gets access to a file when the URL is generated. If you need to control access when the file is *served*, you can define your own file serving HTTP actions instead. ## Serving files from HTTP actions[​](#serving-files-from-http-actions "Direct link to Serving files from HTTP actions") You can serve files directly from [HTTP actions](/functions/http-actions.md). An HTTP action will need to take some parameter(s) that can be mapped to a storage ID, or a storage ID itself. This enables access control at the time the file is served, such as when an image is displayed on a website. But note that the HTTP actions response size is [currently limited](/functions/http-actions.md#limits) to 20MB. For larger files you need to use file URLs as described [above](#generating-file-urls-in-queries). A file [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) object can be generated from a storage ID by the [`storage.get`](/api/interfaces/server.StorageActionWriter.md#get) function of the [`ActionCtx`](/api/interfaces/server.GenericActionCtx.md) object, which can be returned in a `Response`: convex/http.ts TS ``` import { httpRouter } from "convex/server"; import { httpAction } from "./_generated/server"; import { Id } from "./_generated/dataModel"; const http = httpRouter(); http.route({ path: "/getImage", method: "GET", handler: httpAction(async (ctx, request) => { const { searchParams } = new URL(request.url); const storageId = searchParams.get("storageId")! as Id<"_storage">; const blob = await ctx.storage.get(storageId); if (blob === null) { return new Response("Image not found", { status: 404, }); } return new Response(blob); }), }); export default http; ``` The URL of such an action can be used directly in `img` elements to render images: src/App.tsx TS ``` const convexSiteUrl = import.meta.env.VITE_CONVEX_SITE_URL; function Image({ storageId }: { storageId: string }) { // e.g. https://happy-animal-123.convex.site/getImage?storageId=456 const getImageUrl = new URL(`${convexSiteUrl}/getImage`); getImageUrl.searchParams.set("storageId", storageId); return ; } ``` --- # Storing Generated Files Files can be uploaded to Convex from a client and stored directly, see [Upload](/file-storage/upload-files.md). Alternatively files can also be stored after they've been fetched or generated in [actions](/functions/actions.md) and [HTTP actions](/functions/http-actions.md). For example you might call a third-party API to generate an image based on a user prompt and then store that image in Convex. **Example:** [Dall-E Storage & Action](https://github.com/get-convex/convex-demos/tree/main/dall-e-storage-action) ## Storing files in actions[​](#storing-files-in-actions "Direct link to Storing files in actions") Storing files in actions is similar to [uploading a file via an HTTP action](/file-storage/upload-files.md#uploading-files-via-an-http-action). The action takes these steps: 1. Fetch or generate an image. 2. Store the image using [`storage.store()`](/api/interfaces/server.StorageActionWriter.md#store) and receive a storage ID. 3. Save the storage ID into your data model via a mutation. Storage IDs correspond to documents in the `"_storage"` system table (see [Metadata](/file-storage/file-metadata.md)), so they can be validated using the `v.id("_storage")` validator and typed as `Id<"_storage">` in TypeScript. convex/images.ts TS ``` import { action, internalMutation, query } from "./_generated/server"; import { internal } from "./_generated/api"; import { v } from "convex/values"; import { Id } from "./_generated/dataModel"; export const generateAndStore = action({ args: { prompt: v.string() }, handler: async (ctx, args) => { // Not shown: generate imageUrl from `prompt` const imageUrl = "https://...."; // Download the image const response = await fetch(imageUrl); const image = await response.blob(); // Store the image in Convex const storageId: Id<"_storage"> = await ctx.storage.store(image); // Write `storageId` to a document await ctx.runMutation(internal.images.storeResult, { storageId, prompt: args.prompt, }); }, }); export const storeResult = internalMutation({ args: { storageId: v.id("_storage"), prompt: v.string(), }, handler: async (ctx, args) => { const { storageId, prompt } = args; await ctx.db.insert("images", { storageId, prompt }); }, }); ``` --- # Uploading and Storing Files Upload files to Convex by [generated upload urls](#uploading-files-via-upload-urls), or via an [custom HTTP Action](#uploading-files-via-an-http-action). ## Uploading files via upload URLs[​](#uploading-files-via-upload-urls "Direct link to Uploading files via upload URLs") Arbitrarily large files can be uploaded directly to your backend using a generated upload URL. This requires the client to make 3 requests: 1. Generate an upload URL using a mutation that calls [`storage.generateUploadUrl()`](/api/interfaces/server.StorageWriter.md#generateuploadurl). 2. Send a POST request with the file contents to the upload URL and receive a storage ID. 3. Save the storage ID into your data model via another mutation. In the first mutation that generates the upload URL you can control who can upload files to your Convex storage. **Example**: [File Storage with Queries and Mutations](https://github.com/get-convex/convex-demos/tree/main/file-storage) ### Calling the upload APIs from a web page[​](#calling-the-upload-apis-from-a-web-page "Direct link to Calling the upload APIs from a web page") Here's an example of uploading an image via a form submission handler to an upload URL generated by a mutation: src/App.tsx TS ``` import { FormEvent, useRef, useState } from "react"; import { useMutation } from "convex/react"; import { api } from "../convex/_generated/api"; export default function App() { const generateUploadUrl = useMutation(api.messages.generateUploadUrl); const sendImage = useMutation(api.messages.sendImage); const imageInput = useRef(null); const [selectedImage, setSelectedImage] = useState(null); const [name] = useState(() => "User " + Math.floor(Math.random() * 10000)); async function handleSendImage(event: FormEvent) { event.preventDefault(); // Step 1: Get a short-lived upload URL const postUrl = await generateUploadUrl(); // Step 2: POST the file to the URL const result = await fetch(postUrl, { method: "POST", headers: { "Content-Type": selectedImage!.type }, body: selectedImage, }); const { storageId } = await result.json(); // Step 3: Save the newly allocated storage id to the database await sendImage({ storageId, author: name }); setSelectedImage(null); imageInput.current!.value = ""; } return (
setSelectedImage(event.target.files![0])} disabled={selectedImage !== null} /> ); } ``` ### Generating the upload URL[​](#generating-the-upload-url "Direct link to Generating the upload URL") An upload URL can be generated by the [`storage.generateUploadUrl`](/api/interfaces/server.StorageWriter.md#generateuploadurl) function of the [`MutationCtx`](/api/interfaces/server.GenericMutationCtx.md) object: convex/messages.ts TS ``` import { mutation } from "./_generated/server"; export const generateUploadUrl = mutation({ args: {}, handler: async (ctx) => { return await ctx.storage.generateUploadUrl(); }, }); ``` This mutation can control who is allowed to upload files. The upload URL expires in 1 hour and so should be fetched shortly before the upload is made. ### Writing the new storage ID to the database[​](#writing-the-new-storage-id-to-the-database "Direct link to Writing the new storage ID to the database") Since the storage ID is returned to the client it is likely you will want to persist it in the database via another mutation: convex/messages.ts TS ``` import { mutation } from "./_generated/server"; export const sendImage = mutation({ args: { storageId: v.id("_storage"), author: v.string() }, handler: async (ctx, args) => { await ctx.db.insert("messages", { body: args.storageId, author: args.author, format: "image", }); }, }); ``` ### Limits[​](#limits "Direct link to Limits") The file size is not limited, but upload POST request has a 2 minute timeout. ## Uploading files via an HTTP action[​](#uploading-files-via-an-http-action "Direct link to Uploading files via an HTTP action") The file upload process can be more tightly controlled by leveraging [HTTP action](/functions/http-actions.md)s, performing the whole upload flow using a single request, but requiring correct CORS headers configuration. The custom upload HTTP action can control who can upload files to your Convex storage. But note that the HTTP action request size is [currently limited](/functions/http-actions.md#limits) to 20MB. For larger files you need to use upload URLs as described [above](#uploading-files-via-upload-urls). **Example:** [File Storage with HTTP Actions](https://github.com/get-convex/convex-demos/tree/main/file-storage-with-http) ### Calling the upload HTTP action from a web page[​](#calling-the-upload-http-action-from-a-web-page "Direct link to Calling the upload HTTP action from a web page") Here's an example of uploading an image via a form submission handler to the `sendImage` HTTP action defined next. The highlighted lines make the actual request to the HTTP action: src/App.tsx TS ``` import { FormEvent, useRef, useState } from "react"; const convexSiteUrl = import.meta.env.VITE_CONVEX_SITE_URL; export default function App() { const imageInput = useRef(null); const [selectedImage, setSelectedImage] = useState(null); async function handleSendImage(event: FormEvent) { event.preventDefault(); // e.g. https://happy-animal-123.convex.site/sendImage?author=User+123 const sendImageUrl = new URL(`${convexSiteUrl}/sendImage`); sendImageUrl.searchParams.set("author", "Jack Smith"); await fetch(sendImageUrl, { method: "POST", headers: { "Content-Type": selectedImage!.type }, body: selectedImage, }); setSelectedImage(null); imageInput.current!.value = ""; } return (
setSelectedImage(event.target.files![0])} disabled={selectedImage !== null} /> ); } ``` ### Defining the upload HTTP action[​](#defining-the-upload-http-action "Direct link to Defining the upload HTTP action") A file sent in the HTTP request body can be stored using the [`storage.store`](/api/interfaces/server.StorageActionWriter.md#store) function of the [`ActionCtx`](/api/interfaces/server.GenericActionCtx.md) object. This function returns an `Id<"_storage">` of the stored file. From the HTTP action you can call a mutation to write the storage ID to a document in your database. To confirm success back to your hosted website, you will need to set the right [CORS headers](/functions/http-actions.md#cors): convex/http.ts TS ``` 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"); if (author === null) { return new Response("Author is required", { status: 400, }); } 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", }), }); }), }); ``` You also need to handle the pre-flight `OPTIONS` request: convex/http.ts TS ``` // 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(); } }), }); ``` --- # Functions Functions run on the backend and are written in JavaScript (or TypeScript). They are automatically available as APIs accessed through [client libraries](/client/react.md). Everything you do in the Convex backend starts from functions. There are three types of functions: * [Queries](/functions/query-functions.md) read data from your Convex database and are automatically cached and subscribable (realtime, reactive). * [Mutations](/functions/mutation-functions.md) write data to the database and run as a transaction. * [Actions](/functions/actions.md) can call OpenAI, Stripe, Twilio, or any other service or API you need to make your app work. You can also build [HTTP actions](/functions/http-actions.md) 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 | --- # Actions 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](/functions/query-functions.md) and [mutations](/functions/mutation-functions.md). **Example:** [GIPHY Action](https://github.com/get-convex/convex-demos/tree/main/giphy-action) ## Action names[​](#action-names "Direct link to Action names") Actions follow the same naming rules as queries, see [Query names](/functions/query-functions.md#query-names). ## The `action` constructor[​](#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 ``` import { action } from "./_generated/server"; export const doSomething = action({ args: {}, 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[​](#action-arguments-and-responses "Direct link to Action arguments and responses") Action arguments and responses follow the same rules as [mutations](/functions/mutation-functions.md#mutation-arguments): convex/myFunctions.ts TS ``` 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[​](#action-context "Direct link to Action context") The `action` constructor enables interacting with the database, and other Convex features by passing an [ActionCtx](/api/interfaces/server.GenericActionCtx.md) object to the handler function as the first argument: convex/myFunctions.ts TS ``` 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 ``` 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](/functions/internal-functions.md) 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 ``` 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](/functions/internal-functions.md) 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](/file-storage.md). * To check user authentication use the `auth` field. Auth is propagated automatically when calling queries and mutations from the action. Read on about [Authentication](/auth.md). * To schedule functions to run in the future, use the `scheduler` field. Read on about [Scheduled Functions](/scheduling/scheduled-functions.md). * To search a vector index, use the `vectorSearch` field. Read on about [Vector Search](/search/vector-search.md). ### Dealing with circular type inference[​](#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 ``` // 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, there are two options: 1. Type the return value of the handler function explicitly: convex/myFunctions.ts ``` export const myAction = action({ args: {}, handler: async (ctx): Promise => { const result = await ctx.runQuery(api.myFunctions.getSomething); return result; }, }); ``` 2. Type the the result of the `ctx.runQuery` or `ctx.runMutation` call explicitly: convex/myFunctions.ts ``` 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](/understanding/best-practices/typescript.md#type-annotating-server-side-helpers) page for other types which might be helpful when annotating the result. ## Choosing the runtime ("use node")[​](#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 ``` 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 ``` "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](/functions/runtimes.md). ## Splitting up action code via helpers[​](#splitting-up-action-code-via-helpers "Direct link to Splitting up action code via helpers") Just like with [queries](/functions/query-functions.md#splitting-up-query-code-via-helpers) and [mutations](/functions/mutation-functions.md#splitting-up-mutation-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](/api/interfaces/server.GenericActionCtx.md) only has the `auth` field in common with [QueryCtx](/generated-api/server.md#queryctx) and [MutationCtx](/generated-api/server.md#mutationctx). ## Calling actions from clients[​](#calling-actions-from-clients "Direct link to Calling actions from clients") To call an action from [React](/client/react.md) use the [`useAction`](/api/modules/react.md#useaction) hook along with the generated [`api`](/generated-api/api.md) object. src/myApp.tsx TS ``` 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](/functions/mutation-functions.md#calling-mutations-from-clients), 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](/functions/mutation-functions.md) which captures the user intent by writing into the database and then [schedules](/scheduling/scheduled-functions.md) an action: convex/myFunctions.ts TS ``` 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[​](#limits "Direct link to Limits") Actions time out after 10 minutes. [Node.js](/functions/runtimes.md#nodejs-runtime) and [Convex runtime](/functions/runtimes.md#default-convex-runtime) have 512MB and 64MB memory limit respectively. Please [contact us](/production/contact.md) 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](/production/state/limits.md). ## Error handling[​](#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[​](#dangling-promises "Direct link to Dangling promises") Make sure to await all promises created within an action. Async tasks still running when the function returns might or might not complete. In addition, since the Node.js execution environment might be reused between action calls, dangling promises might result in errors in subsequent action invocations. ## Best practices[​](#best-practices "Direct link to Best practices") ### `await ctx.runAction` should only be used for crossing JS runtimes[​](#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 its own system resources, and while you're awaiting this call the parent action call is frozen holding all it's resources. If you pile enough of these calls on top of each other, your app may slow down significantly. **Fix:** The reason this api exists is to let you run code in the [Node.js environment](/functions/runtimes.md). 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](/understanding/best-practices/.md#use-helper-functions-to-write-shared-code) and call the helper instead. ### Avoid `await ctx.runMutation` / `await ctx.runQuery`[​](#avoid-await-ctxrunmutation--await-ctxrunquery "Direct link to avoid-await-ctxrunmutation--await-ctxrunquery") ``` // ❌ 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). ## Related Components[​](#related-components "Direct link to Related Components") [Convex Component](https://www.convex.dev/components/action-cache) ### [Action Cache](https://www.convex.dev/components/action-cache) [Cache expensive or frequently run actions. Allows configurable cache duration and forcing updates.](https://www.convex.dev/components/action-cache) [Convex Component](https://www.convex.dev/components/workpool) ### [Workpool](https://www.convex.dev/components/workpool) [Workpool give critical tasks priority by organizing async operations into separate, customizable queues. Supports retries and parallelism limits.](https://www.convex.dev/components/workpool) [Convex Component](https://www.convex.dev/components/workflow) ### [Workflow](https://www.convex.dev/components/workflow) [Similar to Actions, Workflows can call queries, mutations, and actions. However, they are durable functions that can suspend, survive server crashes, specify retries for action calls, and more.](https://www.convex.dev/components/workflow) --- # Bundling Bundling is the process of gathering, optimizing and transpiling the JS/TS source code of [functions](/functions.md) and their dependencies. During development and when deploying, the code is transformed to a format that Convex [runtimes](/functions/runtimes.md) 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](#external-packages) config. ## Bundling for Convex[​](#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[​](#bundling-limitations "Direct link to Bundling limitations") The nature of bundling comes with a few limitations. ### Code size limits[​](#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](/production/state/limits.md). 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 ``` npm install convex@latest ``` 2. Generate the bundle Note that this will not push code, and just generated a bundle for debugging purposes. ``` 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. ``` 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](/functions/bundling.md#external-packages). ### Dynamic dependencies[​](#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](/functions/runtimes.md#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[​](#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](/functions/runtimes.md#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. ### Package installation on the server[​](#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[​](#specifying-external-packages "Direct link to Specifying external packages") Create a [`convex.json`](/production/project-configuration.md#convexjson) 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: ``` { "node": { "externalPackages": ["*"] } } ``` Alternatively, you can explicitly specify which packages to mark as external: ``` { "node": { "externalPackages": ["aws-sdk", "sharp"] } } ``` The package identifiers should match the string used in `import`/`require` in your [Node.js action](/functions/actions.md#choosing-the-runtime-use-node). ### Troubleshooting external packages[​](#troubleshooting-external-packages "Direct link to Troubleshooting external packages") #### Incorrect package versions[​](#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[​](#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: ``` // ❌ old import { Foo } from "some-module"; // ✅ new import SomeModule from "some-module"; const { Foo } = SomeModule; ``` ### Limitations[​](#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). --- # Debugging Debugging is the process of figuring out why your code isn't behaving as you expect. ## Debugging during development[​](#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 ``` 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](/functions/runtimes.md#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`](/client/react.md), 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](/functions/error-handling/.md#differences-in-error-reporting-between-dev-and-prod). 2. In your Convex dashboard on the [Logs page](/dashboard/deployments/logs.md). 3. In your terminal with [`npx convex dev`](/cli.md#tail-deployment-logs) during development or [`npx convex logs`](/cli.md#tail-deployment-logs), which only prints logs. ### Using a debugger[​](#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](/testing/convex-test.md#debugging-tests). ## Debugging in production[​](#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](/production/integrations/.md) integrations to enable your team easy access to historical logs and additional information logged by your client. ## Finding relevant logs by Request ID[​](#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](/dashboard/deployments/logs.md#filter-logs) for details. --- # Error Handling There are four reasons why your Convex [queries](/functions/query-functions.md) and [mutations](/functions/mutation-functions.md) may hit errors: 1. [Application Errors](#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](#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](/production/integrations/exception-reporting.md). 3. Log the incident using `console.*` and set up reporting with [Log Streaming](/production/integrations/log-streams/.md). 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[​](#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: ``` , ``` 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](/functions/query-functions.md#caching--reactivity--consistency), 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[​](#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](/client/react/optimistic-updates.md) 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: ``` sendMessage(newMessageText).catch((error) => { // Do something with `error` here }); ``` If you're using an `async` handled function you can also use `try...catch`: ``` 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[​](#errors-in-action-functions "Direct link to Errors in action functions") Unlike queries and mutations, [actions](//docs/functions/actions.mdx) 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[​](#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](/functions/error-handling/application-errors.md) will still include their custom `data`. Both development and production deployments log full errors with stack traces which can be found on the [Logs](/dashboard/deployments/logs.md) page of a given deployment. ## Application errors, expected failures[​](#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](/functions/error-handling/application-errors.md). ## Read/write limit errors[​](#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 exact limits are listed in [Limits](/production/state/limits.md#transactions). 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. The number of calls to `db.get` and `db.query` has a limit to prevent a single query from subscribing to too many index ranges, or a mutation from reading from too many ranges that could cause conflicts. In general, if you're running into these limits frequently, we recommend [indexing your queries](/database/reading-data/indexes/.md) 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](/production/state/limits.md). ## Debugging Errors[​](#debugging-errors "Direct link to Debugging Errors") See [Debugging](/functions/debugging.md) and specifically [Finding relevant logs by Request ID](/functions/debugging.md#finding-relevant-logs-by-request-id). ## Related Components[​](#related-components "Direct link to Related Components") [Convex Component](https://www.convex.dev/components/workpool) ### [Workpool](https://www.convex.dev/components/workpool) [Workpool give critical tasks priority by organizing async operations into separate, customizable queues. Supports retries and parallelism limits.](https://www.convex.dev/components/workpool) [Convex Component](https://www.convex.dev/components/workflow) ### [Workflow](https://www.convex.dev/components/workflow) [Simplify programming long running code flows. Workflows execute durably with configurable retries and delays.](https://www.convex.dev/components/workflow) --- # Application Errors If you have expected ways your functions might fail, you can either return different values or throw `ConvexError`s. ## Returning different values[​](#returning-different-values "Direct link to Returning different values") If you're using TypeScript different return types can enforce that you're handling error scenarios. For example, a `createUser` mutation could return ``` Id<"users"> | { error: "EMAIL_ADDRESS_IN_USE" }; ``` to express that either the mutation succeeded or the email address was already taken. This ensures that you remember to handle these cases in your UI. ## Throwing application errors[​](#throwing-application-errors "Direct link to Throwing application errors") You might prefer to throw errors for the following reasons: * You can use the exception bubbling mechanism to throw from a deeply nested function call, instead of manually propagating error results up the call stack. This will work for `runQuery`, `runMutation` and `runAction` calls in [actions](/functions/actions.md) too. * In [mutations](/functions/mutation-functions.md), throwing an error will prevent the mutation transaction from committing * On the client, it might be simpler to handle all kinds of errors, both expected and unexpected, uniformly Convex provides an error subclass, [`ConvexError`](/api/classes/values.ConvexError.md), which can be used to carry information from the backend to the client: convex/myFunctions.ts TS ``` import { ConvexError } from "convex/values"; import { mutation } from "./_generated/server"; export const assignRole = mutation({ args: { // ... }, handler: (ctx, args) => { const isTaken = isRoleTaken(/* ... */); if (isTaken) { throw new ConvexError("Role is already taken"); } // ... }, }); ``` ### Application error `data` payload[​](#application-error-data-payload "Direct link to application-error-data-payload") You can pass the same [data types](/database/types.md) supported by function arguments, return types and the database, to the `ConvexError` constructor. This data will be stored on the `data` property of the error: ``` // error.data === "My fancy error message" throw new ConvexError("My fancy error message"); // error.data === {message: "My fancy error message", code: 123, severity: "high"} throw new ConvexError({ message: "My fancy error message", code: 123, severity: "high", }); // error.data === {code: 123, severity: "high"} throw new ConvexError({ code: 123, severity: "high", }); ``` Error payloads more complicated than a simple `string` are helpful for more structured error logging, or for handling sets of errors differently on the client. ## Handling application errors on the client[​](#handling-application-errors-on-the-client "Direct link to Handling application errors on the client") On the client, application errors also use the `ConvexError` class, and the data they carry can be accessed via the `data` property: src/App.tsx TS ``` import { ConvexError } from "convex/values"; import { useMutation } from "convex/react"; import { api } from "../convex/_generated/api"; export function MyApp() { const doSomething = useMutation(api.myFunctions.mutateSomething); const handleSomething = async () => { try { await doSomething({ a: 1, b: 2 }); } catch (error) { const errorMessage = // Check whether the error is an application error error instanceof ConvexError ? // Access data and cast it to the type we expect (error.data as { message: string }).message : // Must be some developer error, // and prod deployments will not // reveal any more information about it // to the client "Unexpected error occurred"; // do something with `errorMessage` } }; // ... } ``` --- # HTTP Actions HTTP actions allow you to build an HTTP API right in Convex! convex/http.ts TS ``` import { httpRouter } from "convex/server"; import { httpAction } from "./_generated/server"; const http = httpRouter(); http.route({ path: "/", method: "GET", handler: httpAction(async (ctx, request) => { return new Response(`Hello from ${request.url}`); }), }); export default http; ``` 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](/functions/query-functions.md), [mutations](/functions/mutation-functions.md), and [actions](/functions/actions.md). 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[​](#defining-http-actions "Direct link to Defining HTTP actions") HTTP action handlers are defined using the [`httpAction`](/generated-api/server.md#httpaction) constructor, similar to the `action` constructor for normal actions: convex/myHttpActions.ts TS ``` 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`](/api/interfaces/server.GenericActionCtx.md) object, which provides [`auth`](/api/interfaces/server.Auth.md), [`storage`](/api/interfaces/server.StorageActionWriter.md), and [`scheduler`](/api/interfaces/server.Scheduler.md), 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 ``` 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`](/api/classes/server.HttpRouter.md) 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 ``` 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`. ``` 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](/dashboard/deployments/functions.md) of [your dashboard](https://dashboard.convex.dev/) and view logs produced by them in the [Logs view](/dashboard/deployments/logs.md). ## Limits[​](#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](/functions/actions.md), which can run in Node.js. Like [actions](/functions/actions.md#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`](/api/classes/browser.ConvexHttpClient.md) or the [Python client](/client/python.md) to call these functions directly. ## Debugging[​](#debugging "Direct link to Debugging") ### Step 1: Check that your HTTP actions were deployed.[​](#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[​](#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 ``` 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[​](#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](/functions/http-actions.md#cors) below. ## Common patterns[​](#common-patterns "Direct link to Common patterns") ### File Storage[​](#file-storage "Direct link to File Storage") HTTP actions can be used to handle uploading and fetching stored files, see: * [Uploading files via an HTTP action](/file-storage/upload-files.md#uploading-files-via-an-http-action) * [Serving files from HTTP actions](/file-storage/serve-files.md#serving-files-from-http-actions) ### CORS[​](#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 ``` 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"); if (author === null) { return new Response("Author is required", { status: 400, }); } 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 ``` // 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[​](#authentication "Direct link to Authentication") You can leverage Convex's built-in [authentication](/auth.md) integration and access a user identity from [`ctx.auth.getUserIdentity()`](/api/interfaces/server.Auth.md#getuseridentity). To do this call your endpoint with an `Authorization` header including a JWT token: myPage.ts TS ``` const jwtToken = "..."; fetch("https://.convex.site/myAction", { headers: { Authorization: `Bearer ${jwtToken}`, }, }); ``` --- # Internal Functions Internal functions can only be called by other [functions](/functions.md) and cannot be called directly from a [Convex client](/client/react.md). 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](/functions/validation.md) and/or [authentication](/auth/functions-auth.md). ## Use cases for internal functions[​](#use-cases-for-internal-functions "Direct link to Use cases for internal functions") Leverage internal functions by: * Calling them from [actions](/functions/actions.md#action-context) via `runQuery` and `runMutation` * Calling them from [HTTP actions](/functions/http-actions.md) via `runQuery`, `runMutation`, and `runAction` * [Scheduling](/scheduling/scheduled-functions.md) them from other functions to run in the future * Scheduling them to run periodically from [cron jobs](/scheduling/cron-jobs.md) * Running them using the [Dashboard](/dashboard/deployments/functions.md#running-functions) * Running them from the [CLI](/cli.md#run-convex-functions) ## Defining 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 ``` 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 ``` 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[​](#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`](/generated-api/api.md#internal) object. For example, consider this public `upgrade` action that calls the internal `plans.markPlanAsProfessional` mutation we defined above: convex/changes.ts TS ``` 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. --- # Mutations 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 ``` 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[​](#mutation-names "Direct link to Mutation names") Mutations follow the same naming rules as queries, see [Query names](/functions/query-functions.md#query-names). Queries and mutations can be defined in the same file when using named exports. ## The `mutation` constructor[​](#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 ``` import { mutation } from "./_generated/server"; export const mutateSomething = mutation({ args: {}, handler: () => { // implementation will be here }, }); ``` Unlike a query, a mutation can but does not have to return a value. ### Mutation arguments[​](#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 ``` 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 ``` 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](/functions/validation.md) for the full list of supported types and validators. The first parameter to the handler function is reserved for the mutation context. ### Mutation responses[​](#mutation-responses "Direct link to Mutation responses") Queries can return values of any supported [Convex type](/functions/validation.md) 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[​](#mutation-context "Direct link to Mutation context") The `mutation` constructor enables writing data to the database, and other Convex features by passing a [MutationCtx](/generated-api/server.md#mutationctx) object to the handler function as the first parameter: convex/myFunctions.ts TS ``` 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 ``` 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](/database/writing-data.md). * To generate upload URLs for storing files use the `storage` field. Read on about [File Storage](/file-storage.md). * To check user authentication use the `auth` field. Read on about [Authentication](/auth.md). * To schedule functions to run in the future, use the `scheduler` field. Read on about [Scheduled Functions](/scheduling/scheduled-functions.md). ## Splitting up mutation code via helpers[​](#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 ``` 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](/generated-api/server.md#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](/understanding/best-practices/typescript.md#type-annotating-server-side-helpers) for more guidance on TypeScript types. ## Using NPM packages[​](#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](/functions/runtimes.md#default-convex-runtime) for more details. ``` npm install @faker-js/faker ``` convex/myFunctions.ts TS ``` 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[​](#calling-mutations-from-clients "Direct link to Calling mutations from clients") To call a mutation from [React](/client/react.md) use the [`useMutation`](/client/react.md#editing-data) hook along with the generated [`api`](/generated-api/api.md) object. src/myApp.tsx TS ``` 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](/client/react.md) client documentation for all the ways queries can be called. When mutations are called from the [React](/client/react.md) or [Rust](/client/rust.md) 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[​](#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](/functions/actions.md). ## Limits[​](#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. Learn more in [Read/write limit errors](/functions/error-handling/.md#readwrite-limit-errors). For information on other limits, see [Limits](/production/state/limits.md). --- # Queries 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 ``` 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[​](#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 ``` // 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 ``` // This function will be referred to as `api.foo.myQueries.listMessages`. export const listMessages = …; ``` Default exports receive the name `default`. convex/myFunctions.ts TS ``` // This function will be referred to as `api.myFunctions.default`. export default …; ``` The same rules apply to [mutations](/functions/mutation-functions.md) and [actions](/functions/actions.md), while [HTTP actions](/functions/http-actions.md) 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[​](#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 ``` import { query } from "./_generated/server"; export const myConstantString = query({ args: {}, handler: () => { return "My never changing string"; }, }); ``` ### Query arguments[​](#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 ``` 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 ``` 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](/functions/validation.md) for the full list of supported types and validators. The first parameter of the handler function contains the query context. ### Query responses[​](#query-responses "Direct link to Query responses") Queries can return values of any supported [Convex type](/functions/validation.md) 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[​](#query-context "Direct link to Query context") The `query` constructor enables fetching data, and other Convex features by passing a [QueryCtx](/generated-api/server.md#queryctx) object to the handler function as the first parameter: convex/myFunctions.ts TS ``` 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 ``` 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](/database/reading-data/.md). * To return URLs to stored files use the `storage` field. Read more about [File Storage](/file-storage.md). * To check user authentication use the `auth` field. Read more about [Authentication](/auth.md). ## Splitting up query code via helpers[​](#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 ``` 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](/understanding/best-practices/typescript.md#type-annotating-server-side-helpers) for more guidance on TypeScript types. ## Using NPM packages[​](#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](/functions/runtimes.md#default-convex-runtime) for more details. ``` npm install @faker-js/faker ``` convex/myFunctions.ts TS ``` 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[​](#calling-queries-from-clients "Direct link to Calling queries from clients") To call a query from [React](/client/react.md) use the [`useQuery`](/client/react.md#fetching-data) hook along with the generated [`api`](/generated-api/api.md) object. src/MyApp.tsx TS ``` 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](/client/react.md) client documentation for all the ways queries can be called. ## Caching & reactivity & consistency[​](#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](/functions/actions.md). 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](/functions/runtimes.md#default-convex-runtime) for more details on the Convex runtime. ## Limits[​](#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 in [Read/write limit errors](/functions/error-handling/.md#readwrite-limit-errors). For information on other limits, see [Limits](/production/state/limits.md). --- # Runtimes Convex functions can run in two runtimes: * Default [Convex runtime](#default-convex-runtime) * Opt-in [Node.js runtime](#nodejs-runtime) ## Default Convex runtime[​](#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](/database/reading-data/.md). ### Supported APIs[​](#supported-apis "Direct link to 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](#nodejs-runtime), or reach out in [Discord](https://convex.dev/community). We are improving support all the time. #### Network APIs[​](#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](#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[​](#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[​](#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[​](#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[​](#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[​](#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, ``` 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({ args: {}, handler: () => { const now1 = Date.now(); // `now1` is the time when the function execution started. const rand1 = Math.random(); // `rand1` has a new value for each function run. // implementation const now2 = Date.now(); // `now2` === `now1` const rand2 = Math.random(); // `rand1` !== `rand2` }, }); ``` ### Actions[​](#actions "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[​](#nodejs-runtime "Direct link to Node.js runtime") Some JavaScript and TypeScript libraries use features that are not included in the default Convex runtime. Convex actions provide an escape hatch to [Node.js](https://nodejs.org/en/about) via the `"use node"` directive at the top of a file that contains your action. [Learn more](/functions/actions.md#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`](/functions/actions.md#action-context) or [`runMutation`](/functions/actions.md#action-context) helper to call a query or mutation. Every `.ts` and `.js` file in the convex directory [is bundled](/functions/bundling.md) 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. If you encounter bundling errors about Node.js-specific imports like `fs` / `node:fs` not being available when deploying convex functions, running `npx convex dev --once --debug-node-apis` gives more information about these. It uses a slower bundling method to track the train of imports, narrowing down which import is responsible for the error. Note that argument size limits are lower (5MiB instead of 16MiB). ### Node.js version configuration[​](#nodejs-version-configuration "Direct link to Node.js version configuration") By default, all actions ran in the Node.js environment are executed in Node.js 20. This version is configurable in the [convex.json](/production/project-configuration.md#configuring-the-nodejs-version) file. We currently support Node.js 20 and 22. When pushing a new Node.js version to the server, the new code for your functions may be executed in the old Node.js version for up a few minutes. Note: This configuration is not supported when running the self-hosted Convex backend. The node version that is specified in the [.nvmrc](https://github.com/get-convex/convex-backend/blob/main/.nvmrc) will be used instead. --- # Argument and Return Value Validation Argument and return value validators ensure that [queries](/functions/query-functions.md), [mutations](/functions/mutation-functions.md), and [actions](/functions/actions.md) 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](/understanding/best-practices/typescript.md) 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](/functions/internal-functions.md) and optionally validation. **Example:** [Argument Validation](https://github.com/get-convex/convex-demos/tree/main/args-validation) ## Adding validators[​](#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 ``` 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](/understanding/best-practices/typescript.md) 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[​](#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`](/api/modules/values.md#v) object imported from `"convex/values"`. The [database](/database.md) can store the exact same set of [data types](/database/types.md). Additionally you can also express type unions, literals, `any` types, and optional fields. ### Convex values[​](#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](/functions/validation.md) and [Schemas](/database/schemas.md) | `json` Format for [Export](/database/import-export/.md) | Notes | | ----------- | ------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Id | [Id](/database/document-ids.md) ([string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#string_type)) | `doc._id` | `v.id(tableName)` | string | See [Document IDs](/database/document-ids.md). | | 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[​](#unions "Direct link to Unions") You can describe fields that could be one of multiple types using `v.union`: ``` import { mutation } from "./_generated/server"; import { v } from "convex/values"; export default mutation({ args: { stringOrNull: v.union(v.string(), v.null()), }, handler: async (ctx, { stringOrNull }) => { //... }, }); ``` For convenience, `v.nullable(foo)` is equivalent to `v.union(foo, v.null())`. ### Literals[​](#literals "Direct link to Literals") Fields that are a constant can be expressed with `v.literal`. This is especially useful when combined with unions: ``` 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 (ctx, { oneTwoOrThree }) => { //... }, }); ``` ### Record objects[​](#record-objects "Direct link to Record objects") You can describe objects that map arbitrary keys to values with `v.record`: ``` import { mutation } from "./_generated/server"; import { v } from "convex/values"; export default mutation({ args: { simpleMapping: v.record(v.string(), v.boolean()), }, handler: async (ctx, { simpleMapping }) => { //... }, }); ``` You can use other types of string validators for the keys: ``` 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[​](#any "Direct link to Any") Fields that could take on any value can be represented with `v.any()`: ``` import { mutation } from "./_generated/server"; import { v } from "convex/values"; export default mutation({ args: { anyValue: v.any(), }, handler: async (ctx, { anyValue }) => { //... }, }); ``` This corresponds to the `any` type in TypeScript. ### Optional fields[​](#optional-fields "Direct link to Optional fields") You can describe optional fields by wrapping their type with `v.optional(...)`: ``` 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 (ctx, { optionalString, optionalNumber }) => { //... }, }); ``` This corresponds to marking fields as optional with `?` in TypeScript. ## Extracting TypeScript types[​](#extracting-typescript-types "Direct link to Extracting TypeScript types") The [`Infer`](/api/modules/values.md#infer) type allows you to turn validator calls into TypeScript types. This can be useful to remove duplication between your validators and TypeScript types: ``` 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 (ctx, { nested }) => { //... }, }); ``` ### Reusing and extending validators[​](#reusing-and-extending-validators "Direct link to Reusing and extending validators") Validators can be defined once and shared between functions and table schemas. ``` const statusValidator = v.union(v.literal("active"), v.literal("inactive")); const userValidator = v.object({ name: v.string(), email: v.email(), status: statusValidator, profileUrl: v.optional(v.string()), }); const schema = defineSchema({ users: defineTable(userValidator).index("by_email", ["email"]), }); ``` You can create new object validators from existing ones by adding or removing fields using `.pick`, `.omit`, `.extend`, and `.partial` on object validators. ``` // Creates a new validator with only the name and profileUrl fields. const publicUser = userValidator.pick("name", "profileUrl"); // Creates a new validator with all fields except the specified fields. const userWithoutStatus = userValidator.omit("status", "profileUrl"); // Creates a validator where all fields are optional. // This is useful for validating patches to a document. const userPatch = userWithoutStatus.partial(); // Creates a new validator adding system fields to the user validator. const userDocument = userValidator.extend({ _id: v.id("users"), _creationTime: v.number(), }); ``` Notes: * Object validators don't allow extra properties, objects with properties that aren't specified will fail validation. * Top-level table fields cannot start with `_` because they are reserved for system fields like `_id` and `_creationTime`. --- # Generated Code 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: ``` npx convex dev ``` This creates a `convex/_generated` directory that contains: * [`api.js` and `api.d.ts`](/generated-api/api.md) * [`dataModel.d.ts`](/generated-api/data-model.md) * [`server.js` and `server.d.ts`](/generated-api/server.md) --- # api.js 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`](/api/modules/server.md#makefunctionreference) instead. ### 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 ``` import { api } from "../convex/_generated/api"; import { useQuery } from "convex/react"; const data = useQuery(api.messages.list); ``` ### internal[​](#internal "Direct link to internal") Another object of type `API` describing your app's internal Convex API. convex/upgrade.js ``` import { action } from "../_generated/server"; import { internal } from "../_generated/api"; export default action({ handler: 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 }); } }, }); ``` --- # dataModel.d.ts 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/dataModel.d.ts`. Generated data model types. ## Types[​](#types "Direct link to Types") ### TableNames[​](#tablenames "Direct link to TableNames") Ƭ **TableNames**: `string` The names of all of your Convex tables. *** ### Doc[​](#doc "Direct link to Doc") Ƭ **Doc**``: `Object` The type of a document stored in Convex. #### Type parameters[​](#type-parameters "Direct link to Type parameters") | Name | Type | Description | | ----------- | ----------------------------------- | ------------------------------------------------------- | | `TableName` | extends [`TableNames`](#tablenames) | A string literal type of the table name (like "users"). | *** ### Id[​](#id "Direct link to Id") 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](/database/document-ids.md). Documents can be loaded using `db.get(id)` in query and mutation functions. IDs are just strings at runtime, but this type can be used to distinguish them from other strings when type checking. This is an alias of [`GenericId`](/api/modules/values.md#genericid) that is typed for your data model. #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | Description | | ----------- | ----------------------------------- | ------------------------------------------------------- | | `TableName` | extends [`TableNames`](#tablenames) | A string literal type of the table name (like "users"). | *** ### DataModel[​](#datamodel "Direct link to DataModel") Ƭ **DataModel**: `Object` A type describing your Convex data model. This type includes information about what tables you have, the type of documents stored in those tables, and the indexes defined on them. This type is used to parameterize methods like [`queryGeneric`](/api/modules/server.md#querygeneric) and [`mutationGeneric`](/api/modules/server.md#mutationgeneric) to make them type-safe. --- # server.js 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[​](#functions "Direct link to Functions") ### query[​](#query "Direct link to query") ▸ **query**(`func`): [`RegisteredQuery`](/api/modules/server.md#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`](/api/modules/server.md#querygeneric) that is typed for your app's data model. #### Parameters[​](#parameters "Direct link to Parameters") | Name | Description | | ------ | ------------------------------------------------------------------------------------------------------ | | `func` | The query function. It receives a [QueryCtx](/generated-api/server.md#queryctx) as its first argument. | #### Returns[​](#returns "Direct link to Returns") [`RegisteredQuery`](/api/modules/server.md#registeredquery) The wrapped query. Include this as an `export` to name it and make it accessible. *** ### internalQuery[​](#internalquery "Direct link to internalQuery") ▸ **internalQuery**(`func`): [`RegisteredQuery`](/api/modules/server.md#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`](/api/modules/server.md#internalquerygeneric) that is typed for your app's data model. #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Description | | ------ | ------------------------------------------------------------------------------------------------------ | | `func` | The query function. It receives a [QueryCtx](/generated-api/server.md#queryctx) as its first argument. | #### Returns[​](#returns-1 "Direct link to Returns") [`RegisteredQuery`](/api/modules/server.md#registeredquery) The wrapped query. Include this as an `export` to name it and make it accessible. *** ### mutation[​](#mutation "Direct link to mutation") ▸ **mutation**(`func`): [`RegisteredMutation`](/api/modules/server.md#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`](/api/modules/server.md#mutationgeneric) that is typed for your app's data model. #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Description | | ------ | --------------------------------------------------------------------------------------- | | `func` | The mutation function. It receives a [MutationCtx](#mutationctx) as its first argument. | #### Returns[​](#returns-2 "Direct link to Returns") [`RegisteredMutation`](/api/modules/server.md#registeredmutation) The wrapped mutation. Include this as an `export` to name it and make it accessible. *** ### internalMutation[​](#internalmutation "Direct link to internalMutation") ▸ **internalMutation**(`func`): [`RegisteredMutation`](/api/modules/server.md#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`](/api/modules/server.md#internalmutationgeneric) that is typed for your app's data model. #### Parameters[​](#parameters-3 "Direct link to Parameters") | Name | Description | | ------ | --------------------------------------------------------------------------------------------------------------- | | `func` | The mutation function. It receives a [MutationCtx](/generated-api/server.md#mutationctx) as its first argument. | #### Returns[​](#returns-3 "Direct link to Returns") [`RegisteredMutation`](/api/modules/server.md#registeredmutation) The wrapped mutation. Include this as an `export` to name it and make it accessible. *** ### action[​](#action "Direct link to action") ▸ **action**(`func`): [`RegisteredAction`](/api/modules/server.md#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`](#actionctx). This is an alias of [`actionGeneric`](/api/modules/server.md#actiongeneric) that is typed for your app's data model. #### Parameters[​](#parameters-4 "Direct link to Parameters") | Name | Description | | ------ | ---------------------------------------------------------------------------------- | | `func` | The action function. It receives an [ActionCtx](#actionctx) as its first argument. | #### Returns[​](#returns-4 "Direct link to Returns") [`RegisteredAction`](/api/modules/server.md#registeredaction) The wrapped function. Include this as an `export` to name it and make it accessible. *** ### internalAction[​](#internalaction "Direct link to internalAction") ▸ **internalAction**(`func`): [`RegisteredAction`](/api/modules/server.md#registeredaction) Define an action that is only accessible from other Convex functions (but not from the client). This is an alias of [`internalActionGeneric`](/api/modules/server.md#internalactiongeneric) that is typed for your app's data model. #### Parameters[​](#parameters-5 "Direct link to Parameters") | Name | Description | | ------ | ---------------------------------------------------------------------------------------------------------- | | `func` | The action function. It receives an [ActionCtx](/generated-api/server.md#actionctx) as its first argument. | #### Returns[​](#returns-5 "Direct link to Returns") [`RegisteredAction`](/api/modules/server.md#registeredaction) The wrapped action. Include this as an `export` to name it and make it accessible. *** ### httpAction[​](#httpaction "Direct link to httpAction") ▸ **httpAction**(`func: (ctx: ActionCtx, request: Request) => Promise`): [`PublicHttpAction`](/api/modules/server.md#publichttpaction) #### Parameters[​](#parameters-6 "Direct link to Parameters") | Name | Type | Description | | ------ | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `func` | `(ctx: ActionCtx, request: Request) => Promise` | The function. It receives an [`ActionCtx`](/api/modules/server.md#actionctx) as its first argument and a [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) as its second argument. | #### Returns[​](#returns-6 "Direct link to Returns") [`PublicHttpAction`](/api/modules/server.md#publichttpaction) The wrapped function. Import this function from `convex/http.js` and route it to hook it up. ## Types[​](#types "Direct link to Types") ### QueryCtx[​](#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](#mutationctx) because all of the services are read-only. This is an alias of [`GenericQueryCtx`](/api/interfaces/server.GenericQueryCtx.md) that is typed for your app's data model. #### Type declaration[​](#type-declaration "Direct link to Type declaration") | Name | Type | | --------- | ---------------------------------------------------------- | | `db` | [`DatabaseReader`](#databasereader) | | `auth` | [`Auth`](/api/interfaces/server.Auth.md) | | `storage` | [`StorageReader`](/api/interfaces/server.StorageReader.md) | *** ### MutationCtx[​](#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`](/api/interfaces/server.GenericMutationCtx.md) that is typed for your app's data model. #### Type declaration[​](#type-declaration-1 "Direct link to Type declaration") | Name | Type | | ----------- | ---------------------------------------------------------- | | `db` | [`DatabaseWriter`](#databasewriter) | | `auth` | [`Auth`](/api/interfaces/server.Auth.md) | | `storage` | [`StorageWriter`](/api/interfaces/server.StorageWriter.md) | | `scheduler` | [`Scheduler`](/api/interfaces/server.Scheduler.md) | *** ### ActionCtx[​](#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`](/api/modules/server.md#actionctx) that is typed for your app's data model. #### Type declaration[​](#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`](/api/interfaces/server.Auth.md) | | `scheduler` | [`Scheduler`](/api/interfaces/server.Scheduler.md) | | `storage` | [`StorageActionWriter`](/api/interfaces/server.StorageActionWriter.md) | | `vectorSearch` | (`tableName`: `string`, `indexName`: `string`, `query`: [`VectorSearchQuery`](/api/interfaces/server.VectorSearchQuery.md)) => `Promise>` | *** ### DatabaseReader[​](#databasereader "Direct link to DatabaseReader") An interface to read from the database within Convex query functions. This is an alias of [`GenericDatabaseReader`](/api/interfaces/server.GenericDatabaseReader.md) that is typed for your app's data model. *** ### DatabaseWriter[​](#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`](/api/interfaces/server.GenericDatabaseWriter.md) that is typed for your app's data model. --- # Convex HTTP API The public functions that define a deployment are exposed at public HTTP endpoints. ## Convex value format[​](#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](/database/types.md#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[​](#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](/auth/clerk.md#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[​](#functions-api "Direct link to Functions API") ### POST `/api/query`, `/api/mutation`, `/api/action`[​](#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](/dashboard/deployments/deployment-settings.md) page, then the API URL will be `/api/query` etc., for example: * Shell * NodeJS * Python ``` curl https://acoustic-panther-728.convex.cloud/api/query \ -d '{"path": "messages:list", "args": {}, "format": "json"}' \ -H "Content-Type: application/json" ``` ``` 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), }); ``` ``` 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](/functions/query-functions.md#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](/functions/error-handling/application-errors.md) if it was thrown. | | logLines | list\[string] | Log lines printed out during the function execution. | ### POST `/api/run/{functionIdentifier}`[​](#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](/functions/query-functions.md#query-names) with a `/` replacing the `:`. You can find your backend deployment URL on the dashboard [Settings](/dashboard/deployments/deployment-settings.md) page, then the API URL will be `/api/run/{functionIdentifier}` etc., for example: * Shell * NodeJS * Python ``` curl https://acoustic-panther-728.convex.cloud/api/run/messages/list \ -d '{"args": {}, "format": "json"}' \ -H "Content-Type: application/json" ``` ``` 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), }); ``` ``` 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](/functions/error-handling/application-errors.md) if it was thrown. | | logLines | list\[string] | Log lines printed out during the function execution. | --- # Management API info The Convex Management API is openly available in Beta. Please contact if your use case requires additional capabilities. You can provision and manage Convex projects and deployments with the Management API. ## Authorization[​](#authorization "Direct link to Authorization") The Management API uses a Bearer token Authorization header. ``` const token = "ey...0="; const response = await fetch( "https://api.convex.dev/v1/teams/41/list_projects", { headers: { Authorization: `Bearer ${token}`, }, }, ); console.log(await response.json()); ``` [Team Access Tokens](/platform-apis.md#managing-your-own-projects) and [OAuth Application Tokens](/platform-apis/oauth-applications.md) can be used in Bearer tokens depending on whether you are using the Management API on behalf of your own team or on behalf of the team of a user of a Convex integration you've built. ## Required Parameters[​](#required-parameters "Direct link to Required Parameters") Most Management APIs require a team ID or project ID. When creating a Team Access Token the team ID will be available in the Convex dashboard. OAuth applications may request the team (or project, if using project-scoped tokens) ID by calling the [Token Details](/management-api/get-token-details.md) endpoint. When using a team token, projects will be assigned IDs upon creation. The [List Projects](/management-api/list-projects.md) endpoint may also be used to retrieve the ID for a project. ## Responses[​](#responses "Direct link to Responses") All API responses are in JSON format. ## Endpoints[​](#endpoints "Direct link to Endpoints") An OpenAPI spec for the Management API is available at . --- Version: 1.0.0 # Convex Management API Management API for provisioning and managing Convex projects and deployments. ## Authentication[​](#authentication "Direct link to Authentication") * HTTP: Bearer Auth * HTTP: Bearer Auth * HTTP: Bearer Auth Obtained through a [Convex OAuth application](https://docs.convex.dev/management-api). | Security Scheme Type: | http | | -------------------------- | ------ | | HTTP Authorization Scheme: | bearer | Obtained through a [Convex OAuth application](https://docs.convex.dev/management-api). | Security Scheme Type: | http | | -------------------------- | ------ | | HTTP Authorization Scheme: | bearer | Created in the dashboard under team settings for any team you can manage. | Security Scheme Type: | http | | -------------------------- | ------ | | HTTP Authorization Scheme: | bearer | ### License --- # Create custom domain ``` POST /deployments/:deployment_name/create_custom_domain ``` Create custom domain ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 --- # Create deploy key ``` POST /deployments/:deployment_name/create_deploy_key ``` Create a deploy key like "dev:happy-animal-123|ey..." which can be used with the Convex CLI to develop against or deploy code. When access to the deployment is granted through an OAuth token this deploy key will use the same OAuth-granted token. When access to the deployment is granted any other way a new token will be created which grants access only to this deployment. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 --- # Create project ``` POST /teams/:team_id/create_project ``` Create a new project on a team and provision a dev or prod deployment. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 --- # Delete custom domain ``` POST /deployments/:deployment_name/delete_custom_domain ``` Remove a custom domain from a deployment. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 --- # Delete project ``` POST /projects/:project_id/delete ``` Delete a project. Deletes all deployments in the project as well. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 --- # Get token details ``` GET /token_details ``` Returns the team ID for team tokens. Especially useful after receiving a team token from an OAuth flow since most endpoints require team ID. ## Responses[​](#responses "Direct link to Responses") * 200 --- # List custom domains ``` GET /deployments/:deployment_name/custom_domains ``` Get all custom domains configured for a deployment. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 --- # List deployments ``` GET /projects/:project_id/list_deployments ``` List deployments for a projects. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 --- # List projects ``` GET /teams/:team_id/list_projects ``` List all projects for a team. ## Request[​](#request "Direct link to Request") ## Responses[​](#responses "Direct link to Responses") * 200 --- # Platform APIs info Convex Platform APIs are in openly available in Beta. Please contact if your use case requires additional capabilities. This guide is for products that want to orchestrate multiple Convex projects in their accounts or manage projects in their users' accounts. These APIs are most often used by AI app builders, such as [Bloom](https://bloom.diy/) or [A0](https://a0.dev/). These guides assume a good understanding of Convex cloud hierarchy (teams, projects, and deployments) as well as the [development workflow](/understanding/workflow.md). ## Managing your own projects[​](#managing-your-own-projects "Direct link to Managing your own projects") This means that you are creating projects, deployments, and pushing code programmatically in the context of the team you own. To manage projects in your own team, you need to get a team-scoped token and ID from your [Team Settings](https://dashboard.convex.dev/team/settings/access-tokens). caution These tokens are owned by the team member that's logged into the Convex dashboard when you retrieve them. This means that this user owns any dev deployments created by using these tokens. If this user leaves the team, that also deletes all of their dev deployments from the team. We recommend creating a separate service account that's added as a team member. Retrieve the token after logging in as this service account. ## Managing your users' projects[​](#managing-your-users-projects "Direct link to Managing your users' projects") This means your users authorize your product to manage their own Convex team or projects. To do this, you need to create an OAuth 2.0 application so that the user can grant your product the necessary permissions. Follow the [OAuth Applications](/platform-apis/oauth-applications.md) guide to create an OAuth application and request a relevant token. ## APIs to manage projects[​](#apis-to-manage-projects "Direct link to APIs to manage projects") Once you have obtained a token from one of the methods above, you can use it to call the relevant APIs to manage Convex projects and deployments. [Management API Reference](/management-api.md) ## Pushing code to a deployment[​](#pushing-code-to-a-deployment "Direct link to Pushing code to a deployment") Working with your deployment should be scripted primarily with the existing Convex CLI. The Convex CLI manages a lot of the heavy lifting: bundling code, properly handling responses, etc. The examples here assume you are working in a container with shell and file system access from which you can drive the app building process. You likely already have this if you're generating frontend code. Set [`CONVEX_DEPLOY_KEY`](/cli/deploy-key-types.md) is the value returned by the [Create deploy key](/management-api/create-deploy-key.md) API. ### Pushing code to the dev Convex backend[​](#pushing-code-to-the-dev-convex-backend "Direct link to Pushing code to the dev Convex backend") ``` CONVEX_DEPLOY_KEY="YOUR_DEPLOY_KEY" npx convex dev --once ``` ### Pushing code to the prod Convex backend[​](#pushing-code-to-the-prod-convex-backend "Direct link to Pushing code to the prod Convex backend") ``` CONVEX_DEPLOY_KEY="YOUR_DEPLOY_KEY" npx convex deploy ``` To view the full list of commands, refer to the [CLI documentation](/cli.md). --- # Embedding the dashboard Convex provides a hosted dashboard that is embeddable via iframe. Embedding the dashboard is useful for developers building AI app generators, like [Convex Chef](https://chef.convex.dev). You can embed the Convex dashboard by adding an `