# Convex Documentation > For general information about Convex, read [https://www.convex.dev/llms.txt](https://www.convex.dev/llms.txt). ## understanding - [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 - [Convex Overview](/understanding/overview.md): Introduction to Convex - the reactive database with TypeScript queries - [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 - [Quickstarts](/quickstart/overview.md): Get started quickly with your favorite frontend framework or language - [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 - [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 - [Functions](/functions/overview.md): Write functions to define your server behavior - [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 - [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 - [Database](/database/overview.md): Store JSON-like documents with a relational data model - [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 - [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 - [Adding WorkOS AuthKit to an Existing App](/auth/authkit/add-to-app.md): Adding WorkOS AuthKit to an existing Convex application - [Automatic AuthKit Configuration](/auth/authkit/auto-provision.md): Configure WorkOS AuthKit integration with automatic provisioning for Convex deployments - [AuthKit Troubleshooting](/auth/authkit/troubleshooting.md): Debugging issues with 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 - [Authentication](/auth/overview.md): Add authentication to your Convex app. ## scheduling - [Cron Jobs](/scheduling/cron-jobs.md): Schedule recurring functions in Convex - [Scheduling](/scheduling/overview.md): Schedule functions to run once or repeatedly with scheduled functions and cron jobs - [Scheduled Functions](/scheduling/scheduled-functions.md): Schedule functions to run in the future ## file-storage - [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 - [File Storage](/file-storage/overview.md): Store and serve files of any type - [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/overview.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 - [Authoring Components](/components/authoring.md): Creating new components - [Components](/components/overview.md): Self contained building blocks of your app - [Understanding Components](/components/understanding.md): Understanding components - [Using Components](/components/using.md): Using existing components ## ai - [Convex Agent Skills](/ai/agent-skills.md): Install Convex Agent Skills to give your AI coding agent specialized Convex workflows - [Convex MCP Server](/ai/convex-mcp-server.md): Convex MCP server - [Convex Agent Plugins](/ai/convex-plugins.md): What the official Convex plugins for coding agents do, how to install them for Claude Code, Codex, and Cursor, how to use them effectively, and how to give feedback. - [AI Code Generation](/ai/overview.md): How to use AI code generation effectively with Convex - [Using Claude Code with Convex](/ai/using-claude-code.md): Build and scale apps with Claude Code and Convex, and get the full power of Convex out of the official Claude Code plugin: MCP tools, hooks, and skills. - [Using Codex with Convex](/ai/using-codex.md): Build and scale apps with OpenAI Codex and Convex, and get the full power of Convex out of the official Codex plugin: subagents, MCP tools, and skills. - [Using Conductor with Convex](/ai/using-conductor.md): Tips and best practices for using Conductor with Convex - [Using Cursor with Convex](/ai/using-cursor.md): Build and scale apps with Cursor and Convex, and get the full power of Convex out of the official Cursor plugin: MCP tools, hooks, and skills. - [Using GitHub Copilot with Convex](/ai/using-github-copilot.md): Tips and best practices for using GitHub Copilot with Convex ## agents - [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 - [AI Agents](/agents/overview.md): Building AI Agents with Convex - [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 - [Tool Approval](/agents/tool-approval.md): Human-in-the-loop tool approval for the Agent component - [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 - [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 - [Testing](/testing/overview.md): Testing your backend ## production - [Abuse Protection](/production/abuse-protection.md): What Convex deployments are protected from by default, including DDoS attacks, and how to add your own Cloudflare or Vercel edge for more control - [Contact Us](/production/contact.md): Get support, provide feedback, stay updated with Convex releases, and report security vulnerabilities through our community channels. - [Custom Domains](/production/custom-domains.md): Set up a custom domain for your Convex cloud deployment - [Environment Variables](/production/environment-variables.md): Declare, store, and access environment variables in Convex - [Deploy Your Frontend](/production/hosting.md): Deploy your Convex backend alongside your frontend hosting - [Custom Hosting](/production/hosting/custom.md): Host your frontend on any static hosting provider, such as GitHub Pages. - [Using Convex with Netlify](/production/hosting/netlify.md): Host your frontend on Netlify and your backend on Convex - [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 - [Audit Logging](/production/integrations/audit-logging.md): Add transactional audit logging to your Convex functions - [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 - [Working with Multiple Deployments](/production/multiple-deployments.md): Creating multiple deployments in a single project - [Multiple Repositories](/production/multiple-repos.md): Use Convex in multiple repositories - [Networking](/production/networking.md): IP addresses used by Convex for outbound requests - [Deploying Your App to Production](/production/overview.md): Tips for building safe and reliable production apps - [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. - [Regions](/production/regions.md): Learn how to select a region for your Convex deployments - [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 - [Usage Limits](/production/usage-limits.md): Cap how much a deployment can consume per day or month ## self-hosting - [Self Hosting](/self-hosting.md): Self Hosting Convex Projects ## cli - [Agent Mode](/cli/agent-mode.md): Configure agentic development for cloud-based and local deployments - [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 - [CLI](/cli/overview.md): Command-line interface for managing Convex projects and functions - [npx convex ai-files](/cli/reference/ai-files.md): Manage Convex AI files - [npx convex codegen](/cli/reference/codegen.md): Generate backend type definitions - [npx convex dashboard](/cli/reference/dashboard.md): Open the dashboard in the browser - [npx convex data](/cli/reference/data.md): List tables and print data from your database - [npx convex deploy](/cli/reference/deploy.md): Deploy to a production or preview deployment - [npx convex deployment](/cli/reference/deployment.md): Manage deployments - [npx convex dev](/cli/reference/dev.md): Develop against a dev deployment, watching for changes - [npx convex docs](/cli/reference/docs.md): Open the docs in the browser - [npx convex env](/cli/reference/env.md): Set and view environment variables - [npx convex export](/cli/reference/export.md): Export data from your deployment to a ZIP file - [npx convex function-spec](/cli/reference/function-spec.md): List function metadata from your deployment - [npx convex import](/cli/reference/import.md): Import data from a file to your deployment - [npx convex insights](/cli/reference/insights.md): Show health insights for your deployment - [npx convex logout](/cli/reference/logout.md): Log out of Convex on this machine - [npx convex logs](/cli/reference/logs.md): Watch logs from your deployment - [npx convex mcp](/cli/reference/mcp.md): Manage the Model Context Protocol server for Convex [BETA] - [npx convex project](/cli/reference/project.md): Manage projects - [npx convex run](/cli/reference/run.md): Run a function or evaluate an inline readonly query on your deployment - [npx convex update](/cli/reference/update.md): Print instructions for updating the convex package - [Typecheck Performance](/cli/troubleshooting/typecheck-performance.md): Debug slow typechecking performance when pushing code ## client - [Kotlin and Convex type conversion](/client/android/data-types.md): Customizing and converting types between the Kotlin app and Convex - [Android Kotlin](/client/android/overview.md): Android Kotlin client library for mobile 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 - [Convex JavaScript Clients](/client/javascript/overview.md): JavaScript clients for Node.js and browser applications using Convex - [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): While Convex doesn't have first-party clients for languages such as Go, Java, or - [Python](/client/python.md): Python client library for building applications with Convex - [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 - [Convex React](/client/react/overview.md): React client library for interacting with your Convex backend - [Rust](/client/rust.md): Rust client library for building applications with Convex - [Authentication](/client/svelte/authentication.md): Add authentication to a Convex Svelte app with setupAuth and useAuth, including SSR initial state and adapters for Convex Auth and Convex Better Auth. - [Convex Svelte](/client/svelte/overview.md): Reactive Svelte 5 client library for Convex, with real-time subscriptions, mutations, actions, pagination, auth, and SvelteKit SSR. - [Queries, Mutations & Actions](/client/svelte/reactivity.md): Subscribe to Convex queries, call mutations and actions, apply optimistic updates, paginate results, and access the client from Svelte. - [SvelteKit Server Rendering](/client/svelte/sveltekit-server-rendering.md): Server-side render Convex data in SvelteKit with convexLoad and convexLoadPaginated, transport hooks, authenticated SSR fetches, and server helpers. - [Troubleshooting](/client/svelte/troubleshooting.md): Fixes for common convex-svelte errors: effect_in_teardown, missing setupConvex(), and string query names. - [Why server-side rendering with Convex?](/client/svelte/why-server-rendering.md): Why server-side rendering is almost always faster for time-to-data with a realtime Convex backend, with a SvelteKit performance comparison and co-location guidance. - [Swift and Convex type conversion](/client/swift/data-types.md): Customizing and converting types between the Swift app and Convex - [iOS & macOS Swift](/client/swift/overview.md): Swift client library for iOS and macOS applications using 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. - [Nuxt](/client/vue/nuxt.md): Nuxt is a powerful web framework powered by Vue. - [Vue](/client/vue/overview.md): Community-maintained Vue integration for Convex applications ## 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 - [Schema](/dashboard/deployments/schema.md): Visualize your deployment's schema and the relationships between tables in the dashboard - [Dashboard](/dashboard/overview.md): Learn how to use the Convex dashboard - [Profile](/dashboard/profile.md): Manage your Convex account name, email addresses, and account deletion - [Projects](/dashboard/projects.md): Create and manage Convex projects, settings, and deployments - [Teams](/dashboard/teams/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: 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: A chat app](/tutorial/overview.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: 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: ActionMeta](/api/interfaces/server.ActionMeta.md): server.ActionMeta - [Interface: AdvancedRunQueryOptions](/api/interfaces/server.AdvancedRunQueryOptions.md): server.AdvancedRunQueryOptions - [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: MutationMeta](/api/interfaces/server.MutationMeta.md): server.MutationMeta - [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: QueryMeta](/api/interfaces/server.QueryMeta.md): server.QueryMeta - [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: TransactionLimits](/api/interfaces/server.TransactionLimits.md): server.TransactionLimits - [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 Migration Guide](/chef/migration-guide.md): How to continue developing your existing Chef projects after Chef's deprecation. ## deployment-api - [Convex Deployment API](/deployment-api/convex-deployment-api.md): Admin API for interacting with deployments. - [Create log stream](/deployment-api/create-log-stream.md): Create a new log stream for the deployment. Errors if a log stream of the - [Create usage limit](/deployment-api/create-usage-limit.md): Create a new usage limit config for a deployment. - [Data sync](/deployment-api/data-sync-post.md): **Early access:** this API is not yet stable and may change in - [Delete log stream](/deployment-api/delete-log-stream.md): Delete the deployment's log stream with the given id. - [Delete usage limit](/deployment-api/delete-usage-limit.md): Delete an existing usage limit config for a deployment. - [Get canonical URLs](/deployment-api/get-canonical-urls.md): Get the canonical URLs for a deployment. - [Get current usage](/deployment-api/get-current-usage.md): :::info[Beta] - [Get deployment info](/deployment-api/get-deployment-info.md): Returns identity information about this deployment. - [Get log stream](/deployment-api/get-log-stream.md): Get the config for a specific log stream by id. - [List active data syncs](/deployment-api/list-active-syncs-get.md): **Early access:** this API is not yet stable and may change in - [List audit log events](/deployment-api/list-audit-log-events.md): List a deployment's audit log events on or after a timestamp, from least to - [List environment variables](/deployment-api/list-environment-variables.md): Get all environment variables in a deployment. - [List log streams](/deployment-api/list-log-streams.md): List configs for all existing log streams in a deployment. - [List usage limits](/deployment-api/list-usage-limits.md): Get all usage limit configs for a deployment. - [Deployment API](/deployment-api/overview.md): Deployment API - [Pause deployment](/deployment-api/pause-deployment.md): Disables a deployment without deleting any data. The deployment will not - [Rotate webhook log stream secret](/deployment-api/rotate-webhook-secret.md): Rotate the secret for the webhook log stream. - [Unpause deployment](/deployment-api/unpause-deployment.md): Reenables a deployment that was previously paused. The deployment will - [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. - [Update log stream](/deployment-api/update-log-stream.md): Update an existing log stream for the deployment. Omit a field to keep the - [Update usage limit](/deployment-api/update-usage-limit.md): Replace an existing usage limit config for a deployment. ## deployment-platform-api - [Deployment Platform API](/deployment-platform-api.md): Deployment API ## management-api - [Cancel a pending team invitation](/management-api/cancel-team-member-invite.md): Cancel a pending team invitation - [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 a custom role](/management-api/create-custom-role.md): Creates a new custom role for the team with the specified name, - [Create deploy key](/management-api/create-deploy-key.md): Create a deploy key like 'dev:happy-animal-123|ey...' which can be - [Create deployment](/management-api/create-deployment.md): Create a new deployment for a project. - [Create personal access token](/management-api/create-personal-access-token.md): Creates a new personal access token for the authenticated user. - [Create preview deploy key](/management-api/create-preview-deploy-key.md): Create a preview deploy key like 'preview:team-slug:project-slug|ey...' - [Create project](/management-api/create-project.md): Create a new project on a team, optionally provisioning a dev or prod - [Create a team](/management-api/create-team.md): Create a team - [Create a team access token](/management-api/create-team-access-token.md): Create a team access token - [Delete custom domain](/management-api/delete-custom-domain.md): Remove a custom domain from a deployment. - [Delete a custom role](/management-api/delete-custom-role.md): Deletes a custom role from the team. Fails with `CustomRoleInUse` if - [Delete deploy key](/management-api/delete-deploy-key.md): Deletes a deploy key for the specified deployment. The `id` in the request - [Delete deployment](/management-api/delete-deployment.md): Delete a deployment. This will delete all data and files in the deployment, - [Delete personal access token](/management-api/delete-personal-access-token.md): Deletes a personal access token for the authenticated user. The `id` in the - [Delete preview deploy key](/management-api/delete-preview-deploy-key.md): Deletes a preview deploy key for the specified project. The `id` in the - [Delete project](/management-api/delete-project.md): Delete a project. Deletes all deployments in the project as well. - [Delete a team access token](/management-api/delete-team-access-token.md): Deletes a team access token, identified by its secret value or name. - [Get deployment in project by id](/management-api/get-deployment-in-project-by-project-id.md): Get a deployment within a project by reference, default production - [Get deployment in project by slug](/management-api/get-deployment-in-project-by-project-slug.md): Get a deployment within a project identified by team and project slug, - [Get project by ID](/management-api/get-project-by-id.md): Get a project by its ID. - [Get project by slug](/management-api/get-project-by-slug.md): Get a project by its slug. - [Get token details](/management-api/get-token-details.md): Returns the team ID for team tokens. - [Invite a team member](/management-api/invite-team-member.md): Invite a member to the given team by email. `role` is required and must be - [List audit log events](/management-api/list-audit-log-events.md): List a team's audit log events within a time range, with optional filters. - [List custom domains](/management-api/list-custom-domains.md): Get all custom domains configured for a deployment. - [List custom roles](/management-api/list-custom-roles.md): Lists all custom roles for the team with cursor-based pagination. - [List default environment variables](/management-api/list-default-environment-variables.md): Lists all default environment variables for the specified project, with - [List deploy keys](/management-api/list-deploy-keys.md): Lists all deploy keys for the specified deployment. - [List deployment classes](/management-api/list-deployment-classes.md): Lists the available deployment classes for a team. - [List deployment regions](/management-api/list-deployment-regions.md): Lists the available deployment regions for a team. - [List deployments](/management-api/list-deployments.md): List deployments for a projects. - [List deployments for team](/management-api/list-deployments-for-team.md): Lists deployments for a team with pagination, sorting, and filtering. - [List local deployments](/management-api/list-local-deployments-for-team.md): Lists the local deployments for a team. - [List pending team invitations](/management-api/list-pending-team-invites.md): List the pending invitations for the given team. - [List personal access tokens](/management-api/list-personal-access-tokens.md): Lists all personal access tokens for the authenticated user. - [List preview deploy keys](/management-api/list-preview-deploy-keys.md): Lists all preview deploy keys for the specified project. - [List projects](/management-api/list-projects.md): List a page of projects for a team, ordered by descending project ID. Pass - [List team access tokens](/management-api/list-team-access-tokens.md): Lists the team access tokens created by the authenticated member for the - [List team members](/management-api/list-team-members.md): List the members of the given team. - [Management API](/management-api/overview.md): Creating and managing Convex deployments by API - [Get deployment](/management-api/platform-get-deployment.md): Get details about a cloud deployment. - [Transfer deployment](/management-api/transfer-deployment.md): Transfer a deployment from its current project to another project within the - [Update a custom role](/management-api/update-custom-role.md): Updates an existing custom role's name, description, and permission - [Update default environment variables](/management-api/update-default-environment-variables.md): Creates, updates, or deletes default environment variables for the specified - [Update deployment](/management-api/update-deployment.md): Updates properties of an existing deployment. Only the fields provided in - [Update project](/management-api/update-project.md): Update a project's name and/or slug. Returns the updated project. - [Update a team member's role](/management-api/update-team-member-role.md): Sets either the member's built-in `role` (admin/developer) or their ## platform-apis - [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 - [Platform APIs](/platform-apis/overview.md): Convex Platform APIs are in openly available in Beta. Please contact - [Tracking Usage](/platform-apis/track-usage.md): Products built on the Platform APIs often create many Convex deployments ## 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. ## team-management - [Custom Roles](/team-management/custom-roles.md): Define fine-grained permission policies for your Convex team using custom roles. - [Team Management](/team-management/overview.md): Administrative features for managing your Convex team, including Single Sign-On and custom roles. - [Role Actions](/team-management/role-actions.md): Reference for every action a Convex role can grant, and which built-in roles cover which actions. - [Single Sign-On (SSO)](/team-management/sso.md): Set up and manage Single Sign-On (SSO) for your Convex team --- # Full Documentation Content # 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, stepCountIs } 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), }, 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 then 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. ### 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 an `embeddingModel`. 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). embeddingModel: 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", inputSchema: z.object({...}), // Note: annotate the return type of the execute to avoid type cycles. execute: async (ctx, input): Promise => { return "Hello, world!"; }, }), // Standard AI SDK tool myTool: tool({ description: "My tool", inputSchema: z.object({...}), execute: async () => {}}), }, // 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; }, }); ``` ## Tracing LLM calls with OpenTelemetry[​](#tracing-llm-calls-with-opentelemetry "Direct link to Tracing LLM calls with OpenTelemetry") When you pass [`experimental_telemetry`](https://ai-sdk.dev/docs/ai-sdk-core/telemetry) to a generate or stream call, the AI SDK emits OpenTelemetry spans with the model, token usage, prompt, and response. To export them to an OTLP backend, register a tracer provider: ``` import { trace } from "@opentelemetry/api"; import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http"; import { resourceFromAttributes } from "@opentelemetry/resources"; import { BasicTracerProvider, SimpleSpanProcessor, } from "@opentelemetry/sdk-trace-base"; const tracerProvider = new BasicTracerProvider({ resource: resourceFromAttributes({ "service.name": "convex-agent" }), spanProcessors: [ new SimpleSpanProcessor( new OTLPTraceExporter({ url: process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT, headers: { Authorization: `Bearer ${process.env.OTEL_EXPORTER_OTLP_TRACES_TOKEN}`, }, }), ), ], }); trace.setGlobalTracerProvider(tracerProvider); ``` Then enable telemetry on the call, and flush the spans before the handler returns so their exports are [awaited](https://docs.convex.dev/understanding/best-practices/#await-all-promises): ``` export const generateTextWithTelemetry = 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, experimental_telemetry: { isEnabled: true, functionId: "debugging/telemetry", }, }, ); await tracerProvider.forceFlush(); return result.text; }, }); ``` See the full example in [debugging/telemetry.ts](https://github.com/get-convex/agent/blob/main/example/convex/debugging/telemetry.ts). ## 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 dev ``` ## 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, stepCountIs } 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 }, stopWhen: stepCountIs(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. --- # AI Agents Looking to use an AI coding assistant with Convex? This section is about **building AI agent applications on Convex** (threads, tools, RAG, workflows) with the `@convex-dev/agent` component. If instead you want to use an **AI coding assistant** — Cursor, GitHub Copilot, Claude Code, or Codex — to write your Convex app, head to [AI coding](/ai/overview.md) and the [Convex agent plugins](/ai/convex-plugins.md). ## 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/overview.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; }, }); ``` --- # 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 dev ``` 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 }, }); ``` --- # Tool Approval Tool approval lets you require human confirmation before a tool call is executed. This is useful for dangerous or irreversible operations — deleting data, spending money, sending emails — where you want a person to review the action before it happens. ## Defining tools with approval[​](#defining-tools-with-approval "Direct link to Defining tools with approval") Add `needsApproval` to any tool created with `createTool`. It can be a boolean or an async function that receives the tool context and input: ``` import { createTool } from "@convex-dev/agent"; import { z } from "zod/v4"; // Always requires approval const deleteFileTool = createTool({ description: "Delete a file from the system", inputSchema: z.object({ filename: z.string().describe("The name of the file to delete"), }), needsApproval: () => true, execute: async (_ctx, input) => { return `Deleted file: ${input.filename}`; }, }); // Conditionally requires approval (only for large amounts) const transferMoneyTool = createTool({ description: "Transfer money to an account", inputSchema: z.object({ amount: z.number().describe("The amount to transfer"), toAccount: z.string().describe("The destination account"), }), needsApproval: async (_ctx, input) => { return input.amount > 100; }, execute: async (_ctx, input) => { return `Transferred $${input.amount} to ${input.toAccount}`; }, }); ``` Tools without `needsApproval` (or with `needsApproval` returning `false`) execute immediately as usual. ## Server-side flow[​](#server-side-flow "Direct link to Server-side flow") The typical approval flow involves four server functions: 1. **Save the user's message** and schedule generation. 2. **Generate a response.** If the model calls a tool that needs approval, generation pauses and the `tool-approval-request` is persisted in the thread. 3. **Submit an approval or denial** for each pending tool call. `approveToolCall` and `denyToolCall` work from both mutations and actions. 4. **Continue generation** once all pending approvals have been resolved. ``` import { approvalAgent } from "../agents/approval"; // 1. Save message and schedule generation export const sendMessage = mutation({ args: { prompt: v.string(), threadId: v.string() }, handler: async (ctx, { prompt, threadId }) => { const { messageId } = await approvalAgent.saveMessage(ctx, { threadId, prompt, }); await ctx.scheduler.runAfter(0, internal.chat.approval.generateResponse, { threadId, promptMessageId: messageId, }); return { messageId }; }, }); // 2. Generate (stops if approval is needed) export const generateResponse = internalAction({ args: { promptMessageId: v.string(), threadId: v.string() }, handler: async (ctx, { promptMessageId, threadId }) => { const result = await approvalAgent.streamText( ctx, { threadId }, { promptMessageId }, ); await result.consumeStream(); }, }); // 3. Submit an approval decision (can be a mutation or action) export const submitApproval = mutation({ args: { threadId: v.string(), approvalId: v.string(), approved: v.boolean(), reason: v.optional(v.string()), }, returns: v.object({ messageId: v.string() }), handler: async (ctx, { threadId, approvalId, approved, reason }) => { const { messageId } = approved ? await approvalAgent.approveToolCall(ctx, { threadId, approvalId, reason, }) : await approvalAgent.denyToolCall(ctx, { threadId, approvalId, reason, }); return { messageId }; }, }); // 4. Continue generation after all approvals resolved. // Pass the last approval message ID as promptMessageId so the agent // resumes generation from where the approval was issued. export const continueAfterApprovals = internalAction({ args: { threadId: v.string(), lastApprovalMessageId: v.string() }, handler: async (ctx, { threadId, lastApprovalMessageId }) => { const result = await approvalAgent.streamText( ctx, { threadId }, { promptMessageId: lastApprovalMessageId }, ); await result.consumeStream(); }, }); ``` tip You can approve a tool call and continue generation in the same server function. For example, an action can call `approveToolCall` and then immediately call `streamText` to resume — no separate scheduling step needed. ## Handling multiple tool calls[​](#handling-multiple-tool-calls "Direct link to Handling multiple tool calls") When the model calls several tools in a single step, some or all of them may require approval. **Every** pending approval must be resolved (approved or denied) before you continue generation. If a new generation starts while approvals are still unresolved, the unresolved approvals are **automatically denied** with the reason `"auto-denied: new generation started"`. This prevents broken message histories where tool calls lack results. ## Client-side flow[​](#client-side-flow "Direct link to Client-side flow") On the client, use `useUIMessages` to detect pending approvals and show Approve/Deny buttons. Tool parts with `state === "approval-requested"` are waiting for a decision. ``` import { useEffect, useRef } from "react"; import { useMutation } from "convex/react"; import { useUIMessages, type UIMessage } from "@convex-dev/agent/react"; import type { ToolUIPart } from "ai"; function Chat({ threadId }: { threadId: string }) { const lastApprovalMessageIdRef = useRef(null); const { results: messages } = useUIMessages( api.chat.approval.listThreadMessages, { threadId }, { initialNumItems: 10, stream: true }, ); const submitApproval = useMutation(api.chat.approval.submitApproval); const triggerContinuation = useMutation( api.chat.approval.triggerContinuation, ); const hasPendingApprovals = messages.some((m) => m.parts.some( (p) => p.type.startsWith("tool-") && (p as ToolUIPart).state === "approval-requested", ), ); // When all approvals are resolved, trigger continuation useEffect(() => { if (!hasPendingApprovals && lastApprovalMessageIdRef.current) { void triggerContinuation({ threadId, lastApprovalMessageId: lastApprovalMessageIdRef.current, }); lastApprovalMessageIdRef.current = null; } }, [hasPendingApprovals, threadId, triggerContinuation]); // Render approval buttons for tool parts with state "approval-requested" // ... } ``` The `ToolUIPart` states relevant to approval are: | State | Meaning | | -------------------- | ---------------------------------------------------- | | `approval-requested` | Waiting for the user to approve or deny | | `approval-responded` | User responded; tool is being executed (if approved) | | `output-available` | Tool executed successfully | | `output-denied` | Tool was denied | | `output-error` | Tool execution failed | ## Example files[​](#example-files "Direct link to Example files") For a complete working example, see: * **Agent definition:** [`example/convex/agents/approval.ts`](https://github.com/get-convex/agent/blob/main/example/convex/agents/approval.ts) * **Server functions:** [`example/convex/chat/approval.ts`](https://github.com/get-convex/agent/blob/main/example/convex/chat/approval.ts) * **React UI:** [`example/ui/chat/ChatApproval.tsx`](https://github.com/get-convex/agent/blob/main/example/ui/chat/ChatApproval.tsx) --- # 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", inputSchema: 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. ### Using the Agent within a workflow[​](#using-the-agent-within-a-workflow "Direct link to Using the Agent 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). Within a workflow, each "step" is a single idempotent operation. The arguments and return values are stored as part of the workflow's state, so it can resume wherever it left off by replaying the history. This allows workflows to run for a long time, survive server restarts, retry individual steps, pause, and more. Some Agent functions can be called directly from a workflow, passing `step` instead of `ctx`. Under the hood, these functions are calling `step.runMutation` instead of the `ctx.runMutation` that is otherwise done. The two calls are roughly the same, though there is more overhead associated with calling steps since the arguments and return values count towards the workflow's overall database bandwidth limit. As such, try to avoid passing large amounts of data in as arguments or returned from steps, and prefer to save that data and pass around IDs instead. ``` const workflow = new WorkflowManager(components.workflow); export const supportAgentWorkflow = workflow.define({ args: { prompt: v.string(), userId: v.string() }, handler: async (step, { prompt, userId }) => { // Some functions can be called directly from a workflow, passing `step` // instead of `ctx`. This doesn't work for anything action-related. const { threadId } = await createThread(step, components.agent, { userId, title: prompt, }); // Under the hood, these functions are calling step.runMutation, // so saving the message is a workflow step. The equivalent would be to call // step.runMutation with your own mutation that called saveMessage with ctx. const { messageId } = await saveMessage(step, components.agent, { threadId, prompt, }); // For functions that require `fetch` or otherwise need an action, run them // as steps explicitly. const { text } = await step.runAction( internal.example.getSupport, { threadId, userId, promptMessageId: messageId }, // Passing in a promptMessageId allows us to safely retry the step. // If it fails partway, the retry will re-use the same prompt message and // any existing responses. { retry: true }, ); const { object } = await step.runAction( internal.example.getStructuredSupport, { userId, prompt: text, }, ); // You can also run mutations as steps explicitly. await step.runMutation(internal.example.sendUserMessage, { userId, message: object.instruction, }); }, }); ``` ### Exposing Agent functions as Convex Actions[​](#exposing-agent-functions-as-convex-actions "Direct link to Exposing Agent functions as Convex Actions") You can expose the agent's capabilities as Convex functions to be used as steps in a workflow, as an alternative to writing an action for each step. For an action that generates or streams text in a thread: ``` // Similar to thread.generateText / thread.streamText export const getSupport = supportAgent.asTextAction({ stopWhen: stepCountIs(10), }); ``` You can also expose a standalone action that generates an object. ``` // Similar to thread.generateObject / thread.streamObject export const getStructuredSupport = supportAgent.asObjectAction({ schema: z.object({ analysis: z.string().describe("A detailed analysis of the user's request."), instruction: z.string().describe("A suggested action to take."), }), }); ``` See example 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/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) --- # Convex Agent Skills [Agent Skills](https://agentskills.io) are portable packages of instructions and workflows that teach AI coding agents how to perform specialized tasks. Convex provides a set of ready-made skills for common workflows like setting up auth, designing a schema, and running migrations. ## Install[​](#install "Direct link to Install") Use the `npx skills` CLI to add the Convex skills to your project: ``` # Choose which skills to install npx skills add get-convex/agent-skills # Or install all of them at once npx skills add get-convex/agent-skills --all ``` Skills are installed into `.agents/skills/` in your project and are automatically picked up by compatible agents including Cursor, Claude Code, and GitHub Copilot. ## Available Skills[​](#available-skills "Direct link to Available Skills") | Skill | Description | | --------------------------- | ---------------------------------------------------------------------- | | `/convex` | Top-level entry point — routes to the right Convex skill for your task | | `/convex-quickstart` | Set up a new Convex project from scratch | | `/convex-setup-auth` | Configure authentication for your Convex app | | `/convex-migration-helper` | Plan and run data migrations | | `/convex-create-component` | Create a new Convex component | | `/convex-performance-audit` | Audit and optimize Convex queries and mutations | Skills are added and updated regularly, so this list may not be exhaustive. See the [get-convex/agent-skills](https://github.com/get-convex/agent-skills) repo for the latest. ## Using Skills[​](#using-skills "Direct link to Using Skills") Skills are applied automatically when the agent determines they're relevant. How you manually invoke them depends on your tool: | Tool | Manual invocation | | ------------------------ | ----------------- | | Cursor | `/skill-name` | | VS Code (GitHub Copilot) | `/skill-name` | | Claude Code | `/skill-name` | | Codex (OpenAI) | `$skill-name` | For example, to kick off auth setup in Cursor or Claude Code: ``` /convex-setup-auth ``` ## Learn More[​](#learn-more "Direct link to Learn More") * [get-convex/agent-skills](https://github.com/get-convex/agent-skills) - full list of skills, source code, and contributing guide * [Agent Skills standard](https://agentskills.io) - the open standard these skills are built on --- # 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 ``` Or see editor-specific instructions: * [Codex](/ai/using-codex.md#setup-the-convex-mcp-server) * [GitHub Copilot](/ai/using-github-copilot.md#setup-the-convex-mcp-server) * [![](/assets/images/conductor-logo-fa2224a9c0b89cba358b3a954a8e9051.png)](/ai/using-conductor.md#setup-the-convex-mcp-server) [Conductor](/ai/using-conductor.md#setup-the-convex-mcp-server) When using  Claude Code or  Cursor, we recommend installing the [Convex plugin](/ai/overview.md#plugins), which automatically starts the MCP server. ## Configuration Options[​](#configuration-options "Direct link to Configuration Options") The MCP server supports several command-line options to customize its behavior. info For the full list of options, see the [`npx convex mcp` CLI reference](/cli/reference/mcp.md). ### Project Directory[​](#project-directory "Direct link to Project Directory") The tools provided by the MCP server require agents to select a deployment. To find the right deployment to use, agents use the `status` tool. By default, `status` uses the current project directory. If you want to use another project directory by default or run `npx convex mcp` from a folder that is not a Convex project, you can change the project `status` uses with the `--project-dir` flag: ``` npx -y convex@latest mcp start --project-dir /path/to/project ``` warning Setting `--project-dir` doesn’t prevent agents from manually providing a custom `projectDir` in the `status` tool call. It also does not prevent the agent from running tools in deployments that belong to other projects. If you need to enforce security boundaries, check out [*Security*](#security). ### Deployment Selection[​](#deployment-selection "Direct link to Deployment Selection") By default, the MCP server connects to your development deployment. You can specify a different deployment using these options: * `--prod`: Run the MCP server on your project's production deployment (requires `--dangerously-enable-production-deployments`) * `--preview-name `: Run on a preview deployment with the given name * `--deployment-name `: Run on a specific deployment by name * `--env-file `: Path to a custom environment file for choosing the deployment (e.g., containing `CONVEX_DEPLOYMENT` or `CONVEX_SELF_HOSTED_URL`). Uses the same format as `.env.local` or `.env` files. ### Production Deployments[​](#production-deployments "Direct link to Production Deployments") By default, the MCP server cannot access production deployments. This is a safety measure to prevent accidental modifications to production data. If you need to access production deployments, you must explicitly enable this: ``` npx -y convex@latest mcp start --dangerously-enable-production-deployments ``` Use with care Enabling production access allows the MCP server to read and modify data in your production deployment. Only enable this when you specifically need to interact with production, and be careful with any operations that modify data. ### Disabling Tools[​](#disabling-tools "Direct link to Disabling Tools") You can disable specific tools if you want to restrict what the MCP server can do: ``` npx -y convex@latest mcp start --disable-tools data,run,envSet ``` Available tools that can be disabled: `data`, `envGet`, `envList`, `envRemove`, `envSet`, `functionSpec`, `insights`, `logs`, `run`, `runOneoffQuery`, `status`, `tables` ## 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. ### Insights Tools[​](#insights-tools "Direct link to Insights Tools") * **`insights`**: Fetches health insights for a deployment over the last 72 hours. Reports OCC (Optimistic Concurrency Control) conflicts and resource limit issues (bytes read, documents read) that may indicate performance problems or failing functions. Includes recent events with request IDs for debugging. ### 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 ## Security[​](#security "Direct link to Security") The MCP server is safe by default: in [production deployments](/production/multiple-deployments.md#deployment-types), agents can’t access PII, and they can only perform read-only operations. If necessary, you can customize the MCP server settings to grant more permissions in production deployments, or limit the MCP server to a single deployment. info If your agent is allowed to run `npx convex` commands independently, they will be run with the full authorization of your credentials, unless you use a [scoped deploy key](/cli/deploy-key-types.md#deployment-token). ### Allowed tools by deployment type[​](#allowed-tools-by-deployment-type "Direct link to Allowed tools by deployment type") By default, the MCP server only allows **operations on [non-production deployments](/production/multiple-deployments.md#deployment-types)** and **safe operations on [production deployments](/production/multiple-deployments.md#deployment-types)** (i.e. actions that are read-only and don’t expose PII or environment variables). You can start the MCP server with `--cautiously-allow-production-pii` or `--dangerously-enable-production-deployments` to allow your agents to perform more actions on production deployments. | Tool category | Default | `--cautiously-allow-production-pii` | `--dangerously-enable-production-deployments` | | :------------------------------------------------------------------------------------- | :-----: | :---------------------------------: | :-------------------------------------------: | | [**Non-production deployments**](/production/multiple-deployments.md#deployment-types) | | | | | All operations | ✅ | ✅ | ✅ | | [**Production deployments**](/production/multiple-deployments.md#deployment-types) | | | | | Non-PII read-only operations
(`insights`, `tables`, `functionSpec`) | ✅ | ✅ | ✅ | | PII read-only operations
(`data`, `logs`, `runOneoffQuery`) | ❌ | ✅ | ✅ | | Reading environment variables
(`envGet`, `envList`) | ❌ | ❌ | ✅ | | Write operations
(`run`, `envSet`, `envRemove`) | ❌ | ❌ | ✅ | If you want to disable access to particular tools, you can also use the `--disable-tools` CLI flag. ### Limit access to a specific deployment[​](#limit-access-to-a-specific-deployment "Direct link to Limit access to a specific deployment") By default, the MCP server uses the user’s global authentication credentials (set up through `npx convex login`) to access deployments. As a result, agents using the MCP can access all projects that your Convex account has access to. If you want to restrict the MCP server to a particular deployment, [generate a deploy key](/cli/deploy-key-types.md#deployment-token) and set the `CONVEX_DEPLOY_KEY` environment variable. ``` CONVEX_DEPLOY_KEY="dev:happy-capybara-849|…=" npx -y convex@latest mcp start ``` Limitation The `insights` tool is not available when the MCP server is started with `CONVEX_DEPLOY_KEY` (for both production and non-production deployments). Related posts from [![Stack](/img/stack-logo-dark.svg)![Stack](/img/stack-logo-light.svg)](https://stack.convex.dev/) --- # Convex Agent Plugins Convex publishes official plugins for the major coding agents. With the plugin installed, you can describe an app in one sentence and watch your agent scaffold it, running, in front of you, then keep shipping features while it reads your real deployment instead of guessing, catches its own mistakes as it works, and follows idiomatic Convex patterns. This page explains what the plugins do, how to install them, how to get the most out of them, and how to send us feedback. For agent-specific setup, see the dedicated pages for [Claude Code](/ai/using-claude-code.md), [Codex](/ai/using-codex.md), and [Cursor](/ai/using-cursor.md). ## What the plugin does[​](#what-the-plugin-does "Direct link to What the plugin does") Every Convex plugin bundles three kinds of help: * **Tools**: a built-in [Convex MCP server](/ai/convex-mcp-server.md) that lets the agent securely interact with your dev deployment. It can read your data, logs, and insights, and run functions, so the agent works from what your deployment actually contains instead of guessing. * **Hooks and monitors**: background checks that run as the agent works. A pre-commit typecheck, an end-of-turn verify loop, and monitors that surface dev and production errors let the agent find and fix issues without you having to point them out. * **Skills and specialized agents**: focused instructions that teach the agent how to do specific Convex tasks correctly, invoked automatically when relevant or on demand. ## What you can do with it[​](#what-you-can-do-with-it "Direct link to What you can do with it") A plain-English request goes a long way. The agent picks the right skill automatically, or you can invoke one explicitly: | Ask for… | The skill | What it does | | ------------------------- | ------------------- | ----------------------------------------------------------------------------------------------------------------- | | "build me a todo app" | **quickstart** | One sentence in, a running app out, scaffolded and built live in front of you. | | "add sign-in" | **auth** | Full authentication wired end to end, passkeys by default, including the `auth.config.ts` that trips everyone up. | | "add a chatbot" | **agent** | A real in-app AI agent backend: threads, message history, tool calls, and vector-search RAG. | | "change my schema safely" | **migrate** | Change a live schema without breaking data: stage, backfill every existing row, verify, then tighten. | | "add \" | **add** | Pulls in the right piece of the Convex component ecosystem: crons, file storage, and more. | | "review my functions" | **convex-reviewer** | Audits your `convex/` code for validator, auth, and performance issues and shows you the fixes. | On top of the on-demand skills, an always-on Convex specialist quietly reviews every function the agent writes under `convex/`, so idiomatic APIs, correct validators, and indexed queries are the default, not something you have to ask for. New skills land regularly. ## Install[​](#install "Direct link to Install") Pick your agent. Each install is one command (full walkthroughs on the per-agent pages linked above):  Claude Code ``` /plugin install convex@claude-plugins-official ```  Codex (from Codex's built-in plugin directory) ``` codex plugin add convex@openai-curated ``` For the newest build straight from Convex, see the [nightly marketplace install](/ai/using-codex.md#install-the-convex-plugin).  Cursor: install from the Cursor Marketplace, or manually: ``` cd ~/.cursor/plugins git clone https://github.com/get-convex/convex-agent-plugins convex # then restart Cursor ``` ## Using the plugins effectively[​](#using-the-plugins-effectively "Direct link to Using the plugins effectively") A few habits get you the best results: * **Describe the outcome, not the API.** "Let users upload profile photos" routes to the right skill better than naming internal Convex primitives. The plugin knows the mapping. * **Let the checks work.** The hooks catch typecheck and deploy issues on their own; you rarely need to paste errors back in. * **Ask for a review before you ship.** "Audit my Convex functions" runs the security, auth, and performance pass over your backend. * **Trust the deployment tools.** For "what's in my database?" or "why is this slow?", the agent can read your dev deployment directly through the MCP server instead of guessing. ## Giving feedback[​](#giving-feedback "Direct link to Giving feedback") We're constantly working on improving the plugins with rigorous evals and real-world reports. You can help: * **Report a bug or request a skill** by opening an issue on the plugin repo for your agent: [Claude Code](https://github.com/get-convex/convex-backend-skill/issues) · [Codex](https://github.com/get-convex/convex-codex-plugin/issues) · [Cursor](https://github.com/get-convex/convex-agent-plugins/issues). * **Improve the AI rules**: if the agent writes non-idiomatic Convex, contribute a case to the [convex-evals repo](https://github.com/get-convex/convex-evals) so we can measure and fix it. * **Ask the community** in the [Convex Discord](https://convex.dev/community). --- # AI Code Generation 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 boilerplate 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). ## Agent plugins[​](#plugins "Direct link to Agent plugins") Convex publishes official plugins for coding agents that include: * **Tools** that let your agent securely interact with your dev deployment (e.g. read the data/logs/insights or run functions). * **Hooks and monitors** that help your agent automatically identify issues in your code. * **Skills and specialized agents** that teach your agent how to use Convex the most effectively. See these documents for install instructions: * [Claude Code](/ai/using-claude-code.md#install-the-convex-plugin-in-claude-code) * [Codex](/ai/using-codex.md#install-the-convex-plugin) * [Cursor](/ai/using-cursor.md#install-the-convex-plugin-in-cursor) ## 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: * [Codex](/ai/using-codex.md) * [GitHub Copilot](/ai/using-github-copilot.md) * [![](/assets/images/conductor-logo-fa2224a9c0b89cba358b3a954a8e9051.png)](/ai/using-conductor.md) [Conductor](/ai/using-conductor.md) When using  Claude Code or  Cursor, we recommend installing the [Convex plugin](/ai/overview.md#plugins), which automatically include these rules. 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). ## Convex AI files[​](#convex-ai-files "Direct link to Convex AI files") The Convex CLI can install and maintain AI helper files in your project: * `convex/_generated/ai/guidelines.md` * Managed sections in `AGENTS.md` and `CLAUDE.md` * Agent skills installed via `npx skills` Use these commands to manage AI files: * `npx convex ai-files install` - Install or refresh AI files * `npx convex ai-files update` - Update to latest available AI files * `npx convex ai-files status` - Show what is installed and what is stale * `npx convex ai-files disable` - Suppress install and staleness messages in `npx convex dev` * `npx convex ai-files enable` - Re-enable install and staleness messages * `npx convex ai-files remove` - Remove Convex-managed AI files The message preference and target agents are controlled in `convex.json` with: convex.json ``` { "aiFiles": { "enabled": false, "skills": { "agents": ["claude-code", "codex", "cursor"] } } } ``` By default, `aiFiles.skills.agents` targets `["claude-code", "codex"]`. You can override this to target other agents supported by `npx skills`, such as `cursor` see for a full list. ## 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 # npx convex init # allows setting environment variables before pushing # npx convex env set --from-file ./path/to/.env.agent (optional) npx convex dev --once ``` or ``` bun i bun x convex dev --once ``` This command requires "full" internet access to download the binary. ### Cloud dev deployments per agent[​](#cloud-dev-deployments-per-agent "Direct link to Cloud dev deployments per agent") If you'd rather give each agent (or each worktree) its own throwaway *cloud* dev deployment instead of an anonymous local one, a setup script can provision one and hand the agent a deploy key scoped only to it: ``` # Create a new dev deployment and select it. npx convex deployment create --type dev --select \ team-slug:project-slug:dev/$USER/$(basename "$PWD") \ --expiration "in 5 days" # Mint a deploy key scoped only to this deployment and save it to .env.local # as CONVEX_DEPLOY_KEY. npx convex deployment token create agent-token --save-env # Push code once. npx convex dev --once ``` Once `CONVEX_DEPLOY_KEY` is set in `.env.local`, the agent can only push to and develop against its own dev deployment — not prod or other developers' deployments. If the agent needs environment variables, the easiest path is to set them as [project environment variable defaults](/production/environment-variables.md#project-environment-variable-defaults) so they're applied automatically to every new cloud deployment. You can also seed values from another source via `npx convex env set` (which accepts multiple variables on stdin or via `--from-file`). See [Creating and deleting deploy keys from the CLI](/cli/deploy-key-types.md#deployment-token) for the full options on `npx convex deployment token`, and [Working with Multiple Deployments](/production/multiple-deployments.md) for worktree-based recipes (Conductor, Cursor, Codex, T3 Code) that you can adapt to this flow. ## 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. ## Agent Skills[​](#agent-skills "Direct link to Agent Skills") [Agent Skills](/ai/agent-skills.md) are portable packages of instructions and workflows that teach AI coding agents how to perform specialized Convex tasks like setting up auth, designing a schema, and running migrations. --- # Using Claude Code with Convex [Claude Code](https://claude.com/claude-code), Anthropic's agentic coding tool, makes it easy to write and maintain apps built with Convex. Let's walk through how to set up Claude Code for the best possible results with Convex. ## Claude Code and Convex[​](#claude-code-and-convex "Direct link to Claude Code and Convex") Claude Code works great with Convex out of the box. Because Convex is a TypeScript backend with end-to-end type safety, Claude Code's mistakes surface as compile errors, ACID transactions keep concurrent writes consistent, and apps scale without extra infrastructure. That's all you need to build anything from a real-time chat app to an AI agent backend. Adding the plugin lets you leverage the full power of Convex: Claude Code reads your live deployment through the MCP server, catches its own errors with the built-in hooks, and applies the idiomatic Convex patterns its skills and subagents know. ## Install the Convex plugin in Claude Code[​](#install-the-convex-plugin-in-claude-code "Direct link to Install the Convex plugin in Claude Code") The official Convex plugin makes Claude Code work better with your Convex project. It includes: * **Tools** that let your agent securely interact with your dev deployment (e.g. read the data/logs/insights or run functions). * **Hooks and monitors** that keep your generated types in sync and surface errors as the agent works. * **Skills and specialized agents** that teach your agent how to use Convex the most effectively. See the [Agent Plugins overview](/ai/convex-plugins.md) for everything the plugin bundles. To install the plugin, run the following command in Claude Code: ``` /plugin install convex@claude-plugins-official ``` ## Starting a new project[​](#starting-a-new-project "Direct link to Starting a new project") From an empty directory, launch Claude Code with what you want to build: ``` claude "build me a todo app with Convex" --permission-mode auto ``` Claude Code handles the rest. It runs `npm create convex@latest` and `npx convex dev --once`, which [auto-provisions a local backend](/cli/agent-mode.md#local-backend) without prompting for login because the agent's shell is non-interactive. If you'd rather scaffold the project yourself first and then bring in Claude Code, the manual sequence is: ``` npm create convex@latest my-app cd my-app claude ``` ## Adding to an existing project[​](#adding-to-an-existing-project "Direct link to Adding to an existing project") If your project already has Convex set up, [install the Convex plugin](#install-the-convex-plugin-in-claude-code) to make Claude Code Convex-aware. Now start asking Claude Code questions like: * Evaluate my convex schema and suggest improvements * What are this app's public endpoints? * Run the `my_convex_function` query ## Running Claude Code with Convex in the cloud[​](#running-claude-code-with-convex-in-the-cloud "Direct link to Running Claude Code with Convex in the cloud") When running Claude Code in a remote environment (e.g. Claude Code on a CI runner or a cloud VM), use Convex's [Agent Mode](/cli/agent-mode.md) so the agent can iterate on code, run tests, and call one-off functions without needing full deployment permissions. A good setup script: ``` npm i npx convex dev --once ``` In non-interactive shells (the typical case for an agent's setup script), `npx convex` won't prompt the agent to log in. It provisions a local deployment automatically. See [Agent Mode → Local backend](/cli/agent-mode.md#local-backend) for details. This command requires "full" internet access to download the Convex binary. For per-agent cloud dev deployments scoped to a single throwaway deploy key, see [Cloud dev deployments per agent](/ai/overview.md#cloud-dev-deployments-per-agent). --- # Using Codex with Convex [Codex](https://openai.com/codex), OpenAI's coding agent, makes it easy to write and maintain apps built with Convex. Let's walk through how to set up Codex for the best possible results with Convex. ## Codex and Convex[​](#codex-and-convex "Direct link to Codex and Convex") Codex works great with Convex out of the box. One all-in-one TypeScript backend (database, functions, workflows, real-time sync) means no glue code to get wrong, type safety catches guesses at compile time, and transactions keep data consistent under load, which covers everything from a live polling tool to an AI research agent. Adding the plugin lets you leverage the full power of Convex: Codex gets the `convex-expert` and `convex-reviewer` subagents, the Convex MCP server for reading your real deployment, and durable Components (Workpool, Workflow, Agent) for agentic workloads. ## Install the Convex plugin[​](#install-the-convex-plugin "Direct link to Install the Convex plugin") The official Convex plugin makes Codex work better with your Convex project. It includes: * **Tools** that let your agent securely interact with your dev deployment (e.g. read the data/logs/insights or run functions), plus an error watcher that surfaces runtime errors as you work. * **Rules and skills** that teach your agent how to use Convex the most effectively. * **Specialized subagents** (`convex-expert` and `convex-reviewer`) for deep Convex work and code review. See the [Agent Plugins overview](/ai/convex-plugins.md) for everything the plugin bundles. Convex is listed in Codex's built-in plugin directory, so a single command installs the reviewed release: ``` codex plugin add convex@openai-curated ``` caution The directory entry is currently the lighter Convex ChatGPT-app connector. For the full plugin, with skills, subagents, and the runtime error watcher, install the marketplace build below. **Want the newest build?** The directory release is reviewed by OpenAI and can lag the latest plugin. To pull the newest build straight from Convex, add the Convex marketplace and install from it: ``` codex plugin marketplace add get-convex/convex-codex-plugin codex plugin add convex@convex-codex-plugin ``` To update the marketplace build later, run `codex plugin marketplace upgrade` and then re-run `codex plugin add convex@convex-codex-plugin`. ## Starting a new project[​](#starting-a-new-project "Direct link to Starting a new project") From an empty directory, launch Codex with what you want to build: ``` codex "build me a todo app with Convex" ``` Codex handles the rest. It runs `npm create convex@latest`, `npx convex ai-files install` (which writes a managed Convex section into `AGENTS.md` and installs Convex [Agent Skills](/ai/agent-skills.md) into `.agents/skills/`), and `npx convex dev --once`, which [auto-provisions a local backend](/cli/agent-mode.md#local-backend) without prompting for login because the agent's shell is non-interactive. If you'd rather scaffold the project yourself first and then bring in Codex, the manual sequence is: ``` npm create convex@latest my-app cd my-app npx convex ai-files install codex ``` ## Adding to an existing project[​](#adding-to-an-existing-project "Direct link to Adding to an existing project") If your project already has Convex set up, run these two steps from the project root to make Codex Convex-aware. ### Add Convex Rules[​](#add-convex-rules "Direct link to Add Convex Rules") The Convex CLI can install and maintain a managed section in your project's `AGENTS.md` file that teaches Codex about Convex conventions and best practices. ``` npx convex ai-files install ``` This will create or update `AGENTS.md` and install Convex [Agent Skills](/ai/agent-skills.md) into `.agents/skills/` so Codex can use specialized workflows like setting up auth, designing a schema, and running migrations. See [Convex AI files](/ai/overview.md#convex-ai-files) for more on managing these files. 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 Codex access to your Convex deployment to query and optimize your project. Add the following to your Codex MCP configuration (`~/.codex/config.toml`): ``` [mcp_servers.convex] command = "npx" args = ["-y", "convex@latest", "mcp", "start"] ``` Now start asking Codex questions like: * Evaluate my convex schema and suggest improvements * What are this app's public endpoints? * Run the `my_convex_function` query ## Running Codex with Convex in the cloud[​](#running-codex-with-convex-in-the-cloud "Direct link to Running Codex with Convex in the cloud") When running Codex in a remote environment (like ChatGPT's Codex cloud), use Convex's [Agent Mode](/cli/agent-mode.md) so the agent can iterate on code, run tests, and call one-off functions without needing full deployment permissions. A good setup script for ChatGPT Codex looks like: ``` npm i npx convex dev --once ``` In non-interactive shells (the typical case for an agent's setup script), `npx convex` won't prompt the agent to log in. It provisions a local deployment automatically. See [Agent Mode → Local backend](/cli/agent-mode.md#local-backend) for details. This command requires "full" internet access to download the Convex binary. For per-agent cloud dev deployments scoped to a single throwaway deploy key, see [Cloud dev deployments per agent](/ai/overview.md#cloud-dev-deployments-per-agent). --- # Using Conductor with Convex [Conductor](https://conductor.build) is a Mac app that lets you run many coding agents in parallel, each in its own isolated workspace. Conductor pairs naturally with Convex because each agent can run its own `convex dev` against its own deployment without stepping on the others. ## Starting a new project[​](#starting-a-new-project "Direct link to Starting a new project") Create a new Conductor workspace on an empty directory and describe what you want to build. The agent handles the rest. It runs `npm create convex@latest`, `npx convex ai-files install` (which writes a managed Convex section into `CLAUDE.md` and `AGENTS.md` and installs Convex [Agent Skills](/ai/agent-skills.md) into `.agents/skills/`), and `npx convex dev --once`, which [auto-provisions a local backend](/cli/agent-mode.md#local-backend) without prompting for login because the agent's shell is non-interactive. To give each Conductor workspace its own cloud dev deployment automatically, wire the [per-worktree recipe](/cli/agent-mode.md#worktree-setups) into your project's `conductor.json` setup script. If you'd rather scaffold the project yourself first and then point Conductor at it, the manual sequence is: ``` npm create convex@latest my-app cd my-app npx convex ai-files install ``` Then in Conductor, click **New workspace** and point it at `my-app`. ## Adding to an existing project[​](#adding-to-an-existing-project "Direct link to Adding to an existing project") If your project already has Convex set up, run these two steps from a Conductor workspace terminal to make the agent Convex-aware. ### Add Convex Rules[​](#add-convex-rules "Direct link to Add Convex Rules") Conductor workspaces use Claude Code under the hood, so the same Convex AI files apply. ``` npx convex ai-files install ``` This creates or updates `CLAUDE.md` (and `AGENTS.md`) and installs Convex [Agent Skills](/ai/agent-skills.md) into `.agents/skills/` so the agent can use specialized workflows like setting up auth, designing a schema, and running migrations. See [Convex AI files](/ai/overview.md#convex-ai-files) for more on managing these files. ### 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 the agent access to your Convex deployment to query and optimize your project. In each Conductor workspace, add the MCP server with: ``` claude mcp add-json convex '{"type":"stdio","command":"npx","args":["convex","mcp","start"]}' ``` Now you can ask the agent questions like: * Evaluate my convex schema and suggest improvements * What are this app's public endpoints? * Run the `my_convex_function` query --- # 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 set up Cursor for the best possible results with Convex. ## Cursor and Convex[​](#cursor-and-convex "Direct link to Cursor and Convex") Cursor works great with Convex out of the box. Because Convex is one type-safe TypeScript backend (database, functions, real-time sync, and file storage), Cursor writes code that's caught at compile time, stays transactional, and scales without extra infrastructure, which is plenty to build a chat app, a collaborative editor, or a multiplayer game. Adding the plugin lets you leverage the full power of Convex: Cursor reads your real deployment through the MCP server instead of guessing, catches its own type and deploy errors as it works, and follows the idiomatic Convex patterns the skills encode. ## Install the Convex plugin in Cursor[​](#install-the-convex-plugin-in-cursor "Direct link to Install the Convex plugin in Cursor") The official Convex plugin makes Cursor work better with your Convex project. It includes: * **Tools** that let your agent securely interact with your dev deployment (e.g. read the data/logs/insights or run functions). * **Development hooks** that keep your generated types in sync and catch type and deploy errors as the agent works. * **Rules, skills, and specialized agents** that teach your agent how to use Convex the most effectively. See the [Agent Plugins overview](/ai/convex-plugins.md) for everything the plugin bundles. To install the plugin, go to the *Customize* page of the Agents window, search for the *Convex* plugin and click *Add*. Installing the Cursor plugin from the Agents window Alternatively, you can run `/add-plugin convex` from an agent conversation. Using Cursor Cloud Agents / Cursor CLI Cursor plugins aren't available in Cloud Agents or the Cursor CLI. In those environments, we recommend installing rules and the MCP server manually. ## Manual setup[​](#manual-setup "Direct link to Manual setup") If you'd rather not install the plugin, you can wire up rules and the MCP server yourself. ### 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") ### Run Convex during development[​](#run-convex-during-development "Direct link to Run Convex during development") Run Convex (`npx convex dev`) in a terminal while you build so your functions deploy and your app updates live. With the plugin installed, its development hooks keep your [generated types](https://docs.convex.dev/cli#run-the-convex-dev-server) in sync as the agent works, so it won't get stuck in the linting loop that stale types can otherwise cause. Without the plugin, keeping `npx convex dev` running is what keeps those types fresh. ### 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 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 my 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: --- # 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:293](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L293) ## 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:1055](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L1055) ## 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:554](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L554) *** ### 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:633](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L633) *** ### 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:642](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L642) *** ### setAuth[​](#setauth "Direct link to setAuth") ▸ **setAuth**(`fetchToken`, `onChange`, `onRefreshChange?`): `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 | | `onRefreshChange?` | (`isRefreshing`: `boolean`) => `void` | a callback called with `true` when the socket is paused to fetch a replacement token after a server rejection, and `false` when refresh completes | #### Returns[​](#returns-5 "Direct link to Returns") `void` #### Defined in[​](#defined-in-5 "Direct link to Defined in") [browser/sync/client.ts:668](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L668) *** ### 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:680](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L680) *** ### 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:690](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L690) *** ### 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:709](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L709) *** ### 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:742](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L742) *** ### 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:795](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L795) *** ### 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:810](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L810) *** ### 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:856](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L856) *** ### 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:876](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L876) *** ### 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:997](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L997) *** ### 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:1044](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L1044) --- # 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:121](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L121) ## 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:98](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L98) *** ### 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:101](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L101) *** ### 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:112](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L112) ## 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:187](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L187) *** ### 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:265](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L265) *** ### 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:368](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L368) *** ### 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:382](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L382) *** ### 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:395](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L395) *** ### 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:490](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L490) *** ### 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:507](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L507) *** ### 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:523](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L523) *** ### 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:555](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L555) *** ### 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:570](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L570) --- # 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. - `fetch` - A custom fetch implementation to use for all HTTP requests made by this client. | | `options.skipConvexDeploymentUrlCheck?` | `boolean` | - | | `options.logger?` | `boolean` \| `Logger` | - | | `options.auth?` | `string` | - | | `options.fetch?` | (`input`: `URL` \| `RequestInfo`, `init?`: `RequestInit`) => `Promise`<`Response`>(`input`: `string` \| `URL` \| `Request`, `init?`: `RequestInit`) => `Promise`<`Response`> | - | #### Defined in[​](#defined-in "Direct link to Defined in") [browser/http\_client.ts:97](https://github.com/get-convex/convex-js/blob/main/src/browser/http_client.ts#L97) ## 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:147](https://github.com/get-convex/convex-js/blob/main/src/browser/http_client.ts#L147) ## 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:137](https://github.com/get-convex/convex-js/blob/main/src/browser/http_client.ts#L137) *** ### 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:158](https://github.com/get-convex/convex-js/blob/main/src/browser/http_client.ts#L158) *** ### 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:184](https://github.com/get-convex/convex-js/blob/main/src/browser/http_client.ts#L184) *** ### 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:226](https://github.com/get-convex/convex-js/blob/main/src/browser/http_client.ts#L226) *** ### 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:270](https://github.com/get-convex/convex-js/blob/main/src/browser/http_client.ts#L270) *** ### 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:430](https://github.com/get-convex/convex-js/blob/main/src/browser/http_client.ts#L430) *** ### 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:453](https://github.com/get-convex/convex-js/blob/main/src/browser/http_client.ts#L453) --- # 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:333](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L333) ## 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:368](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L368) *** ### 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:732](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L732) ## Methods[​](#methods "Direct link to Methods") ### setAuth[​](#setauth "Direct link to setAuth") ▸ **setAuth**(`fetchToken`, `onChange?`, `onRefreshChange?`): `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 | | `onRefreshChange?` | (`isRefreshing`: `boolean`) => `void` | a callback called with `true` when the socket is paused to fetch a replacement token after a server rejection, and `false` when refresh completes | #### Returns[​](#returns-2 "Direct link to Returns") `void` #### Defined in[​](#defined-in-3 "Direct link to Defined in") [react/client.ts:427](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L427) *** ### 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:451](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L451) *** ### 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:484](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L484) *** ### 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` | [`QueryOptions`](/api/modules/browser.md#queryoptions)<`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:560](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L560) *** ### 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:637](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L637) *** ### 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:658](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L658) *** ### 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:678](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L678) *** ### 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:705](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L705) *** ### 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:721](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L721) *** ### 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:744](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L744) --- # 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:680](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L680) *** ### strictTableNameTypes[​](#stricttablenametypes "Direct link to strictTableNameTypes") • **strictTableNameTypes**: `StrictTableTypes` #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/schema.ts:681](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L681) *** ### schemaValidation[​](#schemavalidation "Direct link to schemaValidation") • `Readonly` **schemaValidation**: `boolean` #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/schema.ts:682](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L682) --- # 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. Indexes speed up queries by allowing efficient lookups on specific fields. Use `.withIndex()` in your queries to leverage them. Index fields must be queried in the same order they are defined. If you need to query by `field2` then `field1`, create a separate index with that field order. **`Example`** ``` defineTable({ userId: v.id("users"), status: v.string(), updatedAt: v.number(), }) // Name indexes after their fields: .index("by_userId", ["userId"]) .index("by_status_updatedAt", ["status", "updatedAt"]) ``` **Best practice:** Always include all index fields in the index name (e.g., `"by_field1_and_field2"`). **`See`** #### 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:257](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L257) ▸ **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/database/reading-data/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:290](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L290) ▸ **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:326](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L326) *** ### 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:379](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L379) ▸ **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:423](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L423) *** ### 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:470](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L470) ▸ **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:513](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L513) *** ### 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:556](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L556) --- # 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:54](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L54) ## 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:37](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L37) *** ### 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:42](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L42) *** ### 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:47](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L47) *** ### 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:52](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L52) *** ### 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:261](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L261) --- # 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:490](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L490) ## 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:37](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L37) *** ### 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:42](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L42) *** ### 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:47](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L47) *** ### 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:52](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L52) *** ### 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:480](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L480) *** ### 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:485](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L485) --- # 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:54](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L54) ## 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:37](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L37) *** ### 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:42](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L42) *** ### 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:47](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L47) *** ### 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:52](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L52) *** ### 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:168](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L168) --- # 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:54](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L54) ## 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:37](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L37) *** ### 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:42](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L42) *** ### 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:47](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L47) *** ### 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:52](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L52) *** ### 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:192](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L192) --- # 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:54](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L54) ## 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:37](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L37) *** ### 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:42](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L42) *** ### 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:47](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L47) *** ### 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:52](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L52) *** ### 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:120](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L120) --- # 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:84](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L84) ## 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:37](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L37) *** ### 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:42](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L42) *** ### 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:47](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L47) *** ### 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:52](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L52) *** ### 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:74](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L74) *** ### 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:79](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L79) --- # 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:54](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L54) ## 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:37](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L37) *** ### 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:42](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L42) *** ### 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:47](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L47) *** ### 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:52](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L52) *** ### 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:145](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L145) --- # 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:441](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L441) ## 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:37](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L37) *** ### 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:42](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L42) *** ### 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:47](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L47) *** ### 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:52](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L52) *** ### 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:431](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L431) *** ### 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:436](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L436) --- # 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:54](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L54) ## 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:37](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L37) *** ### 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:42](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L42) *** ### 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:47](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L47) *** ### 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:52](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L52) *** ### 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:238](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L238) --- # 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:304](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L304) ## 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:37](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L37) *** ### 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:42](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L42) *** ### 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:47](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L47) *** ### 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:52](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L52) *** ### 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:294](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L294) *** ### 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:299](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L299) ## 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:349](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L349) *** ### 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:366](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L366) *** ### 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:386](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L386) *** ### 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:407](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L407) --- # 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:547](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L547) ## 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:37](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L37) *** ### 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:42](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L42) *** ### 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:47](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L47) *** ### 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:52](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L52) *** ### 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:532](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L532) *** ### 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:537](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L537) *** ### 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:542](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L542) --- # 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:54](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L54) ## 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:37](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L37) *** ### 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:42](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L42) *** ### 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:47](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L47) *** ### 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:52](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L52) *** ### 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:214](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L214) --- # 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:619](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L619) ## 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:37](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L37) *** ### 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:42](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L42) *** ### 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:47](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L47) *** ### 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:52](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L52) *** ### 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:609](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L609) *** ### 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:614](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L614) --- # 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 `10`. #### 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) *** ### initialAuthTokenReuse[​](#initialauthtokenreuse "Direct link to initialAuthTokenReuse") • `Optional` **initialAuthTokenReuse**: `boolean` This API is experimental: it may change or disappear. When true, the client reuses the initial cached auth token instead of immediately fetching a fresh one. This avoids a second Authenticate message that causes the server to re-execute all authenticated queries. The cached token's remaining lifetime is estimated using the server's clock skew measurement, and a refresh is scheduled before it expires. Defaults to false, preserving the original behavior of immediately fetching a fresh token after the cached token is confirmed. #### Defined in[​](#defined-in-9 "Direct link to Defined in") [browser/sync/client.ts:155](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L155) --- # 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:226](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L226) --- # 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:206](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L206) --- # 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 `10`. #### 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) *** ### initialAuthTokenReuse[​](#initialauthtokenreuse "Direct link to initialAuthTokenReuse") • `Optional` **initialAuthTokenReuse**: `boolean` This API is experimental: it may change or disappear. When true, the client reuses the initial cached auth token instead of immediately fetching a fresh one. This avoids a second Authenticate message that causes the server to re-execute all authenticated queries. The cached token's remaining lifetime is estimated using the server's clock skew measurement, and a refresh is scheduled before it expires. Defaults to false, preserving the original behavior of immediately fetching a fresh token after the cached token is confirmed. #### Inherited from[​](#inherited-from-9 "Direct link to Inherited from") [BaseConvexClientOptions](/api/interfaces/browser.BaseConvexClientOptions.md).[initialAuthTokenReuse](/api/interfaces/browser.BaseConvexClientOptions.md#initialauthtokenreuse) #### Defined in[​](#defined-in-9 "Direct link to Defined in") [browser/sync/client.ts:155](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L155) --- # 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:283](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L283) --- # 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:137](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L137) --- # 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:65](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L65) ## 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:88](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L88) --- # 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:171](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L171) *** ### 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:183](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L183) *** ### 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:195](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L195) --- # 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:242](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L242) --- # Interface: ActionMeta [server](/api/modules/server.md).ActionMeta Extra context available in Convex action functions. ## Methods[​](#methods "Direct link to Methods") ### getFunctionMetadata[​](#getfunctionmetadata "Direct link to getFunctionMetadata") ▸ **getFunctionMetadata**(): `Promise`<[`FunctionMetadata`](/api/modules/server.md#functionmetadata)> #### Returns[​](#returns "Direct link to Returns") `Promise`<[`FunctionMetadata`](/api/modules/server.md#functionmetadata)> #### Defined in[​](#defined-in "Direct link to Defined in") [server/meta.ts:153](https://github.com/get-convex/convex-js/blob/main/src/server/meta.ts#L153) *** ### getDeploymentMetadata[​](#getdeploymentmetadata "Direct link to getDeploymentMetadata") ▸ **getDeploymentMetadata**(): `Promise`<[`DeploymentMetadata`](/api/modules/server.md#deploymentmetadata)> #### Returns[​](#returns-1 "Direct link to Returns") `Promise`<[`DeploymentMetadata`](/api/modules/server.md#deploymentmetadata)> #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/meta.ts:154](https://github.com/get-convex/convex-js/blob/main/src/server/meta.ts#L154) *** ### getRequestMetadata[​](#getrequestmetadata "Direct link to getRequestMetadata") ▸ **getRequestMetadata**(): `Promise`<[`RequestMetadata`](/api/modules/server.md#requestmetadata)> #### Returns[​](#returns-2 "Direct link to Returns") `Promise`<[`RequestMetadata`](/api/modules/server.md#requestmetadata)> #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/meta.ts:155](https://github.com/get-convex/convex-js/blob/main/src/server/meta.ts#L155) --- # Interface: AdvancedRunQueryOptions [server](/api/modules/server.md).AdvancedRunQueryOptions ## Properties[​](#properties "Direct link to Properties") ### transactionLimits[​](#transactionlimits "Direct link to transactionLimits") • `Optional` **transactionLimits**: [`TransactionLimits`](/api/interfaces/server.TransactionLimits.md) #### Defined in[​](#defined-in "Direct link to Defined in") [server/registration.ts:1216](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L1216) *** ### useStaleSnapshot[​](#usestalesnapshot "Direct link to useStaleSnapshot") • `Optional` **useStaleSnapshot**: `boolean` Run a query on a recent snapshot of the database that is not guaranteed to be up-to-date when this transaction commits. This is an advanced feature which can introduce subtle race conditions, so its use is generally discouraged except for specific use-cases where database read conflicts are expected, e.g. reading from an append-only table with immutable records where the only read conflicts are from concurrent appends. #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/registration.ts:1227](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L1227) --- # 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:97](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L97) *** ### 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:109](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L109) --- # 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:97](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L97) *** ### 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:109](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L109) *** ### 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:410](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L410) *** ### 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:425](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L425) *** ### 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:437](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L437) *** ### 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:447](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L447) --- # 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:749](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L749) *** ### 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:768](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L768) --- # 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 action context is passed as the first argument to any Convex action run on the server. Actions can call external APIs and use Node.js libraries, but do **not** have direct database access (`ctx.db` is not available). Use `ctx.runQuery` and `ctx.runMutation` to interact with the database. You should generally use the `ActionCtx` type from `"./_generated/server"`. **`Example`** ``` import { action } from "./_generated/server"; import { internal } from "./_generated/api"; import { v } from "convex/values"; export const processPayment = action({ args: { orderId: v.id("orders"), amount: v.number() }, returns: v.null(), handler: async (ctx, args) => { // Read data via ctx.runQuery: const order = await ctx.runQuery(internal.orders.get, { id: args.orderId }); // Call external API: const result = await fetch("https://api.stripe.com/v1/charges", { ... }); // Write results back via ctx.runMutation: await ctx.runMutation(internal.orders.markPaid, { id: args.orderId }); return null; }, }); ``` **Common mistake:** `ctx.db` is not available in actions. Do not try to access it, use `ctx.runQuery` and `ctx.runMutation` instead. ## 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:380](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L380) *** ### 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:385](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L385) *** ### 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:390](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L390) *** ### meta[​](#meta "Direct link to meta") • **meta**: [`ActionMeta`](/api/interfaces/server.ActionMeta.md) #### Defined in[​](#defined-in-3 "Direct link to Defined in") [server/registration.ts:413](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L413) ## 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. Each `runQuery` call is a separate read transaction. Consider using an internalQuery to prevent users from calling the query directly. **`Example`** ``` const user = await ctx.runQuery(internal.users.get, { userId }); ``` #### 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-4 "Direct link to Defined in") [server/registration.ts:329](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L329) *** ### 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. Each `runMutation` call is a separate write transaction. Consider using an internalMutation to prevent users from calling it directly. **`Example`** ``` await ctx.runMutation(internal.orders.markPaid, { id: orderId }); ``` #### 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-5 "Direct link to Defined in") [server/registration.ts:349](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L349) *** ### 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. **Important:** Only use `runAction` when you need to cross runtimes (e.g., calling a `"use node"` action from the default Convex runtime). For code in the same runtime, extract shared logic into a plain TypeScript helper function instead, `runAction` has significant overhead (separate function call, separate resource allocation). 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-6 "Direct link to Defined in") [server/registration.ts:372](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L372) *** ### 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-7 "Direct link to Defined in") [server/registration.ts:402](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L402) --- # Interface: GenericDatabaseReader\ [server](/api/modules/server.md).GenericDatabaseReader An interface to read from the database within Convex query functions. Available as `ctx.db` in queries (read-only) and mutations (read-write). You should generally use the `DatabaseReader` type from `"./_generated/server"`. The two entry points are: * [get](/api/interfaces/server.GenericDatabaseReader.md#get), which fetches a single document by table name and [GenericId](/api/modules/values.md#genericid). * [query](/api/interfaces/server.GenericDatabaseReader.md#query), which starts building a query. **`Example`** ``` // Fetch a single document by ID: const user = await ctx.db.get("users", userId); // Query documents with an index: const messages = await ctx.db .query("messages") .withIndex("by_channel", (q) => q.eq("channelId", channelId)) .order("desc") .take(50); ``` **Best practice:** Use `.withIndex()` instead of `.filter()` for efficient queries. Define indexes in your schema for fields you query frequently. **`See`** ## 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. System tables include `_storage` (file metadata) and `_scheduled_functions` (scheduled function state). Use `ctx.db.system.get()` and `ctx.db.system.query()` just like regular tables. **`Example`** ``` // Get file metadata from the _storage system table: const metadata = await ctx.db.system.get("_storage", storageId); // metadata has: _id, _creationTime, contentType, sha256, size ``` #### Defined in[​](#defined-in "Direct link to Defined in") [server/database.ts:162](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L162) ## Methods[​](#methods "Direct link to Methods") ### get[​](#get "Direct link to get") ▸ **get**<`TableName`>(`table`, `id`): `Promise`<`null` | [`DocumentByName`](/api/modules/server.md#documentbyname)<`DataModel`, `TableName`>> Fetch a single document from the database by table name and [GenericId](/api/modules/values.md#genericid). **`Example`** ``` const user = await ctx.db.get("users", userId); ``` #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------- | | `TableName` | extends `string` | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | Description | | ------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------- | | `table` | `TableName` | The name of the table to fetch the document from. | | `id` | [`GenericId`](/api/modules/values.md#genericid)<`NonUnion`<`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:29](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L29) ▸ **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). Supported for backwards compatibility. Prefer `db.get(tableName, id)` in new code, or `db.system.get(tableName, id)` for system tables. #### 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 | | ---- | ------------------------------------------------------------ | --------------------------------------------------------------------------------------------- | | `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-1 "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") BaseDatabaseReader.get #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/database.ts:43](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L43) *** ### 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-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 to query. | #### Returns[​](#returns-2 "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") BaseDatabaseReader.query #### Defined in[​](#defined-in-3 "Direct link to Defined in") [server/database.ts:56](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L56) *** ### 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(tableName, id)` may return `null`). #### 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 | | ----------- | ----------- | ---------------------- | | `tableName` | `TableName` | The name of the table. | | `id` | `string` | The ID string. | #### Returns[​](#returns-3 "Direct link to Returns") `null` | [`GenericId`](/api/modules/values.md#genericid)<`TableName`> #### Inherited from[​](#inherited-from-3 "Direct link to Inherited from") BaseDatabaseReader.normalizeId #### Defined in[​](#defined-in-4 "Direct link to Defined in") [server/database.ts:72](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L72) --- # 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:178](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L178) ## 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:82](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L82) --- # Interface: GenericDatabaseWriter\ [server](/api/modules/server.md).GenericDatabaseWriter An interface to read from and write to the database within Convex mutation functions. Available as `ctx.db` in mutations. You should generally use the `DatabaseWriter` type from `"./_generated/server"`. Extends [GenericDatabaseReader](/api/interfaces/server.GenericDatabaseReader.md) with write operations. All reads and writes within a single mutation are executed **atomically**, you never have to worry about partial writes leaving your data in an inconsistent state. **`Example`** ``` // Insert a new document: const userId = await ctx.db.insert("users", { name: "Alice", email: "alice@example.com" }); // Update specific fields (shallow merge): await ctx.db.patch("users", userId, { name: "Alice Smith" }); // Replace entire document (all non-system fields): await ctx.db.replace("users", userId, { name: "Bob", email: "bob@example.com" }); // Delete a document: await ctx.db.delete("users", userId); // Delete multiple documents (collect first, then delete each): const oldTasks = await ctx.db .query("tasks") .withIndex("by_completed", (q) => q.eq("completed", true)) .collect(); for (const task of oldTasks) { await ctx.db.delete("tasks", task._id); } ``` **`See`** ## 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. System tables include `_storage` (file metadata) and `_scheduled_functions` (scheduled function state). Use `ctx.db.system.get()` and `ctx.db.system.query()` just like regular tables. **`Example`** ``` // Get file metadata from the _storage system table: const metadata = await ctx.db.system.get("_storage", storageId); // metadata has: _id, _creationTime, contentType, sha256, size ``` #### 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:162](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L162) ## Methods[​](#methods "Direct link to Methods") ### get[​](#get "Direct link to get") ▸ **get**<`TableName`>(`table`, `id`): `Promise`<`null` | [`DocumentByName`](/api/modules/server.md#documentbyname)<`DataModel`, `TableName`>> Fetch a single document from the database by table name and [GenericId](/api/modules/values.md#genericid). **`Example`** ``` const user = await ctx.db.get("users", userId); ``` #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------- | | `TableName` | extends `string` | #### Parameters[​](#parameters "Direct link to Parameters") | Name | Type | Description | | ------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------- | | `table` | `TableName` | The name of the table to fetch the document from. | | `id` | [`GenericId`](/api/modules/values.md#genericid)<`NonUnion`<`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:29](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L29) ▸ **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). Supported for backwards compatibility. Prefer `db.get(tableName, id)` in new code, or `db.system.get(tableName, id)` for system tables. #### 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 | | ---- | ------------------------------------------------------------ | --------------------------------------------------------------------------------------------- | | `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-1 "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-2 "Direct link to Inherited from") [GenericDatabaseReader](/api/interfaces/server.GenericDatabaseReader.md).[get](/api/interfaces/server.GenericDatabaseReader.md#get) #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/database.ts:43](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L43) *** ### 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-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 to query. | #### Returns[​](#returns-2 "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-3 "Direct link to Inherited from") [GenericDatabaseReader](/api/interfaces/server.GenericDatabaseReader.md).[query](/api/interfaces/server.GenericDatabaseReader.md#query) #### Defined in[​](#defined-in-3 "Direct link to Defined in") [server/database.ts:56](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L56) *** ### 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(tableName, id)` may return `null`). #### 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 | | ----------- | ----------- | ---------------------- | | `tableName` | `TableName` | The name of the table. | | `id` | `string` | The ID string. | #### Returns[​](#returns-3 "Direct link to Returns") `null` | [`GenericId`](/api/modules/values.md#genericid)<`TableName`> #### Inherited from[​](#inherited-from-4 "Direct link to Inherited from") [GenericDatabaseReader](/api/interfaces/server.GenericDatabaseReader.md).[normalizeId](/api/interfaces/server.GenericDatabaseReader.md#normalizeid) #### Defined in[​](#defined-in-4 "Direct link to Defined in") [server/database.ts:72](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L72) *** ### 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. **`Example`** ``` const taskId = await ctx.db.insert("tasks", { text: "Buy groceries", completed: false, }); ``` #### 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 | | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | | `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 document to insert. System fields (`_id`, `_creationTime`) are added automatically and should not be included. | #### Returns[​](#returns-4 "Direct link to Returns") `Promise`<[`GenericId`](/api/modules/values.md#genericid)<`TableName`>> The [GenericId](/api/modules/values.md#genericid) of the new document. #### Defined in[​](#defined-in-5 "Direct link to Defined in") [server/database.ts:239](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L239) *** ### patch[​](#patch "Direct link to patch") ▸ **patch**<`TableName`>(`table`, `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. Fields not specified in the patch are left unchanged. This method will throw if the document does not exist. **`Example`** ``` // Update only the "completed" field, leaving other fields unchanged: await ctx.db.patch("tasks", taskId, { completed: true }); // Remove an optional field by setting it to undefined: await ctx.db.patch("tasks", taskId, { assignee: undefined }); ``` **Tip:** Use `patch` for partial updates. Use `replace` when you want to overwrite the entire document. #### 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 | | ------- | ------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | | `table` | `TableName` | The name of the table the document is in. | | `id` | [`GenericId`](/api/modules/values.md#genericid)<`NonUnion`<`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 document to merge into the existing document. | #### Returns[​](#returns-5 "Direct link to Returns") `Promise`<`void`> #### Defined in[​](#defined-in-6 "Direct link to Defined in") [server/database.ts:270](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L270) ▸ **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. Fields not specified in the patch are left unchanged. This method will throw if the document does not exist. Supported for backwards compatibility. Prefer `db.patch(tableName, id, value)` in new code. #### Type parameters[​](#type-parameters-7 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------- | | `TableName` | extends `string` | #### Parameters[​](#parameters-6 "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 document to merge into the existing document. | #### Returns[​](#returns-6 "Direct link to Returns") `Promise`<`void`> #### Defined in[​](#defined-in-7 "Direct link to Defined in") [server/database.ts:292](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L292) *** ### replace[​](#replace "Direct link to replace") ▸ **replace**<`TableName`>(`table`, `id`, `value`): `Promise`<`void`> Replace the value of an existing document, overwriting its old value completely. Unlike `patch`, which does a shallow merge, `replace` overwrites the entire document. Any fields not included in the new value will be removed (except system fields `_id` and `_creationTime`). This method will throw if the document does not exist. **`Example`** ``` // Replace the entire document: await ctx.db.replace("users", userId, { name: "New Name", email: "new@example.com", }); ``` #### Type parameters[​](#type-parameters-8 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------- | | `TableName` | extends `string` | #### Parameters[​](#parameters-7 "Direct link to Parameters") | Name | Type | Description | | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------- | | `table` | `TableName` | The name of the table the document is in. | | `id` | [`GenericId`](/api/modules/values.md#genericid)<`NonUnion`<`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 document. System fields can be omitted. | #### Returns[​](#returns-7 "Direct link to Returns") `Promise`<`void`> #### Defined in[​](#defined-in-8 "Direct link to Defined in") [server/database.ts:320](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L320) ▸ **replace**<`TableName`>(`id`, `value`): `Promise`<`void`> Replace the value of an existing document, overwriting its old value completely. Unlike `patch`, which does a shallow merge, `replace` overwrites the entire document. Supported for backwards compatibility. Prefer `db.replace(tableName, id, value)` in new code. #### Type parameters[​](#type-parameters-9 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------- | | `TableName` | extends `string` | #### Parameters[​](#parameters-8 "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 document. System fields can be omitted. | #### Returns[​](#returns-8 "Direct link to Returns") `Promise`<`void`> #### Defined in[​](#defined-in-9 "Direct link to Defined in") [server/database.ts:339](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L339) *** ### delete[​](#delete "Direct link to delete") ▸ **delete**<`TableName`>(`table`, `id`): `Promise`<`void`> Delete an existing document. **`Example`** ``` await ctx.db.delete("tasks", taskId); ``` #### Type parameters[​](#type-parameters-10 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------- | | `TableName` | extends `string` | #### Parameters[​](#parameters-9 "Direct link to Parameters") | Name | Type | Description | | ------- | ------------------------------------------------------------------------ | ---------------------------------------------------------------------------- | | `table` | `TableName` | The name of the table the document is in. | | `id` | [`GenericId`](/api/modules/values.md#genericid)<`NonUnion`<`TableName`>> | The [GenericId](/api/modules/values.md#genericid) of the document to remove. | #### Returns[​](#returns-9 "Direct link to Returns") `Promise`<`void`> #### Defined in[​](#defined-in-10 "Direct link to Defined in") [server/database.ts:355](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L355) ▸ **delete**(`id`): `Promise`<`void`> Delete an existing document. Supported for backwards compatibility. Prefer `db.delete(tableName, id)` in new code. **Note:** Convex queries do not support `.delete()` directly on query results. To delete multiple documents, `.collect()` them first, then delete each one individually. #### Parameters[​](#parameters-10 "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-10 "Direct link to Returns") `Promise`<`void`> #### Defined in[​](#defined-in-11 "Direct link to Defined in") [server/database.ts:372](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L372) --- # Interface: GenericDatabaseWriterWithTable\ [server](/api/modules/server.md).GenericDatabaseWriterWithTable An interface to read from and write to the database within Convex mutation functions. You should generally use the `DatabaseWriter` type from `"./_generated/server"`. 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. ## 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:178](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L178) ## 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:395](https://github.com/get-convex/convex-js/blob/main/src/server/database.ts#L395) --- # 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. Mutations run **transactionally**, all reads and writes within a single mutation are atomic and isolated. You should generally use the `MutationCtx` type from `"./_generated/server"`. **`Example`** ``` import { mutation } from "./_generated/server"; import { internal } from "./_generated/api"; import { v } from "convex/values"; export const createTask = mutation({ args: { text: v.string() }, returns: v.id("tasks"), handler: async (ctx, args) => { // ctx.db: read and write documents const taskId = await ctx.db.insert("tasks", { text: args.text, completed: false }); // ctx.auth: check the authenticated user const identity = await ctx.auth.getUserIdentity(); // ctx.scheduler: schedule functions for later await ctx.scheduler.runAfter(0, internal.notifications.send, { taskId }); return taskId; }, }); ``` ## 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. Use `ctx.db.insert()`, `ctx.db.patch()`, `ctx.db.replace()`, and `ctx.db.delete()` to write data. Use `ctx.db.get()` and `ctx.db.query()` to read data. All operations within a mutation are atomic. #### Defined in[​](#defined-in "Direct link to Defined in") [server/registration.ts:86](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L86) *** ### auth[​](#auth "Direct link to auth") • **auth**: [`Auth`](/api/interfaces/server.Auth.md) Information about the currently authenticated user. Call `await ctx.auth.getUserIdentity()` to get the current user's identity, or `null` if the user is not authenticated. #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/registration.ts:94](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L94) *** ### storage[​](#storage "Direct link to storage") • **storage**: [`StorageWriter`](/api/interfaces/server.StorageWriter.md) A utility for reading and writing files in storage. Use `ctx.storage.generateUploadUrl()` to create an upload URL for clients, `ctx.storage.getUrl(storageId)` to get a URL for a stored file, or `ctx.storage.delete(storageId)` to remove one. #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/registration.ts:103](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L103) *** ### scheduler[​](#scheduler "Direct link to scheduler") • **scheduler**: [`Scheduler`](/api/interfaces/server.Scheduler.md) A utility for scheduling Convex functions to run in the future. **`Example`** ``` // Schedule an action to run immediately after this mutation commits: await ctx.scheduler.runAfter(0, internal.emails.sendWelcome, { userId }); // Schedule a cleanup to run in 24 hours: await ctx.scheduler.runAfter(24 * 60 * 60 * 1000, internal.tasks.cleanup, {}); ``` #### Defined in[​](#defined-in-3 "Direct link to Defined in") [server/registration.ts:117](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L117) *** ### runQuery[​](#runquery "Direct link to runQuery") • **runQuery**: \(`query`: `Query`, ...`args`: [`ArgsAndOptions`](/api/modules/server.md#argsandoptions)<`Query`, [`AdvancedRunQueryOptions`](/api/interfaces/server.AdvancedRunQueryOptions.md)>) => `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. The query runs within the same transaction as the calling mutation, seeing a consistent snapshot of the database. Requires a [FunctionReference](/api/modules/server.md#functionreference) (e.g., `api.myModule.myQuery` or `internal.myModule.myQuery`). NOTE: Often you can extract shared logic into a helper function instead. `runQuery` incurs overhead of running argument and return value validation, and creating a new isolated JS context. **`Example`** ``` const user = await ctx.runQuery(internal.users.getUser, { userId }); ``` ##### 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` | [`ArgsAndOptions`](/api/modules/server.md#argsandoptions)<`Query`, [`AdvancedRunQueryOptions`](/api/interfaces/server.AdvancedRunQueryOptions.md)> | ##### 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:136](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L136) *** ### runMutation[​](#runmutation "Direct link to runMutation") • **runMutation**: \(`mutation`: `Mutation`, ...`args`: [`ArgsAndOptions`](/api/modules/server.md#argsandoptions)<`Mutation`, { `transactionLimits?`: [`TransactionLimits`](/api/interfaces/server.TransactionLimits.md) }>) => `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. The mutation runs in a sub-transaction, so if it throws an error, all of its writes will be rolled back. Requires a [FunctionReference](/api/modules/server.md#functionreference). NOTE: Often you can extract shared logic into a helper function instead. `runMutation` incurs overhead of running argument and return value validation, and creating a new isolated JS context. ##### 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` | [`ArgsAndOptions`](/api/modules/server.md#argsandoptions)<`Mutation`, { `transactionLimits?`: [`TransactionLimits`](/api/interfaces/server.TransactionLimits.md) }> | ##### 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:151](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L151) *** ### meta[​](#meta "Direct link to meta") • **meta**: [`MutationMeta`](/api/interfaces/server.MutationMeta.md) #### Defined in[​](#defined-in-6 "Direct link to Defined in") [server/registration.ts:158](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L158) --- # 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. Queries are **read-only**, they can read from the database but cannot write. They are also **reactive**, when used with `useQuery` on the client, the result automatically updates when data changes. You should generally use the `QueryCtx` type from `"./_generated/server"`. **`Example`** ``` import { query } from "./_generated/server"; import { v } from "convex/values"; export const listTasks = query({ args: {}, returns: v.array(v.object({ _id: v.id("tasks"), _creationTime: v.number(), text: v.string(), completed: v.boolean(), })), handler: async (ctx, args) => { // ctx.db: read-only database access return await ctx.db.query("tasks").order("desc").take(100); }, }); ``` ## 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. Use `ctx.db.get(table, id)` to fetch a single document by ID, or `ctx.db.query("tableName")` to query multiple documents with filtering and ordering. Queries are read-only, no write methods are available. #### Defined in[​](#defined-in "Direct link to Defined in") [server/registration.ts:218](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L218) *** ### auth[​](#auth "Direct link to auth") • **auth**: [`Auth`](/api/interfaces/server.Auth.md) Information about the currently authenticated user. Call `await ctx.auth.getUserIdentity()` to get the current user's identity, or `null` if the user is not authenticated. #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/registration.ts:226](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L226) *** ### storage[​](#storage "Direct link to storage") • **storage**: [`StorageReader`](/api/interfaces/server.StorageReader.md) A utility for reading files in storage. Use `ctx.storage.getUrl(storageId)` to get a URL for a stored file. #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/registration.ts:233](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L233) *** ### runQuery[​](#runquery "Direct link to runQuery") • **runQuery**: \(`query`: `Query`, ...`args`: [`ArgsAndOptions`](/api/modules/server.md#argsandoptions)<`Query`, { `transactionLimits?`: [`TransactionLimits`](/api/interfaces/server.TransactionLimits.md) }>) => `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. The query runs within the same read snapshot. Requires a [FunctionReference](/api/modules/server.md#functionreference) (e.g., `api.myModule.myQuery` or `internal.myModule.myQuery`). NOTE: Often you can extract shared logic into a helper function instead. `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` | [`ArgsAndOptions`](/api/modules/server.md#argsandoptions)<`Query`, { `transactionLimits?`: [`TransactionLimits`](/api/interfaces/server.TransactionLimits.md) }> | ##### 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:246](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L246) *** ### meta[​](#meta "Direct link to meta") • **meta**: [`QueryMeta`](/api/interfaces/server.QueryMeta.md) #### Defined in[​](#defined-in-4 "Direct link to Defined in") [server/registration.ts:251](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L251) --- # 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: MutationMeta [server](/api/modules/server.md).MutationMeta Extra context available in Convex mutation functions. ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * [`QueryMeta`](/api/interfaces/server.QueryMeta.md) ↳ **`MutationMeta`** ## Methods[​](#methods "Direct link to Methods") ### getFunctionMetadata[​](#getfunctionmetadata "Direct link to getFunctionMetadata") ▸ **getFunctionMetadata**(): `Promise`<[`FunctionMetadata`](/api/modules/server.md#functionmetadata)> #### Returns[​](#returns "Direct link to Returns") `Promise`<[`FunctionMetadata`](/api/modules/server.md#functionmetadata)> #### Inherited from[​](#inherited-from "Direct link to Inherited from") [QueryMeta](/api/interfaces/server.QueryMeta.md).[getFunctionMetadata](/api/interfaces/server.QueryMeta.md#getfunctionmetadata) #### Defined in[​](#defined-in "Direct link to Defined in") [server/meta.ts:133](https://github.com/get-convex/convex-js/blob/main/src/server/meta.ts#L133) *** ### getTransactionMetrics[​](#gettransactionmetrics "Direct link to getTransactionMetrics") ▸ **getTransactionMetrics**(): `Promise`<[`TransactionMetrics`](/api/modules/server.md#transactionmetrics)> #### Returns[​](#returns-1 "Direct link to Returns") `Promise`<[`TransactionMetrics`](/api/modules/server.md#transactionmetrics)> #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from") [QueryMeta](/api/interfaces/server.QueryMeta.md).[getTransactionMetrics](/api/interfaces/server.QueryMeta.md#gettransactionmetrics) #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/meta.ts:134](https://github.com/get-convex/convex-js/blob/main/src/server/meta.ts#L134) *** ### getDeploymentMetadata[​](#getdeploymentmetadata "Direct link to getDeploymentMetadata") ▸ **getDeploymentMetadata**(): `Promise`<[`DeploymentMetadata`](/api/modules/server.md#deploymentmetadata)> #### Returns[​](#returns-2 "Direct link to Returns") `Promise`<[`DeploymentMetadata`](/api/modules/server.md#deploymentmetadata)> #### Inherited from[​](#inherited-from-2 "Direct link to Inherited from") [QueryMeta](/api/interfaces/server.QueryMeta.md).[getDeploymentMetadata](/api/interfaces/server.QueryMeta.md#getdeploymentmetadata) #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/meta.ts:135](https://github.com/get-convex/convex-js/blob/main/src/server/meta.ts#L135) *** ### getRequestMetadata[​](#getrequestmetadata "Direct link to getRequestMetadata") ▸ **getRequestMetadata**(): `Promise`<[`RequestMetadata`](/api/modules/server.md#requestmetadata)> #### Returns[​](#returns-3 "Direct link to Returns") `Promise`<[`RequestMetadata`](/api/modules/server.md#requestmetadata)> #### Defined in[​](#defined-in-3 "Direct link to Defined in") [server/meta.ts:144](https://github.com/get-convex/convex-js/blob/main/src/server/meta.ts#L144) --- # 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. **Important:** Prefer using `.withIndex()` over `.filter()` whenever possible. Filters scan all documents matched so far and discard non-matches, while indexes efficiently skip non-matching documents. Define an index in your schema for fields you filter on frequently. #### 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:198](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L198) *** ### 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:227](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L227) *** ### 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. **Warning:** This loads every matching document into memory. If the result set can grow unbounded as your database grows, `.collect()` will eventually cause performance problems or hit limits. Only use `.collect()` when the result set is tightly bounded (e.g., a known small number of items). Prefer `.first()`, `.unique()`, `.take(n)`, or `.paginate()` when the result set may be large or unbounded. For processing many results without loading all into memory, use the `Query` as an `AsyncIterable` with `for await...of`. #### 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:246](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L246) *** ### 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:255](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L255) *** ### 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:262](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L262) *** ### 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. Use this when you expect exactly zero or one result, for example when querying by a unique field. If the query matches more than one document, this will throw an error. **`Example`** ``` const user = await ctx.db .query("users") .withIndex("by_email", (q) => q.eq("email", "alice@example.com")) .unique(); ``` **`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:282](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L282) --- # 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) *** ### endCursor[​](#endcursor "Direct link to endCursor") • `Optional` **endCursor**: `null` | `string` A [Cursor](/api/modules/server.md#cursor) representing the end of this page or `null | undefined` to use `numItems` instead. This explicitly sets the range of documents the query will return, from `cursor` to `endCursor`. It's used by reactive pagination clients to ensure there are no gaps between pages when data changes, and to split pages when `pageStatus` indicates a split is recommended or required. When splitting a page, use the returned `splitCursor` as `endCursor` for the first half and as `cursor` for the second half. #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/pagination.ts:98](https://github.com/get-convex/convex-js/blob/main/src/server/pagination.ts#L98) *** ### maximumRowsRead[​](#maximumrowsread "Direct link to maximumRowsRead") • `Optional` **maximumRowsRead**: `number` The maximum number of rows to read from the database during pagination. This limits rows entering the query pipeline before filters are applied. Use this when filtering for rare items, where low `numItems` won't bound execution time because the query scans many rows to find matches. Currently this is not enforced for search queries. #### Defined in[​](#defined-in-3 "Direct link to Defined in") [server/pagination.ts:109](https://github.com/get-convex/convex-js/blob/main/src/server/pagination.ts#L109) *** ### maximumBytesRead[​](#maximumbytesread "Direct link to maximumBytesRead") • `Optional` **maximumBytesRead**: `number` The maximum number of bytes to read from the database during pagination. This limits bytes entering the query pipeline before filters are applied. Use this to control bandwidth usage when documents are large. If the limit is reached, the query may return an incomplete page and require a page split. Currently this is not enforced for search queries. #### Defined in[​](#defined-in-4 "Direct link to Defined in") [server/pagination.ts:121](https://github.com/get-convex/convex-js/blob/main/src/server/pagination.ts#L121) --- # 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(tableName, 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. **`Example`** ``` // Use .withIndex() for efficient queries (preferred over .filter()): const messages = await ctx.db .query("messages") .withIndex("by_channel", (q) => q.eq("channelId", channelId)) .order("desc") .take(10); // Async iteration for processing large result sets: for await (const task of ctx.db.query("tasks")) { // Process each task without loading all into memory } // Get a single unique result (throws if multiple match): const user = await ctx.db .query("users") .withIndex("by_email", (q) => q.eq("email", email)) .unique(); ``` **Common mistake:** `.collect()` loads **all** matching documents into memory. If the result set can grow unbounded as your database grows, this will eventually cause problems. Prefer `.first()`, `.unique()`, `.take(n)`, or pagination instead. Only use `.collect()` on queries with a tightly bounded result set (e.g., items belonging to a single user with a known small limit). | | | | -------------------------------------------- | ---------------------------------------------------------------------- | | **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/database/reading-data). ## 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:176](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L176) *** ### 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. **Important:** Prefer using `.withIndex()` over `.filter()` whenever possible. Filters scan all documents matched so far and discard non-matches, while indexes efficiently skip non-matching documents. Define an index in your schema for fields you filter on frequently. #### 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:198](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L198) *** ### 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:227](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L227) *** ### 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. **Warning:** This loads every matching document into memory. If the result set can grow unbounded as your database grows, `.collect()` will eventually cause performance problems or hit limits. Only use `.collect()` when the result set is tightly bounded (e.g., a known small number of items). Prefer `.first()`, `.unique()`, `.take(n)`, or `.paginate()` when the result set may be large or unbounded. For processing many results without loading all into memory, use the `Query` as an `AsyncIterable` with `for await...of`. #### 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:246](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L246) *** ### 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:255](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L255) *** ### 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:262](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L262) *** ### 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. Use this when you expect exactly zero or one result, for example when querying by a unique field. If the query matches more than one document, this will throw an error. **`Example`** ``` const user = await ctx.db .query("users") .withIndex("by_email", (q) => q.eq("email", "alice@example.com")) .unique(); ``` **`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:282](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L282) --- # 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:41](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L41) *** ### 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:60](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L60) *** ### 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:89](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L89) *** ### 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:176](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L176) *** ### 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. **Important:** Prefer using `.withIndex()` over `.filter()` whenever possible. Filters scan all documents matched so far and discard non-matches, while indexes efficiently skip non-matching documents. Define an index in your schema for fields you filter on frequently. #### 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:198](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L198) *** ### 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:227](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L227) *** ### 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. **Warning:** This loads every matching document into memory. If the result set can grow unbounded as your database grows, `.collect()` will eventually cause performance problems or hit limits. Only use `.collect()` when the result set is tightly bounded (e.g., a known small number of items). Prefer `.first()`, `.unique()`, `.take(n)`, or `.paginate()` when the result set may be large or unbounded. For processing many results without loading all into memory, use the `Query` as an `AsyncIterable` with `for await...of`. #### 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:246](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L246) *** ### 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:255](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L255) *** ### 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:262](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L262) *** ### 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. Use this when you expect exactly zero or one result, for example when querying by a unique field. If the query matches more than one document, this will throw an error. **`Example`** ``` const user = await ctx.db .query("users") .withIndex("by_email", (q) => q.eq("email", "alice@example.com")) .unique(); ``` **`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:282](https://github.com/get-convex/convex-js/blob/main/src/server/query.ts#L282) --- # Interface: QueryMeta [server](/api/modules/server.md).QueryMeta Extra context available in Convex query functions. ## Hierarchy[​](#hierarchy "Direct link to Hierarchy") * **`QueryMeta`** ↳ [`MutationMeta`](/api/interfaces/server.MutationMeta.md) ## Methods[​](#methods "Direct link to Methods") ### getFunctionMetadata[​](#getfunctionmetadata "Direct link to getFunctionMetadata") ▸ **getFunctionMetadata**(): `Promise`<[`FunctionMetadata`](/api/modules/server.md#functionmetadata)> #### Returns[​](#returns "Direct link to Returns") `Promise`<[`FunctionMetadata`](/api/modules/server.md#functionmetadata)> #### Defined in[​](#defined-in "Direct link to Defined in") [server/meta.ts:133](https://github.com/get-convex/convex-js/blob/main/src/server/meta.ts#L133) *** ### getTransactionMetrics[​](#gettransactionmetrics "Direct link to getTransactionMetrics") ▸ **getTransactionMetrics**(): `Promise`<[`TransactionMetrics`](/api/modules/server.md#transactionmetrics)> #### Returns[​](#returns-1 "Direct link to Returns") `Promise`<[`TransactionMetrics`](/api/modules/server.md#transactionmetrics)> #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/meta.ts:134](https://github.com/get-convex/convex-js/blob/main/src/server/meta.ts#L134) *** ### getDeploymentMetadata[​](#getdeploymentmetadata "Direct link to getDeploymentMetadata") ▸ **getDeploymentMetadata**(): `Promise`<[`DeploymentMetadata`](/api/modules/server.md#deploymentmetadata)> #### Returns[​](#returns-2 "Direct link to Returns") `Promise`<[`DeploymentMetadata`](/api/modules/server.md#deploymentmetadata)> #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/meta.ts:135](https://github.com/get-convex/convex-js/blob/main/src/server/meta.ts#L135) --- # Interface: Scheduler [server](/api/modules/server.md).Scheduler An interface to schedule Convex functions to run in the future. Available as `ctx.scheduler` in mutations and actions. **Execution guarantees:** * **Scheduled mutations** are guaranteed to execute **exactly once**. They are automatically retried on transient errors. * **Scheduled actions** execute **at most once**. They are not retried and may fail due to transient errors. Consider using an `internalMutation` or `internalAction` to ensure that scheduled functions cannot be called directly from a client. **`Example`** ``` import { mutation } from "./_generated/server"; import { internal } from "./_generated/api"; import { v } from "convex/values"; export const createOrder = mutation({ args: { items: v.array(v.string()) }, returns: v.null(), handler: async (ctx, args) => { const orderId = await ctx.db.insert("orders", { items: args.items }); // Run immediately after this mutation commits: await ctx.scheduler.runAfter(0, internal.emails.sendConfirmation, { orderId, }); // Run cleanup in 7 days: await ctx.scheduler.runAfter( 7 * 24 * 60 * 60 * 1000, internal.orders.archiveOrder, { orderId }, ); return null; }, }); ``` **`See`** ## 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. **`Example`** ``` // Schedule to run as soon as possible (if this is a mutation it would be after this mutation commits): await ctx.scheduler.runAfter(0, internal.tasks.process, { taskId }); // Run after 5 seconds: await ctx.scheduler.runAfter(5000, internal.tasks.process, { taskId }); // Run after 1 hour: await ctx.scheduler.runAfter(60 * 60 * 1000, internal.cleanup.run, {}); ``` #### 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"`>> The ID of the scheduled function in the `_scheduled_functions` system table. Use this to cancel it later if needed. #### Defined in[​](#defined-in "Direct link to Defined in") [server/scheduler.ts:87](https://github.com/get-convex/convex-js/blob/main/src/server/scheduler.ts#L87) *** ### 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 specific time. **`Example`** ``` // Run at a specific Date: await ctx.scheduler.runAt( new Date("2030-01-01T00:00:00Z"), internal.events.triggerNewYear, {}, ); // Run at a timestamp (milliseconds since epoch): await ctx.scheduler.runAt(Date.now() + 60000, internal.tasks.process, { taskId }); ``` #### 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"`>> The ID of the scheduled function in the `_scheduled_functions` system table. #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/scheduler.ts:119](https://github.com/get-convex/convex-js/blob/main/src/server/scheduler.ts#L119) *** ### cancel[​](#cancel "Direct link to cancel") ▸ **cancel**(`id`): `Promise`<`void`> Cancel a previously scheduled function. For scheduled **actions**: if the action has not started, it will not run. If it is already in progress, it will continue running but any new functions it tries to schedule will be canceled. If it had already completed, canceling will throw an error. For scheduled **mutations**: the mutation will either show up as "pending", "completed", or "failed", but never "inProgress". Canceling a mutation will atomically cancel it entirely or fail to cancel if it has committed. It is a transaction that will either run to completion and commit or fully roll back. **`Example`** ``` // Cancel a scheduled function: await ctx.scheduler.cancel(scheduledFunctionId); ``` #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | Description | | ---- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | | `id` | [`GenericId`](/api/modules/values.md#genericid)<`"_scheduled_functions"`> | The ID of the scheduled function to cancel (returned by `runAfter` or `runAt`). | #### Returns[​](#returns-2 "Direct link to Returns") `Promise`<`void`> #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/scheduler.ts:147](https://github.com/get-convex/convex-js/blob/main/src/server/scheduler.ts#L147) --- # 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. In actions, `ctx.storage` has additional methods not available in mutations: `get()` to download a file as a Blob, and `store()` to upload a Blob directly. **`Example`** ``` // In an action, download and re-upload a file: const blob = await ctx.storage.get(storageId); if (blob) { const newStorageId = await ctx.storage.store(blob); } ``` ## 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. **`Example`** ``` const url = await ctx.storage.getUrl(storageId); ``` #### 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 the file 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:91](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L91) ▸ **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:103](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L103) *** ### getMetadata[​](#getmetadata "Direct link to getMetadata") ▸ **getMetadata**(`storageId`): `Promise`<`null` | [`FileMetadata`](/api/modules/server.md#filemetadata)> **`Deprecated`** Use `ctx.db.system.get("_storage", storageId)` instead, which returns equivalent metadata from the `_storage` system table (with a slightly different shape): ``` const metadata = await ctx.db.system.get("_storage", storageId); // { _id, _creationTime, sha256, size, contentType? } ``` 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:120](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L120) ▸ **getMetadata**<`T`>(`storageId`): `Promise`<`null` | [`FileMetadata`](/api/modules/server.md#filemetadata)> **`Deprecated`** Use `ctx.db.system.get("_storage", storageId)` 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:130](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L130) *** ### generateUploadUrl[​](#generateuploadurl "Direct link to generateUploadUrl") ▸ **generateUploadUrl**(): `Promise`<`string`> Generate a short-lived URL for uploading a file into storage. The client should make a POST request to this URL with the file as the body. The response will be a JSON object containing a newly allocated `Id<"_storage">` (`{ storageId: "..." }`). **`Example`** ``` // In a mutation, generate the upload URL: export const generateUploadUrl = mutation({ args: {}, returns: v.string(), handler: async (ctx) => { return await ctx.storage.generateUploadUrl(); }, }); // On the client, upload the file: // const uploadUrl = await generateUploadUrl(); // const result = await fetch(uploadUrl, { method: "POST", body: file }); // const { storageId } = await result.json(); ``` #### Returns[​](#returns-4 "Direct link to Returns") `Promise`<`string`> * A short-lived URL for uploading a file via 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:170](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L170) *** ### 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. **`Example`** ``` await ctx.storage.delete(storageId); ``` #### 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:183](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L183) ▸ **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:194](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L194) *** ### get[​](#get "Direct link to get") ▸ **get**(`storageId`): `Promise`<`null` | `Blob`> Download a file from storage as a Blob. Only available in actions and HTTP actions (not in mutations or queries). #### Parameters[​](#parameters-6 "Direct link to Parameters") | Name | Type | Description | | ----------- | ------------------------------------------------------------- | --------------------------------- | | `storageId` | [`GenericId`](/api/modules/values.md#genericid)<`"_storage"`> | The `Id<"_storage">` of the file. | #### Returns[​](#returns-7 "Direct link to Returns") `Promise`<`null` | `Blob`> A Blob containing the file contents, or `null` if the file doesn't exist. #### Defined in[​](#defined-in-7 "Direct link to Defined in") [server/storage.ts:225](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L225) ▸ **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:232](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L232) *** ### store[​](#store "Direct link to store") ▸ **store**(`blob`, `options?`): `Promise`<[`GenericId`](/api/modules/values.md#genericid)<`"_storage"`>> Upload a Blob directly to storage. Only available in actions and HTTP actions. For client-side uploads from mutations, use `generateUploadUrl()` instead. **`Example`** ``` const storageId = await ctx.storage.store(blob); // Save storageId to the database via ctx.runMutation ``` #### Parameters[​](#parameters-8 "Direct link to Parameters") | Name | Type | Description | | ----------------- | -------- | -------------------------------------------------------------- | | `blob` | `Blob` | The Blob to store. | | `options?` | `Object` | Optional settings. Pass `sha256` to verify the file integrity. | | `options.sha256?` | `string` | - | #### Returns[​](#returns-9 "Direct link to Returns") `Promise`<[`GenericId`](/api/modules/values.md#genericid)<`"_storage"`>> The `Id<"_storage">` of the newly stored file. #### Defined in[​](#defined-in-9 "Direct link to Defined in") [server/storage.ts:251](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L251) --- # Interface: StorageReader [server](/api/modules/server.md).StorageReader An interface to read files from storage within Convex query functions. Available as `ctx.storage` in queries (read-only), mutations, and actions. **`Example`** ``` // Get a URL for a stored file: const url = await ctx.storage.getUrl(storageId); if (url) { // Use the URL (e.g., return it to the client) } // Get file metadata via the system table (preferred over deprecated getMetadata): const metadata = await ctx.db.system.get("_storage", storageId); // metadata: { _id, _creationTime, sha256, size, contentType? } ``` **`See`** ## 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. **`Example`** ``` const url = await ctx.storage.getUrl(storageId); ``` #### 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 the file no longer exists. #### Defined in[​](#defined-in "Direct link to Defined in") [server/storage.ts:91](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L91) ▸ **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:103](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L103) *** ### getMetadata[​](#getmetadata "Direct link to getMetadata") ▸ **getMetadata**(`storageId`): `Promise`<`null` | [`FileMetadata`](/api/modules/server.md#filemetadata)> **`Deprecated`** Use `ctx.db.system.get("_storage", storageId)` instead, which returns equivalent metadata from the `_storage` system table (with a slightly different shape): ``` const metadata = await ctx.db.system.get("_storage", storageId); // { _id, _creationTime, sha256, size, contentType? } ``` 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:120](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L120) ▸ **getMetadata**<`T`>(`storageId`): `Promise`<`null` | [`FileMetadata`](/api/modules/server.md#filemetadata)> **`Deprecated`** Use `ctx.db.system.get("_storage", storageId)` 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:130](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L130) --- # Interface: StorageWriter [server](/api/modules/server.md).StorageWriter An interface to write files to storage within Convex mutation functions. Available as `ctx.storage` in mutations. **`See`** ## 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. **`Example`** ``` const url = await ctx.storage.getUrl(storageId); ``` #### 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 the file 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:91](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L91) ▸ **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:103](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L103) *** ### getMetadata[​](#getmetadata "Direct link to getMetadata") ▸ **getMetadata**(`storageId`): `Promise`<`null` | [`FileMetadata`](/api/modules/server.md#filemetadata)> **`Deprecated`** Use `ctx.db.system.get("_storage", storageId)` instead, which returns equivalent metadata from the `_storage` system table (with a slightly different shape): ``` const metadata = await ctx.db.system.get("_storage", storageId); // { _id, _creationTime, sha256, size, contentType? } ``` 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:120](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L120) ▸ **getMetadata**<`T`>(`storageId`): `Promise`<`null` | [`FileMetadata`](/api/modules/server.md#filemetadata)> **`Deprecated`** Use `ctx.db.system.get("_storage", storageId)` 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:130](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L130) *** ### generateUploadUrl[​](#generateuploadurl "Direct link to generateUploadUrl") ▸ **generateUploadUrl**(): `Promise`<`string`> Generate a short-lived URL for uploading a file into storage. The client should make a POST request to this URL with the file as the body. The response will be a JSON object containing a newly allocated `Id<"_storage">` (`{ storageId: "..." }`). **`Example`** ``` // In a mutation, generate the upload URL: export const generateUploadUrl = mutation({ args: {}, returns: v.string(), handler: async (ctx) => { return await ctx.storage.generateUploadUrl(); }, }); // On the client, upload the file: // const uploadUrl = await generateUploadUrl(); // const result = await fetch(uploadUrl, { method: "POST", body: file }); // const { storageId } = await result.json(); ``` #### Returns[​](#returns-4 "Direct link to Returns") `Promise`<`string`> * A short-lived URL for uploading a file via HTTP POST. #### Defined in[​](#defined-in-4 "Direct link to Defined in") [server/storage.ts:170](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L170) *** ### 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. **`Example`** ``` await ctx.storage.delete(storageId); ``` #### 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:183](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L183) ▸ **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:194](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L194) --- # 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: TransactionLimits [server](/api/modules/server.md).TransactionLimits Custom limits for a nested transaction. Each field specifies the absolute maximum allowed for the nested function call. Values are capped at the global transaction limits, so they can only lower limits, never raise them. ## Properties[​](#properties "Direct link to Properties") ### bytesRead[​](#bytesread "Direct link to bytesRead") • `Optional` **bytesRead**: `number` #### Defined in[​](#defined-in "Direct link to Defined in") [server/meta.ts:39](https://github.com/get-convex/convex-js/blob/main/src/server/meta.ts#L39) *** ### bytesWritten[​](#byteswritten "Direct link to bytesWritten") • `Optional` **bytesWritten**: `number` #### Defined in[​](#defined-in-1 "Direct link to Defined in") [server/meta.ts:40](https://github.com/get-convex/convex-js/blob/main/src/server/meta.ts#L40) *** ### databaseQueries[​](#databasequeries "Direct link to databaseQueries") • `Optional` **databaseQueries**: `number` #### Defined in[​](#defined-in-2 "Direct link to Defined in") [server/meta.ts:41](https://github.com/get-convex/convex-js/blob/main/src/server/meta.ts#L41) *** ### documentsRead[​](#documentsread "Direct link to documentsRead") • `Optional` **documentsRead**: `number` #### Defined in[​](#defined-in-3 "Direct link to Defined in") [server/meta.ts:42](https://github.com/get-convex/convex-js/blob/main/src/server/meta.ts#L42) *** ### documentsWritten[​](#documentswritten "Direct link to documentsWritten") • `Optional` **documentsWritten**: `number` #### Defined in[​](#defined-in-4 "Direct link to Defined in") [server/meta.ts:43](https://github.com/get-convex/convex-js/blob/main/src/server/meta.ts#L43) *** ### functionsScheduled[​](#functionsscheduled "Direct link to functionsScheduled") • `Optional` **functionsScheduled**: `number` #### Defined in[​](#defined-in-5 "Direct link to Defined in") [server/meta.ts:44](https://github.com/get-convex/convex-js/blob/main/src/server/meta.ts#L44) *** ### scheduledFunctionArgsBytes[​](#scheduledfunctionargsbytes "Direct link to scheduledFunctionArgsBytes") • `Optional` **scheduledFunctionArgsBytes**: `number` #### Defined in[​](#defined-in-6 "Direct link to Defined in") [server/meta.ts:45](https://github.com/get-convex/convex-js/blob/main/src/server/meta.ts#L45) --- # 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:676](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L676) *** ### 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:690](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L690) --- # 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) *** ### QueryOptions[​](#queryoptions "Direct link to QueryOptions") Ƭ **QueryOptions**<`Query`>: `Object` Options for a Convex query: the query function reference and its arguments. Used with the object-form overload of useQuery. #### Type parameters[​](#type-parameters "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 | Description | | ------- | -------------------------------------------------------------- | ------------------------------------ | | `query` | `Query` | The query function to run. | | `args` | [`FunctionArgs`](/api/modules/server.md#functionargs)<`Query`> | The arguments to the query function. | #### Defined in[​](#defined-in-1 "Direct link to Defined in") [browser/query\_options.ts:11](https://github.com/get-convex/convex-js/blob/main/src/browser/query_options.ts#L11) *** ### ConvexClientOptions[​](#convexclientoptions "Direct link to ConvexClientOptions") Ƭ **ConvexClientOptions**: [`BaseConvexClientOptions`](/api/interfaces/browser.BaseConvexClientOptions.md) & { `disabled?`: `boolean` ; `unsavedChangesWarning?`: `boolean` } #### Defined in[​](#defined-in-2 "Direct link to Defined in") [browser/simple\_client.ts:38](https://github.com/get-convex/convex-js/blob/main/src/browser/simple_client.ts#L38) *** ### AuthTokenFetcher[​](#authtokenfetcher "Direct link to AuthTokenFetcher") Ƭ **AuthTokenFetcher**: (`args`: { `forceRefreshToken`: `boolean` }) => `Promise`<`string` | `null` | `undefined`> #### Type declaration[​](#type-declaration-2 "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-3 "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-3 "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-4 "Direct link to Defined in") [browser/sync/client.ts:163](https://github.com/get-convex/convex-js/blob/main/src/browser/sync/client.ts#L163) *** ### 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-5 "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-1 "Direct link to Type parameters") | Name | Type | | ------ | ------------------------------------------------------------------- | | `Args` | extends `Record`<`string`, [`Value`](/api/modules/values.md#value)> | #### Type declaration[​](#type-declaration-4 "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-6 "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-7 "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-8 "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-9 "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-10 "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-11 "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), [AuthLoading](/api/modules/react.md#authloading) and [AuthRefreshing](/api/modules/react.md#authrefreshing) 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, AuthRefreshing } from "convex/react"; Logged in Logged out Still loading Refreshing token... ``` ### 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) *** ### QueryOptions[​](#queryoptions "Direct link to QueryOptions") Re-exports [QueryOptions](/api/modules/browser.md#queryoptions) ## 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. * `isLoading`: the client is still resolving the initial auth state and waiting for the server to confirm the current token. * `isAuthenticated`: the server has confirmed the current token. * `isRefreshing`: the server rejected a previously-confirmed token and the socket is paused while a replacement is fetched. Only ever `true` when `isAuthenticated` is also `true`. Routine background token rotation does not trigger this state. #### Type declaration[​](#type-declaration "Direct link to Type declaration") | Name | Type | | ----------------- | --------- | | `isLoading` | `boolean` | | `isAuthenticated` | `boolean` | | `isRefreshing` | `boolean` | #### Defined in[​](#defined-in "Direct link to Defined in") [react/ConvexAuthState.tsx:35](https://github.com/get-convex/convex-js/blob/main/src/react/ConvexAuthState.tsx#L35) *** ### 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:818](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L818) *** ### UseQueryResult[​](#usequeryresult "Direct link to UseQueryResult") Ƭ **UseQueryResult**<`QueryResult`, `ThrowOnError`>: { `status`: `"pending"` } | { `status`: `"success"` ; `data`: `QueryResult` } | `ThrowOnError` extends `true` ? `never` : { `status`: `"error"` ; `error`: `Error` } Result returned by object-form [useQuery\_experimental](/api/modules/react.md#usequery_experimental). #### Type parameters[​](#type-parameters-1 "Direct link to Type parameters") | Name | Type | | -------------- | --------------------------- | | `QueryResult` | `QueryResult` | | `ThrowOnError` | extends `boolean` = `false` | #### Defined in[​](#defined-in-2 "Direct link to Defined in") [react/client.ts:828](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L828) *** ### 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-2 "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-3 "Direct link to Defined in") [react/hydration.tsx:12](https://github.com/get-convex/convex-js/blob/main/src/react/hydration.tsx#L12) *** ### PaginatedQueryReference[​](#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-4 "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-3 "Direct link to Type parameters") | Name | | ------ | | `Item` | #### Defined in[​](#defined-in-5 "Direct link to Defined in") [react/use\_paginated\_query.ts:506](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L506) *** ### 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-6 "Direct link to Defined in") [react/use\_paginated\_query.ts:547](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L547) *** ### 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-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:555](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L555) *** ### 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-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:564](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L564) *** ### 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-6 "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`PaginatedQueryReference`](/api/modules/react.md#paginatedqueryreference) | #### Defined in[​](#defined-in-9 "Direct link to Defined in") [react/use\_paginated\_query.ts:572](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L572) *** ### UsePaginatedQueryOptions[​](#usepaginatedqueryoptions "Direct link to UsePaginatedQueryOptions") Ƭ **UsePaginatedQueryOptions**<`Query`, `ThrowOnError`>: `Object` Options for object-form [usePaginatedQuery\_experimental](/api/modules/react.md#usepaginatedquery_experimental). #### Type parameters[​](#type-parameters-7 "Direct link to Type parameters") | Name | Type | | -------------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`PaginatedQueryReference`](/api/modules/react.md#paginatedqueryreference) | | `ThrowOnError` | extends `boolean` = `false` | #### Type declaration[​](#type-declaration-2 "Direct link to Type declaration") | Name | Type | Description | | ----------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `query` | `Query` | - | | `args` | [`PaginatedQueryArgs`](/api/modules/react.md#paginatedqueryargs)<`Query`> \| `"skip"` | - | | `initialNumItems` | `number` | - | | `throwOnError?` | `ThrowOnError` | When `true` (default for positional form), errors are thrown and caught by an error boundary. When `false` (default for object form), errors are returned as `{ status: "Error", error: Error }` instead of being thrown. | #### Defined in[​](#defined-in-10 "Direct link to Defined in") [react/use\_paginated\_query2.ts:22](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query2.ts#L22) *** ### UsePaginatedQueryObjectReturnType[​](#usepaginatedqueryobjectreturntype "Direct link to UsePaginatedQueryObjectReturnType") Ƭ **UsePaginatedQueryObjectReturnType**<`Query`, `ThrowOnError`>: { `data`: [`PaginatedQueryItem`](/api/modules/react.md#paginatedqueryitem)<`Query`>\[] | `undefined` ; `status`: `"pending"` ; `canLoadMore`: `false` ; `isLoading`: `true` ; `error`: `undefined` ; `loadMore`: (`numItems`: `number`) => `void` } | { `data`: [`PaginatedQueryItem`](/api/modules/react.md#paginatedqueryitem)<`Query`>\[] ; `status`: `"success"` ; `canLoadMore`: `boolean` ; `isLoading`: `false` ; `error`: `undefined` ; `loadMore`: (`numItems`: `number`) => `void` } | `ThrowOnError` extends `true` ? `never` : { `data`: [`PaginatedQueryItem`](/api/modules/react.md#paginatedqueryitem)<`Query`>\[] ; `status`: `"error"` ; `canLoadMore`: `false` ; `isLoading`: `false` ; `error`: `Error` ; `loadMore`: (`numItems`: `number`) => `void` } Return type of the object-form [usePaginatedQuery\_experimental](/api/modules/react.md#usepaginatedquery_experimental) overload. Uses lowercase query status (`"pending" | "success" | "error"`) and a `canLoadMore` boolean instead of the TitleCase pagination status strings used by the positional form. #### Type parameters[​](#type-parameters-8 "Direct link to Type parameters") | Name | Type | | -------------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`PaginatedQueryReference`](/api/modules/react.md#paginatedqueryreference) | | `ThrowOnError` | extends `boolean` = `false` | #### Defined in[​](#defined-in-11 "Direct link to Defined in") [react/use\_paginated\_query2.ts:46](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query2.ts#L46) *** ### 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-12 "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. See [ConvexAuthState](/api/modules/react.md#convexauthstate) for the meaning of each field. #### Returns[​](#returns "Direct link to Returns") `Object` The current [ConvexAuthState](/api/modules/react.md#convexauthstate). | Name | Type | | ----------------- | --------- | | `isLoading` | `boolean` | | `isAuthenticated` | `boolean` | | `isRefreshing` | `boolean` | #### Defined in[​](#defined-in-13 "Direct link to Defined in") [react/ConvexAuthState.tsx:53](https://github.com/get-convex/convex-js/blob/main/src/react/ConvexAuthState.tsx#L53) *** ### 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-14 "Direct link to Defined in") [react/ConvexAuthState.tsx:86](https://github.com/get-convex/convex-js/blob/main/src/react/ConvexAuthState.tsx#L86) *** ### 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-15 "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-16 "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-17 "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) *** ### AuthRefreshing[​](#authrefreshing "Direct link to AuthRefreshing") ▸ **AuthRefreshing**(`«destructured»`): `null` | `Element` Renders children while the client is refreshing the auth token for an already-authenticated session (the server rejected the current token and the socket is paused while a new one is fetched). Routine background token rotation does not trigger this state. Whether used inside of `` or not, children will only be rendered if the user is authenticated. #### Parameters[​](#parameters-4 "Direct link to Parameters") | Name | Type | | ---------------- | ----------- | | `«destructured»` | `Object` | | › `children` | `ReactNode` | #### Returns[​](#returns-5 "Direct link to Returns") `null` | `Element` #### Defined in[​](#defined-in-18 "Direct link to Defined in") [react/auth\_helpers.tsx:56](https://github.com/get-convex/convex-js/blob/main/src/react/auth_helpers.tsx#L56) *** ### 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-6 "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-19 "Direct link to Defined in") [react/client.ts:793](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L793) *** ### 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-5 "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-7 "Direct link to Returns") `null` | `ReactElement`<`any`, `any`> #### Defined in[​](#defined-in-20 "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 subscribes to a Convex query and causes a rerender whenever the query result changes. The subscription is managed automatically -- it starts when the component mounts and stops when it unmounts. Throws an error if not used under [ConvexProvider](/api/modules/react.md#convexprovider). **`Example`** ``` import { useQuery } from "convex/react"; import { api } from "../convex/_generated/api"; function TaskList() { // Reactively loads tasks, re-renders when data changes: const tasks = useQuery(api.tasks.list, { completed: false }); // Returns `undefined` while loading: if (tasks === undefined) return
Loading...
; return tasks.map((task) =>
{task.text}
); } // Pass "skip" to conditionally disable the query: function MaybeProfile({ userId }: { userId?: Id<"users"> }) { const profile = useQuery( api.users.get, userId ? { userId } : "skip", ); // ... } ``` **`See`** #### Type parameters[​](#type-parameters-9 "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 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-8 "Direct link to Returns") `Query`\[`"_returnType"`] | `undefined` the result of the query. Returns `undefined` while loading. #### Defined in[​](#defined-in-21 "Direct link to Defined in") [react/client.ts:885](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L885) *** ### useQuery\_experimental[​](#usequery_experimental "Direct link to useQuery_experimental") ▸ **useQuery\_experimental**<`Query`, `ThrowOnError`>(`options`): [`UseQueryResult`](/api/modules/react.md#usequeryresult)<`Query`\[`"_returnType"`], `ThrowOnError`> Load a reactive query within a React component using an options object. This is an experimental form of [useQuery](/api/modules/react.md#usequery) that accepts a single UseQueryOptions object instead of positional arguments. Consumers are expected to check the returned object `status` field to make proper use of the result. If an error occurs, it will be present in the result object unless `throwOnError` is `true`, in which case the error will be thrown instead. **`Example`** ``` import { useQuery_experimental as useQuery } from "convex/react"; import { api } from "../convex/_generated/api"; function TaskList() { const state = useQuery({ query: api.tasks.list, args: { completed: false } }); if (state.status === "pending") return
Loading...
; if (state.status === "error") return
Error: {state.error.message}
; return state.data.map((task) =>
{task.text}
); } ``` **`See`** #### Type parameters[​](#type-parameters-10 "Direct link to Type parameters") | Name | Type | | -------------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"query"`> | | `ThrowOnError` | extends `boolean` = `false` | #### Parameters[​](#parameters-7 "Direct link to Parameters") | Name | Type | Description | | --------- | ------------------------------------------ | -------------------------------------------------------- | | `options` | `UseQueryOptions`<`Query`, `ThrowOnError`> | Query options. Pass `args: "skip"` to disable the query. | #### Returns[​](#returns-9 "Direct link to Returns") [`UseQueryResult`](/api/modules/react.md#usequeryresult)<`Query`\[`"_returnType"`], `ThrowOnError`> the current query state as a [UseQueryResult](/api/modules/react.md#usequeryresult) object. #### Defined in[​](#defined-in-22 "Direct link to Defined in") [react/client.ts:949](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L949) *** ### 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). Returns a function that you can call to execute a Convex mutation. The returned function is stable across renders (same reference identity), so it can be safely used in dependency arrays and memoization. Mutations can optionally be configured with [optimistic updates](https://docs.convex.dev/client/react/optimistic-updates) for instant UI feedback. Throws an error if not used under [ConvexProvider](/api/modules/react.md#convexprovider). **`Example`** ``` import { useMutation } from "convex/react"; import { api } from "../convex/_generated/api"; function CreateTask() { const createTask = useMutation(api.tasks.create); const handleClick = async () => { await createTask({ text: "New task" }); }; return ; } ``` **`See`** #### Type parameters[​](#type-parameters-11 "Direct link to Type parameters") | Name | Type | | ---------- | ------------------------------------------------------------------------------------- | | `Mutation` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"mutation"`> | #### Parameters[​](#parameters-8 "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-10 "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-23 "Direct link to Defined in") [react/client.ts:1045](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L1045) *** ### 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). Returns a function that you can call to execute a Convex action. Actions can call third-party APIs and perform side effects. The returned function is stable across renders (same reference identity). **Error handling:** Actions can fail (e.g., if an external API is down). Always wrap action calls in try/catch or handle the rejected promise. **Note:** In most cases, calling an action directly from a client is an anti-pattern. Prefer having the client call a mutation that captures the user's intent (by writing to the database) and then schedules the action via `ctx.scheduler.runAfter`. This ensures the intent is durably recorded even if the client disconnects. Throws an error if not used under [ConvexProvider](/api/modules/react.md#convexprovider). **`Example`** ``` import { useAction } from "convex/react"; import { api } from "../convex/_generated/api"; function GenerateSummary() { const generate = useAction(api.ai.generateSummary); const handleClick = async () => { try { const summary = await generate({ text: "Some long text..." }); console.log(summary); } catch (error) { console.error("Action failed:", error); } }; return ; } ``` **`See`** #### Type parameters[​](#type-parameters-12 "Direct link to Type parameters") | Name | Type | | -------- | ----------------------------------------------------------------------------------- | | `Action` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"action"`> | #### Parameters[​](#parameters-9 "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-11 "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-24 "Direct link to Defined in") [react/client.ts:1114](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L1114) *** ### 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-12 "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-25 "Direct link to Defined in") [react/client.ts:1153](https://github.com/get-convex/convex-js/blob/main/src/react/client.ts#L1153) *** ### 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-13 "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`FunctionReference`](/api/modules/server.md#functionreference)<`"query"`> | #### Parameters[​](#parameters-10 "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-13 "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-26 "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-14 "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 | | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | | `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-14 "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-27 "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-15 "Direct link to Returns") `void` #### Defined in[​](#defined-in-28 "Direct link to Defined in") [react/use\_paginated\_query.ts:485](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L485) *** ### 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-15 "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 | | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | | `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-16 "Direct link to Returns") `void` #### Defined in[​](#defined-in-29 "Direct link to Defined in") [react/use\_paginated\_query.ts:618](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L618) *** ### 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-16 "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.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-30 "Direct link to Defined in") [react/use\_paginated\_query.ts:680](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L680) *** ### 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-17 "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 | | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `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-18 "Direct link to Returns") `void` #### Defined in[​](#defined-in-31 "Direct link to Defined in") [react/use\_paginated\_query.ts:729](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L729) *** ### 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-18 "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`PaginatedQueryReference`](/api/modules/react.md#paginatedqueryreference) | #### Parameters[​](#parameters-15 "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-19 "Direct link to Returns") `void` #### Defined in[​](#defined-in-32 "Direct link to Defined in") [react/use\_paginated\_query.ts:810](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query.ts#L810) *** ### 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-19 "Direct link to Type parameters") | Name | Type | | ------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`PaginatedQueryReference`](/api/modules/react.md#paginatedqueryreference) | #### Parameters[​](#parameters-16 "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-20 "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-33 "Direct link to Defined in") [react/use\_paginated\_query2.ts:133](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query2.ts#L133) ▸ **usePaginatedQuery\_experimental**<`Query`, `ThrowOnError`>(`options`): [`UsePaginatedQueryObjectReturnType`](/api/modules/react.md#usepaginatedqueryobjectreturntype)<`Query`, `ThrowOnError`> Experimental new usePaginatedQuery implementation that accepts an options object rather than positional arguments. #### Type parameters[​](#type-parameters-20 "Direct link to Type parameters") | Name | Type | | -------------- | ---------------------------------------------------------------------------------- | | `Query` | extends [`PaginatedQueryReference`](/api/modules/react.md#paginatedqueryreference) | | `ThrowOnError` | extends `boolean` = `false` | #### Parameters[​](#parameters-17 "Direct link to Parameters") | Name | Type | Description | | --------- | ----------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | | `options` | [`UsePaginatedQueryOptions`](/api/modules/react.md#usepaginatedqueryoptions)<`Query`, `ThrowOnError`> | A [UsePaginatedQueryOptions](/api/modules/react.md#usepaginatedqueryoptions) object including `query` and `args`. | #### Returns[​](#returns-21 "Direct link to Returns") [`UsePaginatedQueryObjectReturnType`](/api/modules/react.md#usepaginatedqueryobjectreturntype)<`Query`, `ThrowOnError`> A [UsePaginatedQueryObjectReturnType](/api/modules/react.md#usepaginatedqueryobjectreturntype) object with `data`, `status`, `canLoadMore`, `isLoading`, `error`, and `loadMore`. `status` is `"pending"` while loading, `"success"` when data is available, or `"error"` if the query threw. When `throwOnError` is `true`, the `"error"` status is excluded from the return type since errors will be thrown instead. `canLoadMore` is `true` only when idle and more pages exist. #### Defined in[​](#defined-in-34 "Direct link to Defined in") [react/use\_paginated\_query2.ts:159](https://github.com/get-convex/convex-js/blob/main/src/react/use_paginated_query2.ts#L159) *** ### 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-18 "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-22 "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-35 "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/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:43](https://github.com/get-convex/convex-js/blob/main/src/react-clerk/ConvexProviderWithClerk.tsx#L43) --- # 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) * [TransactionLimits](/api/interfaces/server.TransactionLimits.md) * [QueryMeta](/api/interfaces/server.QueryMeta.md) * [MutationMeta](/api/interfaces/server.MutationMeta.md) * [ActionMeta](/api/interfaces/server.ActionMeta.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) * [AdvancedRunQueryOptions](/api/interfaces/server.AdvancedRunQueryOptions.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 FilterKeysInApi\]: 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:287](https://github.com/get-convex/convex-js/blob/main/src/server/api.ts#L287) *** ### 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:397](https://github.com/get-convex/convex-js/blob/main/src/server/api.ts#L397) *** ### 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:405](https://github.com/get-convex/convex-js/blob/main/src/server/api.ts#L405) *** ### 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:439](https://github.com/get-convex/convex-js/blob/main/src/server/api.ts#L439) *** ### 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:450](https://github.com/get-convex/convex-js/blob/main/src/server/api.ts#L450) *** ### 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:464](https://github.com/get-convex/convex-js/blob/main/src/server/api.ts#L464) *** ### 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:476](https://github.com/get-convex/convex-js/blob/main/src/server/api.ts#L476) *** ### ValidatorTypeToReturnType[​](#validatortypetoreturntype "Direct link to ValidatorTypeToReturnType") Ƭ **ValidatorTypeToReturnType**<`T`>: `Promise`<`NullToUndefinedOrNull`<`T`>> | `NullToUndefinedOrNull`<`T`> #### Type parameters[​](#type-parameters-8 "Direct link to Type parameters") | Name | | ---- | | `T` | #### Defined in[​](#defined-in-10 "Direct link to Defined in") [server/api.ts:492](https://github.com/get-convex/convex-js/blob/main/src/server/api.ts#L492) *** ### AuditLogBody[​](#auditlogbody "Direct link to AuditLogBody") Ƭ **AuditLogBody**: `Object` #### Index signature[​](#index-signature "Direct link to Index signature") ▪ \[key: `string`]: [`AuditLogValue`](/api/modules/server.md#auditlogvalue) #### Defined in[​](#defined-in-11 "Direct link to Defined in") [server/audit\_logging.ts:5](https://github.com/get-convex/convex-js/blob/main/src/server/audit_logging.ts#L5) *** ### AuditLogValue[​](#auditlogvalue "Direct link to AuditLogValue") Ƭ **AuditLogValue**: `null` | `undefined` | `boolean` | `number` | `string` | `LogVar` | [`AuditLogValue`](/api/modules/server.md#auditlogvalue)\[] | { `[key: string]`: [`AuditLogValue`](/api/modules/server.md#auditlogvalue); } #### Defined in[​](#defined-in-12 "Direct link to Defined in") [server/audit\_logging.ts:6](https://github.com/get-convex/convex-js/blob/main/src/server/audit_logging.ts#L6) *** ### 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-13 "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-14 "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-9 "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-15 "Direct link to Defined in") [server/components/index.ts:45](https://github.com/get-convex/convex-js/blob/main/src/server/components/index.ts#L45) *** ### ComponentDefinition[​](#componentdefinition "Direct link to ComponentDefinition") Ƭ **ComponentDefinition**<`Exports`, `Env`>: `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-10 "Direct link to Type parameters") | Name | Type | | --------- | ----------------------------------------------------------------- | | `Exports` | extends `ComponentExports` = `any` | | `Env` | extends [`EnvDefinition`](/api/modules/server.md#envdefinition) = | #### Type declaration[​](#type-declaration-2 "Direct link to Type declaration") | Name | Type | Description | | ----------- | ----------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `use` | \(`definition`: `Definition`, `options?`: `UseOptions`<`Definition`>) => `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. | | `env` | `EnvRefFromDefinition`<`Env`> | References to this component's declared env vars. Pass one of these in `app.use(child, { env: { ... } })` to bind a child's env var by reference to this component's env var. | | `__env` | `Env` | Internal type-only property tracking env definition. **`Deprecated`** This is a type-only property, don't use it. | #### Defined in[​](#defined-in-16 "Direct link to Defined in") [server/components/index.ts:94](https://github.com/get-convex/convex-js/blob/main/src/server/components/index.ts#L94) *** ### EnvDefinition[​](#envdefinition "Direct link to EnvDefinition") Ƭ **EnvDefinition**: `Record`<`string`, `StringLikeValidator` | [`VOptional`](/api/modules/values.md#voptional)<`StringLikeValidator`>> A definition of environment variables for the app. Maps environment variable names to string-like validators. Use `v.string()` for a plain string, `v.literal("a")` for an enum value, or `v.union(v.literal("a"), v.literal("b"))` for an enum. Wrap in `v.optional(...)` for optional vars. **`Example`** ``` import { defineApp } from "convex/server"; import { v } from "convex/values"; const app = defineApp({ env: { OPENAI_API_KEY: v.string(), DEBUG_MODE: v.optional(v.string()), }, }); ``` #### Defined in[​](#defined-in-17 "Direct link to Defined in") [server/components/index.ts:215](https://github.com/get-convex/convex-js/blob/main/src/server/components/index.ts#L215) *** ### EnvFromDefinition[​](#envfromdefinition "Direct link to EnvFromDefinition") Ƭ **EnvFromDefinition**<`E`>: [`Expand`](/api/modules/server.md#expand)<{ \[K in keyof E as E\[K] extends VOptional\ ? never : K]: Infer\ } & { \[K in keyof E as E\[K] extends VOptional\ ? K : never]?: Infer\ }> Compute the typed environment object from an [EnvDefinition](/api/modules/server.md#envdefinition). Required entries get the validator's inferred string type; optional entries are `T | undefined`. #### Type parameters[​](#type-parameters-11 "Direct link to Type parameters") | Name | Type | | ---- | --------------------------------------------------------------- | | `E` | extends [`EnvDefinition`](/api/modules/server.md#envdefinition) | #### Defined in[​](#defined-in-18 "Direct link to Defined in") [server/components/index.ts:228](https://github.com/get-convex/convex-js/blob/main/src/server/components/index.ts#L228) *** ### EnvFromAppDefinition[​](#envfromappdefinition "Direct link to EnvFromAppDefinition") Ƭ **EnvFromAppDefinition**<`A`>: `A` extends [`AppDefinition`](/api/modules/server.md#appdefinition)\ ? [`EnvFromDefinition`](/api/modules/server.md#envfromdefinition)<`E`> : `Record`<`string`, `never`> Extract the typed environment from an [AppDefinition](/api/modules/server.md#appdefinition). #### Type parameters[​](#type-parameters-12 "Direct link to Type parameters") | Name | | ---- | | `A` | #### Defined in[​](#defined-in-19 "Direct link to Defined in") [server/components/index.ts:263](https://github.com/get-convex/convex-js/blob/main/src/server/components/index.ts#L263) *** ### AppDefinition[​](#appdefinition "Direct link to AppDefinition") Ƭ **AppDefinition**<`Env`>: `Object` An object of this type should be the default export of a convex.config.ts file in a component-aware convex 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-13 "Direct link to Type parameters") | Name | Type | | ----- | ------------------------------------------------------------------------------------------------------------------------- | | `Env` | extends [`EnvDefinition`](/api/modules/server.md#envdefinition) = [`EnvDefinition`](/api/modules/server.md#envdefinition) | #### Type declaration[​](#type-declaration-3 "Direct link to Type declaration") | Name | Type | Description | | ------- | ----------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `use` | \(`definition`: `Definition`, `options?`: `UseOptions`<`Definition`>) => `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 | | `env` | `EnvRefFromDefinition`<`Env`> | References to this app's declared env vars. Pass one of these in `app.use(child, { env: { ... } })` to bind a child's env var by reference to this app's env var. | | `__env` | `Env` | Internal type-only property tracking env definition. **`Deprecated`** This is a type-only property, don't use it. | #### Defined in[​](#defined-in-20 "Direct link to Defined in") [server/components/index.ts:275](https://github.com/get-convex/convex-js/blob/main/src/server/components/index.ts#L275) *** ### AnyChildComponents[​](#anychildcomponents "Direct link to AnyChildComponents") Ƭ **AnyChildComponents**: `Record`<`string`, `AnyComponentReference`> #### Defined in[​](#defined-in-21 "Direct link to Defined in") [server/components/index.ts:766](https://github.com/get-convex/convex-js/blob/main/src/server/components/index.ts#L766) *** ### AnyComponents[​](#anycomponents "Direct link to AnyComponents") Ƭ **AnyComponents**: [`AnyChildComponents`](/api/modules/server.md#anychildcomponents) #### Defined in[​](#defined-in-22 "Direct link to Defined in") [server/components/index.ts:806](https://github.com/get-convex/convex-js/blob/main/src/server/components/index.ts#L806) *** ### GenericDocument[​](#genericdocument "Direct link to GenericDocument") Ƭ **GenericDocument**: `Record`<`string`, [`Value`](/api/modules/values.md#value)> A document stored in Convex. #### Defined in[​](#defined-in-23 "Direct link to Defined in") [server/data\_model.ts:10](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L10) *** ### 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-24 "Direct link to Defined in") [server/data\_model.ts:19](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L19) *** ### 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-25 "Direct link to Defined in") [server/data\_model.ts:30](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L30) *** ### 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-26 "Direct link to Defined in") [server/data\_model.ts:38](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L38) *** ### GenericSearchIndexConfig[​](#genericsearchindexconfig "Direct link to GenericSearchIndexConfig") Ƭ **GenericSearchIndexConfig**: `Object` A type describing the configuration of a search index. #### Type declaration[​](#type-declaration-4 "Direct link to Type declaration") | Name | Type | | -------------- | -------- | | `searchField` | `string` | | `filterFields` | `string` | #### Defined in[​](#defined-in-27 "Direct link to Defined in") [server/data\_model.ts:44](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L44) *** ### 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-28 "Direct link to Defined in") [server/data\_model.ts:55](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L55) *** ### GenericVectorIndexConfig[​](#genericvectorindexconfig "Direct link to GenericVectorIndexConfig") Ƭ **GenericVectorIndexConfig**: `Object` A type describing the configuration of a vector index. #### Type declaration[​](#type-declaration-5 "Direct link to Type declaration") | Name | Type | | -------------- | -------- | | `vectorField` | `string` | | `dimensions` | `number` | | `filterFields` | `string` | #### Defined in[​](#defined-in-29 "Direct link to Defined in") [server/data\_model.ts:64](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L64) *** ### 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-30 "Direct link to Defined in") [server/data\_model.ts:76](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L76) *** ### 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-14 "Direct link to Type parameters") | Name | Type | | ----------- | ------------------------------------------------------------------- | | `Document` | extends [`GenericDocument`](/api/modules/server.md#genericdocument) | | `FieldPath` | extends `string` | #### Defined in[​](#defined-in-31 "Direct link to Defined in") [server/data\_model.ts:105](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L105) *** ### 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-15 "Direct link to Type parameters") | Name | Type | | ----------- | ------------------------------------------------------------------- | | `Document` | extends [`GenericDocument`](/api/modules/server.md#genericdocument) | | `FieldPath` | extends `string` | #### Defined in[​](#defined-in-32 "Direct link to Defined in") [server/data\_model.ts:121](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L121) *** ### GenericTableInfo[​](#generictableinfo "Direct link to GenericTableInfo") Ƭ **GenericTableInfo**: `Object` A type describing the document type and indexes in a table. #### Type declaration[​](#type-declaration-6 "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-33 "Direct link to Defined in") [server/data\_model.ts:146](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L146) *** ### 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-16 "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `TableInfo` | extends [`GenericTableInfo`](/api/modules/server.md#generictableinfo) | #### Defined in[​](#defined-in-34 "Direct link to Defined in") [server/data\_model.ts:158](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L158) *** ### 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-17 "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:168](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L168) *** ### 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-18 "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:177](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L177) *** ### 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-19 "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `TableInfo` | extends [`GenericTableInfo`](/api/modules/server.md#generictableinfo) | #### Defined in[​](#defined-in-37 "Direct link to Defined in") [server/data\_model.ts:183](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L183) *** ### 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-20 "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-38 "Direct link to Defined in") [server/data\_model.ts:190](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L190) *** ### 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-21 "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `TableInfo` | extends [`GenericTableInfo`](/api/modules/server.md#generictableinfo) | #### Defined in[​](#defined-in-39 "Direct link to Defined in") [server/data\_model.ts:201](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L201) *** ### 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-22 "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `TableInfo` | extends [`GenericTableInfo`](/api/modules/server.md#generictableinfo) | #### Defined in[​](#defined-in-40 "Direct link to Defined in") [server/data\_model.ts:208](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L208) *** ### 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-23 "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-41 "Direct link to Defined in") [server/data\_model.ts:215](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L215) *** ### 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-24 "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `TableInfo` | extends [`GenericTableInfo`](/api/modules/server.md#generictableinfo) | #### Defined in[​](#defined-in-42 "Direct link to Defined in") [server/data\_model.ts:226](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L226) *** ### 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-25 "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `TableInfo` | extends [`GenericTableInfo`](/api/modules/server.md#generictableinfo) | #### Defined in[​](#defined-in-43 "Direct link to Defined in") [server/data\_model.ts:233](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L233) *** ### 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-26 "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-44 "Direct link to Defined in") [server/data\_model.ts:240](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L240) *** ### 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-45 "Direct link to Defined in") [server/data\_model.ts:253](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L253) *** ### 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-1 "Direct link to Index signature") ▪ \[tableName: `string`]: { `document`: `any` ; `fieldPaths`: [`GenericFieldPaths`](/api/modules/server.md#genericfieldpaths) ; `indexes`: [`SystemIndexes`](/api/modules/server.md#systemindexes) ; `searchIndexes`: ; `vectorIndexes`: } #### Defined in[​](#defined-in-46 "Direct link to Defined in") [server/data\_model.ts:262](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L262) *** ### 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-27 "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `DataModel` | extends [`GenericDataModel`](/api/modules/server.md#genericdatamodel) | #### Defined in[​](#defined-in-47 "Direct link to Defined in") [server/data\_model.ts:276](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L276) *** ### 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-28 "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `DataModel` | extends [`GenericDataModel`](/api/modules/server.md#genericdatamodel) | | `TableName` | extends keyof `DataModel` | #### Defined in[​](#defined-in-48 "Direct link to Defined in") [server/data\_model.ts:285](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L285) *** ### 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-29 "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-49 "Direct link to Defined in") [server/data\_model.ts:294](https://github.com/get-convex/convex-js/blob/main/src/server/data_model.ts#L294) *** ### 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-30 "Direct link to Type parameters") | Name | Type | | ---- | -------------------------------------------------------------- | | `T` | extends [`Value`](/api/modules/values.md#value) \| `undefined` | #### Defined in[​](#defined-in-50 "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) *** ### TransactionMetric[​](#transactionmetric "Direct link to TransactionMetric") Ƭ **TransactionMetric**: `Object` Used and remaining amounts for a single transaction limit. #### Type declaration[​](#type-declaration-7 "Direct link to Type declaration") | Name | Type | | ----------- | -------- | | `used` | `number` | | `remaining` | `number` | #### Defined in[​](#defined-in-51 "Direct link to Defined in") [server/meta.ts:9](https://github.com/get-convex/convex-js/blob/main/src/server/meta.ts#L9) *** ### TransactionMetrics[​](#transactionmetrics "Direct link to TransactionMetrics") Ƭ **TransactionMetrics**: `Object` The remaining headroom for a transaction before hitting limits. See #### Type declaration[​](#type-declaration-8 "Direct link to Type declaration") | Name | Type | | ---------------------------- | --------------------------------------------------------------- | | `bytesRead` | [`TransactionMetric`](/api/modules/server.md#transactionmetric) | | `bytesWritten` | [`TransactionMetric`](/api/modules/server.md#transactionmetric) | | `databaseQueries` | [`TransactionMetric`](/api/modules/server.md#transactionmetric) | | `documentsRead` | [`TransactionMetric`](/api/modules/server.md#transactionmetric) | | `documentsWritten` | [`TransactionMetric`](/api/modules/server.md#transactionmetric) | | `functionsScheduled` | [`TransactionMetric`](/api/modules/server.md#transactionmetric) | | `scheduledFunctionArgsBytes` | [`TransactionMetric`](/api/modules/server.md#transactionmetric) | #### Defined in[​](#defined-in-52 "Direct link to Defined in") [server/meta.ts:21](https://github.com/get-convex/convex-js/blob/main/src/server/meta.ts#L21) *** ### FunctionMetadata[​](#functionmetadata "Direct link to FunctionMetadata") Ƭ **FunctionMetadata**: `Object` Metadata about the currently executing Convex function. #### Type declaration[​](#type-declaration-9 "Direct link to Type declaration") | Name | Type | Description | | --------------- | ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | | `name` | `string` | The name of the function, in the format `"path/to/module:functionName"` | | `componentPath` | `string` | The path of the component this function belongs to. This is an empty string `""` for the app. | | `type` | [`FunctionType`](/api/modules/server.md#functiontype) | Whether it's a query, mutation, or action. | | `visibility` | [`FunctionVisibility`](/api/modules/server.md#functionvisibility) | Whether the function is public or internal. | #### Defined in[​](#defined-in-53 "Direct link to Defined in") [server/meta.ts:53](https://github.com/get-convex/convex-js/blob/main/src/server/meta.ts#L53) *** ### DeploymentMetadata[​](#deploymentmetadata "Direct link to DeploymentMetadata") Ƭ **DeploymentMetadata**: `Object` Metadata about the deployment this function is running on. #### Type declaration[​](#type-declaration-10 "Direct link to Type declaration") | Name | Type | Description | | -------- | --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | `string` | The deployment name, e.g. `"tall-tiger-123"` for cloud deployments, `"local-my_team-my_project"` for local deployments, or `"anonymous-*"` for anonymous deployments. | | `region` | `string` \| `null` | The deployment region, e.g. `"aws-us-east-1"`. `null` for local and self-hosted deployments. | | `class` | `"s16"` \| `"s256"` \| `"d1024"` \| `"d2048"` | The deployment class, e.g. `"s16"`, `"s256"`, `"d1024"`, or `"d2048"`. | #### Defined in[​](#defined-in-54 "Direct link to Defined in") [server/meta.ts:74](https://github.com/get-convex/convex-js/blob/main/src/server/meta.ts#L74) *** ### RequestMetadata[​](#requestmetadata "Direct link to RequestMetadata") Ƭ **RequestMetadata**: `Object` Metadata about the HTTP request that triggered the current function execution. `ip` and `userAgent` are `null` when the function was not triggered by an HTTP request (e.g. scheduled jobs or cron jobs). Functions called from within a function (i.e. using `runMutation` or `runAction`) will have the same request metadata as the parent function. #### Type declaration[​](#type-declaration-11 "Direct link to Type declaration") | Name | Type | Description | | --------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `ip` | `string` \| `null` | - | | `userAgent` | `string` \| `null` | - | | `requestId` | `string` | - | | `scheduledFunctionId` | `string` \| `null` | The ID of the scheduled function document (in `_scheduled_functions`) that this execution belongs to, or `null` otherwise. This is set for the scheduled function itself and for any functions it calls (e.g. a mutation invoked via `runMutation` by a scheduled action), propagating the top-level scheduled function's ID down the call tree. It is `null` when the function was not scheduled. | | `authToken` | `string` \| `null` | The raw auth token (a JWT) the request was authenticated with, or `null` when the request was unauthenticated or authenticated with an admin key. This is the same token that `ctx.auth.getUserIdentity()` derives its attributes from. | #### Defined in[​](#defined-in-55 "Direct link to Defined in") [server/meta.ts:103](https://github.com/get-convex/convex-js/blob/main/src/server/meta.ts#L103) *** ### 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-56 "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. You should generally use the `MutationCtx` type from `"./_generated/server"`. #### Type parameters[​](#type-parameters-31 "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `DataModel` | extends [`GenericDataModel`](/api/modules/server.md#genericdatamodel) | #### Defined in[​](#defined-in-57 "Direct link to Defined in") [server/registration.ts:172](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L172) *** ### 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-32 "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------- | | `DataModel` | extends [`GenericDataModel`](/api/modules/server.md#genericdatamodel) | #### Defined in[​](#defined-in-58 "Direct link to Defined in") [server/registration.ts:266](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L266) *** ### 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-59 "Direct link to Defined in") [server/registration.ts:424](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L424) *** ### 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-60 "Direct link to Defined in") [server/registration.ts:447](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L447) *** ### 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-33 "Direct link to Type parameters") | Name | Type | | ------ | ------------------------------------------------------- | | `Args` | extends [`ArgsArray`](/api/modules/server.md#argsarray) | #### Defined in[​](#defined-in-61 "Direct link to Defined in") [server/registration.ts:462](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L462) *** ### FunctionVisibility[​](#functionvisibility "Direct link to FunctionVisibility") Ƭ **FunctionVisibility**: `"public"` | `"internal"` A type representing the visibility of a Convex function. #### Defined in[​](#defined-in-62 "Direct link to Defined in") [server/registration.ts:470](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L470) *** ### 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-34 "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-63 "Direct link to Defined in") [server/registration.ts:495](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L495) *** ### 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-35 "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-64 "Direct link to Defined in") [server/registration.ts:524](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L524) *** ### 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-36 "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-65 "Direct link to Defined in") [server/registration.ts:553](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L553) *** ### 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-12 "Direct link to Type declaration") | Name | Type | | -------- | ------ | | `isHttp` | `true` | #### Defined in[​](#defined-in-66 "Direct link to Defined in") [server/registration.ts:582](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L582) *** ### 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-37 "Direct link to Type parameters") | Name | Type | | --------- | ------------------------------------------------------- | | `Ctx` | `Ctx` | | `Args` | extends [`ArgsArray`](/api/modules/server.md#argsarray) | | `Returns` | `Returns` | #### Defined in[​](#defined-in-67 "Direct link to Defined in") [server/registration.ts:620](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L620) *** ### ReturnValueForOptionalValidator[​](#returnvalueforoptionalvalidator "Direct link to ReturnValueForOptionalValidator") Ƭ **ReturnValueForOptionalValidator**<`ReturnsValidator`>: \[`ReturnsValidator`] extends \[[`Validator`](/api/modules/values.md#validator)<`any`, `any`, `any`>] ? [`ValidatorTypeToReturnType`](/api/modules/server.md#validatortypetoreturntype)<[`Infer`](/api/modules/values.md#infer)<`ReturnsValidator`>> : \[`ReturnsValidator`] extends \[[`PropertyValidators`](/api/modules/values.md#propertyvalidators)] ? [`ValidatorTypeToReturnType`](/api/modules/server.md#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-38 "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-68 "Direct link to Defined in") [server/registration.ts:722](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L722) *** ### 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-39 "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-69 "Direct link to Defined in") [server/registration.ts:730](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L730) *** ### 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-40 "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-70 "Direct link to Defined in") [server/registration.ts:738](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L738) *** ### 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-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-13 "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-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 "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-71 "Direct link to Defined in") [server/registration.ts:752](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L752) *** ### 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-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-14 "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-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-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-72 "Direct link to Defined in") [server/registration.ts:845](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L845) *** ### 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-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-15 "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-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-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-73 "Direct link to Defined in") [server/registration.ts:938](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L938) *** ### 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-47 "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-16 "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-48 "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-74 "Direct link to Defined in") [server/registration.ts:1027](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L1027) *** ### 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-49 "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-17 "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-50 "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-75 "Direct link to Defined in") [server/registration.ts:1116](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L1116) *** ### 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-18 "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-76 "Direct link to Defined in") [server/registration.ts:1211](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L1211) *** ### 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-77 "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-19 "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-78 "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-20 "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-79 "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-80 "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-81 "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-82 "Direct link to Defined in") [server/schema.ts:667](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L667) *** ### 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-51 "Direct link to Type parameters") | Name | Type | | ----------- | --------------------------------------------------------------------------------------- | | `SchemaDef` | extends [`SchemaDefinition`](/api/classes/server.SchemaDefinition.md)<`any`, `boolean`> | #### Defined in[​](#defined-in-83 "Direct link to Defined in") [server/schema.ts:847](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L847) *** ### SystemTableNames[​](#systemtablenames "Direct link to SystemTableNames") Ƭ **SystemTableNames**: [`TableNamesInDataModel`](/api/modules/server.md#tablenamesindatamodel)<[`SystemDataModel`](/api/interfaces/server.SystemDataModel.md)> #### Defined in[​](#defined-in-84 "Direct link to Defined in") [server/schema.ts:906](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L906) *** ### StorageId[​](#storageid "Direct link to StorageId") Ƭ **StorageId**: `string` **`Deprecated`** This ID format is no longer returned by stable file storage APIs. Use `Id<"_storage">` instead. The old ID format used by Convex file storage. ⚠️ Security warning: Anyone that has knows to this ID can download the underlying file from `https://.convex.cloud/api/storage/`. (Note that it’s safe to share the new ID format, `Id<"_storage">`, to anyone). #### Defined in[​](#defined-in-85 "Direct link to Defined in") [server/storage.ts:14](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L14) *** ### FileStorageId[​](#filestorageid "Direct link to FileStorageId") Ƭ **FileStorageId**: [`GenericId`](/api/modules/values.md#genericid)<`"_storage"`> | [`StorageId`](/api/modules/server.md#storageid) **`Deprecated`** This type is only necessary for backwards compatibility with Convex versions that pre-date `convex@1.6.0`. Use `Id<"_storage">` instead. #### Defined in[​](#defined-in-86 "Direct link to Defined in") [server/storage.ts:20](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L20) *** ### FileMetadata[​](#filemetadata "Direct link to FileMetadata") Ƭ **FileMetadata**: `Object` **`Deprecated`** This type is only returned by [storage.getUrl](/api/interfaces/server.StorageReader.md#geturl). To get the details of a document, use `ctx.db.system.get("_storage", storageId)` instead. Metadata for a single file as returned by [storage.getMetadata](/api/interfaces/server.StorageReader.md#getmetadata). #### Type declaration[​](#type-declaration-21 "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)) This is an older ID format that is no longer returned by stable file storage APIs. Consider using `Id<"_storage">` instead. ⚠️ Security warning: Anyone that has knows to this ID can download the underlying file from `https://.convex.cloud/api/storage/`. (Note that it’s safe to share the new ID format, `Id<"_storage">`, to anyone). | | `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-87 "Direct link to Defined in") [server/storage.ts:30](https://github.com/get-convex/convex-js/blob/main/src/server/storage.ts#L30) *** ### 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-22 "Direct link to Type declaration") | Name | Type | | --------------- | -------- | | `_creationTime` | `number` | #### Defined in[​](#defined-in-88 "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-52 "Direct link to Type parameters") | Name | Type | | ----------- | ---------------- | | `TableName` | extends `string` | #### Type declaration[​](#type-declaration-23 "Direct link to Type declaration") | Name | Type | | ----- | ------------------------------------------------------------ | | `_id` | [`GenericId`](/api/modules/values.md#genericid)<`TableName`> | #### Defined in[​](#defined-in-89 "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-53 "Direct link to Type parameters") | Name | Type | | ---------- | ------------------------------------------------------------------- | | `Document` | extends [`GenericDocument`](/api/modules/server.md#genericdocument) | #### Defined in[​](#defined-in-90 "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-54 "Direct link to Type parameters") | Name | Type | | ---------- | ------------------------------------------------------------------- | | `Document` | extends [`GenericDocument`](/api/modules/server.md#genericdocument) | #### Defined in[​](#defined-in-91 "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-24 "Direct link to Type declaration") | Name | Type | | ------------------ | -------------------- | | `by_id` | \[`"_id"`] | | `by_creation_time` | \[`"_creationTime"`] | #### Defined in[​](#defined-in-92 "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-93 "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-55 "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-25 "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-94 "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-56 "Direct link to Type parameters") | Name | Type | | ------------ | ------------------------------ | | `ObjectType` | extends `Record`<`any`, `any`> | #### Defined in[​](#defined-in-95 "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-57 "Direct link to Type parameters") | Name | Type | | ---- | ----------------- | | `T` | `T` | | `K` | extends keyof `T` | #### Defined in[​](#defined-in-96 "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-97 "Direct link to Defined in") [server/api.ts:431](https://github.com/get-convex/convex-js/blob/main/src/server/api.ts#L431) *** ### log[​](#log "Direct link to log") • `Const` **log**: `Log` #### Defined in[​](#defined-in-98 "Direct link to Defined in") [server/log.ts:31](https://github.com/get-convex/convex-js/blob/main/src/server/log.ts#L31) *** ### 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). Use this as the args validator in paginated query functions so that clients can pass pagination options. **`Example`** ``` import { query } from "./_generated/server"; import { paginationOptsValidator } from "convex/server"; import { v } from "convex/values"; export const listMessages = query({ args: { channelId: v.id("channels"), paginationOpts: paginationOptsValidator, }, handler: async (ctx, args) => { return await ctx.db .query("messages") .withIndex("by_channel", (q) => q.eq("channelId", args.channelId)) .order("desc") .paginate(args.paginationOpts); }, }); ``` On the client, use `usePaginatedQuery` from `"convex/react"`: ``` const { results, status, loadMore } = usePaginatedQuery( api.messages.listMessages, { channelId }, { initialNumItems: 25 }, ); ``` **`See`** #### Defined in[​](#defined-in-99 "Direct link to Defined in") [server/pagination.ts:163](https://github.com/get-convex/convex-js/blob/main/src/server/pagination.ts#L163) *** ### 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-100 "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-101 "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-58 "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-102 "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-59 "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-103 "Direct link to Defined in") [server/api.ts:305](https://github.com/get-convex/convex-js/blob/main/src/server/api.ts#L305) *** ### 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-60 "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-104 "Direct link to Defined in") [server/components/index.ts:64](https://github.com/get-convex/convex-js/blob/main/src/server/components/index.ts#L64) *** ### defineComponent[​](#definecomponent "Direct link to defineComponent") ▸ **defineComponent**<`Exports`, `Env`>(`name`, `options?`): [`ComponentDefinition`](/api/modules/server.md#componentdefinition)<`Exports`, `Env`> Define a component, a piece of a Convex deployment with namespaced resources. Optionally define typed environment variables that will be available via the `env` export from `_generated/server` in all Convex functions within this component. Values are passed by the parent via `app.use(component, { env: { ... } })`. #### Type parameters[​](#type-parameters-61 "Direct link to Type parameters") | Name | Type | | --------- | ----------------------------------------------------------------- | | `Exports` | extends `ComponentExports` = `any` | | `Env` | extends [`EnvDefinition`](/api/modules/server.md#envdefinition) = | #### Parameters[​](#parameters-11 "Direct link to Parameters") | Name | Type | Description | | -------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | `string` | 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. | | `options?` | `Object` | - | | `options.env?` | `Env` | - | #### Returns[​](#returns-11 "Direct link to Returns") [`ComponentDefinition`](/api/modules/server.md#componentdefinition)<`Exports`, `Env`> #### Defined in[​](#defined-in-105 "Direct link to Defined in") [server/components/index.ts:663](https://github.com/get-convex/convex-js/blob/main/src/server/components/index.ts#L663) *** ### defineApp[​](#defineapp "Direct link to defineApp") ▸ **defineApp**<`Env`>(`options?`): [`AppDefinition`](/api/modules/server.md#appdefinition)<`Env`> Attach components, reuseable pieces of a Convex deployment, to this Convex app. Optionally define typed environment variables that will be available via the `env` export from `_generated/server` in all Convex functions. **`Example`** ``` import { defineApp } from "convex/server"; import { v } from "convex/values"; const app = defineApp({ env: { OPENAI_API_KEY: v.string(), DEBUG_MODE: v.optional(v.string()), }, }); export default app; ``` This is a feature of components, which are in beta. This API is unstable and may change in subsequent releases. #### Type parameters[​](#type-parameters-62 "Direct link to Type parameters") | Name | Type | | ----- | ------------------------------------------------------------------------------------------------------------------------- | | `Env` | extends [`EnvDefinition`](/api/modules/server.md#envdefinition) = [`EnvDefinition`](/api/modules/server.md#envdefinition) | #### Parameters[​](#parameters-12 "Direct link to Parameters") | Name | Type | | --------------------- | -------- | | `options?` | `Object` | | `options.httpPrefix?` | `string` | | `options.env?` | `Env` | #### Returns[​](#returns-12 "Direct link to Returns") [`AppDefinition`](/api/modules/server.md#appdefinition)<`Env`> #### Defined in[​](#defined-in-106 "Direct link to Defined in") [server/components/index.ts:726](https://github.com/get-convex/convex-js/blob/main/src/server/components/index.ts#L726) *** ### 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-107 "Direct link to Defined in") [server/components/index.ts:804](https://github.com/get-convex/convex-js/blob/main/src/server/components/index.ts#L804) *** ### 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-13 "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-108 "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-109 "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. You should generally use the `mutation` function from `"./_generated/server"`. Mutations can read from and write to the database, and are accessible from the client. They run **transactionally**, all database reads and writes within a single mutation are atomic and isolated from other mutations. **`Example`** ``` import { mutation } from "./_generated/server"; import { v } from "convex/values"; export const createTask = mutation({ args: { text: v.string() }, returns: v.id("tasks"), handler: async (ctx, args) => { const taskId = await ctx.db.insert("tasks", { text: args.text, completed: false, }); return taskId; }, }); ``` **Best practice:** Always include `args` and `returns` validators on all mutations. If the function doesn't return a value, use `returns: v.null()`. Argument validation is critical for security since public mutations are exposed to the internet. **Common mistake:** Mutations cannot call third-party APIs or use `fetch`. They must be deterministic. Use actions for external API calls. **Common mistake:** Do not use `mutation` for sensitive internal functions that should not be called by clients. Use `internalMutation` instead. **`See`** #### 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-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-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-110 "Direct link to Defined in") [server/registration.ts:756](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L756) *** ### 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). You should generally use the `internalMutation` function from `"./_generated/server"`. Internal mutations can read from and write to the database but are **not** exposed as part of your app's public API. They can only be called by other Convex functions using `ctx.runMutation` or by the scheduler. Like public mutations, they run transactionally. **`Example`** ``` import { internalMutation } from "./_generated/server"; import { v } from "convex/values"; // This mutation can only be called from other Convex functions: export const markTaskCompleted = internalMutation({ args: { taskId: v.id("tasks") }, returns: v.null(), handler: async (ctx, args) => { await ctx.db.patch("tasks", args.taskId, { completed: true }); return null; }, }); ``` **Best practice:** Use `internalMutation` for any mutation that should not be directly callable by clients, such as write-back functions from actions or scheduled background work. Reference it via the `internal` object: `await ctx.runMutation(internal.myModule.markTaskCompleted, { taskId })`. **`See`** #### Type parameters[​](#type-parameters-64 "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 | | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `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-111 "Direct link to Defined in") [server/registration.ts:756](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L756) *** ### 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. You should generally use the `query` function from `"./_generated/server"`. Queries can read from the database and are accessible from the client. They are **reactive**, when used with `useQuery` in React, the component automatically re-renders whenever the underlying data changes. Queries cannot modify the database. Query results are automatically cached by the Convex client and kept consistent via WebSocket subscriptions. **`Example`** ``` import { query } from "./_generated/server"; import { v } from "convex/values"; export const listTasks = query({ args: { completed: v.optional(v.boolean()) }, returns: v.array(v.object({ _id: v.id("tasks"), _creationTime: v.number(), text: v.string(), completed: v.boolean(), })), handler: async (ctx, args) => { if (args.completed !== undefined) { return await ctx.db .query("tasks") .withIndex("by_completed", (q) => q.eq("completed", args.completed)) .collect(); } return await ctx.db.query("tasks").collect(); }, }); ``` **Best practice:** Always include `args` and `returns` validators. Use `.withIndex()` instead of `.filter()` for efficient database queries. Queries should be fast since they run on every relevant data change. **Common mistake:** Queries are pure reads, they cannot write to the database, call external APIs, or schedule functions. Use actions for HTTP calls and mutations for database writes and scheduling. **`See`** #### Type parameters[​](#type-parameters-65 "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-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-112 "Direct link to Defined in") [server/registration.ts:942](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L942) *** ### 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). You should generally use the `internalQuery` function from `"./_generated/server"`. Internal queries can read from the database but are **not** exposed as part of your app's public API. They can only be called by other Convex functions using `ctx.runQuery`. This is useful for loading data in actions or for helper queries that shouldn't be client-facing. **`Example`** ``` import { internalQuery } from "./_generated/server"; import { v } from "convex/values"; // Only callable from other Convex functions: export const getUser = internalQuery({ args: { userId: v.id("users") }, returns: v.union( v.object({ _id: v.id("users"), _creationTime: v.number(), name: v.string(), email: v.string(), }), v.null(), ), handler: async (ctx, args) => { return await ctx.db.get("users", args.userId); }, }); ``` **Best practice:** Use `internalQuery` for data-loading in actions via `ctx.runQuery(internal.myModule.getUser, { userId })`. **`See`** #### Type parameters[​](#type-parameters-66 "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 | | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `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-113 "Direct link to Defined in") [server/registration.ts:942](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L942) *** ### 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. Actions can call third-party APIs, use Node.js libraries, and perform other side effects. Unlike queries and mutations, actions do **not** have direct database access (`ctx.db` is not available). Instead, use `ctx.runQuery` and `ctx.runMutation` to read and write data. You should generally use the `action` function from `"./_generated/server"`. Actions are accessible from the client and run outside of the database transaction, so they are not atomic. They are best for integrating with external services. **`Example`** ``` // Add "use node"; at the top of the file if using Node.js built-in modules. import { action } from "./_generated/server"; import { v } from "convex/values"; import { internal } from "./_generated/api"; export const generateSummary = action({ args: { text: v.string() }, returns: v.string(), handler: async (ctx, args) => { // Call an external API: const response = await fetch("https://api.example.com/summarize", { method: "POST", body: JSON.stringify({ text: args.text }), }); const { summary } = await response.json(); // Write results back via a mutation: await ctx.runMutation(internal.myModule.saveSummary, { text: args.text, summary, }); return summary; }, }); ``` **Best practice:** Minimize the number of `ctx.runQuery` and `ctx.runMutation` calls from actions. Each call is a separate transaction, so splitting logic across multiple calls introduces the risk of race conditions. Try to batch reads/writes into single query/mutation calls. **`"use node"` runtime:** Actions run in Convex's default JavaScript runtime, which supports `fetch` and most NPM packages. Only add `"use node";` at the top of the file if a third-party library specifically requires Node.js built-in APIs, it is a last resort, not the default. Node.js actions have slower cold starts, and **only actions can be defined in `"use node"` files** (no queries or mutations), so prefer the default runtime whenever possible. **Common mistake:** Do not try to access `ctx.db` in an action, it is not available. Use `ctx.runQuery` and `ctx.runMutation` instead. **`See`** #### Type parameters[​](#type-parameters-67 "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-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-114 "Direct link to Defined in") [server/registration.ts:1120](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L1120) *** ### 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). You should generally use the `internalAction` function from `"./_generated/server"`. Internal actions behave like public actions (they can call external APIs and use Node.js libraries) but are **not** exposed in your app's public API. They can only be called by other Convex functions using `ctx.runAction` or via the scheduler. **`Example`** ``` import { internalAction } from "./_generated/server"; import { v } from "convex/values"; export const sendEmail = internalAction({ args: { to: v.string(), subject: v.string(), body: v.string() }, returns: v.null(), handler: async (ctx, args) => { // Call an external email service (fetch works in the default runtime): await fetch("https://api.email-service.com/send", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(args), }); return null; }, }); ``` **Best practice:** Use `internalAction` for background work scheduled from mutations: `await ctx.scheduler.runAfter(0, internal.myModule.sendEmail, { ... })`. Only use `ctx.runAction` from another action if you need to cross runtimes (e.g., default Convex runtime to Node.js). Otherwise, extract shared code into a helper function. **`"use node"` runtime:** Only add `"use node";` at the top of the file as a last resort when a third-party library requires Node.js APIs. Node.js actions have slower cold starts, and **only actions can be defined in `"use node"` files** (no queries or mutations). **`See`** #### Type parameters[​](#type-parameters-68 "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-19 "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-115 "Direct link to Defined in") [server/registration.ts:1120](https://github.com/get-convex/convex-js/blob/main/src/server/registration.ts#L1120) *** ### httpActionGeneric[​](#httpactiongeneric "Direct link to httpActionGeneric") ▸ **httpActionGeneric**(`func`): [`PublicHttpAction`](/api/modules/server.md#publichttpaction) Define a Convex HTTP action. HTTP actions handle raw HTTP requests and return HTTP responses. They are registered by routing URL paths to them in `convex/http.ts` using [HttpRouter](/api/classes/server.HttpRouter.md). Like regular actions, they can call external APIs and use `ctx.runQuery` / `ctx.runMutation` but do not have direct `ctx.db` access. **`Example`** ``` // convex/http.ts import { httpRouter } from "convex/server"; import { httpAction } from "./_generated/server"; const http = httpRouter(); http.route({ path: "/api/webhook", method: "POST", handler: httpAction(async (ctx, request) => { const body = await request.json(); // Process the webhook payload... return new Response(JSON.stringify({ ok: true }), { status: 200, headers: { "Content-Type": "application/json" }, }); }), }); export default http; ``` **Best practice:** HTTP actions are registered at the exact path specified. For example, `path: "/api/webhook"` registers at `/api/webhook`. **`See`** #### Parameters[​](#parameters-20 "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 a [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.ts`. #### Defined in[​](#defined-in-116 "Direct link to Defined in") [server/impl/registration\_impl.ts:741](https://github.com/get-convex/convex-js/blob/main/src/server/impl/registration_impl.ts#L741) *** ### 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-69 "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-21 "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-117 "Direct link to Defined in") [server/pagination.ts:192](https://github.com/get-convex/convex-js/blob/main/src/server/pagination.ts#L192) *** ### 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-118 "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-70 "Direct link to Type parameters") | Name | Type | | ---------------- | ------------------------------------------------------------------------------------------------------- | | `DocumentSchema` | extends [`Validator`](/api/modules/values.md#validator)<`Record`<`string`, `any`>, `"required"`, `any`> | #### Parameters[​](#parameters-22 "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-119 "Direct link to Defined in") [server/schema.ts:615](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L615) ▸ **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-71 "Direct link to Type parameters") | Name | Type | | ---------------- | ----------------------------------------------------------------------------------------- | | `DocumentSchema` | extends `Record`<`string`, [`GenericValidator`](/api/modules/values.md#genericvalidator)> | #### Parameters[​](#parameters-23 "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-120 "Direct link to Defined in") [server/schema.ts:643](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L643) *** ### 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 as the default export from a `schema.ts` file in your `convex/` directory. The schema enables runtime validation of documents and provides end-to-end TypeScript type safety. Every document in Convex automatically has two system fields: * `_id` - a unique document ID with validator `v.id("tableName")` * `_creationTime` - a creation timestamp with validator `v.number()` You do not need to include these in your schema definition, they are added automatically. **`Example`** ``` // convex/schema.ts import { defineSchema, defineTable } from "convex/server"; import { v } from "convex/values"; export default defineSchema({ users: defineTable({ name: v.string(), email: v.string(), }).index("by_email", ["email"]), messages: defineTable({ body: v.string(), userId: v.id("users"), channelId: v.id("channels"), }).index("by_channel", ["channelId"]), channels: defineTable({ name: v.string(), }), // Discriminated union table: results: defineTable( v.union( v.object({ kind: v.literal("error"), message: v.string() }), v.object({ kind: v.literal("success"), value: v.number() }), ) ), }); ``` **Best practice:** Always include all index fields in the index name. For example, an index on `["field1", "field2"]` should be named `"by_field1_field2"`. **`See`** #### Type parameters[​](#type-parameters-72 "Direct link to Type parameters") | Name | Type | | ---------------------- | --------------------------------------------------------------- | | `Schema` | extends [`GenericSchema`](/api/modules/server.md#genericschema) | | `StrictTableNameTypes` | extends `boolean` = `true` | #### Parameters[​](#parameters-24 "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-121 "Direct link to Defined in") [server/schema.ts:830](https://github.com/get-convex/convex-js/blob/main/src/server/schema.ts#L830) --- # 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:424](https://github.com/get-convex/convex-js/blob/main/src/values/validator.ts#L424) *** ### 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:434](https://github.com/get-convex/convex-js/blob/main/src/values/validator.ts#L434) *** ### 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:476](https://github.com/get-convex/convex-js/blob/main/src/values/validator.ts#L476) *** ### 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:648](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L648) *** ### 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:681](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L681) *** ### 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:706](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L706) *** ### 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:747](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L747) *** ### 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:749](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L749) *** ### 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:768](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L768) *** ### 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:773](https://github.com/get-convex/convex-js/blob/main/src/values/validators.ts#L773) *** ### 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(tableName, 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 are used in two places: 1. **Schema definitions** - to define the shape of documents in your tables. 2. **Function arguments and return values** - to validate inputs and outputs of your Convex queries, mutations, and actions. Always include `args` and `returns` validators on all Convex functions. If a function doesn't return a value, use `returns: v.null()`. **Convex type reference:** | Convex Type | JS/TS Type | Validator | | ----------- | ------------- | ---------------------------- | | Id | `string` | `v.id("tableName")` | | Null | `null` | `v.null()` | | Float64 | `number` | `v.number()` | | Int64 | `bigint` | `v.int64()` | | Boolean | `boolean` | `v.boolean()` | | String | `string` | `v.string()` | | Bytes | `ArrayBuffer` | `v.bytes()` | | Array | `Array` | `v.array(element)` | | Object | `Object` | `v.object({ field: value })` | | Record | `Record` | `v.record(keys, values)` | **Modifiers and meta-types:** * `v.union(member1, member2)` - a value matching at least one validator * `v.literal("value")` - a specific literal string, number, bigint, or boolean * `v.optional(validator)` - makes a property optional in an object (`T | undefined`) **Important notes:** * JavaScript's `undefined` is **not** a valid Convex value. Functions that return `undefined` or have no return will return `null` to the client. Objects with `undefined` values will strip those keys during serialization. For arrays, use an explicit `null` instead. * `v.bigint()` is deprecated, use `v.int64()` instead. * `v.map()` and `v.set()` are not supported. Use `v.array()` of tuples or `v.record()` as alternatives. **`Example`** ``` import { v } from "convex/values"; // Use in function definition: export const createUser = mutation({ args: { name: v.string(), email: v.string(), age: v.optional(v.number()), }, returns: v.id("users"), handler: async (ctx, args) => { return await ctx.db.insert("users", args); }, }); ``` **`See`** * * #### 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:134](https://github.com/get-convex/convex-js/blob/main/src/values/validator.ts#L134) ## 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) *** ### getConvexSize[​](#getconvexsize "Direct link to getConvexSize") ▸ **getConvexSize**(`value`): `number` Calculate the size in bytes of a Convex value. This matches how Convex calculates document size for bandwidth tracking and size limit enforcement. #### Parameters[​](#parameters-1 "Direct link to Parameters") | Name | Type | Description | | ------- | ------------------------------------------------------ | ------------------------- | | `value` | `undefined` \| [`Value`](/api/modules/values.md#value) | A Convex value to measure | #### Returns[​](#returns-1 "Direct link to Returns") `number` The size in bytes #### Defined in[​](#defined-in-18 "Direct link to Defined in") [values/size.ts:40](https://github.com/get-convex/convex-js/blob/main/src/values/size.ts#L40) *** ### getDocumentSize[​](#getdocumentsize "Direct link to getDocumentSize") ▸ **getDocumentSize**(`value`, `options?`): `number` Calculate the size of a document including system fields. If your value already has \_id and \_creationTime fields, this will count them in the normal size calculation. Otherwise, it adds the constant overhead for system fields. #### Parameters[​](#parameters-2 "Direct link to Parameters") | Name | Type | Description | | ---------- | ----------------------------------------------------------- | ------------------------------- | | `value` | `Record`<`string`, [`Value`](/api/modules/values.md#value)> | A Convex object (document body) | | `options?` | `Object` | Options for size calculation | #### Returns[​](#returns-2 "Direct link to Returns") `number` The size in bytes #### Defined in[​](#defined-in-19 "Direct link to Defined in") [values/size.ts:155](https://github.com/get-convex/convex-js/blob/main/src/values/size.ts#L155) *** ### 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-3 "Direct link to Parameters") | Name | Type | | ----- | ---- | | `obj` | `V` | #### Returns[​](#returns-3 "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-20 "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-4 "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-4 "Direct link to Returns") [`Value`](/api/modules/values.md#value) The JavaScript representation of the Convex value. #### Defined in[​](#defined-in-21 "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-5 "Direct link to Parameters") | Name | Type | Description | | ------- | --------------------------------------- | ------------------------------------ | | `value` | [`Value`](/api/modules/values.md#value) | A Convex value to convert into JSON. | #### Returns[​](#returns-5 "Direct link to Returns") [`JSONValue`](/api/modules/values.md#jsonvalue) The JSON representation of `value`. #### Defined in[​](#defined-in-22 "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) --- # Custom OIDC Provider **Note: This is an advanced feature!** We recommend sticking with the [supported third-party authentication providers](/auth/overview.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 ``` 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.tsx ``` 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.tsx ``` 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), [`AuthLoading`](/api/modules/react.md#authloading) and [`AuthRefreshing`](/api/modules/react.md#authrefreshing) 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/overview.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 ``` 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 ``` 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 ``` 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 ``` 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 ``` 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 ``` 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`, `AuthLoading` and `AuthRefreshing` helper components which use the `useConvexAuth` hook under the hood. `AuthRefreshing` renders when queries and mutations are paused for token refresh (generally a rare case). src/App.ts ``` import { Authenticated, Unauthenticated, AuthLoading, AuthRefreshing, } from "convex/react"; function App() { return (
Logged in Logged out Still loading Refreshing token...
); } ``` ## 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 ``` 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 ``` 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/storybook/pages_project_deployment_settings_environment_variables_auth_0_light.webp) 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](/quickstart/overview.md) or the relevant documentation for the platform you're using. Change the props to `Auth0Provider` to take in environment variables: src/main.tsx ``` 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](/quickstart/overview.md) 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. You can use your own WorkOS account with AuthKit or let Convex create a managed WorkOS team which enables provisioning and configuration of AuthKit environments automatically. The docs below are targeted at starting a new project with WorkOS AuthKit and Convex. If you have an existing app that you'd like to migrate, see the [Add to Existing App](/auth/authkit/add-to-app.md) instructions instead. ## Get started[​](#get-started "Direct link to Get started") Use the following command to start a new project. It will prompt you to select a framework and authentication option. Choose whichever framework you want and AuthKit as your authentication option: ``` npm create convex@latest ``` Start your newly created application in dev mode: ``` cd my-app # or whatever you name the directory npm run dev ``` That will kick off a Convex+WorkOS onboarding flow. For guidance on how to proceed, follow the instructions in one of the sections below. ## Option 1: use a Convex-managed WorkOS team[​](#managed-team "Direct link to Option 1: use a Convex-managed WorkOS team") tip Choose this option if you're new to WorkOS or if you want the convenience of the auto-provisioning and auto-configuration that the full integration offers. info Permissions: provisioning the Convex-managed WorkOS team, disconnecting it, inviting WorkOS team members, and creating/deleting shared project-level WorkOS environments all require **team admin** (or project admin, for the project-level operations). Provisioning a WorkOS environment for an individual deployment uses the same permission as managing that deployment, so any team member can self-serve a WorkOS env for their dev/preview deployment but only admins can do so for production. Follow the prompts to create a WorkOS team that will be associated with your Convex team. After this, team members of this Convex team can self-serve WorkOS environments for their dev/preview deployments, and team admins can provision shared project-level environments and production envs. See what additional functionality is available in [Next steps](#next-steps) and see [AuthKit configuration in convex.json](/auth/authkit/auto-provision.md) to modify the convex.json file in this template for your needs. What if I already have a WorkOS team but want to use the Convex-managed features? If you you are an existing WorkOS user but want the Convex auto-configuration and auto-provisioning support, you'll need to **start with a new WorkOS team** that is managed by Convex. To do that, make sure you select an email address that isn't already associated with a WorkOS team when prompted. The email address will need to be linked with your Convex account. You can [link additional email addresses](https://dashboard.convex.dev/profile) to your Convex account in the dashboard. Depending on your email provider, you might be able to use a `+` address for this step (e.g. `your.name+workos@example.com`) to avoid having to create an entirely new email account. If using **an existing WorkOS team** is more important than the auto-provisioning and auto-configuration support, you should exit out of the prompt flow triggered by `npm run dev` and follow along with [the section below](#existing-team) instead. Just note that using an existing team means that *Convex won't be able to auto-configure new applications or auto-provision WorkOS environments for each of your deployments.* ## Option 2: use an existing WorkOS team[​](#existing-team "Direct link to Option 2: use an existing WorkOS team") tip Choose this option if you're an established WorkOS AuthKit user and using your existing WorkOS team is more important than the auto-provisioning and auto-configuration that the full integration offers. When you are prompted to create a new WorkOS team, choose No. You'll then need to manually configure your Convex deployment and client framework. 1. Find your WorkOS Client ID and API Key From the WorkOS dashboard [get started](https://dashboard.workos.com/get-started) page under **Quick start**, find your `WORKOS_CLIENT_ID` and `WORKOS_API_KEY`. ![Getting your WorkOS Client ID](/screenshots/workos-client-id.png) 2. Set the values in your deployment Use the `npx convex` CLI to set environment variables for `WORKOS_CLIENT_ID` and `WORKOS_API_KEY` with values from the WorkOS dashboard in the previous step. ``` npx convex env set WORKOS_CLIENT_ID $YOUR_CLIENT_ID_HERE npx convex env set WORKOS_API_KEY $YOUR_API_KEY_HERE ``` 3. Deploy your application Run `npx convex dev` to automatically sync your configuration to your backend. ``` npx convex dev ``` info For multiple Convex applications integrated with an existing WorkOS team you'll need to decide if the [single-tenant or multi-tenant model](https://workos.com/docs/authkit/modeling-your-app/single-tenant-and-multi-tenant-models) is right for your situation. That may include manually provisioning additional WorkOS environments. ## Next steps[​](#next-steps "Direct link to Next steps") ### Syncing data and handling events using the WorkOS Component[​](#syncing-data-and-handling-events-using-the-workos-component "Direct link to Syncing data and handling events using the WorkOS Component") You can integrate the [WorkOS Component](https://www.convex.dev/components/workos-authkit) into your application to sync user data into your application and handle other events (like account lifecycle) from WorkOS. ### 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 ``` 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 and referenced in `convex/auth.config.ts`. As long as you started from `npm create convex` or the instructions for [adding AuthKit to an existing Convex app](/auth/authkit/add-to-app.md), your `convex/auth.config.ts` file will make use of the `WORKOS_CLIENT_ID` value referenced below. Sample auth.config.ts convex/auth.config.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; ``` **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" ``` ## 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. --- # Adding WorkOS AuthKit to an Existing App Follow along to learn how to configure an existing Convex application to use WorkOS AuthKit. If you're just getting started with Convex and WorkOS AuthKit, see the [Getting Started](/auth/authkit/.md) instructions instead. ## Project configuration[​](#project-configuration "Direct link to Project configuration") The first step to getting your app up and running with WorkOS AuthKit is getting your Convex project properly configured. Most users should opt for using a **Managed WorkOS team** where Convex provisions and automatically configures WorkOS environments for projects and deployments. If you have an existing WorkOS team and account that you want to use with your Convex application then you should follow the **Standard WorkOS team** instructions. info Setting up the Managed WorkOS team and inviting members to it require **team admin**. Per-deployment WorkOS environments use the deployment's own management permission, so any team member can provision one for their dev/preview deployment, while prod envs and shared project-level envs require team admin or project admin. * Managed WorkOS team * Standard WorkOS team 1. Create or update convex.json You'll need a `convex.json` file in the root of your project with contents that match your framework. You can find more details about the `authKit` section of `convex.json` in the [Automatic Config](/auth/authkit/auto-provision.md) docs. If you don't see an example for your framework, consult its documentation for details about how to specify environment variables and which ports it uses for development servers and alter one of the examples accordingly. Take care to not expose your `WORKOS_API_KEY` in a public environment variable. On the other hand, the `WORKOS_CLIENT_ID` is safe to include in your client bundle. * React (Vite) * Next.js * TanStack Start convex.json ``` { "$schema": "./node_modules/convex/schemas/convex.schema.json", "authKit": { "dev": { "configure": { "redirectUris": ["http://localhost:5173/callback"], "appHomepageUrl": "http://localhost:5173", "corsOrigins": ["http://localhost:5173"] }, "localEnvVars": { "VITE_WORKOS_CLIENT_ID": "${authEnv.WORKOS_CLIENT_ID}", "VITE_WORKOS_REDIRECT_URI": "http://localhost:5173/callback" } }, "preview": { "configure": { "redirectUris": ["https://${buildEnv.VERCEL_BRANCH_URL}/callback"], "appHomepageUrl": "https://${buildEnv.VERCEL_PROJECT_PRODUCTION_URL}", "corsOrigins": ["https://${buildEnv.VERCEL_BRANCH_URL}"] } }, "prod": { "configure": { "redirectUris": [ "https://${buildEnv.VERCEL_PROJECT_PRODUCTION_URL}/callback" ], "appHomepageUrl": "https://${buildEnv.VERCEL_PROJECT_PRODUCTION_URL}", "corsOrigins": ["https://${buildEnv.VERCEL_PROJECT_PRODUCTION_URL}"] } } } } ``` convex.json ``` { "$schema": "./node_modules/convex/schemas/convex.schema.json", "authKit": { "dev": { "configure": { "redirectUris": ["http://localhost:3000/callback"], "appHomepageUrl": "http://localhost:3000", "corsOrigins": ["http://localhost:3000"] }, "localEnvVars": { "WORKOS_CLIENT_ID": "${authEnv.WORKOS_CLIENT_ID}", "WORKOS_API_KEY": "${authEnv.WORKOS_API_KEY}", "NEXT_PUBLIC_WORKOS_REDIRECT_URI": "http://localhost:3000/callback" } }, "preview": { "configure": { "redirectUris": ["https://${buildEnv.VERCEL_BRANCH_URL}/callback"], "appHomepageUrl": "https://${buildEnv.VERCEL_PROJECT_PRODUCTION_URL}", "corsOrigins": ["https://${buildEnv.VERCEL_BRANCH_URL}"] } }, "prod": { "environmentType": "production", "configure": { "redirectUris": [ "https://${buildEnv.VERCEL_PROJECT_PRODUCTION_URL}/callback" ], "appHomepageUrl": "https://${buildEnv.VERCEL_PROJECT_PRODUCTION_URL}", "corsOrigins": ["https://${buildEnv.VERCEL_PROJECT_PRODUCTION_URL}"] } } } } ``` convex.json ``` { "$schema": "./node_modules/convex/schemas/convex.schema.json", "authKit": { "dev": { "configure": { "redirectUris": ["http://localhost:3000/callback"], "appHomepageUrl": "http://localhost:3000", "corsOrigins": ["http://localhost:3000"] }, "localEnvVars": { "WORKOS_CLIENT_ID": "${authEnv.WORKOS_CLIENT_ID}", "WORKOS_API_KEY": "${authEnv.WORKOS_API_KEY}", "WORKOS_REDIRECT_URI": "http://localhost:3000/callback" } }, "preview": { "configure": { "redirectUris": ["https://${buildEnv.VERCEL_BRANCH_URL}/callback"], "appHomepageUrl": "https://${buildEnv.VERCEL_PROJECT_PRODUCTION_URL}", "corsOrigins": ["https://${buildEnv.VERCEL_BRANCH_URL}"] } }, "prod": { "configure": { "redirectUris": [ "https://${buildEnv.VERCEL_PROJECT_PRODUCTION_URL}/callback" ], "appHomepageUrl": "https://${buildEnv.VERCEL_PROJECT_PRODUCTION_URL}", "corsOrigins": ["https://${buildEnv.VERCEL_PROJECT_PRODUCTION_URL}"] } } } } ``` 2. Create or update auth.config.ts In your app's `convex/` folder, create or update the `auth.config.ts` file with the following code. This is the server-side configuration for validating access tokens. convex/auth.config.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; ``` 3. Deploy your configuration to your dev environment During deployment, you will be prompted to create a new Convex-managed WorkOS team or an existing one will be detected and used. Convex will then provision a new environment for your application in your WorkOS team. ``` npx convex dev ``` 1) Find your WorkOS Client ID and API Key From the WorkOS dashboard [get started](https://dashboard.workos.com/get-started) page under **Quick start**, find your `WORKOS_CLIENT_ID` and `WORKOS_API_KEY`. ![Getting your WorkOS Client ID](/screenshots/workos-client-id.png) 2) Set the values in your deployment Use the `npx convex` CLI to set environment variables for `WORKOS_CLIENT_ID` and `WORKOS_API_KEY` with values from the WorkOS dashboard in the previous step. ``` npx convex env set WORKOS_CLIENT_ID $YOUR_CLIENT_ID_HERE npx convex env set WORKOS_API_KEY $YOUR_API_KEY_HERE ``` 3) Configure auth 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 ``` 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. ``` npx convex dev ``` Read on to learn how to update your client code to integrate WorkOS AuthKit. ## 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 * Next.js * TanStack Start **Example:** [React with Convex and AuthKit](https://github.com/get-convex/templates/tree/main/template-react-vite-authkit) This guide assumes you have [AuthKit set up](#project-configuration) 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 tip If you're using a Convex-managed WorkOS team, this was done for you in [Project configuration](#project-configuration). 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 tip If you're using a Convex-managed WorkOS team, this was done for you in [Project configuration](#project-configuration). 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. Install AuthKit In a new terminal window, install the AuthKit React SDK: ``` npm install @workos-inc/authkit-react @convex-dev/workos ``` 4. 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 ``` 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( , ); ``` 5. 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. 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. tip If you choose to build your own auth-integrated components without using the helpers, 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. src/App.tsx ``` 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'}

); } ``` 6. 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 ``` import { v } from "convex/values"; import { query } from "./_generated/server"; export const listNumbers = query({ args: { count: v.number(), }, handler: async (ctx, args) => { const identity = await ctx.auth.getUserIdentity(); if (identity === null) { throw new Error("Not authenticated"); } const numbers = await ctx.db .query("numbers") // Ordered by _creationTime, return most recent .order("desc") .take(args.count); return { viewer: identity.name, numbers: numbers.reverse().map((number) => number.value), }; }, }); ``` **Note:** The [React template](https://github.com/get-convex/templates/tree/main/template-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. **Example:** [Next.js with Convex and AuthKit](https://github.com/get-convex/templates/tree/main/template-nextjs-authkit) This guide assumes you have [AuthKit set up](#project-configuration) 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 tip If you're using a Convex-managed WorkOS team, this was done for you in [Project configuration](#project-configuration). Update your `.env.local` file to look something like this example. **Note:** `WORKOS_CLIENT_ID` and `WORKOS_API_KEY` can be found in your [WorkOS Dashboard](https://dashboard.workos.com/). `WORKOS_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`. `NEXT_PUBLIC_WORKOS_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. .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. Install AuthKit In a new terminal window, install the AuthKit Next.js SDK: ``` npm install @workos-inc/authkit-nextjs @convex-dev/workos ``` 3. 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)(.*)', ], }; ``` 4. 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 ``` import { handleAuth } from '@workos-inc/authkit-nextjs'; export const GET = handleAuth(); ``` 5. Create the sign-in route app/sign-in/route.ts ``` import { redirect } from 'next/navigation'; import { getSignInUrl } from '@workos-inc/authkit-nextjs'; export async function GET() { const authorizationUrl = await getSignInUrl(); return redirect(authorizationUrl); } ``` 6. Create the sign-up route To redirect users to WorkOS sign-up: app/sign-up/route.ts ``` import { redirect } from 'next/navigation'; import { getSignUpUrl } from '@workos-inc/authkit-nextjs'; export async function GET() { const authorizationUrl = await getSignUpUrl(); return redirect(authorizationUrl); } ``` 7. 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 ``` 'use client'; import { ReactNode, useCallback, useState } from 'react'; import { ConvexReactClient } from 'convex/react'; import { ConvexProviderWithAuth } from 'convex/react'; import { AuthKitProvider, useAuth, useAccessToken } from '@workos-inc/authkit-nextjs/components'; export function ConvexClientProvider({ children }: { children: ReactNode }) { const [convex] = useState(() => { return new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!); }); return ( {children} ); } function useAuthFromAuthKit() { const { user, loading: isLoading } = useAuth(); const { getAccessToken, refresh } = useAccessToken(); const isAuthenticated = !!user; const fetchAccessToken = useCallback( async ({ forceRefreshToken }: { forceRefreshToken?: boolean } = {}): Promise => { if (!user) { return null; } try { if (forceRefreshToken) { return (await refresh()) ?? null; } return (await getAccessToken()) ?? null; } catch (error) { console.error('Failed to get access token:', error); return null; } }, [user, refresh, getAccessToken], ); return { isLoading, isAuthenticated, fetchAccessToken, }; } ``` 8. Add to your layout Update `app/layout.tsx` to use the provider: app/layout.tsx ``` 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} ); } ``` 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. 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. tip If you choose to build your own auth-integrated components without using the helpers, 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. app/page.tsx ``` "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'}

); } ``` 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/myFunctions.ts ``` import { v } from "convex/values"; import { query } from "./_generated/server"; export const listNumbers = query({ args: { count: v.number(), }, handler: async (ctx, args) => { const identity = await ctx.auth.getUserIdentity(); if (identity === null) { throw new Error("Not authenticated"); } const numbers = await ctx.db .query("numbers") // Ordered by _creationTime, return most recent .order("desc") .take(args.count); return { viewer: identity.name, numbers: numbers.reverse().map((number) => number.value), }; }, }); ``` **Note:** The [Next.js template](https://github.com/get-convex/templates/tree/main/template-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. **Example:** [TanStack Start with Convex and WorkOS AuthKit](https://github.com/get-convex/templates/tree/main/template-tanstack-start-authkit) This guide assumes you have [AuthKit set up](#project-configuration) and have a working TanStack Start app with Convex. If not, follow the [Convex TanStack Start Quickstart](/quickstart/tanstack-start.md) first. Then: 1. Set up your environment variables tip If you're using a Convex-managed WorkOS team, this was done for you in [Project configuration](#project-configuration). In your `.env.local` file, set the following environment variables. **Note:** `WORKOS_CLIENT_ID` and `WORKOS_API_KEY` can be found in your [WorkOS Dashboard](https://dashboard.workos.com/). `WORKOS_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`. .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 WORKOS_REDIRECT_URI=http://localhost:3000/callback # Convex Configuration (you don't have to fill these out, they're generated by Convex) VITE_CONVEX_URL=https://your-convex-url.convex.cloud ``` 2. Install AuthKit In a new terminal window, install the AuthKit TanStack Start SDK: ``` npm install @workos/authkit-tanstack-react-start ``` 3. Configure Start middleware WorkOS AuthKit requires server-side middleware to manage authentication sessions. Update your `src/start.ts` to include the AuthKit middleware: src/start.ts ``` import { createStart } from '@tanstack/react-start'; import { authkitMiddleware } from '@workos/authkit-tanstack-react-start'; export const startInstance = createStart(() => { return { requestMiddleware: [authkitMiddleware()], }; }); ``` 4. Configure ConvexProviderWithAuth Update your `src/router.tsx` to wrap the router with `` and ``, and provide a custom `useAuthFromAuthKit` hook that bridges WorkOS's auth state to Convex. src/router.tsx ``` import { createRouter } from '@tanstack/react-router'; import { ConvexQueryClient } from '@convex-dev/react-query'; import { QueryClient } from '@tanstack/react-query'; import { setupRouterSsrQueryIntegration } from '@tanstack/react-router-ssr-query'; import { ConvexProviderWithAuth, ConvexReactClient } from 'convex/react'; import { AuthKitProvider, useAccessToken, useAuth } from '@workos/authkit-tanstack-react-start/client'; import { useCallback, useMemo } from 'react'; import { routeTree } from './routeTree.gen'; export function getRouter() { 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); const convexQueryClient = new ConvexQueryClient(convex); const queryClient = new QueryClient({ defaultOptions: { queries: { queryKeyHashFn: convexQueryClient.hashFn(), queryFn: convexQueryClient.queryFn(), gcTime: 5000, }, }, }); convexQueryClient.connect(queryClient); const router = createRouter({ routeTree, defaultPreload: 'intent', scrollRestoration: true, defaultPreloadStaleTime: 0, // Let React Query handle all caching defaultErrorComponent: (err) =>

{err.error.stack}

, defaultNotFoundComponent: () =>

not found

, context: { queryClient, convexClient: convex, convexQueryClient }, Wrap: ({ children }) => ( {children} ), }); setupRouterSsrQueryIntegration({ router, queryClient }); return router; } function useAuthFromAuthKit() { const { loading, user } = useAuth(); const { getAccessToken, refresh } = useAccessToken(); const fetchAccessToken = useCallback( async ({ forceRefreshToken }: { forceRefreshToken: boolean }) => { if (!user) { return null; } if (forceRefreshToken) { return (await refresh()) ?? null; } return (await getAccessToken()) ?? null; }, [user, refresh, getAccessToken], ); return useMemo( () => ({ isLoading: loading, isAuthenticated: !!user, fetchAccessToken, }), [loading, user, fetchAccessToken], ); } ``` 5. Add SSR auth in the root route To make authenticated Convex queries work during server-side rendering, call WorkOS's `getAuth()` in `beforeLoad` and pass the access token to the Convex client. src/routes/\_\_root.tsx ``` import { HeadContent, Outlet, Scripts, createRootRouteWithContext } from '@tanstack/react-router'; import { getAuth } from '@workos/authkit-tanstack-react-start'; import appCssUrl from '../app.css?url'; import type { QueryClient } from '@tanstack/react-query'; import type { ReactNode } from 'react'; import type { ConvexReactClient } from 'convex/react'; import type { ConvexQueryClient } from '@convex-dev/react-query'; export const Route = createRootRouteWithContext<{ queryClient: QueryClient; convexClient: ConvexReactClient; convexQueryClient: ConvexQueryClient; }>()({ head: () => ({ meta: [ { charSet: 'utf-8', }, { name: 'viewport', content: 'width=device-width, initial-scale=1', }, { title: 'Convex + TanStack Start + WorkOS AuthKit', }, ], links: [ { rel: 'stylesheet', href: appCssUrl }, { rel: 'icon', href: '/convex.svg' }, ], }), component: RootComponent, notFoundComponent: () =>
Not Found
, beforeLoad: async (ctx) => { const auth = await getAuth(); // During SSR only (the only time serverHttpClient exists), // set the WorkOS auth token to make HTTP queries with. if (auth.user) { ctx.context.convexQueryClient.serverHttpClient?.setAuth(auth.accessToken); } return { user: auth.user }; }, }); function RootComponent() { return ( ); } function RootDocument({ children }: Readonly<{ children: ReactNode }>) { return ( {children} ); } ``` 6. Add callback route Unlike the React SPA integration, TanStack Start uses server-side authentication which requires an explicit callback route to handle the OAuth redirect from WorkOS. src/routes/callback.tsx ``` import { createFileRoute } from '@tanstack/react-router'; import { handleCallbackRoute } from '@workos/authkit-tanstack-react-start'; export const Route = createFileRoute('/callback')({ server: { handlers: { GET: handleCallbackRoute(), }, }, }); ``` 7. Add sign-in and sign-up redirect routes Create dedicated server routes that call `getSignInUrl()` / `getSignUpUrl()` and redirect. Link to these routes from your UI. src/routes/sign-in.tsx ``` import { createFileRoute } from '@tanstack/react-router'; import { getSignInUrl } from '@workos/authkit-tanstack-react-start'; export const Route = createFileRoute('/sign-in')({ server: { handlers: { GET: async ({ request }: { request: Request }) => { const returnPathname = new URL(request.url).searchParams.get('returnPathname'); const url = await getSignInUrl(returnPathname ? { data: { returnPathname } } : undefined); return new Response(null, { status: 307, headers: { Location: url }, }); }, }, }, }); ``` src/routes/sign-up.tsx ``` import { createFileRoute } from '@tanstack/react-router'; import { getSignUpUrl } from '@workos/authkit-tanstack-react-start'; export const Route = createFileRoute('/sign-up')({ server: { handlers: { GET: async ({ request }: { request: Request }) => { const returnPathname = new URL(request.url).searchParams.get('returnPathname'); const url = await getSignUpUrl(returnPathname ? { data: { returnPathname } } : undefined); return new Response(null, { status: 307, headers: { Location: url }, }); }, }, }, }); ``` 8. 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. In TanStack Start, you can use WorkOS's server-side `getAuth()` in a route loader to get the user before the page renders. tip If you choose to build your own auth-integrated components without using the helpers, 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. src/routes/index.tsx ``` import { createFileRoute } from '@tanstack/react-router'; import { Authenticated, Unauthenticated } from 'convex/react'; import { useAuth } from '@workos/authkit-tanstack-react-start/client'; import { getAuth } from '@workos/authkit-tanstack-react-start'; import { convexQuery } from '@convex-dev/react-query'; import { useSuspenseQuery } from '@tanstack/react-query'; import { api } from '../../convex/_generated/api'; export const Route = createFileRoute('/')({ component: Home, loader: async () => { const { user } = await getAuth(); return { user }; }, }); function Home() { const { user } = Route.useLoaderData(); const { signOut } = useAuth(); return (
); } function Content() { const { data } = useSuspenseQuery( convexQuery(api.myFunctions.listNumbers, { count: 10 }), ); return (

Welcome {data.viewer}!

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

); } ``` 9. 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 ``` import { v } from "convex/values"; import { query } from "./_generated/server"; export const listNumbers = query({ args: { count: v.number(), }, handler: async (ctx, args) => { const identity = await ctx.auth.getUserIdentity(); if (identity === null) { throw new Error("Not authenticated"); } const numbers = await ctx.db .query("numbers") // Ordered by _creationTime, return most recent .order("desc") .take(args.count); return { viewer: identity.name, numbers: numbers.reverse().map((number) => number.value), }; }, }); ``` **Note:** The [TanStack Start template](https://github.com/get-convex/templates/tree/main/template-tanstack-start-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") Now that your app is up and running on Convex and AutKit, refer to the [main docs](/auth/authkit/.md#next-steps) to learn about additional functionality. --- # Automatic AuthKit Configuration Convex can **create** AuthKit environments in a WorkOS account made on your behalf. By default WorkOS gives you only two environments, but giving each Convex dev deployment its own AuthKit environment is useful for isolating development user data and configuration changes between multiple developers or agents working in parallel. The Convex CLI will **configure** AuthKit environments, regardless of whether Convex or you created them, if the `WORKOS_CLIENT_ID` and `WORKOS_API_KEY` environment variables are present in the build environment or the Convex deployment. While developing locally, Convex can write environment variables to `.env.local` to make setting up an AuthKit environment a breeze. This automatic configuration is available whether you're [starting a new application](/auth/authkit/.md) or adding WorkOS AuthKit to an [existing application](/auth/authkit/add-to-app.md). Read on for some additional details about how the auto-configuration works and some things that you may need to configure manually based on your specific needs. info Provisioning or disconnecting the underlying Convex-managed WorkOS team requires **team admin**. Provisioning a per-deployment WorkOS environment uses the deployment's own management permission — any team member can do this for their dev or preview deployment, but production envs require team admin (or project admin). Shared project-level WorkOS environments require team admin or project admin. ## Production deployments[​](#production-deployments "Direct link to Production deployments") In the Convex dashboard settings for your production deployment, create an AuthKit environment in the WorkOS Authentication integration under settings, integrations. Copy these credentials to your hosting provider environment variables (in addition to other setup, like adding a production `CONVEX_DEPLOY_KEY`, setting the build command, and setting other framework-specific AuthKit environment variables). ## Preview deployments[​](#preview-deployments "Direct link to Preview deployments") In the Convex dashboard settings for any deployment in your project, create a new project-level AuthKit environment in the WorkOS Authentication integration under settings, integrations. Copy these credentials to your hosting provider environment variables (in addition to other setup, like adding a preview `CONVEX_DEPLOY_KEY`, setting the build command, and setting other framework-specific AuthKit environment variables). ## How it works[​](#how-it-works "Direct link to How it works") AuthKit provisioning and configuration is triggered by the presence of a `convex.json` file with an `authKit` section with a property corresponding to the type of code push: `dev`, `preview`, or `prod`. If this section is present, an AuthKit environment may be provisioned (dev only), local environment variables set (dev only), and configured (all code push types). ### Finding the AuthKit environment[​](#finding-the-authkit-environment "Direct link to Finding the AuthKit environment") The CLI looks for WorkOS credentials `WORKOS_CLIENT_ID` and `WORKOS_API_KEY` in the following order: 1. Environment variables in the build environment shell or `.env.local` file 2. Convex deployment environment variables In remote build environments (e.g. building a project in Vercel, Netlify, Cloudflare) if these two environment variables are not found, the build will fail. During local dev, credentials are next fetched from the Convex Cloud API for a new or existing AuthKit environment. A link to this deployment in the WorkOS dashboard can be found in the Convex dashboard under the WorkOS integration. ### Configuring the AuthKit environment[​](#configuring-the-authkit-environment "Direct link to Configuring the AuthKit environment") Once credentials are found, the `WORKOS_API_KEY` is used to configure the environment based on the `configure` section of the relevant `authKit` object. This sets things like an environment's [redirect URIs](https://workos.com/docs/sso/redirect-uris), [allowed CORS origins](https://workos.com/docs/authkit/client-only). ### Setting local environment variables[​](#setting-local-environment-variables "Direct link to Setting local environment variables") For dev deployments only, environment variables are written to `.env.local` based on the `localEnvVars` section of the relevant `authKit` config. ## Project-level vs deployment level AuthKit environments[​](#project-level-vs-deployment-level-authkit-environments "Direct link to Project-level vs deployment level AuthKit environments") In hosting providers with remote build pipelines like Vercel, it's difficult to set environment variables like `WORKOS_API_KEY` at build time in a way that's available to server-side code like Next.js middleware. This makes it necessary set the `WORKOS_*` environment variables in advance for preview and production deployments built on these platforms. After creating the WorkOS AuthKit environments for production and preview deployments in the dashboard, copy relevant environment variables like `WORKOS_CLIENT_ID`, `WORKOS_API_KEY`, `WORKOS_REDIRECT_URI`, and `WORKOS_COOKIE_PASSWORD` to the preview and production environment variables in your hosting provider. Deployment-specific AuthKit environments can be created for any deployment are difficult set up automatically so shared project-level environments are generally a better fit. In the `authKit` section of `convex.json`, `localEnvVars` `automate setting up dev environments by automatically setting the right environment variables in .env.local and automatically configuring the environment with a `redirectUri\`. Environments for hosting providers in build environments like Vercel (production and preview deploys) can be configured at build time, but the environment variables for these build environments must be set manually in the build settings. --- # AuthKit Troubleshooting ## 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). ## Platform not authorized[​](#platform-not-authorized "Direct link to Platform not authorized") ``` WorkOSPlatformNotAuthorized: Your WorkOS platform API key is not authorized to access this team. Please ensure the API key has the correct permissions in the WorkOS dashboard. ``` This error occurs when your WorkOS platform API key is not authorized to access the WorkOS team associated with your Convex team. This typically happens when the WorkOS workspace has had Convex removed. You can contact WorkOS support to ask to restore this permission, or unlink the current workspace and create a new one: ``` npx convex integration workos disconnect-team npx convex integration workos provision-team ``` You'll need to use a different email address to create your new WorkOS Workspace as an email address can only be associated with a single WorkOS workspace. --- # 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. Activate the Convex integration in Clerk In the Clerk Dashboard, activate the [Convex integration](https://dashboard.clerk.com/apps/setup/convex). ![Activate the Convex integration in Clerk](/screenshots/clerk-convex-integration.png) Copy your Clerk app's *Frontend API URL*. In development, its format will be `https://verb-noun-00.clerk.accounts.dev`. In production, its format will be `https://clerk..com`. 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 ``` import { AuthConfig } from "convex/server"; export default { providers: [ { // Replace with your Clerk Frontend API URL // 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/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 ``` import React from "react"; import ReactDOM from "react-dom/client"; import App from "./App"; import "./index.css"; import { ClerkProvider, useAuth } from "@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. 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. `` renders when queries and mutations are pending and the socket is paused for token refresh (a generally rare case). tip If you choose to build your own auth-integrated components without using the helpers, 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. src/App.tsx ``` import { SignInButton, UserButton } from "@clerk/react"; import { Authenticated, Unauthenticated, AuthLoading, AuthRefreshing, useQuery, } from "convex/react"; import { api } from "../convex/_generated/api"; function App() { return (

Still loading

Refreshing token...

); } 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 ``` 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") .withIndex("by_author", (q) => q.eq("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. Activate the Convex integration in Clerk In the Clerk Dashboard, activate the [Convex integration](https://dashboard.clerk.com/apps/setup/convex). ![Activate the Convex integration in Clerk](/screenshots/clerk-convex-integration.png) Copy your Clerk app's *Frontend API URL*. In development, its format will be `https://verb-noun-00.clerk.accounts.dev`. In production, its format will be `https://clerk..com`. 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 ``` import { AuthConfig } from "convex/server"; export default { providers: [ { // Replace with your Clerk Frontend API URL // 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. 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. `` renders when queries and mutations are pending and the socket is paused for token refresh (a generally rare case). tip If you choose to build your own auth-integrated components without using the helpers, 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. app/page.tsx ``` "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 ``` 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") .withIndex("by_author", (q) => q.eq("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 ``` export default function Badge() { const { user } = useUser(); return Logged in as {user.fullName}; } ``` ### Factor verification age[​](#factor-verification-age "Direct link to Factor verification age") Clerk's `fva` (factor verification age) claim updates every minute until it hits 99, so it's [excluded from the Convex identity](/auth/functions-auth.md#clerk-claims-configuration) to avoid rerunning authenticated queries on every token refresh. If you need step-up auth for sensitive actions, use Clerk's [reverification](https://clerk.com/docs/guides/secure/reverification) rather than reading `fva` directly. ## 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 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 ``` 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/storybook/pages_project_deployment_settings_environment_variables_clerk_light.webp) 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 Clerk's [redirect URL props or environment variables](https://clerk.com/docs/guides/development/customize-redirect-urls). 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.tsx ``` 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("users", 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 ``` import { useUser } from "@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 ``` import { SignInButton, UserButton } from "@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 ``` 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 ``` 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("users", 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 ``` 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("users", 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("users", 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 ``` 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 ``` 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 ``` 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("users", 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 ``` 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 ``` 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/react"; const { getToken } = useAuth(); console.log(getToken()); ``` * 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` 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/overview.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 ``` 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 ``` 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 the claims configured in your Clerk integration. If you've set custom claims, they will be returned by `getUserIdentity` as well. Not every claim in the token is returned by `getUserIdentity`: * Standard OIDC claims are surfaced as named fields (`subject`, `issuer`, `name`, `email`, and so on) rather than as custom claims. * A few claims are dropped entirely. JWT housekeeping claims (`jti`, `nbf`) and Clerk's `fva` (factor verification age) are not available, the latter because it's time-varying and would bust the query cache. See [our Clerk docs](/auth/clerk.md#factor-verification-age) for an alternative to `fva`. ### 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 ``` 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/) --- # 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("users", userId, { imageId: undefined, image: undefined }); }, }); ``` Related posts from [![Stack](/img/stack-logo-dark.svg)![Stack](/img/stack-logo-light.svg)](https://stack.convex.dev/) --- # Chef Migration Guide Convex Chef has had a good run but we’re in the process of replacing it with a new incarnation better suited to long-term application development on Convex. Your Chef projects will continue running but your Chef development flow will be impacted in the meantime. We apologize for the inconvenience! Read on for instructions on how to continue developing your existing Chef projects. ## Continuing to develop on Chef projects[​](#continuing-to-develop-on-chef-projects "Direct link to Continuing to develop on Chef projects") If you’re a new user we recommend getting started on Convex directly via a coding agent or tutorial. If you have an existing Chef app however and don’t want to wait for the Chef successor, we recommend exporting your project for local development. Chef projects are fully fledged Convex projects and can be maintained either by hand or via a coding agent such as [OpenCode](https://opencode.ai/) or [Claude Code](https://claude.com/claude-code). Your data will still be intact and your Convex project will continue to run as normal. ### Download your project[​](#download-your-project "Direct link to Download your project") Go to [chef.convex.dev](https://chef.convex.dev) and navigate to your chat. Click the download code button in the Chef UI to get a zip file of your project. Unzip the file and put the folder in your desired location. We recommend renaming the folder to the name of your app for convenience. ### Open the project in your IDE[​](#open-the-project-in-your-ide "Direct link to Open the project in your IDE") Open the folder in the IDE of your choice ([VS Code](https://code.visualstudio.com/), [Cursor](https://cursor.com/), [IntelliJ](https://www.jetbrains.com/idea/), etc.). From here you can use any coding agent — like [OpenCode](https://opencode.ai/) or [Claude Code](https://claude.com/claude-code) — to continue developing your project. ### Install dependencies[​](#install-dependencies "Direct link to Install dependencies") Open the terminal, `cd` into your app folder, and install all dependencies: ``` cd ~/ npm i ``` ### Run your app[​](#run-your-app "Direct link to Run your app") Run the following command to start your app, and set up Convex if you haven’t already: ``` npm run dev ``` Follow any instructions to log in to Convex from your machine. This will run your Chef app locally — you will need to deploy using the CLI to get your app on the `convex.app` domain (see [Deploying to convex.app](#deploying-to-convexapp) below). 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. Happy building! Reach out to Convex support if you have any questions. ## Deploying to convex.app[​](#deploying-to-convexapp "Direct link to Deploying to convex.app") The Convex platform doesn’t natively support hosting frontend code, just the backend for your application. We typically recommend using a hosting provider like [Netlify](/production/hosting/netlify.md) or [Vercel](/production/hosting/vercel.md) for hosting. If you’re a regular Chef developer however, you will have been able to host your app frontend on a `*.convex.app` domain and may want to keep using this. You can continue pushing changes to this same hosted frontend via a special CLI tool. note Detailed CLI instructions for pushing to your existing `*.convex.app` frontend are coming soon. Note that this tool will only allow you to push to existing Chef projects. If you’d love to see built-in hosting as a generally available Convex service, feel free to put in a request at [ship.convex.dev](https://ship.convex.dev/). ## Advanced: Running Chef locally[​](#advanced-running-chef-locally "Direct link to Advanced: Running Chef locally") The Chef codebase is open source and available to run locally or to fork and modify. Projects created by open source Chef will still run on the Convex cloud with the same guarantees as regular Convex projects. See the Running Locally section at [github.com/get-convex/chef](https://github.com/get-convex/chef) for instructions. --- # 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 Cloud 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! You have two options for giving an agent its own isolated Convex environment: 1. **Local backend** — the agent runs Convex locally, storing its data in a `.convex/` folder. Best for ephemeral agents that don't require webhooks or default environment variables. 2. **Cloud dev deployment per agent** — the agent gets its own real Convex cloud deployment. Best when the agent needs default environment variables, inbound public http traffic, such as webhooks, or integrations that don't run locally. ## Local backend[​](#local-backend "Direct link to Local backend") The CLI will spin up a separate Convex backend on the VM where the agent is working ([anonymous development](/cli/local-deployments.md)), with no need for a Convex login or deploy key. A typical setup script: ``` npm i npx convex dev --once ``` or with bun: ``` bun i bun x convex dev --once ``` The setup script needs "full" internet access the first time so the CLI can download the local backend binary. In non-interactive shells (the typical case for an agent's setup script), `npx convex` will never prompt the agent to log in — when no deployment is already configured and `CONVEX_DEPLOY_KEY` isn't set, the CLI defaults to provisioning a local deployment automatically. ## Cloud dev deployment per agent[​](#cloud-dev-deployment-per-agent "Direct link to Cloud dev deployment per agent") If the agent needs a real cloud deployment (e.g. for dashboard access, crons, or integrations that aren't available locally), provision a fresh dev deployment in your project and hand the agent a deploy key scoped only to it: ``` # Create a new dev deployment and select it. npx convex deployment create --type dev --select \ team-slug:project-slug:dev/$USER/$(basename "$PWD") \ --expiration "in 5 days" # Mint a deploy key scoped only to this deployment and save it as # CONVEX_DEPLOY_KEY in .env.local. npx convex deployment token create agent-token --save-env # Push code once. npx convex dev --once ``` Once `CONVEX_DEPLOY_KEY` is set in `.env.local`, the agent can only push to and develop against its own dev deployment — not prod or other developers' deployments. If the agent needs environment variables, the easiest path is to set them as [project environment variable defaults](/production/environment-variables.md#project-environment-variable-defaults) so they're applied automatically to every new cloud deployment. You can also seed values directly with `npx convex env set` (which accepts variables on stdin or via `--from-file`). `env set` needs a deployment to be configured first, so run it *after* `deployment create` (or after `npx convex init` for a local backend) and *before* `npx convex dev --once` so the deployed code sees the new values. See [Creating and deleting deploy keys from the CLI](/cli/deploy-key-types.md#deployment-token) for the full options on `npx convex deployment token`. ## Worktree setups[​](#worktree-setups "Direct link to Worktree setups") If you use a tool that creates a separate worktree for each agent task (Codex, Conductor, Cursor local worktrees, T3 Code), you can wire the cloud deployment-per-agent recipe into the tool's setup script so each worktree gets its own dev deployment automatically. When including `--select`, the deployment created during setup will be the one used by `npx convex` commands run from that worktree afterward. Replace `my-team` and `my-project` with your team and project slugs in the snippets below. Using the Codex app Open the Codex app settings and go to *Environments*. Select the environment for your project or create one if needed. Use the following setup script: ``` npm ci && npx convex deployment create --type=dev my-team:my-project:dev/$USER-codex/$(basename \"$(dirname \"$CODEX_WORKTREE_PATH\")\") --select ``` When starting a new worktree, select the environment that you just created. Using Conductor Add the following setup command to the `conductor.json` file of your project: ``` { "scripts": { "setup": "npm ci && npx convex deployment create --type=dev my-team:my-project:dev/$USER-conductor/$CONDUCTOR_WORKSPACE_NAME --select" } } ``` Using Cursor local worktrees Add the following setup command to the `.cursor/worktrees.json` file of your project: ``` { "setup-worktree": [ "npm ci", "npx convex deployment create --type=dev my-team:my-project:dev/$USER-cursor/$(basename \"$PWD\") --select" ] } ``` Using T3 Code Click on **Add action** in the top bar. Enable *Run automatically on worktree creation* and use the following command: ``` npm ci && npx convex deployment create --type=dev my-team:my-project:dev/$USER-t3code/$(basename "$PWD" | sed 's/^t3code-//') --select ``` To also mint a per-worktree deploy key, append the `npx convex deployment token create agent-token --save-env` step from the [cloud-deployment recipe](#cloud-dev-deployment-per-agent) after the `deployment create` line. ## Switching between cloud and local[​](#switching-between-cloud-and-local "Direct link to Switching between cloud and local") You can flip a worktree between a cloud and local deployment at any time: ``` # Create and select a local deployment for this worktree. npx convex deployment create local --select # Or, if a local deployment already exists, just select it. npx convex deployment select local ``` `npx convex deployment select ` switches back to a cloud deployment by its reference (or `dev`/`prod`). --- # 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/multiple-deployments.md#preview). ### 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). ## Creating and deleting deploy keys[​](#deployment-token "Direct link to Creating and deleting deploy keys") You can create and delete deploy keys for any cloud deployment you have access to from either the dashboard or the CLI. ### From the dashboard[​](#from-the-dashboard "Direct link to From the dashboard") Open the [deployment settings page](https://dashboard.convex.dev/deployment/settings) for the deployment you want a key for. In the *Deploy keys* section, click *Generate a deploy key* to open the deploy key creation panel. Give the key a memorable name and choose which actions it's allowed to perform. For a CI/CD pipeline that runs `npx convex deploy`, enable the `deployment:deploy` permission. For CLI usage or AI agents, you may want to grant more permissions, such as viewing logs and reading/writing data or environment variables. See [Role Actions](/team-management/role-actions.md#data-plane-and-runtime) for the full list. ![Create Deploy Key panel with the deployment:deploy permission enabled](/screenshots/storybook/pages_project_deployment_deployment_settings_create_deploy_key_light.webp) To delete a key, find it in the *Deploy keys* list and use its delete action. ### From the CLI[​](#from-the-cli "Direct link to From the CLI") You can also mint and revoke deploy keys with `npx convex deployment token`. This is useful in setup scripts (e.g. for a coding agent) where you want a deploy key scoped to a single deployment without having to click around the dashboard. You must be logged in with a personal access token (`npx convex login`) — these commands cannot be invoked with a `CONVEX_DEPLOY_KEY` already in scope. #### `npx convex deployment token create`[​](#npx-convex-deployment-token-create "Direct link to npx-convex-deployment-token-create") ``` npx convex deployment token create [--deployment ] [--save-env [path]] ``` * `` — required. A human-readable name for the new key (shown in the dashboard's deploy keys list). * `--deployment ` — optional. The target deployment. Accepts a deployment name (`joyful-capybara-123`), a reference (`dev/james`, `staging`), or `dev`/`prod`/`local`. Defaults to the currently-selected deployment. * `--save-env [path]` — optional. Save the new key as `CONVEX_DEPLOY_KEY` in an env file instead of printing it. Defaults to `.env.local`. Pass an explicit path to write somewhere else. By default the new deploy key is printed to stdout (status messages go to stderr, so you can pipe the key into another command): ``` KEY=$(npx convex deployment token create my-token) ``` With `--save-env`, the key is written into `.env.local` (or the path you provide) as `CONVEX_DEPLOY_KEY`. Subsequent `npx convex` commands run in that directory will use it automatically and run only against that deployment. #### `npx convex deployment token delete`[​](#npx-convex-deployment-token-delete "Direct link to npx-convex-deployment-token-delete") ``` npx convex deployment token delete [--deployment ] ``` * `` — required. Either the human-readable name passed to `token create`, or the deploy key value itself (e.g. `'dev:joyful-capybara-123|ey...'`). When passing the value, single-quote it so the shell doesn't consume the `|` and everything after it. * `--deployment ` — optional. The deployment the key belongs to. Defaults to the currently-selected deployment. --- # 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/multiple-deployments.md#preview). 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 in a `.convex` directory in your project. ### 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 deployment select local ``` The CLI commands you run next (for instance `npx convex dev`) will target your local deployment. If you want to go back to your personal cloud dev deployment, run: ``` npx convex deployment select dev ``` ## 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/overview.md). Alternatively, you can self-host a production deployment using the [open source convex-backend repo](https://github.com/get-convex/convex-backend). ## 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 the same version of Node.js as your project is [configured for](/production/project-configuration.md#configuring-the-nodejs-version). By default this is Node.js 20 today, though this may change in the future. To resolve this you can install and set up [nvm](https://github.com/nvm-sh/nvm) and then install the required Node.js version. You don't need to use this version 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** --- # 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 ``` The available CLI commands are: * [`npx convex dev`](/cli/reference/dev.md) — Develop against a dev deployment, watching for changes * [`npx convex deploy`](/cli/reference/deploy.md) — Deploy to a production or preview deployment * [`npx convex run`](/cli/reference/run.md) — Run a function or evaluate an inline readonly query on your deployment * [`npx convex import`](/cli/reference/import.md) — Import data from a file to your deployment * [`npx convex dashboard`](/cli/reference/dashboard.md) — Open the dashboard in the browser * [`npx convex docs`](/cli/reference/docs.md) — Open the docs in the browser * [`npx convex logs`](/cli/reference/logs.md) — Watch logs from your deployment * [`npx convex export`](/cli/reference/export.md) — Export data from your deployment to a ZIP file * [`npx convex env`](/cli/reference/env.md) — Set and view environment variables * [`npx convex data`](/cli/reference/data.md) — List tables and print data from your database * [`npx convex deployment`](/cli/reference/deployment.md) — Manage deployments * [`npx convex project`](/cli/reference/project.md) — Manage projects * [`npx convex codegen`](/cli/reference/codegen.md) — Generate backend type definitions * [`npx convex update`](/cli/reference/update.md) — Print instructions for updating the convex package * [`npx convex logout`](/cli/reference/logout.md) — Log out of Convex on this machine * [`npx convex function-spec`](/cli/reference/function-spec.md) — List function metadata from your deployment * [`npx convex insights`](/cli/reference/insights.md) — Show health insights for your deployment * [`npx convex mcp`](/cli/reference/mcp.md) — Manage the Model Context Protocol server for Convex \[BETA] * [`npx convex ai-files`](/cli/reference/ai-files.md) — Manage Convex AI files ## 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/overview.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/overview.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. #### Run an inline query[​](#run-an-inline-query "Direct link to Run an inline query") You can also evaluate a readonly inline query on your deployment: ``` npx convex run --inline-query 'await ctx.db.query("messages").take(5)' ``` For multi-statement queries, use an explicit `return`: ``` npx convex run --inline-query 'const firstMessage = await ctx.db.query("messages").first(); console.log(firstMessage?._id); return firstMessage;' ``` If you need full control, you can pass a full module source that exports a default query: ``` npx convex run --inline-query 'export default query({ handler: async (ctx) => { console.log("Write and test your query function here!"); return await ctx.db.query("YOUR_TABLE_NAME").take(10); }, })' ``` The function call is also completely sandboxed, so it can only read data and cannot modify the database or access the network. Use `--component ` to run the inline query inside a mounted component. Use `--prod` to run the inline query on 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. ### Show deployment health insights[​](#show-deployment-health-insights "Direct link to Show deployment health insights") ``` npx convex insights npx convex insights --details npx convex insights --prod ``` Show health insights for a Convex deployment over the last 72 hours. Reports [OCC (Optimistic Concurrency Control)](/error.md#1) conflicts and resource limit issues that may indicate performance problems. Add `--details` to include recent events for each insight. Use `--prod` to check the production deployment, `--preview-name ` for a preview deployment, or `--deployment-name ` for a specific deployment. ### 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](/production/environment-variables.md). You can alternatively use the [settings page on the dashboard](/dashboard/deployments/deployment-settings.md#environment-variables). Tip: to avoid secrets from ending up in your terminal shell history, you can pass the value via stdin, from a file, or interactively. Useful commands: ``` # Set a value interactively npx convex env set API_KEY # Set from MacOS clipboard pbpaste | npx convex env set API_KEY # Windows PowerShell Get-Clipboard | npx convex env set API_KEY # Read a value from a file npx convex env set PUBLIC_KEY --from-file key.pub # Set multiple variables via a file npx convex env set --from-file .env.defaults # Save environment variables to a file npx convex env list >> .env.convex # append npx convex env list > .env.convex # overwrite # Update values after editing them locally: npx convex env set --force < .env.convex ``` Note: to set variables on your production deployment, pass `--prod`. ## 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/multiple-deployments.md#preview)[​](#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. --- # `npx convex ai-files` Convex AI files help AI coding assistants (Cursor, Claude Code, etc.) understand Convex patterns and APIs. They are set up during your first `npx convex dev` and can be managed at any time with the commands below. ## Usage[​](#usage "Direct link to Usage") ``` npx convex ai-files [options] [command] ``` ## Subcommands[​](#subcommands "Direct link to Subcommands") * [`npx convex ai-files status`](#status) — Show the current status of Convex AI files * [`npx convex ai-files install`](#install) — Install or refresh Convex AI files * [`npx convex ai-files enable`](#enable) — Enable Convex AI files * [`npx convex ai-files update`](#update) — Update Convex AI files to the latest version * [`npx convex ai-files disable`](#disable) — Disable Convex AI files without removing them * [`npx convex ai-files remove`](#remove) — Remove all Convex AI files from the project ## `npx convex ai-files status`[​](#status "Direct link to status") Prints whether Convex AI files are enabled, and for each component: * convex/\_generated/ai/guidelines.md * AGENTS.md (Convex section) * CLAUDE.md (if installed by Convex) * Agent skills Fetches the latest hashes from version.convex.dev to report whether each file is up to date. If the network is unavailable the staleness check is skipped silently. ### Usage[​](#usage-1 "Direct link to Usage") ``` npx convex ai-files status [options] ``` ## `npx convex ai-files install`[​](#install "Direct link to install") Installs the following (or refreshes them if already present): * convex/\_generated/ai/guidelines.md * AGENTS.md (Convex section only) * CLAUDE.md (Convex section only) * Agent skills (installed to each coding agent's native path, configured via convex.json) ### Usage[​](#usage-2 "Direct link to Usage") ``` npx convex ai-files install [options] ``` ## `npx convex ai-files enable`[​](#enable "Direct link to enable") Re-enables Convex AI files by writing `aiFiles.enabled: true` to `convex.json`, then installs or refreshes the managed AI files. ### Usage[​](#usage-3 "Direct link to Usage") ``` npx convex ai-files enable [options] ``` ## `npx convex ai-files update`[​](#update "Direct link to update") Updates the following to their latest versions: * convex/\_generated/ai/guidelines.md * AGENTS.md (Convex section only) * CLAUDE.md (Convex section only) * Agent skills (installed to each coding agent's native path, configured via convex.json) ### Usage[​](#usage-4 "Direct link to Usage") ``` npx convex ai-files update [options] ``` ## `npx convex ai-files disable`[​](#disable "Direct link to disable") Writes `aiFiles.enabled: false` to `convex.json` so `npx convex dev` stops prompting to install AI files and suppresses staleness messages. Files already installed are left untouched - use `npx convex ai-files remove` if you also want to delete them. Run `npx convex ai-files enable` to re-enable at any time. ### Usage[​](#usage-5 "Direct link to Usage") ``` npx convex ai-files disable [options] ``` ## `npx convex ai-files remove`[​](#remove "Direct link to remove") Removes the following: * convex/\_generated/ai/ directory (guidelines.md, ai-files.state.json) * Convex sections from AGENTS.md and CLAUDE.md * Agent skills installed by `npx convex ai-files install` If removing the managed section leaves AGENTS.md or CLAUDE.md empty, the empty file is deleted. Otherwise the rest of the file is kept. Skills installed from other sources are not affected. Note: after `remove`, `npx convex dev` will suggest reinstalling AI files. Use `npx convex ai-files disable` to opt out entirely without deleting files. ### Usage[​](#usage-6 "Direct link to Usage") ``` npx convex ai-files remove [options] ``` --- # `npx convex codegen` Generate code in `convex/_generated/` based on the current contents of `convex/`. This code is generated automatically while running `npx convex dev` and should be committed to the repo (your code won't typecheck without it!). Regenerating it explicitly is rarely needed (e.g. in CI to ensure the correct code was checked in). This doesn't modify the code running on the deployment. ## Usage[​](#usage "Direct link to Usage") ``` npx convex codegen [options] ``` ## Options[​](#options "Direct link to Options") * `--dry-run` Print out the generated configuration to stdout instead of writing to convex directory * `--typecheck ` Whether to check TypeScript files with `tsc --noEmit`. * `--init` Also (over-)write the default convex/README.md and convex/tsconfig.json files, otherwise only written when creating a new Convex project. * `--component-dir ` Generate code for a specific component directory instead of the current application. --- # `npx convex dashboard` Open the dashboard in the browser ## Usage[​](#usage "Direct link to Usage") ``` npx convex dashboard [options] ``` ## Aliases[​](#aliases "Direct link to Aliases") * `dash` ## Options[​](#options "Direct link to Options") * `--no-open` Don't automatically open the dashboard in the default browser * `--prod` Open the dashboard for this project's default production deployment. * `--deployment ` Open the dashboard for a specific deployment. Accepts: * a deployment name (e.g. joyful-capybara-123) * a deployment reference (e.g. dev/james, staging) * `dev` (for your personal dev deployment) * `prod` (for your project’s default production deployment) * `local` (for your local dev deployment). You can also select deployments in other projects with `project-slug:reference` or `team-slug:project-slug:reference`. --- # `npx convex data` Inspect your Convex deployment's database. * List tables: `npx convex data` * List documents in a table: `npx convex data tableName` By default, this inspects your dev deployment. This works with system tables, such as `_storage`, in addition to your own tables. ## Usage[​](#usage "Direct link to Usage") ``` npx convex data [options] [table] ``` ## Arguments[​](#arguments "Direct link to Arguments") * `[table]` If specified, list documents in this table. ## Options[​](#options "Direct link to Options") * `--limit ` List only the `n` the most recently created documents. * `--order ` Order the documents by their `_creationTime`. * `--component ` Path to the component (e.g. "workflow" or "workflow/workpool") * `--format ` Format to print the data in. This flag is only required if the filename is missing an extension. * jsonArray (aka json): print the data as a JSON array of objects. * jsonLines (aka jsonl): print the data as a JSON object per line. * pretty: print the data in a human-readable format. * `--prod` Inspect the database in this project's default production deployment. * `--deployment ` Inspect the database in a specific deployment. Accepts: * a deployment name (e.g. joyful-capybara-123) * a deployment reference (e.g. dev/james, staging) * `dev` (for your personal dev deployment) * `prod` (for your project’s default production deployment) * `local` (for your local dev deployment). You can also select deployments in other projects with `project-slug:reference` or `team-slug:project-slug:reference`. --- # `npx convex deploy` Deploys code to a deployment. This is typically used for deploying to a prod or preview deployment manually or from CI; to deploy to your dev deployment when developing, use `npx convex dev`. The target deployment is chosen like this: * If the `CONVEX_DEPLOYMENT` environment variable is set (typical during local development), the target is the project’s default production deployment. * If the `CONVEX_DEPLOY_KEY` environment variable is set (typical in CI), it is the deployment associated with that key. * When it’s set to a preview deploy key, it will deploy to a preview deployment: * with the name of the current Git branch when running in CI (Vercel, Netlify, Cloudflare Pages, GitHub) * or with the name specified by the `--preview-name` or `--preview-create` flags `npx convex deploy` will: 1. Run a command if specified with `--cmd`, with the deployment URL available as an environment variable. 2. Typecheck your Convex functions. 3. Regenerate the generated code in the `convex/_generated` directory. 4. Bundle your Convex functions and their dependencies. 5. Push your functions, indexes, and schema to the deployment. 6. When deploying to a preview deployment, it runs the function specified by `--preview-run`. If any step fails, the next steps do not run. ## Usage[​](#usage "Direct link to Usage") ``` npx convex deploy [options] ``` ## Options[​](#options "Direct link to Options") * `-v, --verbose` Show full listing of changes * `--dry-run` Print out the generated configuration without deploying to your Convex deployment * `--typecheck ` Whether to check TypeScript files with `tsc --noEmit` before deploying. * `--typecheck-components` Check TypeScript files within component implementations with `tsc --noEmit`. * `--codegen ` Whether to regenerate code in `convex/_generated/` before pushing. * `--cmd ` Command to run as part of deploying your app (e.g. `vite build`). This command can depend on the environment variables specified in `--cmd-url-env-var-name` being set. * `--cmd-url-env-var-name ` Environment variable name to set Convex deployment URL (e.g. `VITE_CONVEX_URL`) when using `--cmd` * `--preview-run ` Function to run if deploying to a preview deployment. This is ignored if deploying to a production deployment. * `--preview-name ` The name to associate with this preview deployment. Defaults to the current Git branch name in Vercel, Netlify, Cloudflare Pages and GitHub CI. Reuses the existing deployment if one exists. * `--preview-create ` Like --preview-name, but deletes and recreates an existing preview deployment with the same name. This parameter can only be used with a preview deploy key (when used with another type of key, the command will return an error). * `--env-file ` Path to a custom file of environment variables, for choosing the deployment, e.g. CONVEX\_DEPLOYMENT or CONVEX\_SELF\_HOSTED\_URL. Same format as .env.local or .env files, and overrides them. * `--message ` Optional message to attach to this deployment in the audit log. --- # `npx convex deployment` Manage deployments in your project. ## Usage[​](#usage "Direct link to Usage") ``` npx convex deployment [options] [command] ``` ## Subcommands[​](#subcommands "Direct link to Subcommands") * [`npx convex deployment select`](#select) — Select the deployment to use when running commands * [`npx convex deployment create`](#create) — Create a new deployment for a project * [`npx convex deployment token`](#token) — Manage access tokens ## `npx convex deployment select`[​](#select "Direct link to select") Select the deployment to use when running commands. The deployment will be used by all `npx convex` commands, except `npx convex deploy`. You can also run individual commands on another deployment by using the --deployment flag on that command. * Select your personal cloud dev deployment in the current project: `npx convex deployment select dev` * Select your local deployment: `npx convex deployment select local` * Select a deployment in the same project by its reference: `npx convex deployment select dev/james` * Select a deployment in another project in the same team: `npx convex deployment select some-project:dev/james` * Select a deployment in a particular team/project: `npx convex deployment select some-team:some-project:dev/james` ### Usage[​](#usage-1 "Direct link to Usage") ``` npx convex deployment select [options] ``` ### Arguments[​](#arguments "Direct link to Arguments") * `` The deployment to use ## `npx convex deployment create`[​](#create "Direct link to create") Create a new deployment for a project. * Create a dev deployment and select it: `npx convex deployment create dev/my-new-feature --type dev --select` * Create a prod deployment named “staging”: `npx convex deployment create staging --type prod` ### Usage[​](#usage-2 "Direct link to Usage") ``` npx convex deployment create [options] [reference] ``` ### Arguments[​](#arguments-1 "Direct link to Arguments") * `[reference]` The reference for the new deployment, e.g. `staging` or `dev/my-feature`. Use `local` to create a local deployment. You can specify a team and project with `team-slug:project-slug:ref` (e.g. `my-team:my-project:staging` or `my-team:my-project:local`). Can be omitted when using `--default`. ### Options[​](#options "Direct link to Options") * `--type ` Deployment type * `--region ` Deployment region * `--select` Select the new deployment. This will update the Convex environment variables in .env.local. Subsequent `npx convex` commands will run against this deployment. * `--default` Make the new deployment your default production deployment (used by `npx convex deploy`) or your personal dev deployment. * `--expiration ` When the deployment expires (e.g. "none", "in 7 days", "2026-04-01T00:00:00Z", or a UNIX timestamp in seconds or milliseconds) ## `npx convex deployment token`[​](#token "Direct link to token") Create and delete access tokens. Currently supports deploy keys. ### Usage[​](#usage-3 "Direct link to Usage") ``` npx convex deployment token [options] [command] ``` ### `npx convex deployment token create`[​](#token-create "Direct link to token-create") Creates a deploy key that, when set as `CONVEX_DEPLOY_KEY`, scopes all commands to the target deployment. * Print a new deploy key to stdout: `npx convex deployment token create my-token` * Save a new deploy key in `.env.local`: `npx convex deployment token create my-token --save-env` * Save a new deploy key in a custom env file: `npx convex deployment token create ci-token --save-env .env.production` * Create a key for the project's prod: `npx convex deployment token create ci-token --deployment prod` #### Usage[​](#usage-4 "Direct link to Usage") ``` npx convex deployment token create [options] ``` #### Arguments[​](#arguments-2 "Direct link to Arguments") * `` Name for the new deploy key #### Options[​](#options-1 "Direct link to Options") * `--save-env [path]` Save the new key as CONVEX\_DEPLOY\_KEY in an env file instead of printing it. Defaults to .env.local. * `--prod` Create a deploy key for this project's default production deployment. * `--deployment ` Create a deploy key for a specific deployment. Accepts: * a deployment name (e.g. joyful-capybara-123) * a deployment reference (e.g. dev/james, staging) * `dev` (for your personal dev deployment) * `prod` (for your project’s default production deployment) * `local` (for your local dev deployment). You can also select deployments in other projects with `project-slug:reference` or `team-slug:project-slug:reference`. ### `npx convex deployment token delete`[​](#token-delete "Direct link to token-delete") Delete an access token. Currently only deploy keys (deployment-scoped access tokens) are supported. The positional `` can be the unique name of the deploy key (as passed to `token create`) or the deploy key value itself. The target deployment defaults to the currently-selected one; pass `--deployment` to target a different deployment. * Delete by name: `npx convex deployment token delete my-token` * Delete by value: `npx convex deployment token delete 'dev:happy-animal-123|ey...'` * Target prod: `npx convex deployment token delete ci-token --deployment prod` #### Usage[​](#usage-5 "Direct link to Usage") ``` npx convex deployment token delete [options] ``` #### Arguments[​](#arguments-3 "Direct link to Arguments") * `` The unique name of the deploy key, or the deploy key value itself. #### Options[​](#options-2 "Direct link to Options") * `--prod` Delete a deploy key for this project's default production deployment. * `--deployment ` Delete a deploy key for a specific deployment. Accepts: * a deployment name (e.g. joyful-capybara-123) * a deployment reference (e.g. dev/james, staging) * `dev` (for your personal dev deployment) * `prod` (for your project’s default production deployment) * `local` (for your local dev deployment). You can also select deployments in other projects with `project-slug:reference` or `team-slug:project-slug:reference`. --- # `npx convex dev` Develop against a dev deployment, watching for changes 1. Configures a new or existing project (if needed) 2. Updates generated types and pushes code to the configured dev deployment 3. Runs the provided command (if `--start` or `--run` is used) 4. Watches for file changes, and repeats step 2 ## Usage[​](#usage "Direct link to Usage") ``` npx convex dev [options] ``` ## Options[​](#options "Direct link to Options") * `-v, --verbose` Show full listing of changes * `--typecheck ` Check TypeScript files with `tsc --noEmit`. * `--typecheck-components` Check TypeScript files within component implementations with `tsc --noEmit`. * `--codegen ` Regenerate code in `convex/_generated/` * `--once` Execute only the first 3 steps, stop on any failure * `--until-success` Execute only the first 3 steps, on failure watch for local and remote changes and retry steps 2 and 3 * `--start ` Start a long-running command alongside `npx convex dev`, like a frontend dev server. The command inherits stdin/stdout so you can interact with it directly. Example: npx convex dev --start 'vite --open' * `--run ` The identifier of the function to run in step 3, like `api.init.createData` or `myDir/myFile:myFunction` * `--run-component ` If --run is used and the function is in a component, the path to the component (e.g. "workflow" or "workflow/workpool"). Components are a beta feature. This flag is unstable and may change in subsequent releases. * `--tail-logs [mode]` Choose whether to tail Convex function logs in this terminal: * `always` shows logs continuously * `pause-on-deploy` (the default) pauses logs during deploys so you can spot sync issues * `disable` hides logs while developing. * `--configure [choice]` Ignore existing configuration and configure new or existing project, interactively or set by --team \, --project \, and --dev-deployment local|cloud * `--env-file ` Path to a custom file of environment variables, for choosing the deployment, e.g. CONVEX\_DEPLOYMENT or CONVEX\_SELF\_HOSTED\_URL. Same format as .env.local or .env files, and overrides them. --- # `npx convex docs` Open the docs in the browser ## Usage[​](#usage "Direct link to Usage") ``` npx convex docs [options] ``` ## Options[​](#options "Direct link to Options") * `--no-open` Print docs URL instead of opening it in your browser --- # `npx convex env` Set and view environment variables on your deployment * Set a variable: `npx convex env set NAME 'value'` * Set interactively: `npx convex env set NAME` * Set multiple from file: `npx convex env set --from-file .env` * Unset a variable: `npx convex env remove NAME` * List all variables and their values: `npx convex env list` * List only variable names (no values): `npx convex env list --names-only` * Print a variable's value: `npx convex env get NAME` By default, this sets and views variables on your dev deployment. See the environment variables guide () to learn more. ## Usage[​](#usage "Direct link to Usage") ``` npx convex env [options] [command] ``` ## Options[​](#options "Direct link to Options") * `--prod` Set and view environment variables on this project's default production deployment. * `--deployment ` Set and view environment variables on a specific deployment. Accepts: * a deployment name (e.g. joyful-capybara-123) * a deployment reference (e.g. dev/james, staging) * `dev` (for your personal dev deployment) * `prod` (for your project’s default production deployment) * `local` (for your local dev deployment). You can also select deployments in other projects with `project-slug:reference` or `team-slug:project-slug:reference`. ## Subcommands[​](#subcommands "Direct link to Subcommands") * [`npx convex env set`](#set) — Set a variable * [`npx convex env get`](#get) — Print a variable's value * [`npx convex env remove`](#remove) — Unset a variable * [`npx convex env list`](#list) — List all environment variables and their values * [`npx convex env default`](#default) — Manage project-level default environment variables ## `npx convex env set`[​](#set "Direct link to set") Set environment variables on your deployment. * `npx convex env set NAME 'value'` * `npx convex env set NAME # omit a value to set one interactively` * `npx convex env set NAME --from-file value.txt` * `npx convex env set --from-file .env.defaults` When setting multiple values, it will refuse all changes if any variables are already set to different values by default. Pass --force to overwrite the provided values. To keep secrets out of your shell history, omit the value to pipe it in via stdin, for instance: * `pbpaste | npx convex env set API_KEY` (macOS) * `Get-Clipboard | npx convex env set API_KEY` (Windows PowerShell) To update many variables at once, save them with `npx convex env list > .env.convex`, edit the file, then reapply the changes with `npx convex env set --force < .env.convex`. ### Usage[​](#usage-1 "Direct link to Usage") ``` npx convex env set [options] [name] [value] ``` ### Arguments[​](#arguments "Direct link to Arguments") * `[name]` The name of the environment variable to set. * `[value]` The value to set the variable to. Omit to set it interactively. ### Options[​](#options-1 "Direct link to Options") * `--from-file ` Read environment variables from a .env file. Without --force, fails if any existing variable has a different value. * `--force` When setting multiple variables, overwrite existing environment variable values instead of failing on mismatch. ## `npx convex env get`[​](#get "Direct link to get") Print a variable's value: `npx convex env get NAME` ### Usage[​](#usage-2 "Direct link to Usage") ``` npx convex env get [options] ``` ### Arguments[​](#arguments-1 "Direct link to Arguments") * `` The name of the environment variable to print. ## `npx convex env remove`[​](#remove "Direct link to remove") Unset a variable: `npx convex env remove NAME` If the variable doesn't exist, the command doesn't do anything and succeeds. ### Usage[​](#usage-3 "Direct link to Usage") ``` npx convex env remove [options] ``` ### Aliases[​](#aliases "Direct link to Aliases") * `rm` * `unset` ### Arguments[​](#arguments-2 "Direct link to Arguments") * `` The name of the environment variable to unset. ## `npx convex env list`[​](#list "Direct link to list") * List all variables and their values: `npx convex env list` * List only variable names (no values): `npx convex env list --names-only` * Save all variables to a file: `npx convex env list > .env.convex` * Append to a file: `npx convex env list >> .env.convex` ### Usage[​](#usage-4 "Direct link to Usage") ``` npx convex env list [options] ``` ### Options[​](#options-2 "Direct link to Options") * `--names-only` List only the names of environment variables, without their values ## `npx convex env default`[​](#default "Direct link to default") Manage default environment variables for your project. The default environment variables read and written to by this command are the ones for the deployment type of the current deployment (i.e. dev in most cases), unless --type is provided. * Set a default variable: `npx convex env default set NAME 'value'` * Unset a default variable: `npx convex env default remove NAME` * List all default variables and their values: `npx convex env default list` * List only default variable names (no values): `npx convex env default list --names-only` * Print a default variable's value: `npx convex env default get NAME` ### Usage[​](#usage-5 "Direct link to Usage") ``` npx convex env default [options] [command] ``` ### `npx convex env default set`[​](#default-set "Direct link to default-set") Set default environment variables for your project's deployment type. * `npx convex env default set NAME 'value'` * `npx convex env default set NAME # omit a value to set one interactively` * `npx convex env default set NAME --from-file value.txt` * `npx convex env default set --from-file .env.defaults` When setting multiple values, it will refuse all changes if any variables are already set to different values by default. Pass --force to overwrite the provided values. The deployment type is determined by the current deployment (local maps to dev), or by --type if provided. #### Usage[​](#usage-6 "Direct link to Usage") ``` npx convex env default set [options] [name] [value] ``` #### Arguments[​](#arguments-3 "Direct link to Arguments") * `[name]` The name of the default environment variable to set. * `[value]` The value to set the variable to. Omit to set it interactively. #### Options[​](#options-3 "Direct link to Options") * `--from-file ` Read environment variables from a .env file. Without --force, fails if any existing variable has a different value. * `--force` When setting multiple variables, overwrite existing environment variable values instead of failing on mismatch. * `--type ` Manage default env vars for the given deployment type (dev, preview, prod) instead of inferring from the current deployment. * `--project ` Select a project manually. Accepts `team-slug:project-slug` or just `project-slug` (team inferred from your current project). Requires --type. ### `npx convex env default get`[​](#default-get "Direct link to default-get") Print a default variable's value: `npx convex env default get NAME` The deployment type is determined by the current deployment (local maps to dev), or by --type if provided. #### Usage[​](#usage-7 "Direct link to Usage") ``` npx convex env default get [options] ``` #### Arguments[​](#arguments-4 "Direct link to Arguments") * `` The name of the default environment variable to print. #### Options[​](#options-4 "Direct link to Options") * `--type ` Manage default env vars for the given deployment type (dev, preview, prod) instead of inferring from the current deployment. * `--project ` Select a project manually. Accepts `team-slug:project-slug` or just `project-slug` (team inferred from your current project). Requires --type. ### `npx convex env default remove`[​](#default-remove "Direct link to default-remove") Unset a default variable. * `npx convex env default remove NAME` If the variable doesn't exist, the command doesn't do anything and succeeds. The deployment type is determined by the current deployment (local maps to dev), or by --type if provided. #### Usage[​](#usage-8 "Direct link to Usage") ``` npx convex env default remove [options] ``` #### Aliases[​](#aliases-1 "Direct link to Aliases") * `rm` * `unset` #### Arguments[​](#arguments-5 "Direct link to Arguments") * `` The name of the default environment variable to unset. #### Options[​](#options-5 "Direct link to Options") * `--type ` Manage default env vars for the given deployment type (dev, preview, prod) instead of inferring from the current deployment. * `--project ` Select a project manually. Accepts `team-slug:project-slug` or just `project-slug` (team inferred from your current project). Requires --type. ### `npx convex env default list`[​](#default-list "Direct link to default-list") * List all default variables and their values: `npx convex env default list` * List only default variable names (no values): `npx convex env default list --names-only` The deployment type is determined by the current deployment (local maps to dev), or by --type if provided. #### Usage[​](#usage-9 "Direct link to Usage") ``` npx convex env default list [options] ``` #### Options[​](#options-6 "Direct link to Options") * `--names-only` List only the names of environment variables, without their values * `--type ` Manage default env vars for the given deployment type (dev, preview, prod) instead of inferring from the current deployment. * `--project ` Select a project manually. Accepts `team-slug:project-slug` or just `project-slug` (team inferred from your current project). Requires --type. --- # `npx convex export` Export data, and optionally file storage, from your Convex deployment to a ZIP file. * Export to a directory: `npx convex export --path dir/` * Export to a ZIP file: `npx convex export --path snapshot.zip` * Include file storage: `npx convex export --include-file-storage --path dir/` By default, this exports from your dev deployment. See the data export guide () for details and use cases. ## Usage[​](#usage "Direct link to Usage") ``` npx convex export [options] ``` ## Options[​](#options "Direct link to Options") * `--path ` Exports data into a ZIP file at this path, which may be a directory or unoccupied .zip path * `--include-file-storage` Includes stored files () in a \_storage folder within the ZIP file * `--prod` Export data from this project's default production deployment. * `--deployment ` Export data from a specific deployment. Accepts: * a deployment name (e.g. joyful-capybara-123) * a deployment reference (e.g. dev/james, staging) * `dev` (for your personal dev deployment) * `prod` (for your project’s default production deployment) * `local` (for your local dev deployment). You can also select deployments in other projects with `project-slug:reference` or `team-slug:project-slug:reference`. --- # `npx convex function-spec` List argument and return values to your Convex functions. By default, this inspects your dev deployment. ## Usage[​](#usage "Direct link to Usage") ``` npx convex function-spec [options] ``` ## Options[​](#options "Direct link to Options") * `--file` Output as JSON to a file. * `--prod` Read function metadata from this project's default production deployment. * `--deployment ` Read function metadata from a specific deployment. Accepts: * a deployment name (e.g. joyful-capybara-123) * a deployment reference (e.g. dev/james, staging) * `dev` (for your personal dev deployment) * `prod` (for your project’s default production deployment) * `local` (for your local dev deployment). You can also select deployments in other projects with `project-slug:reference` or `team-slug:project-slug:reference`. --- # `npx convex import` Import data from a file to your Convex deployment. * From a snapshot: `npx convex import snapshot.zip` * For a single table: `npx convex import --table tableName file.json` By default, this imports into your dev deployment. See the data import guide () for details and use cases. ## Usage[​](#usage "Direct link to Usage") ``` npx convex import [options] ``` ## Arguments[​](#arguments "Direct link to Arguments") * `` Path to the input file ## Options[​](#options "Direct link to Options") * `--table
` Destination table name. Required if format is csv, jsonLines, or jsonArray. Not supported if format is zip. * `--replace` Replace all existing data in any of the imported tables * `--append` Append imported data to any existing tables * `--replace-all` Replace all existing data in the deployment with the imported tables, deleting tables that don't appear in the import file or the schema, and clearing tables that appear in the schema but not in the import file * `-y, --yes` Skip confirmation prompt when import leads to deleting existing documents * `--format ` Input file format. This flag is only required if the filename is missing an extension. * CSV files must have a header, and each row's entries are interpreted either as a (floating point) number or a string. * JSON files must be an array of JSON objects. * JSONLines files must have a JSON object per line. * ZIP files must have one directory per table, containing \
/documents.jsonl. Snapshot exports from the Convex dashboard have this format. * `--component ` Path to the component (e.g. "workflow" or "workflow/workpool") * `--prod` Import data into this project's default production deployment. * `--deployment ` Import data into a specific deployment. Accepts: * a deployment name (e.g. joyful-capybara-123) * a deployment reference (e.g. dev/james, staging) * `dev` (for your personal dev deployment) * `prod` (for your project’s default production deployment) * `local` (for your local dev deployment). You can also select deployments in other projects with `project-slug:reference` or `team-slug:project-slug:reference`. --- # `npx convex insights` Show health insights for a Convex deployment over the last 72 hours. Displays OCC conflicts and resource limit issues that may indicate performance problems. * Show insights: `npx convex insights` * Include recent events for each insight: `npx convex insights --details` * Check the production deployment: `npx convex insights --prod` This command is only available for Convex cloud deployments when logged in as a user. ## Usage[​](#usage "Direct link to Usage") ``` npx convex insights [options] ``` ## Options[​](#options "Direct link to Options") * `--details` Show recent events for each insight * `--json` Output insights as JSON * `--prod` Show insights for this project's default production deployment. * `--deployment ` Show insights for a specific deployment. Accepts: * a deployment name (e.g. joyful-capybara-123) * a deployment reference (e.g. dev/james, staging) * `dev` (for your personal dev deployment) * `prod` (for your project’s default production deployment) * `local` (for your local dev deployment). You can also select deployments in other projects with `project-slug:reference` or `team-slug:project-slug:reference`. --- # `npx convex logout` Log out of Convex on this machine ## Usage[​](#usage "Direct link to Usage") ``` npx convex logout [options] ``` --- # `npx convex logs` Stream function logs from your Convex deployment. By default, this streams from your project's dev deployment. ## Usage[​](#usage "Direct link to Usage") ``` npx convex logs [options] ``` ## Options[​](#options "Direct link to Options") * `--history [n]` Show `n` most recent logs. Defaults to showing all available logs. * `--success` Print a log line for every successful function execution * `--jsonl` Output raw log events as JSONL * `--prod` Watch logs from this project's default production deployment. * `--deployment ` Watch logs from a specific deployment. Accepts: * a deployment name (e.g. joyful-capybara-123) * a deployment reference (e.g. dev/james, staging) * `dev` (for your personal dev deployment) * `prod` (for your project’s default production deployment) * `local` (for your local dev deployment). You can also select deployments in other projects with `project-slug:reference` or `team-slug:project-slug:reference`. --- # `npx convex mcp` Commands to initialize and run a Model Context Protocol server for Convex that can be used with AI tools. This server exposes your Convex codebase to AI tools in a structured way. ## Usage[​](#usage "Direct link to Usage") ``` npx convex mcp [options] [command] ``` ## Subcommands[​](#subcommands "Direct link to Subcommands") * [`npx convex mcp start`](#start) — Start the MCP server ## `npx convex mcp start`[​](#start "Direct link to start") Start the Model Context Protocol server for Convex that can be used with AI tools. ### Usage[​](#usage-1 "Direct link to Usage") ``` npx convex mcp start [options] ``` ### Options[​](#options "Direct link to Options") * `--project-dir ` Run the MCP server for a single project. By default, the MCP server can run for multiple projects, and each tool call specifies its project directory. * `--disable-tools ` Comma separated list of tool names to disable (options: data, envGet, envList, envRemove, envSet, functionSpec, insights, logs, run, runOneoffQuery, status, tables) * `--cautiously-allow-production-pii` Allow read-only tools (data, logs, queries) on production deployments. These tools may expose PII. Defaults to false. * `--dangerously-enable-production-deployments` DANGEROUSLY allow the MCP server to access production deployments, including mutating tools. Defaults to false. * `--prod` Run the MCP server on this project's default production deployment. * `--deployment ` Run the MCP server on a specific deployment. Accepts: * a deployment name (e.g. joyful-capybara-123) * a deployment reference (e.g. dev/james, staging) * `dev` (for your personal dev deployment) * `prod` (for your project’s default production deployment) * `local` (for your local dev deployment). You can also select deployments in other projects with `project-slug:reference` or `team-slug:project-slug:reference`. --- # `npx convex project` Manage projects in your team. ## Usage[​](#usage "Direct link to Usage") ``` npx convex project [options] [command] ``` ## Subcommands[​](#subcommands "Direct link to Subcommands") * [`npx convex project create`](#create) — Create a new project ## `npx convex project create`[​](#create "Direct link to create") Create a new project. Provisioning a deployment is a separate step — after creating the project, run `npx convex deployment create` to add one. * Create a project in your only team: `npx convex project create my-app` * Pick the team: `npx convex project create my-app --team my-team` ### Usage[​](#usage-1 "Direct link to Usage") ``` npx convex project create [options] [name] ``` ### Arguments[​](#arguments "Direct link to Arguments") * `[name]` The name of the new project. Prompted for when omitted in an interactive terminal; required otherwise. ### Options[​](#options "Direct link to Options") * `--team ` The team to create the project in. Defaults to your only team, or prompts when you belong to several. --- # `npx convex run` Run a function or evaluate an inline readonly query on your deployment. * Run a function with JSON arguments: `npx convex run messages:send '{"body": "hello", "author": "me"}'` * Run a function on prod: `npx convex run messages:list --prod` * Live-update a query's result: `npx convex run messages:list --watch` * Push local code before running: `npx convex run messages:send '{}' --push` * Evaluate an inline readonly query: `npx convex run --inline-query 'await ctx.db.query("messages").take(5)'` Arguments are specified as a JSON object. By default, this runs on your dev deployment. ## Usage[​](#usage "Direct link to Usage") ``` npx convex run [options] [functionName] [args] ``` ## Arguments[​](#arguments "Direct link to Arguments") * `[functionName]` identifier of the function to run, like `listMessages` or `dir/file:myFunction` * `[args]` JSON-formatted arguments object to pass to the function. ## Options[​](#options "Direct link to Options") * `-w, --watch` Watch a query, printing its result if the underlying data changes. Given function must be a query. * `--inline-query ` JavaScript to evaluate as a readonly query. The query is completely sandboxed, so it can only read data and cannot modify the database or access the network. This is a one-shot query and cannot be combined with `--watch`. Use `--component` to target a mounted component. To format the query: * Simple expressions are returned automatically, for example: `await ctx.db.query("messages").take(5)`. * For multi-statement queries, use an explicit return, for example: `const firstMessage = await ctx.db.query("messages").first(); console.log(firstMessage?._id); return firstMessage;`. * For full control, pass a module source that exports a default query, for example: `export default query({ handler: async (ctx) => { return await ctx.db.query("messages").take(10); } })`. * `--push` Push code to deployment before running the function. * `--identity ` JSON-formatted UserIdentity object, e.g. '{ name: "John", address: "0x123" }' * `--typecheck ` Whether to check TypeScript files with `tsc --noEmit`. * `--typecheck-components` Check TypeScript files within component implementations with `tsc --noEmit`. * `--codegen ` Regenerate code in `convex/_generated/` * `--component ` Path to the component (e.g. "workflow" or "workflow/workpool") * `--prod` Run the function on this project's default production deployment. * `--deployment ` Run the function on a specific deployment. Accepts: * a deployment name (e.g. joyful-capybara-123) * a deployment reference (e.g. dev/james, staging) * `dev` (for your personal dev deployment) * `prod` (for your project’s default production deployment) * `local` (for your local dev deployment). You can also select deployments in other projects with `project-slug:reference` or `team-slug:project-slug:reference`. --- # `npx convex update` Print instructions for updating the convex package ## Usage[​](#usage "Direct link to Usage") ``` npx convex update [options] ``` --- # Typecheck Performance When you are experiencing slow typechecking performance when pushing code to your Convex deployment (e.g. when running `npx convex dev`), there are a few different strategies you can try to improve performance or debug typechecking bottlenecks. ## Use the TypeScript 7 compiler[​](#use-the-typescript-7-compiler "Direct link to Use the TypeScript 7 compiler") The TypeScript 7 native preview, `tsgo`, may run faster than `tsc`. You can [configure your project](/production/project-configuration.md#configuring-the-typescript-compiler) to use `tsgo` with the `typescriptCompiler` option in `convex.json`. ## Debug slow typechecking[​](#debug-slow-typechecking "Direct link to Debug slow typechecking") Sometimes the TypeScript compiler can get stuck in a complex type inference loop. Often, adding a single manual type can help break the loop. You can [use the `generateTrace` flag](https://github.com/microsoft/TypeScript-wiki/blob/main/Performance-Tracing.md) to determine where the compiler is spending the most time: ``` npx tsc -p path/to/convex --generateTrace output_directory --incremental false ``` ## Use static codegen[​](#use-static-codegen "Direct link to Use static codegen") Static codegen is in beta Static codegen 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)! [Using static codegen](/production/project-configuration.md#using-static-code-generation-beta) can improve typechecking performance, but currently comes with [some caveats](/production/project-configuration.md#using-static-code-generation-beta). ## Disable typechecking[​](#disable-typechecking "Direct link to Disable typechecking") You can disable typechecking using the `--typecheck=disable` option with `npx convex dev` and `npx convex deploy`. In general, we do not recommend disabling typechecking. However, this can be used as a last resort workaround. --- # 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) ``` --- # 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.8.0@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[​](#authentication "Direct link to Authentication") You can use `ConvexClientWithAuth` in place of `ConvexClient` to use an authentication provider. You'll need to choose an existing `AuthProvider` implementation or possibly create your own. See the `AuthProvider` options below and consult the overall [Convex authentication docs](/auth/overview.md) as needed. ### Auth0[​](#authentication-with-auth0 "Direct link to Auth0") To use Auth0, you'll need the `convex-android-auth0` library 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. ### Clerk[​](#authentication-with-clerk "Direct link to Clerk") To use Clerk, you'll need to add a dependency on the `clerk-convex-kotlin` library as well as have a Clerk account and application configured to use Convex. See the [README](https://github.com/clerk/clerk-convex-kotlin/blob/main/README.md) in the `clerk-convex-kotlin` repo for detailed setup instructions. Clerk also has [a version of the Workout example app](https://github.com/clerk/clerk-convex-kotlin/tree/main/samples/workout-tracker) available so you can see a real-world integration. ### Custom auth providers[​](#custom-auth-providers "Direct link to Custom auth providers") It should also be possible to integrate other similar OpenID Connect authentication providers. See the [`AuthProvider`](https://github.com/get-convex/convex-mobile/blob/720a79a752e76297cc8c905d4f6e2dfbbc82bae7/android/convexmobile/src/main/java/dev/convex/android/ConvexClient.kt#L376) 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. ### Observing WebSocket state[​](#observing-websocket-state "Direct link to Observing WebSocket state") You can use the `webSocketStateFlow` attribute on a client to get a `StateFlow` that will keep you up to date on the status of the Convex WebSocket connection. The connection is either in `CONNECTED` or `CONNECTING` state, as Convex always tries to maintain a connection to the backend. *Available since [version 0.7.0](https://github.com/get-convex/convex-mobile/releases/tag/kotlin%400.7.0).* ### Debug logging[​](#debug-logging "Direct link to Debug logging") While developing your application, it can be useful to see the underlying state of the Convex client. Calling the `initConvexLogging()` function in your `Application` `onCreate` method will cause Convex to output log messages to `logcat` where they can easily be viewed in during development. caution The debug logs can contain sensitive data that your application sends to/from your Convex backend. Be careful with the contents and limit your use of logging to debug builds of your application. *Available since [version 0.6.1](https://github.com/get-convex/convex-mobile/releases/tag/kotlin%400.6.1).* --- # 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"`. --- # 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/overview.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 ``` 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 ``` 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 ``` 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, ); ``` --- # 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/overview.md). [Convex React library documentation](/client/react/overview.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 ``` "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`, `AuthLoading` and `AuthRefreshing` 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` package functions as both a client and a server context provider so you probably won't need the `ClerkProvider` from `@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 ``` 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 ``` "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 ``` 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 ``` 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 ``` 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 ``` 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 ``` import { auth } from "@clerk/nextjs/server"; export async function getAuthToken() { return (await (await auth()).getToken()) ?? undefined; } ``` app/auth.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/overview.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.tsx ``` 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`, `AuthLoading` and `AuthRefreshing` 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/overview.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.ts ``` 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.ts` in the `convex/` folder with a query function that loads the data. Exporting a query function from this file declares an API function named after the file and the export name, `api.tasks.get`. convex/tasks.ts ``` 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 While Convex doesn't have first-party clients for languages such as Go, Java, or C++, 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. 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. ``` npm i openapi-generator-cli npx openapi-generator-cli generate -i convex-spec.yaml -g go -o convex_client ``` 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. convex/load.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 Native To use Convex in [React Native](https://reactnative.dev/) use the [Convex React client library](/client/react/overview.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/overview.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.ts ``` 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 ``` 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 ``` 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. --- # 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/overview.md) 3. Authenticate users using [Authentication](/auth/overview.md) 4. Implement full text [Search](/search/overview.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 ``` 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 ``` 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. ### Experimental: query result object[​](#experimental-query-result-object "Direct link to Experimental: query result object") If you want a richer result object to handle when querying, try `useQuery_experimental`. It always returns an object with a `status` field, and does not throw errors by default. The `status` of the result object will be one of `"pending" | "success" | "error"`. To help ensure correct handling of query results, the return type requires that you check the `status` before accessing other fields (`data` or `error`). src/App.tsx ``` import { useQuery_experimental as useQuery } from "convex/react"; import { api } from "../convex/_generated/api"; function TaskList() { const result = useQuery({ query: api.tasks.list, args: { completed: false }, }); if (result.status === "pending") return
Loading...
; if (result.status === "error") return
Error: {result.error.message}
; // `status` guaranteed to be `"success"` at this point; `data` available. return result.data.map((task) =>
{task.text}
); } ``` If you're migrating existing code that leverages error boundaries, you can use the `throwOnError: true` option to maintain that behavior. ### 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 ``` 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 ``` 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 ``` 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 ``` 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 ``` 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 ``` 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 ``` 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 ``` 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. --- # 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). --- # Authentication `convex-svelte` integrates with any authentication provider through a small, reactive API. The `setupAuth()` / `useAuth()` primitives below are the low-level integration point; on top of them, the [Auth adapters](#auth-adapters) section covers higher-level options that wire a specific auth system to Convex for you. For background on how authentication works in Convex generally — including hosted providers and the OpenID Connect model — see [Authentication](/auth/overview.md). ## setupAuth / useAuth[​](#setupauth--useauth "Direct link to setupAuth / useAuth") `setupAuth()` accepts a **reactive getter** returning the auth provider's state and automatically manages `client.setAuth()` / `client.clearAuth()`. This mirrors React's `ConvexProviderWithAuth` — when the provider state changes (sign-in, sign-out, token refresh), the auth lifecycle updates automatically. src/routes/+layout.svelte ``` ``` `useAuth()` reads the resulting state in any child component: ``` {#if auth.isLoading} Checking authentication... {:else if !auth.isAuthenticated} Please sign in. {:else} Welcome, {user.data?.name}! {/if} ``` When the auth provider's `isAuthenticated` changes from `true` to `false` (user signs out), the internal `$effect` re-runs, calls `clearAuth()` automatically, and `useAuth().isAuthenticated` updates to `false`. No manual cleanup needed. ## SSR initial state[​](#ssr-initial-state "Direct link to SSR initial state") Pass `initialState` to seed the server render before any client-side `$effect` runs: src/routes/+layout.svelte ``` ``` The server state is trusted until the client-side auth flow settles, then the client takes over. For authenticated server-side data fetching, see [Authenticated fetches](/client/svelte/sveltekit-server-rendering.md#authenticated-fetches). ## Auth adapters[​](#auth-adapters "Direct link to Auth adapters") The primitives above let you wire up any provider by hand. In practice, most apps reach for a higher-level adapter that connects a specific auth system to Convex and calls `setupAuth()` for you, so `useAuth()` works out of the box. ### Convex Auth[​](#convex-auth "Direct link to Convex Auth") [Convex Auth](/auth/convex-auth.md) is Convex's built-in, officially documented auth library — authentication runs entirely on your own Convex deployment with no third-party service. * **Svelte adapter:** [`@mmailaender/convex-auth-svelte`](https://github.com/mmailaender/convex-auth-svelte) (community-maintained) — wires Convex Auth to `setupAuth()` / `useAuth()`, with SvelteKit SSR support. ### Convex Better Auth[​](#convex-better-auth "Direct link to Convex Better Auth") [Convex Better Auth](https://labs.convex.dev/better-auth) integrates the powerful [Better Auth](https://www.better-auth.com) library with Convex. * **Svelte adapter:** [`@mmailaender/convex-better-auth-svelte`](https://github.com/mmailaender/convex-better-auth-svelte) (community-maintained) — its `createSvelteAuthClient()` calls `setupAuth()` internally with a reactive session getter, so `useAuth()` from either package works. SSR-ready. * **UI components:** [Convex Better Auth UI](https://github.com/mmailaender/Convex-Better-Auth-UI) (community-maintained) — production-ready, shadcn-style auth and organization management for SvelteKit (and Next.js), copied into your project. Gets user and organization management running in minutes while keeping full control of the code. ### Hosted providers[​](#hosted-providers "Direct link to Hosted providers") Convex also works with hosted identity platforms via OpenID Connect JWTs — [Clerk](/auth/clerk.md), [WorkOS AuthKit](/auth/authkit/.md), and [Auth0](/auth/auth0.md). There are no dedicated `convex-svelte` wrappers for these yet, so in a Svelte app you integrate them through the low-level [`setupAuth()`](#setupauth--useauth) pattern: return the provider's reactive auth state (`isLoading`, `isAuthenticated`, `fetchAccessToken`) from the getter. ## Low-level: client.setAuth()[​](#low-level-clientsetauth "Direct link to Low-level: client.setAuth()") You can also use `client.setAuth()` directly for custom integrations: ``` ``` ## API reference[​](#api-reference "Direct link to API reference") Authentication exports from `convex-svelte`: | Export | Kind | Description | | ------------------------------- | -------- | ---------------------------------------------------------------------------- | | `setupAuth(provider, options?)` | Function | Set up reactive authentication. Manages `setAuth`/`clearAuth` automatically. | | `useAuth()` | Function | Read auth state (`isLoading`, `isAuthenticated`) from context. | | `ConvexAuthProvider` | Type | Auth provider state: `isLoading`, `isAuthenticated`, `fetchAccessToken`. | | `SetupAuthOptions` | Type | Options for `setupAuth`: `initialState` for SSR hydration. | | `UseAuthReturn` | Type | Return type of `useAuth`: `isLoading`, `isAuthenticated`. | --- # Convex Svelte [Convex Svelte](https://www.npmjs.com/package/convex-svelte) is the client library enabling your Svelte application to interact with your Convex backend. It enhances the [`ConvexClient`](/api/classes/browser.ConvexClient.md) with declarative subscriptions for [Svelte 5](https://svelte.dev/), so your frontend code can: 1. Receive live updates to your [queries](/functions/query-functions.md) with automatic reactivity 2. Call your [mutations](/functions/mutation-functions.md) and [actions](/functions/actions.md) 3. [Paginate](/database/pagination.md) through large datasets 4. [Authenticate users](/auth/overview.md) 5. [Server-side render](/client/svelte/sveltekit-server-rendering.md) data in SvelteKit Source & issues Source: [get-convex/convex-svelte](https://github.com/get-convex/convex-svelte).
Found a bug or have a feature request? Open an issue in its [issue tracker](https://github.com/get-convex/convex-svelte/issues). Follow the [Svelte Quickstart](/quickstart/svelte.md) to get started, or read on for the full setup. ## Installation[​](#installation "Direct link to Installation") Install the Convex client and server library: * npm * pnpm * yarn * bun ``` npm install convex convex-svelte ``` ``` pnpm add convex convex-svelte ``` ``` yarn add convex convex-svelte ``` ``` bun add convex convex-svelte ``` Svelte doesn't like referencing code outside of `src/`, so customize the Convex functions directory. Create a `convex.json` in your project root: convex.json ``` { "functions": "src/convex/" } ``` Set up a Convex dev deployment: ``` npx convex dev ``` This will prompt you to log in, create a project, and save your deployment URLs. It also creates a `src/convex/` folder for your backend API functions. ## Setup[​](#setup "Direct link to Setup") Call `setupConvex()` once in a root layout component (e.g. `+layout.svelte`). This initializes a [`ConvexClient`](/api/classes/browser.ConvexClient.md) and stores it in Svelte context so child components can access it. The client is app-scoped: it stays open for the lifetime of the app (remounts and HMR reuse the same connection) and supports a single deployment URL. For explicit teardown — e.g. in tests — call `closeConvex()`. src/routes/+layout.svelte ``` ``` `setupConvex()` returns the `ConvexClient` instance, which you can use directly in the layout for mutations or actions (e.g. an auth nav bar). In child components and `.ts` files, use `getConvexClient()` to retrieve it — see [Client access](/client/svelte/reactivity.md#client-access). You can pass `ConvexClientOptions` as the second argument to configure the [`ConvexClient`](/api/classes/browser.ConvexClient.md). Non-SvelteKit usage If you're using plain Vite + Svelte (no SvelteKit), replace `$env/static/public` with `import.meta.env.VITE_CONVEX_URL` and set `VITE_CONVEX_URL` in your `.env` file. ## Fetching data[​](#fetching-data "Direct link to Fetching data") Use `useQuery()` to subscribe to a Convex query with automatic real-time updates. When the data changes on the server, your component re-renders automatically. src/routes/+page.svelte ``` {#if messages.isLoading} Loading... {:else if messages.error != null} failed to load: {messages.error.toString()} {:else}
    {#each messages.data as message}
  • {message.author} {message.body}
  • {/each}
{/if} ``` See [Queries, Mutations & Actions](/client/svelte/reactivity.md) for the full reactive API — query options, skipping, mutations, actions, optimistic updates, pagination, and accessing the client outside of components. ## Next steps[​](#next-steps "Direct link to Next steps") * [Queries, Mutations & Actions](/client/svelte/reactivity.md) — the core reactive API * [Authentication](/client/svelte/authentication.md) — wire up auth providers * [SvelteKit Server Rendering](/client/svelte/sveltekit-server-rendering.md) — SSR with `convexLoad` * [Why server-side rendering with Convex?](/client/svelte/why-server-rendering.md) — performance deep dive * [Troubleshooting](/client/svelte/troubleshooting.md) — common errors and fixes --- # Queries, Mutations & Actions This page covers the core reactive API of [`convex-svelte`](https://www.npmjs.com/package/convex-svelte). Everything here works in **any Svelte app** — SvelteKit, Vite + Svelte, or any other setup. Make sure you've called `setupConvex()` in a root layout first — see [Overview](/client/svelte/overview.md#setup). ## Two clients[​](#two-clients "Direct link to Two clients") Convex Svelte talks to your backend through two clients, and the one you use decides what's available: | | `ConvexClient` (WebSocket) | `ConvexHttpClient` (`fetch`) | | ---------------------- | ------------------------------------ | ---------------------------- | | **Queries** | `useQuery()` | `.query()` | | **Mutations** | `useMutation()` — optimistic updates | `.mutation()` | | **Actions** | `useAction()` | `.action()` | | **Live subscriptions** | ✓ | - | `ConvexClient` is the live WebSocket client that `setupConvex()` opens — the `useQuery` / `useMutation` / `useAction` helpers are thin Svelte wrappers around it, and you can retrieve it directly with [`getConvexClient()` / `useConvexClient()`](#client-access). `ConvexHttpClient` is a stateless `fetch`-based client for single calls from server code or scripts — see [One-time calls](#one-time-calls). Live subscriptions and optimistic updates are WebSocket-only, and optimistic updates apply to mutations only. ## Queries[​](#queries "Direct link to Queries") Use `useQuery()` to subscribe to a Convex query with automatic real-time updates. When the data changes on the server, your component re-renders automatically. ``` {#if messages.isLoading} Loading... {:else if messages.error != null} failed to load: {messages.error.toString()} {:else}
    {#each messages.data as message}
  • {message.author} {message.body}
  • {/each}
{/if} ``` The returned object is reactive and has the following shape: | Property | Type | Description | | ----------- | -------------------- | ---------------------------------------------------------- | | `data` | `T \| undefined` | The query result, or `undefined` while loading | | `error` | `Error \| undefined` | The error, if the query failed | | `isLoading` | `boolean` | `true` until the first result or error is received | | `isStale` | `boolean` | `true` when displaying cached data from previous arguments | ### Options[​](#options "Direct link to Options") * **`initialData`** — pre-loaded data for SSR/hydration, avoids the loading state (see [SSR with initialData](/client/svelte/sveltekit-server-rendering.md#ssr-with-initialdata-manual-alternative)) * **`keepPreviousData`** — when `true`, keeps displaying the previous result while new data loads after args change ### Skipping queries[​](#skipping-queries "Direct link to Skipping queries") You can conditionally skip a query by returning `'skip'` from the arguments function. This is useful when a query depends on some condition, like authentication state or user input. ``` {#if user.isLoading} Loading user... {:else if user.error} Error: {user.error} {:else if user.data} Welcome, {user.data.name}! {/if} ``` When a query is skipped, `isLoading` will be `false`, `error` will be `null`, and `data` will be `undefined`. ## Mutations & Actions[​](#mutations--actions "Direct link to Mutations & Actions") Use `useMutation()` and `useAction()` to get callable functions for your Convex mutations and actions. Both use the module-level singleton (`getConvexClient()`) internally, so they work in `.svelte` components **and** plain `.ts` / `.js` files — anywhere after `setupConvex()` has been called. ```
``` Actions are similar to mutations but can have side effects like calling third-party APIs: ``` import { useAction } from "convex-svelte"; import { api } from "../convex/_generated/api.js"; const generateUploadUrl = useAction(api.files.generateUploadUrl); const uploadUrl = await generateUploadUrl({}); ``` ### Optimistic updates[​](#optimistic-updates "Direct link to Optimistic updates") Optimistic updates let you update the UI immediately when a mutation is called, without waiting for the server to respond. Pass an `optimisticUpdate` callback in the mutation options at the call site to update the local query cache. ``` ``` Inside the `optimisticUpdate` callback, use `store.setQuery()` to update the local cache for a specific query. The arguments are: 1. **Query reference** — the query to update (e.g. `api.user.get`) 2. **Query arguments** — must match the arguments used by the active `useQuery()` subscription 3. **New value** — the optimistic data to display immediately If the mutation fails, the optimistic update is automatically rolled back and the UI reverts to the server state. ## Client access[​](#client-access "Direct link to Client access") ### `getConvexClient()` — universal client access[​](#getconvexclient--universal-client-access "Direct link to getconvexclient--universal-client-access") `getConvexClient()` retrieves the client from a **module-level singleton**. It works anywhere — `.svelte` components, plain `.ts` utility files, service layers, async callbacks — as long as `setupConvex()` has been called first. This is the recommended way to access the client outside of the layout where `setupConvex()` returns it directly. ### `useConvexClient()` — Svelte context alternative[​](#useconvexclient--svelte-context-alternative "Direct link to useconvexclient--svelte-context-alternative") `useConvexClient()` retrieves the same client from **Svelte context** via `getContext()`. It only works during component initialization — inside `.svelte` files or code called synchronously from a component's `
{ e.preventDefault(); createTask(text); text = ""; }} > ``` note The `.svelte.ts` file extension enables Svelte 5 runes (`$state`, `$derived`, `$effect`) but does **not** make `getContext()` work outside components. If you need the client in a plain `.ts` file, use `getConvexClient()`, not `useConvexClient()`. ## One-time calls[​](#one-time-calls "Direct link to One-time calls") `useQuery` keeps a live subscription open. When you instead need a single result with no ongoing binding — a SvelteKit load function, a form action, an endpoint, or a one-off script — use the stateless [`ConvexHttpClient`](/client/javascript/overview.md#http-client), which runs `query` / `mutation` / `action` over `fetch` with no WebSocket. ``` import { ConvexHttpClient } from "convex/browser"; import { api } from "../convex/_generated/api.js"; const client = new ConvexHttpClient(process.env.CONVEX_URL!); const count = await client.query(api.tasks.count, {}); ``` In SvelteKit, the [`createConvexHttpClient()`](/client/svelte/sveltekit-server-rendering.md#server-helpers) helper builds one with per-request auth wired in. The HTTP client supports one-shot calls only — no subscriptions and no optimistic updates. Mutations and actions have no "live" form to opt out of: `useMutation()` and `useAction()` are already one-shot calls (thin wrappers over the WebSocket client), so they cover writes in both reactive and non-reactive code. ## Paginated queries[​](#paginated-queries "Direct link to Paginated queries") For queries that return large datasets, use `usePaginatedQuery()` to load results incrementally. This hook manages cursor-based pagination automatically and provides a `loadMore` function to fetch additional pages. ``` {#if paginatedMessages.isLoading} Loading... {:else if paginatedMessages.error} Error: {paginatedMessages.error.toString()} {:else}
    {#each paginatedMessages.results as message}
  • {message.author} {message.body}
  • {/each}
{#if paginatedMessages.status === "CanLoadMore"} {/if} {/if} ``` ### Options[​](#options-1 "Direct link to Options") * **`initialNumItems`** (required) — number of items to load on the first page * **`initialData`** — optional initial data for SSR/hydration * **`keepPreviousData`** — when `true`, keeps previous results visible while loading new data after args change You can also skip a paginated query by returning `'skip'` from the arguments function, just like with `useQuery()`. ``` ``` ## API reference[​](#api-reference "Direct link to API reference") Functions and types exported from `convex-svelte`: | Export | Kind | Description | | ----------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------- | | `setupConvex(url, options?)` | Function | Initialize the Convex client and store it in Svelte context. Call once in a root layout. Returns `ConvexClient`. | | `useConvexClient()` | Function | Retrieve the `ConvexClient` from Svelte context. Must be called during component initialization. | | `getConvexClient()` | Function | Retrieve the `ConvexClient` module singleton. Works anywhere — no Svelte context needed. | | `closeConvex()` | Function | Close the app-scoped client and clear the singleton. For explicit teardown, e.g. in tests. Returns `Promise`. | | `useQuery(query, args, options?)` | Function | Subscribe to a Convex query with reactive updates. Returns `UseQueryReturn`. | | `UseQueryOptions` | Type | Options for `useQuery`: `initialData`, `keepPreviousData`. | | `UseQueryReturn` | Type | Return type of `useQuery`: `data`, `error`, `isLoading`, `isStale`. | | `usePaginatedQuery(query, args, options)` | Function | Subscribe to a paginated Convex query with cursor management. Returns `UsePaginatedQueryReturn`. | | `UsePaginatedQueryOptions` | Type | Options for `usePaginatedQuery`: `initialNumItems`, `initialData`, `keepPreviousData`. | | `UsePaginatedQueryReturn` | Type | Return type of `usePaginatedQuery`: `results`, `status`, `isLoading`, `loadMore`, `error`. | Authentication exports (`setupAuth`, `useAuth`, and related types) are documented on the [Authentication](/client/svelte/authentication.md) page. --- # SvelteKit Server Rendering This page builds on the core [Queries, Mutations & Actions](/client/svelte/reactivity.md) API. Make sure `setupConvex()` is in your root layout before using these features — see [Overview](/client/svelte/overview.md#setup). Import from `convex-svelte/sveltekit` for SvelteKit-specific features: SSR transport with live upgrade, and a server-side HTTP client helper. Why bother with SSR on a realtime backend? The client will open a WebSocket and get live updates anyway — so is SSR worth it? Almost always yes: it's faster for time-to-data on first page load. See [Why server-side rendering with Convex?](/client/svelte/why-server-rendering.md) for the full comparison. ## SSR with convexLoad / convexLoadPaginated (recommended)[​](#ssr-with-convexload--convexloadpaginated-recommended "Direct link to SSR with convexLoad / convexLoadPaginated (recommended)") `convexLoad()` and `convexLoadPaginated()` fetch data on the server and automatically upgrade to live subscriptions on the client. No manual `initialData` wiring needed. Use `convexLoad()` for regular queries and `convexLoadPaginated()` for paginated queries. ### Setup[​](#setup "Direct link to Setup") Add `initConvex()` and the transport hooks to `hooks.ts` (universal hooks — runs on both server and client). `initConvex()` creates the `ConvexClient` singleton early so the transport decoder can upgrade SSR data to live subscriptions. `setupConvex()` in your root layout automatically reuses this singleton. If you only use `convexLoad()`, you only need the `ConvexLoadResult` transport. Add `ConvexLoadPaginatedResult` when using `convexLoadPaginated()`. src/hooks.ts ``` import { initConvex, encodeConvexLoad, decodeConvexLoad, encodeConvexLoadPaginated, decodeConvexLoadPaginated, } from "convex-svelte/sveltekit"; import { PUBLIC_CONVEX_URL } from "$env/static/public"; initConvex(PUBLIC_CONVEX_URL); export const transport = { ConvexLoadResult: { encode: encodeConvexLoad, decode: decodeConvexLoad, }, // Only needed if you use convexLoadPaginated() ConvexLoadPaginatedResult: { encode: encodeConvexLoadPaginated, decode: decodeConvexLoadPaginated, }, }; ``` ### Usage with convexLoad[​](#usage-with-convexload "Direct link to Usage with convexLoad") src/routes/+page.ts ``` import { convexLoad } from "convex-svelte/sveltekit"; import { api } from "$convex/_generated/api"; export const load = async () => ({ tasks: await convexLoad(api.tasks.get, {}), }); ``` src/routes/+page.svelte ``` {#if tasks.isLoading} Loading... {:else if tasks.error} Error: {tasks.error.message} {:else}
    {#each tasks.data as task}
  • {task.text}
  • {/each}
{/if} ``` The result has the same shape as `useQuery()` — `.data`, `.isLoading`, `.error`, `.isStale` — and is reactive. On first load, data arrives via SSR (no loading flash). After hydration, a live WebSocket subscription takes over automatically. ### Usage with convexLoadPaginated[​](#usage-with-convexloadpaginated "Direct link to Usage with convexLoadPaginated") `convexLoadPaginated()` works the same way but for paginated queries. It fetches the first page on the server and upgrades to a live paginated subscription on the client — with `loadMore()` support for incremental loading. src/routes/+page.ts ``` import { convexLoadPaginated } from "convex-svelte/sveltekit"; import { api } from "$convex/_generated/api"; export const load = async () => ({ messages: await convexLoadPaginated( api.messages.paginatedList, { searchWords: [] }, { initialNumItems: 10 }, ), }); ``` src/routes/+page.svelte ``` {#if messages.isLoading} Loading... {:else if messages.error} Error: {messages.error.message} {:else}
    {#each messages.results as message}
  • {message.author}: {message.body}
  • {/each}
{#if messages.status === "CanLoadMore"} {/if} {/if} ``` The result has the same shape as `usePaginatedQuery()` — `.results`, `.status`, `.isLoading`, `.error`, `.loadMore()` — and is reactive. On first load, the first page arrives via SSR (no loading flash). After hydration, a live WebSocket subscription takes over and `loadMore()` becomes functional. ### Authenticated fetches[​](#authenticated-fetches "Direct link to Authenticated fetches") For authenticated SSR fetches, use `withServerConvexToken` in your server hook. This stores the auth token per-request via `AsyncLocalStorage`, so `convexLoad` and `createConvexHttpClient` pick it up automatically — no `{ token }` option needed. src/hooks.server.ts ``` import type { Handle } from "@sveltejs/kit"; import { withServerConvexToken } from "convex-svelte/sveltekit/server"; export const handle: Handle = async ({ event, resolve }) => { const token = await getAuthToken(event.cookies); // your auth provider event.locals.token = token; return withServerConvexToken(token, () => resolve(event)); }; ``` Then use `convexLoad` in **any** load function — `+page.ts` or `+page.server.ts`: src/routes/+page.ts ``` // Universal — works for both SSR and client-side navigation import { convexLoad } from "convex-svelte/sveltekit"; import { api } from "$convex/_generated/api"; export const load = async () => ({ tasks: await convexLoad(api.tasks.get, {}), }); ``` The explicit `{ token }` option still works as a manual override: src/routes/+page.server.ts ``` // Explicit token (escape hatch) export const load = async ({ locals }) => ({ tasks: await convexLoad(api.tasks.get, {}, { token: locals.token }), }); ``` ### Skipping queries[​](#skipping-queries "Direct link to Skipping queries") Pass `'skip'` as args to avoid fetching — useful for auth-gated queries that should not run when the user is unauthenticated: src/routes/+page.server.ts ``` // Skip when unauthenticated export const load = async ({ locals }) => ({ user: await convexLoad(api.users.get, locals.token ? {} : "skip"), }); ``` When skipped, `convexLoad` returns `{ data: undefined, isLoading: false, error: undefined, isStale: false }` without making any request. `convexLoadPaginated` returns `{ results: [], status: 'Exhausted', isLoading: false, error: undefined, loadMore: () => false }`. ### Choosing between `+page.ts` and `+page.server.ts`[​](#choosing-between-pagets-and-pageserverts "Direct link to choosing-between-pagets-and-pageserverts") `convexLoad` works in both universal (`+page.ts`) and server-only (`+page.server.ts`) load functions. The difference is what happens during **client-side navigation** (after the first SSR page load): * **`+page.ts` (universal):** On client-side navigation, `convexLoad` runs in the browser and queries Convex directly — no server roundtrip. Auth is handled implicitly via the already-authenticated `ConvexClient` singleton (configured by `setupAuth()` in your root layout). * **`+page.server.ts` (server-only):** On client-side navigation, SvelteKit fetches from your server, which then queries Convex — adding an extra network hop. Auth is always explicit (server-side via `withServerConvexToken` or `locals.token`). Both produce identical SSR on first page load. Use `+page.ts` for best navigation performance. Use `+page.server.ts` if you need access to server-only data (e.g. `locals`, cookies) or prefer explicit auth handling. ## SSR with initialData (manual alternative)[​](#ssr-with-initialdata-manual-alternative "Direct link to SSR with initialData (manual alternative)") If you prefer server-only load functions (`+page.server.ts`) or need more control, you can use the `initialData` option on `useQuery()` and `usePaginatedQuery()` directly. src/routes/+page.server.ts ``` import { ConvexHttpClient } from "convex/browser"; import type { PageServerLoad } from "./$types.js"; import { PUBLIC_CONVEX_URL } from "$env/static/public"; import { api } from "../convex/_generated/api.js"; export const load = (async () => { const client = new ConvexHttpClient(PUBLIC_CONVEX_URL!); return { messages: await client.query(api.messages.list, { searchWords: [] }), }; }) satisfies PageServerLoad; ``` src/routes/+page.svelte ``` ``` Combining `initialData` with `keepPreviousData: true` (or never changing the query arguments) should be enough to avoid ever seeing a loading state. When to use this over convexLoad Use `initialData` when building a library that needs to support Svelte-only, SvelteKit SPA, and SvelteKit SSR without requiring the transport hook setup. ## Server helpers[​](#server-helpers "Direct link to Server helpers") These are server-only helpers (`hooks.server.ts`, `+page.server.ts`, form actions, endpoints) for authenticating SSR fetches and running one-off calls from the server. For one-off calls from the **client**, use [`getConvexClient()`](/client/svelte/reactivity.md#one-time-calls) instead. ### withServerConvexToken (recommended)[​](#withserverconvextoken-recommended "Direct link to withServerConvexToken (recommended)") Import from `convex-svelte/sveltekit/server`. Wraps your SvelteKit `resolve()` call to store the auth token per-request via `AsyncLocalStorage`. Both `convexLoad` and `createConvexHttpClient` automatically read it during SSR. src/hooks.server.ts ``` import type { Handle } from "@sveltejs/kit"; import { withServerConvexToken } from "convex-svelte/sveltekit/server"; export const handle: Handle = async ({ event, resolve }) => { const token = await getAuthToken(event.cookies); event.locals.token = token; // still available for direct use return withServerConvexToken(token, () => resolve(event)); }; ``` src/app.d.ts ``` declare global { namespace App { interface Locals { token: string | undefined; } } } ``` With this setup, `convexLoad()` and `createConvexHttpClient()` automatically authenticate during SSR — no `{ token }` option needed in load functions. ### Setting up `locals.token` (without withServerConvexToken)[​](#setting-up-localstoken-without-withserverconvextoken "Direct link to setting-up-localstoken-without-withserverconvextoken") If you prefer not to use `withServerConvexToken`, you can still extract the token and pass it explicitly: src/hooks.server.ts ``` import type { Handle } from "@sveltejs/kit"; export const handle: Handle = async ({ event, resolve }) => { event.locals.token = await getAuthToken(event.cookies); return resolve(event); }; ``` Then pass `{ token: locals.token }` to `convexLoad` or `createConvexHttpClient` in each load function. ### createConvexHttpClient[​](#createconvexhttpclient "Direct link to createConvexHttpClient") For server-only code (`+page.server.ts`, form actions, API routes), use `createConvexHttpClient()`: src/routes/+page.server.ts ``` // With withServerConvexToken (no args needed) import { createConvexHttpClient } from "convex-svelte/sveltekit"; import { api } from "$convex/_generated/api"; export const load = async () => { const client = createConvexHttpClient(); const tasks = await client.query(api.tasks.get, {}); return { tasks }; }; ``` Explicit token still works as an override: src/routes/+page.server.ts ``` // Explicit token (escape hatch) export const load = async ({ locals }) => { const client = createConvexHttpClient({ token: locals.token }); const tasks = await client.query(api.tasks.get, {}); return { tasks }; }; ``` The `url` option falls back to the URL set by `initConvex()`. ## Deploying[​](#deploying "Direct link to Deploying") See [Deploy Your Frontend](/production/hosting/.md) and [`npx convex deploy`](/cli/reference/deploy.md) for detailed instructions on deploying your app and Convex functions to production. For the biggest SSR performance win, co-locate your framework server in the same region as Convex — see [Co-locate your server with Convex](/client/svelte/why-server-rendering.md#co-locate-your-server-with-convex). ## API reference[​](#api-reference "Direct link to API reference") Functions and types exported from `convex-svelte/sveltekit`: | Export | Kind | Description | | ------------------------------------------- | -------- | ------------------------------------------------------------------------------------------ | | `initConvex(url, options?)` | Function | Create the `ConvexClient` singleton early. Only needed for [convexLoad SSR setup](#setup). | | `getConvexUrl()` | Function | Retrieve the deployment URL set by `initConvex()` or `setupConvex()`. | | `closeConvex()` | Function | Close the app-scoped client and clear the singleton (also exported from `convex-svelte`). | | `convexLoad(query, args, options?)` | Function | Fetch data server-side, upgrade to live subscription on client. | | `encodeConvexLoad` | Function | Transport encoder — use in `hooks.ts` (see [Setup](#setup)). | | `decodeConvexLoad` | Function | Transport decoder — use in `hooks.ts` (see [Setup](#setup)). | | `convexLoadPaginated(query, args, options)` | Function | Fetch first page server-side, upgrade to live paginated subscription on client. | | `encodeConvexLoadPaginated` | Function | Paginated transport encoder — use in `hooks.ts`. | | `decodeConvexLoadPaginated` | Function | Paginated transport decoder — use in `hooks.ts`. | | `createConvexHttpClient(options?)` | Function | Create a `ConvexHttpClient` for server-side use. | | `CreateConvexHttpClientOptions` | Type | Options for `createConvexHttpClient`: `url`, `token`, `options`. | The server-only helper `withServerConvexToken` is imported from `convex-svelte/sveltekit/server`. --- # Troubleshooting Common errors when using [`convex-svelte`](/client/svelte/overview.md) and how to fix them. ## `effect_in_teardown` error[​](#effect_in_teardown-error "Direct link to effect_in_teardown-error") If you encounter `effect_in_teardown` errors when using `useQuery` in components that can be conditionally rendered (like dialogs, modals, or popups), this is caused by wrapping `useQuery` in a `$derived` block that depends on reactive state. When `useQuery` is wrapped in `$derived`, state changes during component cleanup can trigger re-evaluation of the `$derived`, which attempts to create a new `useQuery` instance. Since `useQuery` internally creates a `$effect`, and effects cannot be created during cleanup, this throws an error. Use [Skipping queries](/client/svelte/reactivity.md#skipping-queries) instead. By calling `useQuery` unconditionally at the top level and passing a function that returns `'skip'`, the function is evaluated inside `useQuery`'s own effect tracking, preventing query recreation during cleanup. ## Missing `setupConvex()` error[​](#missing-setupconvex-error "Direct link to missing-setupconvex-error") If you see `No ConvexClient was found in Svelte context`, make sure `setupConvex()` is called in a parent layout or component (e.g. `+layout.svelte`) before any child component calls `useQuery()` or `useConvexClient()`. See [Setup](/client/svelte/overview.md#setup). ## String query names[​](#string-query-names "Direct link to String query names") Query references must be `api.*` function references, not plain strings. If you pass a string like `"messages.list"`, you will get an error. Always import and use `api` from your generated API: ``` import { api } from "../convex/_generated/api.js"; ``` --- # Why server-side rendering with Convex? With a realtime backend like Convex, you might wonder whether SSR is worth the effort — after all, the client will open a WebSocket and get live updates anyway. The short answer: **SSR with Convex is almost always faster for time-to-data on first page load.** This page explains why. For the how, see [SvelteKit Server Rendering](/client/svelte/sveltekit-server-rendering.md). ## The client-side waterfall[​](#the-client-side-waterfall "Direct link to The client-side waterfall") Without SSR, every first page load hits a sequential waterfall: ``` 1. Client → Framework server: request page 2. Framework server → Client: HTML shell (empty) ← skeleton visible 3. Browser parses HTML, discovers ``` 10. Update script to start development server By default, Convex stores environment variables in `.env.local`, and Nuxt looks for environment variables in `.env`. To use the default `npm run dev` command, update your `package.json` to use the `--dotenv .env.local` flag. package.json ``` { "name": "nuxt-app", "private": true, "type": "module", "scripts": { "build": "nuxt build", "dev": "nuxt dev --dotenv .env.local", "generate": "nuxt generate", "preview": "nuxt preview", "postinstall": "nuxt prepare" }, "dependencies": { "convex": "^1.25.2", "convex-nuxt": "^0.1.3", "nuxt": "^3.17.6", "vue": "^3.5.17", "vue-router": "^4.5.1" } } ``` 11. Start the app Start the app, open in a browser, and see the list of tasks. ``` npm run dev ``` For more examples, take a look at the [Nuxt Convex module repository](https://github.com/chris-visser/convex-nuxt). See the complete [Nuxt npm package documentation](https://www.npmjs.com/package/convex-nuxt). --- # Quickstarts Quickly get up and running with your favorite frontend tooling: * [React](/quickstart/react.md) * [Next.js](/quickstart/nextjs.md) * [Remix](/quickstart/remix.md) * [TanStack Start](/quickstart/tanstack-start.md) * [React Native](/quickstart/react-native.md) * [Vue](/quickstart/vue.md) * [Nuxt](/quickstart/nuxt.md) * [Svelte](/quickstart/svelte.md) * [Node.js](/quickstart/nodejs.md) * [Bun](/quickstart/bun.md) * [Script tag](/quickstart/script-tag.md) Quickly get up and running with your favorite languages: * [JavaScript](/client/javascript/overview.md) * [Python](/quickstart/python.md) * [iOS Swift](/quickstart/swift.md) * [Android Kotlin](/quickstart/android.md) * [Rust](/quickstart/rust.md) --- # Python Quickstart Learn how to query data from Convex in a Python app. 1. Create a Python script folder Create a folder for your Python script with a virtual environment. ``` python3 -m venv my-app/venv ``` 2. Install the Convex client and server libraries To get started, install the `convex` npm package which enables you to write your backend. And also install the `convex` Python client library and `python-dotenv` for working with `.env` files. ``` cd my-app && npm init -y && npm install convex && venv/bin/pip install convex python-dotenv ``` 3. Set up a Convex dev deployment Next, run `npx convex dev`. This will prompt you to log in with GitHub, create a project, and save your production and deployment URLs. It will also create a `convex/` folder for you to write your backend API functions in. The `dev` command will then continue running to sync your functions with your dev deployment in the cloud. ``` 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.ts` in the `convex/` folder with a query function that loads the data. Exporting a query function from this file declares an API function named after the file and the export name, `"tasks:get"`. convex/tasks.ts ``` import { query } from "./_generated/server"; export const get = query({ args: {}, handler: async ({ db }) => { return await db.query("tasks").collect(); }, }); ``` 7. Create a script to load data from Convex In a new file `main.py`, create a `ConvexClient` and use it to fetch from your `"tasks:get"` API. main.py ``` import os from convex import ConvexClient from dotenv import load_dotenv load_dotenv(".env.local") CONVEX_URL = os.getenv("CONVEX_URL") # or you can hardcode your deployment URL instead # CONVEX_URL = "https://happy-otter-123.convex.cloud" client = ConvexClient(CONVEX_URL) print(client.query("tasks:get")) for tasks in client.subscribe("tasks:get"): print(tasks) # this loop lasts forever, ctrl-c to exit it ``` 8. Run the script Run the script and see the serialized list of tasks. ``` venv/bin/python -m main ``` See the [docs on PyPI](https://pypi.org/project/convex/) for more details. --- # React Quickstart [YouTube video player](https://www.youtube.com/embed/4MgsvjMb59Q) To get setup quickly with Convex and React run **`npm create convex@latest`** or follow the guide below. *** Learn how to query data from Convex in a React app using Vite. 1. Create a React app Create a React app using the `create vite` command. ``` npm create vite@latest my-app -- --template react-ts ``` 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 directory 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. (optional) Define a schema Add a new file `schema.ts` in the `convex/` folder with a description of your data. This will declare the types of your data for optional typechecking with TypeScript, and it will be also enforced at runtime. convex/schema.ts ``` import { defineSchema, defineTable } from "convex/server"; import { v } from "convex/values"; export default defineSchema({ tasks: defineTable({ text: v.string(), isCompleted: v.boolean(), }), }); ``` 7. Expose a database query Add a new file `tasks.ts` in the `convex/` folder with a query function that loads the data. Exporting a query function from this file declares an API function named after the file and the export name, `api.tasks.get`. convex/tasks.ts ``` import { query } from "./_generated/server"; export const get = query({ args: {}, handler: async (ctx) => { return await ctx.db.query("tasks").collect(); }, }); ``` 8. Connect the app to your backend In `src/main.tsx`, create a `ConvexReactClient` and pass it to a `ConvexProvider` wrapping your app. src/main.tsx ``` import React from "react"; import ReactDOM from "react-dom/client"; import App from "./App"; import "./index.css"; import { ConvexProvider, ConvexReactClient } from "convex/react"; const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL as string); ReactDOM.createRoot(document.getElementById("root")!).render( , ); ``` 9. Display the data in your app In `src/App.tsx`, use the `useQuery` hook to fetch from your `api.tasks.get` API function and display the data. src/App.tsx ``` import "./App.css"; import { useQuery } from "convex/react"; import { api } from "../convex/_generated/api"; function App() { const tasks = useQuery(api.tasks.get); return (
{tasks?.map(({ _id, text }) => (
{text}
))}
); } export default App; ``` 10. Start the app Start the app, open in a browser, and see the list of tasks. ``` npm run dev ``` See the complete [React documentation](/client/react/overview.md). --- # React Native Quickstart Learn how to query data from Convex in a React Native app. 1. Create a React Native app Create a React Native app using the `npx create-expo-app` command. ``` npx create-expo-app my-app ``` 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 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.ts` in the `convex/` folder with a query function that loads the data. Exporting a query function from this file declares an API function named after the file and the export name, `api.tasks.get`. convex/tasks.ts ``` import { query } from "./_generated/server"; export const get = query({ args: {}, handler: async (ctx) => { return await ctx.db.query("tasks").collect(); }, }); ``` 7. Reset the Expo project If you haven't done so yet, reset the Expo project to get a fresh `app` directory. ``` npm run reset-project ``` 8. Connect the app to your backend In `_layout.tsx`, create a `ConvexReactClient` and pass it to a `ConvexProvider` wrapping your component tree. app/\_layout.tsx ``` import { ConvexProvider, ConvexReactClient } from "convex/react"; import { Stack } from "expo-router"; const convex = new ConvexReactClient(process.env.EXPO_PUBLIC_CONVEX_URL!, { unsavedChangesWarning: false, }); export default function RootLayout() { return ( ); } ``` 9. Display the data in your app In `index.tsx` use the `useQuery` hook to fetch from your `api.tasks.get` API. app/index.tsx ``` import { api } from "@/convex/_generated/api"; import { useQuery } from "convex/react"; import { Text, View } from "react-native"; export default function Index() { const tasks = useQuery(api.tasks.get); return ( {tasks?.map(({ _id, text }) => ( {text} ))} ); } ``` 10. Start the app Start the app, scan the provided QR code with your phone, and see the serialized list of tasks in the center of the screen. ``` npm start ``` React native uses the same library as React web. See the complete [React documentation](/client/react/overview.md). --- # Remix Quickstart Learn how to query data from Convex in a Remix app. 1. Create a Remix site Create a Remix site using the `npx create-remix@latest` command.
``` npx create-remix@latest my-remix-app ``` 2. Install the Convex library To get started, install the `convex` package. ``` cd my-remix-app && npm install convex ``` 3. Set up a Convex dev deployment Next, run `npx convex dev`. This will prompt you to log in with GitHub, create a project, and save your production and deployment URLs. It will also create a `convex/` folder for you to write your backend API functions in. The `dev` command will then continue running to sync your functions with your dev deployment in the cloud. ``` npx convex dev ``` 4. Create sample data for your database Create a `sampleData.jsonl` file at the root of you app and fill it with the sample data given. 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 you just created in `sampleData.jsonl` 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.ts` in the `convex/` folder with a query function that loads the data. Exporting a query function from this file declares an API function named after the file and the export name, `api.tasks.get`. convex/tasks.ts ``` import { query } from "./_generated/server"; export const get = query({ args: {}, handler: async (ctx) => { return await ctx.db.query("tasks").collect(); }, }); ``` 7. Wire up the ConvexProvider Modify `app/root.tsx` to set up the Convex client there to make it available on every page of your app. app/root.tsx ``` import { Links, Meta, Outlet, Scripts, ScrollRestoration, useLoaderData, } from "@remix-run/react"; import { ConvexProvider, ConvexReactClient } from "convex/react"; import { useState } from "react"; export async function loader() { const CONVEX_URL = process.env["CONVEX_URL"]!; return { ENV: { CONVEX_URL } }; } export function Layout({ children }: { children: React.ReactNode }) { const { ENV } = useLoaderData(); const [convex] = useState(() => new ConvexReactClient(ENV.CONVEX_URL)); return ( {children} ); } export default function App() { return ; } ``` 8. Display the data in your app In `app/routes/_index.tsx` use `useQuery` to subscribe your `api.tasks.get` API function. app/routes/\_index.tsx ``` import type { MetaFunction } from "@remix-run/node"; import { api } from "convex/_generated/api"; import { useQuery } from "convex/react"; export const meta: MetaFunction = () => { return [ { title: "New Remix App" }, { name: "description", content: "Welcome to Remix!" }, ]; }; export default function Index() { const tasks = useQuery(api.tasks.get); return (

Welcome to Remix

{tasks === undefined ? "loading..." : tasks.map(({ _id, text }) =>
{text}
)}
); } ``` 9. Start the app Start the app, open in a browser, and see the list of tasks. ``` npm run dev ``` Remix uses the React web library. See the complete [React documentation](/client/react/overview.md). --- # Rust Quickstart Learn how to query data from Convex in a Rust app with Tokio. 1. Create a Cargo project Create a new Cargo project. ``` cargo new my_app cd my_app ``` 2. Install the Convex client and server libraries To get started, install the `convex` npm package which enables you to write your backend. And also install the `convex` Rust client library, the `tokio` runtime, and `dotenvy` for working with `.env` files. ``` npm init -y && npm install convex && cargo add convex tokio dotenvy ``` 3. Set up a Convex dev deployment Next, run `npx convex dev`. This will prompt you to log in with GitHub, create a project, and save your production and deployment URLs. It will also create a `convex/` folder for you to write your backend API functions in. The `dev` command will then continue running to sync your functions with your dev deployment in the cloud. ``` 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.ts` in the `convex/` folder with a query function that loads the data. Exporting a query function from this file declares an API function named after the file and the export name, `"tasks:get"`. convex/tasks.ts ``` import { query } from "./_generated/server"; export const get = query({ handler: async ({ db }) => { return await db.query("tasks").collect(); }, }); ``` 7. Connect the app to your backend In the file `src/main.rs`, create a `ConvexClient` and use it to fetch from your `"tasks:get"` API. src/main.rs ``` use std::{ collections::BTreeMap, env, }; use convex::ConvexClient; #[tokio::main] async fn main() { dotenvy::from_filename(".env.local").ok(); dotenvy::dotenv().ok(); let deployment_url = env::var("CONVEX_URL").unwrap(); let mut client = ConvexClient::new(&deployment_url).await.unwrap(); let result = client.query("tasks:get", BTreeMap::new()).await.unwrap(); println!("{result:#?}"); } ``` 8. Run the app Run the app and see the serialized list of tasks. ``` cargo run ``` See the complete [Rust documentation](https://docs.rs/convex/latest/convex/). --- # Script Tag Quickstart Learn how to query data from Convex from script tags in HTML. 1. Create a new npm project Create a new directory for your Convex project. ``` mkdir my-project && cd my-project && npm init -y ``` 2. Install the Convex client and server library Install the `convex` package which provides a convenient interface for working with Convex from JavaScript. ``` 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.ts` in the `convex/` folder with a query function that loads the data. Exporting a query function from this file declares an API function named after the file and the export name, `api.tasks.get`. convex/tasks.ts ``` import { query } from "./_generated/server"; export const get = query({ args: {}, handler: async (ctx) => { return await ctx.db.query("tasks").collect(); }, }); ``` 7. Copy the deployment URL Open the `.env.local` file and copy the `CONVEX_URL` of your development environment for use in the HTML file. 8. Add the script to your webpage In a new file `index.html`, create a `ConvexClient` using the URL of your development environment. Open this file in a web browser and you'll see it run each time the `tasks` table is modified. index.html ``` ``` See the complete [Script Tag documentation](/client/javascript/script-tag.md). --- # Svelte Quickstart Learn how to query data from Convex in a Svelte app. 1. Create a SvelteKit app Create a SvelteKit app using the `npx sv create` command. Other sets of options will work with the library but for this quickstart guide: * For "Which Svelte app template," choose **"SvelteKit minimal."** * For a package manager, choose **"npm."** * For "Add type checking with TypeScript," choose **"Yes, using TypeScript syntax."** * For "Select additional options," you don't need to enable anything.
``` npx sv@latest create my-app ``` 2. Install the Convex client and server library To get started, install the `convex` and `convex-svelte` packages. ``` cd my-app && npm install convex convex-svelte ``` 3. Customize the convex path SvelteKit doesn't like referencing code outside of source, so customize the convex functionsDir to be under `src/`. convex.json ``` { "functions": "src/convex/" } ``` 4. 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 `src/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 ``` 5. 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} ``` 6. 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 ``` 7. Expose a database query Add a new file `tasks.ts` in the `convex/` folder with a query function that loads the data. Exporting a query function from this file declares an API function named after the file and the export name, `api.tasks.get`. src/convex/tasks.ts ``` import { query } from "./_generated/server"; export const get = query({ args: {}, handler: async (ctx) => { const tasks = await ctx.db.query("tasks").collect(); return tasks.map((task) => ({ ...task, assigner: "tom" })); }, }); ``` 8. Set up Convex Create a new file `src/routes/+layout.svelte` and set up the Convex client there to make it available on every page of your app. src/routes/+layout.svelte ``` {@render children()} ``` 9. Display the data in your app In `src/routes/+page.svelte` use `useQuery` to subscribe your `api.tasks.get` API function. src/routes/+page.svelte ``` {#if query.isLoading} Loading... {:else if query.error} failed to load: {query.error.toString()} {:else}
    {#each query.data as task}
  • {task.isCompleted ? '☑' : '☐'} {task.text} assigned by {task.assigner}
  • {/each}
{/if} ``` 10. Start the app Start the app, open in a browser, and see the list of tasks. ``` npm run dev ``` See the [Convex Svelte docs](/client/svelte/overview.md) for the full reactive API, authentication, and SvelteKit server rendering. --- # iOS Swift Quickstart Learn how to query data from Convex in an application targeting iOS and MacOS devices built with Swift and SwiftUI. This quickstart assumes that you have a Mac with Xcode, node and npm installed. If you don’t have those tools, take time to install them first. 1. Create a new iOS app in Xcode 1. Click *Create New Project* 2. Select iOS App and click *Next* 3. Name your project something like “ConvexQuickstart” 4. Ensure Language is set to Swift and User Interface is SwiftUI 5. Click *Next* ![Create new iOS project](/screenshots/swift_qs_step_1.png) 2. Configure dependencies 1. Click on the top-level ConvexQuickstart app container in the project navigator on the left 2. Click on ConvexQuickstart under the PROJECT heading 3. Click the Package Dependencies tab 4. Click the + button (See Screenshot) 5. Paste ``` https://github.com/get-convex/convex-swift ``` into the search box and press enter 6. When the `convex-swift` package loads, click the *Add Package* button 7. In the *Package Products* dialog, select ConvexQuickstart in the *Add to Target* dropdown 8. Click the Add Package button ![Add Convex dependency to package](/screenshots/swift_qs_step_2.png) 3.
Install the Convex backend Open a terminal and `cd` to the directory for the Xcode project you created. Run the following commands to install the Convex client and server library. ``` npm init -y npm install convex ``` 4. Start Convex Start a Convex dev deployment. Follow the command line instructions to create a new project. ``` npx convex dev ``` 5. Create sample data for your database Create a new `sampleData.jsonl` file in your Swift project directory with these contents ``` {"text": "Buy groceries", "isCompleted": true} {"text": "Go for a swim", "isCompleted": true} {"text": "Integrate Convex", "isCompleted": false} ``` 6. Add the sample data to a table called \`tasks\` in your database Open another terminal tab by pressing ⌘+T which should open in your Swift project directory and run ``` npx convex import --table tasks sampleData.jsonl ``` 7. Expose a database query Create a `tasks.ts` file in the `convex/` directory within your Swift project with the following contents ``` import { query } from "./_generated/server"; export const get = query({ args: {}, handler: async (ctx) => { return await ctx.db.query("tasks").collect(); }, }); ``` 8. Create a Swift struct Back in Xcode, create a `struct` at the bottom of the `ContentView` file to match the sample data ``` // We're using the name Todo instead of Task to avoid clashing with // Swift's builtin Task type. struct Todo: Decodable { let _id: String let text: String let isCompleted: Bool } ``` 9. Connect the app to your backend 1. Get the deployment URL of your dev server with `cat .env.local | grep CONVEX_URL` 2. Create a `ConvexClient` instance near the top of the file, just above the `ContentView` struct ``` import SwiftUI import ConvexMobile let convex = ConvexClient(deploymentUrl: "YOUR_CONVEX_URL") struct ContentView: View { ... ``` 10. Create your UI Replace the default `ContentView` with the following code that will refresh the list of todo items whenever the backend data changes. ``` struct ContentView: View { @State private var todos: [Todo] = [] var body: some View { List { ForEach(todos, id: \._id) { todo in Text(todo.text) } }.task { for await todos: [Todo] in convex.subscribe(to: "tasks:get") .replaceError(with: []).values { self.todos = todos } }.padding() } } ``` 11. Run the app 1. Press ⌘+R or click *Product → Run* 2. You can also try adding, updating or deleting documents in your `tasks` table at `dashboard.convex.dev` - the app will update with the changes in real-time. ![App preview](/screenshots/swift_qs_final.png) See the complete [iOS Swift documentation](/client/swift/overview.md). --- # TanStack Start Quickstart TanStack Start is in Release Candidate [TanStack Start](https://tanstack.com/start/latest) is a new React framework currently in the Release Candidate stage. You can use it today but there may be bugs or breaking changes before a stable release. To get setup quickly with Convex and TanStack Start run **`npm create convex@latest -- -t tanstack-start`** or follow the guide below. To use an auth provider with Convex and TanStack Start, see the [TanStack Start + Clerk guide](/client/tanstack/tanstack-start/clerk.md) or the [TanStack Start + WorkOS AuthKit guide](/auth/authkit/add-to-app.md). *** Learn how to query data from Convex in a TanStack Start site. 1. Create a TanStack Start site Create a TanStack Start app using the `create-start-app` command: ``` npx create-start-app@latest ``` 2. Install the Convex client and server library To get started with Convex install the `convex` package and a few React Query-related packages. ``` npm install convex @convex-dev/react-query @tanstack/react-router-ssr-query @tanstack/react-query ``` 3. Update src/routes/\_\_root.tsx Add a `QueryClient` to the router context to make React Query usable anywhere in the TanStack Start site. src/routes/\_\_root.tsx ``` import { QueryClient } from "@tanstack/react-query"; import { createRootRouteWithContext } from "@tanstack/react-router"; import { Outlet, Scripts, HeadContent } from "@tanstack/react-router"; import * as React from "react"; export const Route = createRootRouteWithContext<{ queryClient: QueryClient; }>()({ head: () => ({ meta: [ { charSet: "utf-8", }, { name: "viewport", content: "width=device-width, initial-scale=1", }, { title: "TanStack Start Starter", }, ], }), component: RootComponent, }); function RootComponent() { return ( ); } function RootDocument({ children }: { children: React.ReactNode }) { return ( {children} ); } ``` 4. Update src/router.tsx Replace the file `src/router.tsx` with these contents. This creates a `ConvexClient` and a `ConvexQueryClient` and wires in a `ConvexProvider`. src/router.tsx ``` import { createRouter } from "@tanstack/react-router"; import { QueryClient } from "@tanstack/react-query"; import { setupRouterSsrQueryIntegration } from "@tanstack/react-router-ssr-query"; import { ConvexQueryClient } from "@convex-dev/react-query"; import { ConvexProvider } from "convex/react"; import { routeTree } from "./routeTree.gen"; export function getRouter() { const CONVEX_URL = (import.meta as any).env.VITE_CONVEX_URL!; if (!CONVEX_URL) { console.error("missing envar VITE_CONVEX_URL"); } const convexQueryClient = new ConvexQueryClient(CONVEX_URL); const queryClient: QueryClient = new QueryClient({ defaultOptions: { queries: { queryKeyHashFn: convexQueryClient.hashFn(), queryFn: convexQueryClient.queryFn(), }, }, }); convexQueryClient.connect(queryClient); const router = createRouter({ routeTree, defaultPreload: "intent", context: { queryClient }, scrollRestoration: true, Wrap: ({ children }) => ( {children} ), }); setupRouterSsrQueryIntegration({ router, queryClient }); return router; } ``` 5. 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 ``` 6. 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} ``` 7. 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 ``` 8. Expose a database query Add a new file `tasks.ts` in the `convex/` folder with a query function that loads the data. Exporting a query function from this file declares an API function named after the file and the export name, `api.tasks.get`. convex/tasks.ts ``` import { query } from "./_generated/server"; export const get = query({ args: {}, handler: async (ctx) => { return await ctx.db.query("tasks").collect(); }, }); ``` 9. Display the data in your app Replace the file `src/routes/index.tsx` with these contents. The `useSuspenseQuery` hook renders the API function `api.tasks.get` query result on the server initially, then it updates live in the browser. src/routes/index.tsx ``` import { convexQuery } from "@convex-dev/react-query"; import { useSuspenseQuery } from "@tanstack/react-query"; import { createFileRoute } from "@tanstack/react-router"; import { api } from "../../convex/_generated/api"; export const Route = createFileRoute("/")({ component: Home, }); function Home() { const { data } = useSuspenseQuery(convexQuery(api.tasks.get, {})); return (
{data.map(({ _id, text }) => (
{text}
))}
); } ``` 10. Start the app Start the app, open in a browser, and see the list of tasks. ``` npm run dev ``` For more see the [TanStack Start with Convex](/client/tanstack/tanstack-start/.md) client documentation page. --- # Vue Quickstart Learn how to query data from Convex in a Vue app. This quickstart guide uses a [community-maintained](/client/vue/overview.md) Vue client for Convex. 1. Create a Vue site Create a Vue site using the `npm create vue@latest my-vue-app` command. Convex will work with any set of options but to follow this quickstart most closely choose: * Yes to "Add TypeScript?" * No to everything else
``` npm create vue@latest my-vue-app ``` 2. Install the Convex library To get started, install the `convex` package. ``` cd my-vue-app && npm install convex convex-vue ``` 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.ts` in the `convex/` folder with a query function that loads the data. Exporting a query function from this file declares an API function named after the file and the export name, `api.tasks.get`. convex/tasks.ts ``` import { query } from "./_generated/server"; export const get = query({ args: {}, handler: async (ctx) => { return await ctx.db.query("tasks").collect(); }, }); ``` 7. Wire up the ConvexProvider In `src/main.ts` set up the Convex client there to make it available on every page of your app. src/main.ts ``` import { convexVue } from 'convex-vue' import { createApp } from 'vue' import App from './App.vue' const app = createApp(App) app.use(convexVue, { url: import.meta.env.VITE_CONVEX_URL, }) app.mount('#app') ``` 8. Display the data in your app In `src/App.vue` use `useQuery` to subscribe your `api.tasks.get` API function. src/App.vue ``` ``` 9. Start the app Start the app, open in a browser, and see the list of tasks. ``` npm run dev ``` See the complete [Vue npm package documentation](https://www.npmjs.com/package/convex-vue). --- # Realtime Turns out Convex is automatically realtime! You don’t have to do anything special if you are already using [query functions](/functions/query-functions.md), [database](/database/overview.md), and [client libraries](/client/react/overview.md) in your app. Convex tracks the dependencies to your query functions, including database changes, and triggers the subscription in the client libraries. ![Convex is automatically reactive and realtime](/assets/images/realtime-3197272a21b075792f6ac922af228378.gif) Aside from building a highly interactive app with ease, there are other benefits to the realtime architecture of Convex: ## Automatic caching[​](#automatic-caching "Direct link to Automatic caching") Convex automatically caches the result of your query functions so that future calls just read from the cache. The cache is updated if the data ever changes. You don't get charged for database bandwidth for cached reads. This requires no work or bookkeeping from you. ## Consistent data across your app[​](#consistent-data-across-your-app "Direct link to Consistent data across your app") Every client subscription gets updated simultaneously to the same snapshot of the database. Your app always displays the most consistent view of your data. This avoids bugs like increasing the number of items in the shopping cart and not showing that an item is sold out. ## Learn more[​](#learn-more "Direct link to Learn more") Learn how to work with realtime and reactive queries in Convex on [Stack](https://stack.convex.dev/tag/Reactivity). Related posts from [![Stack](/img/stack-logo-dark.svg)![Stack](/img/stack-logo-light.svg)](https://stack.convex.dev/) --- # Cron Jobs Convex allows you to schedule functions to run on a recurring basis. For example, cron jobs can be used to clean up data at a regular interval, send a reminder email at the same time every month, or schedule a backup every Saturday. **Example:** [Cron Jobs](https://github.com/get-convex/convex-demos/tree/main/cron-jobs) ## Defining your cron jobs[​](#defining-your-cron-jobs "Direct link to Defining your cron jobs") Cron jobs are defined in a `crons.ts` file in your `convex/` directory and look like: convex/crons.ts ``` import { cronJobs } from "convex/server"; import { internal } from "./_generated/api"; const crons = cronJobs(); crons.interval( "clear messages table", { minutes: 1 }, // every minute internal.messages.clearAll, ); crons.monthly( "payment reminder", { day: 1, hourUTC: 16, minuteUTC: 0 }, // Every month on the first day at 8:00am PST internal.payments.sendPaymentEmail, { email: "my_email@gmail.com" }, // argument to sendPaymentEmail ); // An alternative way to create the same schedule as above with cron syntax crons.cron( "payment reminder duplicate", "0 16 1 * *", internal.payments.sendPaymentEmail, { email: "my_email@gmail.com" }, // argument to sendPaymentEmail ); export default crons; ``` The first argument is a unique identifier for the cron job. The second argument is the schedule at which the function should run, see [Supported schedules](/scheduling/cron-jobs.md#supported-schedules) below. The third argument is the name of the public function or [internal function](/functions/internal-functions.md), either a [mutation](/functions/mutation-functions.md) or an [action](/functions/actions.md). ## Supported schedules[​](#supported-schedules "Direct link to Supported schedules") * [`crons.interval()`](/api/classes/server.Crons.md#interval) runs a function every specified number of `seconds`, `minutes`, or `hours`. The first run occurs when the cron job is first deployed to Convex. Unlike traditional crons, this option allows you to have seconds-level granularity. * [`crons.cron()`](/api/classes/server.Crons.md#cron) the traditional way of specifying cron jobs by a string with five fields separated by spaces (e.g. `"* * * * *"`). Times in cron syntax are in the UTC timezone. [Crontab Guru](https://crontab.guru/) is a helpful resource for understanding and creating schedules in this format. * [`crons.hourly()`](/api/classes/server.Crons.md#cron), [`crons.daily()`](/api/classes/server.Crons.md#daily), [`crons.weekly()`](/api/classes/server.Crons.md#weekly), [`crons.monthly()`](/api/classes/server.Crons.md#monthly) provide an alternative syntax for common cron schedules with explicitly named arguments. ## Viewing your cron jobs[​](#viewing-your-cron-jobs "Direct link to Viewing your cron jobs") You can view all your cron jobs in the [Convex dashboard cron jobs view](/dashboard/deployments/schedules.md#cron-jobs-ui). You can view added, updated, and deleted cron jobs in the logs and history view. Results of previously executed runs of the cron jobs are also available in the logs view. ## Error handling[​](#error-handling "Direct link to Error handling") Mutations and actions have the same guarantees that are described in [Error handling](/scheduling/scheduled-functions.md#error-handling) for scheduled functions. At most one run of each cron job can be executing at any moment. If the function scheduled by the cron job takes too long to run, following runs of the cron job may be skipped to avoid execution from falling behind. Skipping a scheduled run of a cron job due to the previous run still executing logs a message visible in the logs view of the dashboard. --- # Scheduling Convex lets you easily schedule a function to run once or repeatedly in the future. This allows you to build durable workflows like sending a welcome email a day after someone joins or regularly reconciling your accounts with Stripe. Convex provides two different features for scheduling: * [Scheduled Functions](/scheduling/scheduled-functions.md) can be scheduled durably by any other function to run at a later point in time. You can schedule functions minutes, days, and even months in the future. * [Cron Jobs](/scheduling/cron-jobs.md) schedule functions to run on a recurring basis, such as daily. ## Durable function components[​](#durable-function-components "Direct link to Durable function components") Built-in scheduled functions and crons work well for simpler apps and workflows. If you're operating at high scale or need more specific guarantees, use the following higher-level [components](/components/overview.md) for durable functions. [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/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) [Convex Component](https://www.convex.dev/components/crons) ### [Crons](https://www.convex.dev/components/crons) [Use cronspec to run functions on a repeated schedule at runtime.](https://www.convex.dev/components/crons) Related posts from [![Stack](/img/stack-logo-dark.svg)![Stack](/img/stack-logo-light.svg)](https://stack.convex.dev/) --- # Scheduled Functions Convex allows you to schedule functions to run in the future. This allows you to build powerful durable workflows without the need to set up and maintain queues or other infrastructure. Scheduled functions are stored in the database. This means you can schedule functions minutes, days, and even months in the future. Scheduling is resilient against unexpected downtime or system restarts. **Example:** [Scheduling](https://github.com/get-convex/convex-demos/tree/main/scheduling) ## Scheduling functions[​](#scheduling-functions "Direct link to Scheduling functions") You can schedule public functions and [internal functions](/functions/internal-functions.md) from mutations and actions via the [scheduler](/api/interfaces/server.Scheduler.md) provided in the respective function context. * [runAfter](/api/interfaces/server.Scheduler.md#runafter) schedules a function to run after a delay (measured in milliseconds). * [runAt](/api/interfaces/server.Scheduler.md#runat) schedules a function run at a date or timestamp (measured in milliseconds elapsed since the epoch). The rest of the arguments are the path to the function and its arguments, similar to invoking a function from the client. For example, here is how to send a message that self-destructs in five seconds. convex/messages.ts ``` import { mutation, internalMutation } from "./_generated/server"; import { internal } from "./_generated/api"; import { v } from "convex/values"; export const sendExpiringMessage = mutation({ args: { body: v.string(), author: v.string() }, handler: async (ctx, args) => { const { body, author } = args; const id = await ctx.db.insert("messages", { body, author }); await ctx.scheduler.runAfter(5000, internal.messages.destruct, { messageId: id, }); }, }); export const destruct = internalMutation({ args: { messageId: v.id("messages"), }, handler: async (ctx, args) => { await ctx.db.delete("messages", args.messageId); }, }); ``` A single function can schedule up to 1000 functions with total argument size of 8MB. ### Scheduling from mutations[​](#scheduling-from-mutations "Direct link to Scheduling from mutations") Scheduling functions from [mutations](/functions/mutation-functions.md#transactions) is atomic with the rest of the mutation. This means that if the mutation succeeds, the scheduled function is guaranteed to be scheduled. On the other hand, if the mutations fails, no function will be scheduled, even if the function fails after the scheduling call. ### Scheduling from actions[​](#scheduling-from-actions "Direct link to Scheduling from actions") Unlike mutations, [actions](/functions/actions.md) don't execute as a single database transaction and can have side effects. Thus, scheduling from actions does not depend on the outcome of the function. This means that an action might succeed to schedule some functions and later fail due to transient error or a timeout. The scheduled functions will still be executed. ### Scheduling immediately[​](#scheduling-immediately "Direct link to Scheduling immediately") Using `runAfter()` with delay set to 0 is used to immediately add a function to the event queue. This usage may be familiar to you if you're used to calling `setTimeout(fn, 0)`. As noted above, actions are not atomic and are meant to cause side effects. Scheduling immediately becomes useful when you specifically want to trigger an action from a mutation that is conditional on the mutation succeeding. [This post](https://stack.convex.dev/pinecone-and-embeddings#kick-off-a-background-action) goes over a direct example of this in action, where the application depends on an external service to fill in information to the database. ## Retrieving scheduled function status[​](#retrieving-scheduled-function-status "Direct link to Retrieving scheduled function status") Every scheduled function is reflected as a document in the `"_scheduled_functions"` system table. `runAfter()` and `runAt()` return the id of scheduled function. You can read data from system tables using the `db.system.get` and `db.system.query` methods, which work the same as the standard `db.get` and `db.query` methods. convex/messages.ts ``` export const listScheduledMessages = query({ args: {}, handler: async (ctx, args) => { return await ctx.db.system.query("_scheduled_functions").collect(); }, }); export const getScheduledMessage = query({ args: { id: v.id("_scheduled_functions"), }, handler: async (ctx, args) => { return await ctx.db.system.get("_scheduled_functions", args.id); }, }); ``` This is an example of the returned document: ``` { "_creationTime": 1699931054642.111, "_id": "3ep33196167235462543626ss0scq09aj4gqn9kdxrdr", "args": [{}], "completedTime": 1699931054690.366, "name": "messages.js:destruct", "scheduledTime": 1699931054657, "state": { "kind": "success" } } ``` The returned document has the following fields: * `name`: the path of the scheduled function * `args`: the arguments passed to the scheduled function * `scheduledTime`: the timestamp of when the function is scheduled to run (measured in milliseconds elapsed since the epoch) * `completedTime`: the timestamp of when the function finished running, if it has completed (measured in milliseconds elapsed since the epoch) * `state`: the status of the scheduled function. Here are the possible states a scheduled function can be in: * `Pending`: the function has not been started yet * `InProgress`: the function has started running is not completed yet (only applies to actions) * `Success`: the function finished running successfully with no errors * `Failed`: the function hit an error while running, which can either be a user error or an internal server error * `Canceled`: the function was canceled via the dashboard, `ctx.scheduler.cancel`, or recursively by a parent scheduled function that was canceled while in progress Scheduled function results are available for 7 days after they have completed. ## Canceling scheduled functions[​](#canceling-scheduled-functions "Direct link to Canceling scheduled functions") You can cancel a previously scheduled function with [`cancel`](/api/interfaces/server.Scheduler.md#cancel) via the [scheduler](/api/interfaces/server.Scheduler.md) provided in the respective function context. convex/messages.ts ``` export const cancelMessage = mutation({ args: { id: v.id("_scheduled_functions"), }, handler: async (ctx, args) => { await ctx.scheduler.cancel(args.id); }, }); ``` What `cancel` does depends on the state of the scheduled function: * If it hasn't started running, it won't run. * If it already started, it will continue to run, but any functions it schedules will not run. ## Debugging[​](#debugging "Direct link to Debugging") You can view logs from previously executed scheduled functions in the Convex dashboard [Logs view](/dashboard/deployments/logs.md). You can view and cancel yet to be executed functions in the [Functions view](/dashboard/deployments/functions.md). ## Error handling[​](#error-handling "Direct link to Error handling") Once scheduled, mutations are guaranteed to be executed exactly once. Convex will automatically retry any internal Convex errors, and only fail on developer errors. See [Error Handling](/functions/error-handling/.md) for more details on different error types. Since actions may have side effects, they are not automatically retried by Convex. Thus, actions will be executed at most once, and permanently fail if there are transient errors while executing them. Developers can retry those manually by scheduling a mutation that checks if the desired outcome has been achieved and if not schedule the action again. ## Auth[​](#auth "Direct link to Auth") The auth is not propagated from the scheduling to the scheduled function. If you want to authenticate or check authorization, you'll have to pass the requisite user information in as a parameter. --- # AI & Search Whether building RAG enabled chatbots or quick search in your applications, Convex provides easy apis to create powerful AI and search enabled products. [Vector Search](/search/vector-search.md) enables searching for documents based on their semantic meaning. It uses vector embeddings to calculate similarity and retrieve documents that are similar to a given query. Vector search is a key part of common AI techniques like RAG. [Full Text Search](/search/text-search.md) enables keyword and phrase search within your documents. It supports prefix matching to enable typeahead search. Convex full text search is also reactive and always up to date like all Convex queries, making it easy to build reliable quick search boxes. [Convex Actions](/functions/actions.md) easily enable you to call AI apis, save data to your database, and drive your user interface. See examples of how you can use this to [build sophisticated AI applications](https://stack.convex.dev/tag/AI). Related posts from [![Stack](/img/stack-logo-dark.svg)![Stack](/img/stack-logo-light.svg)](https://stack.convex.dev/) --- # Full Text Search Full text search allows you to find Convex documents that approximately match a search query. Unlike normal [document queries](/database/reading-data/.md#querying-documents), search queries look *within* a string field to find the keywords. Search queries are useful for building features like searching for messages that contain certain words. Search queries are automatically reactive, consistent, transactional, and work seamlessly with pagination. They even include new documents created with a mutation! **Example:** [Search App](https://github.com/get-convex/convex-demos/tree/main/search) To use full text search you need to: 1. Define a search index. 2. Run a search query. Search indexes are built and queried using Convex's multi-segment search algorithm on top of [Tantivy](https://github.com/quickwit-oss/tantivy), a powerful, open-source, full-text search library written in Rust. ## Defining search indexes[​](#defining-search-indexes "Direct link to Defining search indexes") Like [database indexes](/database/reading-data/indexes/.md), search indexes are a data structure that is built in advance to enable efficient querying. Search indexes are defined as part of your Convex [schema](/database/schemas.md). Every search index definition consists of: 1. A name. * Must be unique per table. 2. A `searchField` * This is the field which will be indexed for full text search. * It must be of type `string`. 3. \[Optional] A list of `filterField`s * These are additional fields that are indexed for fast equality filtering within your search index. 4. \[Optional] A boolean `staged` flag * If set to `true`, the index will be backfilled asynchronously from the deploy similar to [staged database indexes](/database/reading-data/indexes/.md#staged-indexes). This is useful for large tables where the index backfill time is significant. Defaults to `false`. To add a search index onto a table, use the [`searchIndex`](/api/classes/server.TableDefinition.md#searchindex) method on your table's schema. For example, if you want an index which can search for messages matching a keyword in a channel, your schema could look like: convex/schema.ts ``` import { defineSchema, defineTable } from "convex/server"; import { v } from "convex/values"; export default defineSchema({ messages: defineTable({ body: v.string(), channel: v.string(), }).searchIndex("search_body", { searchField: "body", filterFields: ["channel"], staged: false, }), }); ``` You can specify search and filter fields on nested documents by using a dot-separated path like `properties.name`. ## Running search queries[​](#running-search-queries "Direct link to Running search queries") A query for "10 messages in channel '#general' that best match the query 'hello hi' in their body" would look like: ``` const messages = await ctx.db .query("messages") .withSearchIndex("search_body", (q) => q.search("body", "hello hi").eq("channel", "#general"), ) .take(10); ``` This is just a normal [database read](/database/reading-data/.md) that begins by querying the search index! The [`.withSearchIndex`](/api/interfaces/server.QueryInitializer.md#withsearchindex) method defines which search index to query and how Convex will use that search index to select documents. The first argument is the name of the index and the second is a *search filter expression*. A search filter expression is a description of which documents Convex should consider when running the query. A search filter expression is always a chained list of: 1. 1 search expression against the index's search field defined with [`.search`](/api/interfaces/server.SearchFilterBuilder.md#search). 2. 0 or more equality expressions against the index's filter fields defined with [`.eq`](/api/interfaces/server.SearchFilterFinalizer.md#eq). ### Search expressions[​](#search-expressions "Direct link to Search expressions") Search expressions are issued against a search index, filtering and ranking documents by their relevance to the search expression's query. Internally, Convex will break up the query into separate words (called *terms*) and approximately rank documents matching these terms. In the example above, the expression `search("body", "hello hi")` would internally be split into `"hi"` and `"hello"` and matched against words in your document (ignoring case and punctuation). The behavior of search incorporates [prefix matching rules](#search-behavior). ### Equality expressions[​](#equality-expressions "Direct link to Equality expressions") Unlike search expressions, equality expressions will filter to only documents that have an exact match in the given field. In the example above, `eq("channel", "#general")` will only match documents that have exactly `"#general"` in their `channel` field. Equality expressions support fields of any type (not just text). To filter to documents that are missing a field, use `q.eq("fieldName", undefined)`. ### Other filtering[​](#other-filtering "Direct link to Other filtering") Because search queries are normal database queries, you can also [filter results](/database/reading-data/filters.md) using the [`.filter` method](/api/interfaces/server.Query.md#filter)! Here's a query for "messages containing 'hi' sent in the last 10 minutes": ``` const messages = await ctx.db .query("messages") .withSearchIndex("search_body", (q) => q.search("body", "hi")) .filter((q) => q.gt(q.field("_creationTime", Date.now() - 10 * 60000))) .take(10); ``` **For performance, always put as many of your filters as possible into `.withSearchIndex`.** Every search query is executed by: 1. First, querying the search index using the search filter expression in `withSearchIndex`. 2. Then, filtering the results one-by-one using any additional `filter` expressions. Having a very specific search filter expression will make your query faster and less likely to hit Convex's limits because Convex will use the search index to efficiently cut down on the number of results to consider. ### Retrieving results and paginating[​](#retrieving-results-and-paginating "Direct link to Retrieving results and paginating") Just like ordinary database queries, you can [retrieve the results](/database/reading-data/.md#retrieving-results) using [`.collect()`](/api/interfaces/server.Query.md#collect), [`.take(n)`](/api/interfaces/server.Query.md#take), [`.first()`](/api/interfaces/server.Query.md#first), and [`.unique()`](/api/interfaces/server.Query.md#unique). Additionally, search results can be [paginated](/database/pagination.md) using [`.paginate(paginationOpts)`](/api/interfaces/server.OrderedQuery.md#paginate). Note that `collect()` will throw an exception if it attempts to collect more than the limit of 1024 documents. It is often better to pick a smaller limit and use `take(n)` or paginate the results. ### Ordering[​](#ordering "Direct link to Ordering") Search queries always return results in [relevance order](#relevance-order) based on how well the document matches the search query. Different ordering of results are not supported. ## Search Behavior[​](#search-behavior "Direct link to Search Behavior") ### Typeahead Search[​](#typeahead-search "Direct link to Typeahead Search") Convex full-text search is designed to power as-you-type search experiences. In your search queries, the final search term has *prefix search* enabled, matching any term that is a prefix of the original term. For example, the expression `search("body", "r")` would match the documents: * `"rabbit"` * `"send request"` Fuzzy search matches are deprecated. After January 15, 2025, search results will not include `"snake"` for a typo like `"stake"`. ### Relevance order[​](#relevance-order "Direct link to Relevance order") **Relevance order is subject to change.** The relevance of search results and the exact rules Convex applies is subject to change to improve the quality of search results. Search queries return results in relevance order. Internally, Convex ranks the relevance of a document based on a combination of its [BM25 score](https://en.wikipedia.org/wiki/Okapi_BM25) and several other criteria such as the proximity of matches, the number of exact matches, and more. The BM25 score takes into account: * How many words in the search query appear in the field? * How many times do they appear? * How long is the text field? If multiple documents have the same score, the newest documents are returned first. ## Limits[​](#limits "Direct link to Limits") Search indexes work best with English or other Latin-script languages. Text is tokenized using Tantivy's [`SimpleTokenizer`](https://docs.rs/tantivy/latest/tantivy/tokenizer/struct.SimpleTokenizer.html), which splits on whitespace and punctuation. We also limit terms to 32 characters in length and lowercase them. Search indexes must have: * Exactly 1 search field. * Up to 16 filter fields. Search indexes count against the [limit of 32 indexes per table](/database/reading-data/indexes/.md#limits). Search queries can have: * Up to 16 terms (words) in the search expression. * Up to 8 filter expressions. Additionally, search queries can scan up to 1024 results from the search index. The source of truth for these limits is our [source code](https://github.com/get-convex/convex-backend/blob/main/crates/search/src/constants.rs). For information on other limits, see [here](/production/state/limits.md). --- # Vector Search Vector search allows you to find Convex documents similar to a provided vector. Typically, vectors will be embeddings which are numerical representations of text, images, or audio. Embeddings and vector search enable you to provide useful context to LLMs for AI powered applications, recommendations for similar content and more. Vector search is consistent and fully up-to-date. You can write a vector and immediately read it from a vector search. Unlike [full text search](/search/overview.md), however, vector search is only available in [Convex actions](/functions/actions.md). **Example:** [Vector Search App](https://github.com/get-convex/convex-demos/tree/main/vector-search) To use vector search you need to: 1. Define a vector index. 2. Run a vector search from within an [action](/functions/actions.md). ## Defining vector indexes[​](#defining-vector-indexes "Direct link to Defining vector indexes") Like [database indexes](/database/reading-data/indexes/.md), vector indexes are a data structure that is built in advance to enable efficient querying. Vector indexes are defined as part of your Convex [schema](/database/schemas.md). To add a vector index onto a table, use the [`vectorIndex`](/api/classes/server.TableDefinition.md#vectorindex) method on your table's schema. Every vector index has a unique name and a definition with: 1. `vectorField` string * The name of the field indexed for vector search. 2. `dimensions` number * The fixed size of the vectors index. If you're using embeddings, this dimension should match the size of your embeddings (e.g. `1536` for OpenAI). 3. \[Optional] `filterFields` array * The names of additional fields that are indexed for fast filtering within your vector index. 4. \[Optional] `staged` boolean * If set to `true`, the index will be backfilled asynchronously from the deploy similar to [staged database indexes](/database/reading-data/indexes/.md#staged-indexes). This is useful for large tables where the index backfill time is significant. Defaults to `false`. For example, if you want an index that can search for similar foods within a given cuisine, your table definition could look like: convex/schema.ts ``` foods: defineTable({ description: v.string(), cuisine: v.string(), embedding: v.array(v.float64()), }).vectorIndex("by_embedding", { vectorField: "embedding", dimensions: 1536, filterFields: ["cuisine"], }), ``` You can specify vector and filter fields on nested documents by using a dot-separated path like `properties.name`. ## Running vector searches[​](#running-vector-searches "Direct link to Running vector searches") Unlike database queries or full text search, vector searches can only be performed in a [Convex action](/functions/actions.md). They generally involve three steps: 1. Generate a vector from provided input (e.g. using OpenAI) 2. Use [`ctx.vectorSearch`](/api/interfaces/server.GenericActionCtx.md#vectorsearch) to fetch the IDs of similar documents 3. Load the desired information for the documents Here's an example of the first two steps for searching for similar French foods based on a description: convex/foods.ts ``` import { v } from "convex/values"; import { action } from "./_generated/server"; export const similarFoods = action({ args: { descriptionQuery: v.string(), }, handler: async (ctx, args) => { // 1. Generate an embedding from your favorite third party API: const embedding = await embed(args.descriptionQuery); // 2. Then search for similar foods! const results = await ctx.vectorSearch("foods", "by_embedding", { vector: embedding, limit: 16, filter: (q) => q.eq("cuisine", "French"), }); // ... }, }); ``` An example of the first step can be found [here](https://github.com/get-convex/convex-demos/blob/main/vector-search/convex/foods.ts#L18) in the vector search demo app. Focusing on the second step, the `vectorSearch` API takes in the table name, the index name, and finally a [`VectorSearchQuery`](/api/interfaces/server.VectorSearchQuery.md) object describing the search. This object has the following fields: 1. `vector` array * An array of numbers (e.g. embedding) to use in the search. * The search will return the document IDs of the documents with the most similar stored vectors. * It must have the same length as the `dimensions` of the index. 2. \[Optional] `limit` number * The number of results to get back. If specified, this value must be between 1 and 256. 3. \[Optional] `filter` * An expression that restricts the set of results based on the `filterFields` in the `vectorIndex` in your schema. See [Filter expressions](#filter-expressions) for details. It returns an `Array` of objects containing exactly two fields: 1. `_id` * The [Document ID](https://docs.convex.dev/database/document-ids) for the matching document in the table 2. `_score` * An indicator of how similar the result is to the vector you were searching for, ranging from -1 (least similar) to 1 (most similar) Neither the underlying document nor the vector are included in `results`, so once you have the list of results, you will want to load the desired information about the results. There are a few strategies for loading this information documented in the [Advanced Patterns](#advanced-patterns) section. For now, let's load the documents and return them from the action. To do so, we'll pass the list of results to a Convex query and run it inside of our action, returning the result: convex/foods.ts ``` export const fetchResults = internalQuery({ args: { ids: v.array(v.id("foods")) }, handler: async (ctx, args) => { const results = []; for (const id of args.ids) { const doc = await ctx.db.get("foods", id); if (doc === null) { continue; } results.push(doc); } return results; }, }); ``` convex/foods.ts ``` export const similarFoods = action({ args: { descriptionQuery: v.string(), }, handler: async (ctx, args) => { // 1. Generate an embedding from your favorite third party API: const embedding = await embed(args.descriptionQuery); // 2. Then search for similar foods! const results = await ctx.vectorSearch("foods", "by_embedding", { vector: embedding, limit: 16, filter: (q) => q.eq("cuisine", "French"), }); // 3. Fetch the results const foods: Array> = await ctx.runQuery( internal.foods.fetchResults, { ids: results.map((result) => result._id) }, ); return foods; }, }); ``` ### Filter expressions[​](#filter-expressions "Direct link to Filter expressions") As mentioned above, vector searches support efficiently filtering results by additional fields on your document using either exact equality on a single field, or an `OR` of expressions. For example, here's a filter for foods with cuisine exactly equal to "French": ``` filter: (q) => q.eq("cuisine", "French"), ``` You can also filter documents by a single field that contains several different values using an `or` expression. Here's a filter for French or Indonesian dishes: ``` filter: (q) => q.or(q.eq("cuisine", "French"), q.eq("cuisine", "Indonesian")), ``` For indexes with multiple filter fields, you can also use `.or()` filters on different fields. Here's a filter for dishes whose cuisine is French or whose main ingredient is butter: ``` filter: (q) => q.or(q.eq("cuisine", "French"), q.eq("mainIngredient", "butter")), ``` **Both `cuisine` and `mainIngredient` would need to be included in the `filterFields` in the `.vectorIndex` definition.** ### Other filtering[​](#other-filtering "Direct link to Other filtering") Results can be filtered based on how similar they are to the provided vector using the `_score` field in your action: ``` const results = await ctx.vectorSearch("foods", "by_embedding", { vector: embedding, }); const filteredResults = results.filter((result) => result._score >= 0.9); ``` Additional filtering can always be done by passing the vector search results to a query or mutation function that loads the documents and performs filtering using any of the fields on the document. **For performance, always put as many of your filters as possible into `.vectorSearch`.** ### Ordering[​](#ordering "Direct link to Ordering") Vector queries always return results in relevance order. Currently Convex searches vectors using an [approximate nearest neighbor search](https://en.wikipedia.org/wiki/Nearest_neighbor_search#Approximate_nearest_neighbor) based on [cosine similarity](https://en.wikipedia.org/wiki/Cosine_similarity). Support for more similarity metrics [will come in the future](#future-development). If multiple documents have the same score, ties are broken by the document ID. ## Advanced patterns[​](#advanced-patterns "Direct link to Advanced patterns") ### Using a separate table to store vectors[​](#using-a-separate-table-to-store-vectors "Direct link to Using a separate table to store vectors") There are two main options for setting up a vector index: 1. Storing vectors in the same table as other metadata 2. Storing vectors in a separate table, with a reference The examples above show the first option, which is simpler and works well for reading small amounts of documents. The second option is more complex, but better supports reading or returning large amounts of documents. Since vectors are typically large and not useful beyond performing vector searches, it's nice to avoid loading them from the database when reading other data (e.g. `db.get()`) or returning them from functions by storing them in a separate table. A table definition for movies, and a vector index supporting search for similar movies filtering by genre would look like this: convex/schema.ts ``` movieEmbeddings: defineTable({ embedding: v.array(v.float64()), genre: v.string(), }).vectorIndex("by_embedding", { vectorField: "embedding", dimensions: 1536, filterFields: ["genre"], }), movies: defineTable({ title: v.string(), genre: v.string(), description: v.string(), votes: v.number(), embeddingId: v.optional(v.id("movieEmbeddings")), }).index("by_embedding", ["embeddingId"]), ``` Generating an embedding and running a vector search are the same as using a single table. Loading the relevant documents given the vector search result is different since we have an ID for `movieEmbeddings` but want to load a `movies` document. We can do this using the `by_embedding` database index on the `movies` table: convex/movies.ts ``` export const fetchMovies = query({ args: { ids: v.array(v.id("movieEmbeddings")), }, handler: async (ctx, args) => { const results = []; for (const id of args.ids) { const doc = await ctx.db .query("movies") .withIndex("by_embedding", (q) => q.eq("embeddingId", id)) .unique(); if (doc === null) { continue; } results.push(doc); } return results; }, }); ``` ### Fetching results and adding new documents[​](#fetching-results-and-adding-new-documents "Direct link to Fetching results and adding new documents") Returning information from a vector search involves an action (since vector search is only available in actions) and a query or mutation to load the data. The example above used a query to load data and return it from an action. Since this is an action, the data returned is not reactive. An alternative would be to return the results of the vector search in the action, and have a separate query that reactively loads the data. The search results will not update reactively, but the data about each result would be reactive. The [Vector Search Demo App](https://github.com/get-convex/convex-demos/tree/main/vector-search) uses this strategy to show similar movies with a reactive "Votes" count. ## Limits[​](#limits "Direct link to Limits") Convex supports millions of vectors today. This is an ongoing project and we will continue to scale this offering out with the rest of Convex. Vector indexes must have: * Exactly 1 vector index field. * The field must be of type `v.array(v.float64())` (or a union in which one of the possible types is `v.array(v.float64())`) * Exactly 1 dimension field with a value between 2 and 4096. * Up to 16 filter fields. Vector indexes count towards the [limit of 32 indexes per table](/database/reading-data/indexes/.md#limits). In addition you can have up to 4 vector indexes per table. Vector searches can have: * Exactly 1 vector to search by in the `vector` field * Up to 64 filter expressions * Up to 256 requested results (defaulting to 10). If your action performs a vector search then passes the results to a query or mutation function, you may find that one or more results from the vector search have been deleted or mutated. Because vector search is only available in actions, you cannot perform additional transactional queries or mutations based on the results. If this is important for your use case, please [let us know on Discord](https://convex.dev/community)! Only documents that contain a vector of the size and in the field specified by a vector index will be included in the index and returned by the vector search. For information on limits, see [here](/production/state/limits.md). ## Future development[​](#future-development "Direct link to Future development") We're always open to customer feedback and requests. Some ideas we've considered for improving vector search in Convex include: * More sophisticated filters and filter syntax * Filtering by score in the `vectorSearch` API * Better support for generating embeddings If any of these features is important for your app, [let us know on Discord](https://convex.dev/community)! --- # Self Hosting If you're excited about self-hosting, you can run the Convex backend on your own servers. Self-hosted Convex runs the [open-source backend](https://github.com/get-convex/convex-backend), and contains the same fully up-to-date code the cloud service uses. To get started with self hosting, follow the self-hosting guide: [Self-hosting guide](https://github.com/get-convex/convex-backend/blob/main/self-hosted/README.md) Join the `#self-hosted` channel in the [Discord community](https://convex.dev/community) for self-hosting support. Self hosting is not for everyone. If you're looking for a more hands-off solution, we recommend using the [Convex-hosted product](https://convex.dev/pricing). ## Open Source Convex Backend[​](#open-source-convex-backend "Direct link to Open Source Convex Backend") The majority of the backend is written in Rust, with a healthy dose of TypeScript supporting the server-side function environment. You can learn more about open-sourcing at Convex in our [announcement](https://news.convex.dev/convex-goes-open-source/) and the [software engineering daily podcast](https://softwareengineeringdaily.com/2024/03/20/going-open-source-at-convex-with-james-cowling/). Convex uses an [FSL Apache 2.0 License](https://fsl.software/) which is a [fair source](https://fair.io) license. You can do almost anything Apache-2.0 allows, except create another product designed to compete with the hosted Convex Cloud. This ensures the sustainability of Convex's development while giving the community maximum freedom. All code is automatically converted to full Apache-2.0 two years after its creation. For legal text, see [FSL Apache 2.0 License](https://fsl.software/). ## Other Convex Open Source Projects[​](#other-convex-open-source-projects "Direct link to Other Convex Open Source Projects") The Convex backend, client libraries, dashboard, and CLI are all open-source. You can explore everything on the [Convex GitHub page](https://github.com/get-convex). ### Convex Clients[​](#convex-clients "Direct link to Convex Clients") All Convex Clients are open-source. * [Convex JavaScript/TypeScript clients & CLI](https://github.com/get-convex/convex-js) * [Convex Python Client](https://github.com/get-convex/convex-py) * [Convex Rust Client](https://github.com/get-convex/convex-rs) ### Much Much More[​](#much-much-more "Direct link to Much Much More") Convex also open-sources many other helpful projects including [helpers](https://github.com/get-convex/convex-helpers), [templates](https://github.com/orgs/get-convex/repositories?type=all\&q=template), [demos](https://github.com/get-convex/convex-demos), a [testing harness](https://github.com/get-convex/convex-test) and much more. See the complete list of all our public repositories [at GitHub](https://github.com/orgs/get-convex/repositories?type=all). Related posts from [![Stack](/img/stack-logo-dark.svg)![Stack](/img/stack-logo-light.svg)](https://stack.convex.dev/) --- # Custom Roles info Custom Roles are available in beta on the Convex Business and Enterprise plans. Custom roles let you define permission policies that go beyond the built-in [Admin and Developer roles](/dashboard/teams/teams.md#team-roles). A custom role contains a list of statements that grant or deny specific actions on specific resources. A team member is assigned *either* a built-in team role (Admin or Developer) *or* one or more custom roles. Built-in roles and custom roles are mutually exclusive at the team-role level. The [Project Admin role](/dashboard/teams/teams.md#project-admins) is independent of both: a member can hold Project Admin on specific projects regardless of their team-level role, and it grants full access to those projects on top of whatever access the team role provides. Custom roles are managed on the **Team Settings > Custom Roles** page in the Convex dashboard. The Convex dashboard offers a number of templates to get you started. We recommend starting with the template that fits your use case best and making edits to meet your needs. ## How custom roles are evaluated[​](#how-custom-roles-are-evaluated "Direct link to How custom roles are evaluated") When Convex checks whether a member with custom roles can perform an action on a resource, it evaluates each of the member's custom roles independently and combines the results: 1. **Default deny.** If no statement in any role matches the action and resource, access is denied. Custom roles only ever grant access; they never start from "everything is allowed." 2. **Within a role, deny overrides allow.** When a role has both an `allow` and a `deny` statement that match the same action and resource, the role evaluates to denied. Because evaluation short-circuits as soon as a deny is found, **the order of allow and deny statements within a role does not matter**. The result is the same regardless of how the statements are arranged. 3. **Across roles, allows are combined.** The action is allowed if *any* of the member's roles evaluates to allowed for it. A `deny` in one role does **not** override an `allow` in another role. Project Admin permissions are layered on independently. Even with a restrictive set of custom roles, a member who is a Project Admin on a given project still has full access to that project. ## Grammar[​](#grammar "Direct link to Grammar") A custom role is a list of **statements**. Each statement is a JSON object with three fields: ``` { "effect": "allow", "actions": ["deployment:view", "deployment:logs:view"], "resource": "project:*:deployment:type=prod" } ``` ### Statements[​](#statements "Direct link to Statements") A statement grants or denies a set of actions on a set of resources. A custom role must have at least one statement. Each statement is evaluated independently against the action being checked. ### Effects[​](#effects "Direct link to Effects") The `effect` field is one of: * `"allow"` grants the listed actions on the matching resources. * `"deny"` within the same role, blocks the listed actions on the matching resources, overriding any `allow` statement in that role. ### Actions[​](#actions "Direct link to Actions") The `actions` field of a statement is either: * The string `"*"`, matching every action that targets the same [resource kind](#resource-specifiers) as the statement's resource, or * An array of specific action names. All actions in a single statement must apply to the same top-level [resource kind](#resource-specifiers) as the **leaf segment** of the statement's resource path. For example, you cannot mix `project:view` (a project action) with `deployment:view` (a deployment action) in the same statement. For the full list of action names see [Role Actions](/team-management/role-actions.md). ### Resource specifiers[​](#resource-specifiers "Direct link to Resource specifiers") A resource specifier is a colon-separated path that describes which resources a statement applies to. The path has two kinds of pieces: * **Resource kinds**: `team`, `project`, `deployment`, `member`, `customRole`, `billing`, `oauthApplication`, `sso`, `integration`, `defaultEnvironmentVariable`, or `token`. * **Selectors:** filters that follow a kind and narrow which resources of that kind match. Selectors use `attribute=value` syntax, like `slug=my-app` or `type=prod`. The leaf (rightmost) kind of the path determines which actions are valid in the statement. #### Symbols[​](#symbols "Direct link to Symbols") * `:` separates pieces of the path. For example, `project:*:deployment:*` means "any deployment in any project." * `*` is a wildcard, matching all resources of the given kind. `project:*` matches every project. * `=` binds a selector attribute to a value, like `id=42`. Project, deployment, and member IDs can be looked up through the [Platform API](/platform-apis/overview.md). * `,` separates multiple selectors on the same kind. **Multiple selectors are OR'd**: `deployment:type=prod,creator=5` matches any deployment that is either a production deployment *or* created by member 5. #### Selectors by kind[​](#selectors-by-kind "Direct link to Selectors by kind") info Selector support is limited while custom roles is in beta. More selectors will be supported in the future. | Kind | Selectors | | ----------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | | `project` | `*`, `id=`, `slug=` | | `deployment` | `*`, `id=`, `type=prod\|dev\|preview\|custom`, `creator=` | | `token` | `*`, `creator=` | | `team`, `member`, `customRole`, `billing`, `oauthApplication`, `sso`, `integration`, `defaultEnvironmentVariable` | `*` only: these resources do not currently support any selectors. | #### Nesting[​](#nesting "Direct link to Nesting") Most resource kinds appear at the top level of a path. A few must be nested: * `deployment` must appear under a project, e.g. `project:*:deployment:*`. * `defaultEnvironmentVariable` must appear under a project, e.g. `project:*:defaultEnvironmentVariable:*`. * `token` must appear under its owning resource (a team, project, or deployment), e.g. `team:*:token:*`, `project:*:token:*`, or `project:*:deployment:*:token:*`. #### Example specifiers[​](#example-specifiers "Direct link to Example specifiers") | Specifier | Matches | | ----------------------------------------- | ---------------------------------------------------- | | `team:*` | The team itself. | | `billing:*` | The team's billing settings. | | `sso:*` | The team's SSO configuration. | | `member:*` | All team members. | | `project:*` | All projects in the team. | | `project:slug=my-app` | The project whose slug is `my-app`. | | `project:*:deployment:*` | All deployments in any project. | | `project:*:deployment:type=prod` | All production deployments. | | `project:*:deployment:type=dev,creator=5` | Dev deployments OR deployments created by member 5. | | `project:*:defaultEnvironmentVariable:*` | Default project environment variables. | | `team:*:token:*` | All team-scoped access tokens. | | `project:*:deployment:*:token:creator=7` | Deployment-scoped access tokens created by member 7. | #### Scoping access token actions[​](#scoping-access-token-actions "Direct link to Scoping access token actions") There is currently no Platform API for one team member to list team access tokens created by another member, so granting `team:token:view` on `team:*:token:*` effectively only surfaces the holder's own tokens. The API may broaden in the future, however, so we recommend scoping token-management actions to the holder's own tokens by using `creator=self` . For example, a role that lets a member manage only their own team tokens would use a resource like `team:*:token:creator=7` rather than `team:*:token:*`. ## Privilege escalation[​](#privilege-escalation "Direct link to Privilege escalation") caution A few actions effectively grant the ability to escalate privileges, and should be treated as equivalent to full team admin access when included in a custom role. Be especially careful when granting these actions. Each one can be used to gain permissions the holder doesn't otherwise have, so granting any of them can be effectively the same as granting all Team-Admin or Project-Admin permissions. Only include them in custom roles assigned to people you would otherwise trust at that level. **Membership and roles:** * **`member:invite`** lets the holder invite any email address to the team, including at the built-in Admin role. A member with this permission can invite themselves at a different email address as a team Admin and gain full team access that way. * **`member:role:update`** lets the holder change any other member's team role, including promoting another member (or themselves, indirectly via a second account) to Admin. * **`project:updateMemberRole`** lets the holder assign Project Admin on a project. Granting this allows the holder to promote themselves to Project Admin, which provides full access to every deployment in that project, including production. **Resource scoping:** The built-in roles use a resource's team, project, and deployment type to decide what a member can do (for example, Developer can manage non-prod deployments via team membership, but production deployments require Team Admin or Project Admin). Any action that changes those bindings is a privilege escalation: * **`project:update`** lets the holder rename a project's slug. Custom-role resource specifiers that match by `slug=` are evaluated against the project's current slug, so renaming a project can move it into or out of an `allow` or `deny` rule. A holder could rename a project to match a more permissive `allow` selector, or away from a `deny` selector, to gain access the role would otherwise withhold. Selectors that use `id=` are not affected, since project IDs are immutable. * **`deployment:updateType`** lets the holder change a deployment's type. A holder who can manage non-prod deployments could create one, then promote it to `type=prod`, or downgrade an existing prod deployment to a less protected type to operate on it without prod gating. * **`deployment:transfer`** moves a deployment into another project. If the holder has Project Admin or a more permissive custom role on the destination project, they get that broader access on the transferred deployment. * **`project:transfer`** moves a project (and all its deployments) into another team. If the holder has Admin or a more permissive custom role on the destination team, they gain that broader access on the transferred project. **Authentication:** * **`sso:update`** lets the holder change the team's SSO configuration. The holder could point SSO at an identity provider they control and impersonate other team members at sign-in. * **`sso:disable`** turns off SSO. Members with alternative sign-in paths could then bypass IdP-enforced policies such as MFA or session controls. The `customRole:create`, `customRole:update`, and `customRole:delete` actions have no equivalent in custom-role statements at all: they cannot be granted even with a wildcard `"*"`, and remain reserved for the built-in Admin role. This prevents a custom role from defining or escalating itself. ## Note on custom role visibility[​](#note-on-custom-role-visibility "Direct link to Note on custom role visibility") Listing every custom role on the team requires the `customRole:view` permission. However, the Convex dashboard loads a team member's own custom role definitions regardless of whether they hold `customRole:view`. Treat custom role definitions as visible to the members of the team that hold them, and avoid encoding sensitive information in role names or descriptions. For example, if you'd prefer to not disclose a project's slug in the deny rule of a custom role definition, use that project's ID instead. ## JSON Schema[​](#json-schema "Direct link to JSON Schema") The following [JSON Schema](https://json-schema.org/) represents the shape of valid Custom Roles. ``` { "$schema": "http://json-schema.org/draft-07/schema#", "title": "Custom Role Statements", "type": "array", "items": { "$ref": "#/definitions/statement" }, "definitions": { "statement": { "type": "object", "required": ["effect", "actions", "resource"], "additionalProperties": false, "properties": { "effect": { "enum": ["allow", "deny"] }, "actions": { "$ref": "#/definitions/actionPattern" }, "resource": { "$ref": "#/definitions/resourceSpecifier" } }, "allOf": [ { "if": { "required": ["resource"], "properties": { "resource": { "pattern": "^team:[^:]+$" } } }, "then": { "properties": { "actions": { "if": { "type": "array" }, "then": { "minItems": 1, "items": { "type": "string", "enum": [ "team:update", "team:delete", "team:auditLog:view", "team:usage:view" ] } }, "else": { "const": "*" } } } } }, { "if": { "required": ["resource"], "properties": { "resource": { "pattern": "^project:[^:]+$" } } }, "then": { "properties": { "actions": { "if": { "type": "array" }, "then": { "minItems": 1, "items": { "type": "string", "enum": [ "project:create", "project:transfer", "project:receive", "project:update", "project:delete", "project:view", "project:updateMemberRole" ] } }, "else": { "const": "*" } } } } }, { "if": { "required": ["resource"], "properties": { "resource": { "pattern": "^project:[^:]+:deployment:[^:]+$" } } }, "then": { "properties": { "actions": { "if": { "type": "array" }, "then": { "minItems": 1, "items": { "type": "string", "enum": [ "deployment:create", "deployment:receive", "deployment:transfer", "deployment:delete", "deployment:view", "deployment:updateReference", "deployment:updateDashboardEditConfirmation", "deployment:updateExpiresAt", "deployment:updateSendLogsToClient", "deployment:updateClass", "deployment:updateIsDefault", "deployment:updateType", "deployment:integrations:view", "deployment:integrations:write", "deployment:customDomain:create", "deployment:customDomain:delete", "deployment:customDomain:view", "deployment:insights:view", "deployment:backups:create", "deployment:backups:import", "deployment:backups:configurePeriodic", "deployment:backups:disablePeriodic", "deployment:backups:delete", "deployment:backups:view", "deployment:backups:download", "deployment:deploy", "deployment:pause", "deployment:unpause", "deployment:env:view", "deployment:env:write", "deployment:logs:view", "deployment:metrics:view", "deployment:auditLog:view", "deployment:data:view", "deployment:data:write", "deployment:functions:actAsUser", "deployment:functions:runInternalQueries", "deployment:functions:runInternalMutations", "deployment:functions:runInternalActions", "deployment:functions:runTestQuery" ] } }, "else": { "const": "*" } } } } }, { "if": { "required": ["resource"], "properties": { "resource": { "pattern": "^member:[^:]+$" } } }, "then": { "properties": { "actions": { "if": { "type": "array" }, "then": { "minItems": 1, "items": { "type": "string", "enum": [ "member:invite", "member:cancelInvitation", "member:remove", "member:updateRole", "member:view" ] } }, "else": { "const": "*" } } } } }, { "if": { "required": ["resource"], "properties": { "resource": { "pattern": "^team:[^:]+:token:[^:]+$" } } }, "then": { "properties": { "actions": { "if": { "type": "array" }, "then": { "minItems": 1, "items": { "type": "string", "enum": [ "team:token:create", "team:token:update", "team:token:delete", "team:token:view" ] } }, "else": { "const": "*" } } } } }, { "if": { "required": ["resource"], "properties": { "resource": { "pattern": "^project:[^:]+:token:[^:]+$" } } }, "then": { "properties": { "actions": { "if": { "type": "array" }, "then": { "minItems": 1, "items": { "type": "string", "enum": [ "project:token:create", "project:token:update", "project:token:delete", "project:token:view" ] } }, "else": { "const": "*" } } } } }, { "if": { "required": ["resource"], "properties": { "resource": { "pattern": "^project:[^:]+:deployment:[^:]+:token:[^:]+$" } } }, "then": { "properties": { "actions": { "if": { "type": "array" }, "then": { "minItems": 1, "items": { "type": "string", "enum": [ "deployment:token:create", "deployment:token:update", "deployment:token:delete", "deployment:token:view" ] } }, "else": { "const": "*" } } } } }, { "if": { "required": ["resource"], "properties": { "resource": { "pattern": "^customRole:[^:]+$" } } }, "then": { "properties": { "actions": { "if": { "type": "array" }, "then": { "minItems": 1, "items": { "type": "string", "enum": ["customRole:view"] } }, "else": { "const": "*" } } } } }, { "if": { "required": ["resource"], "properties": { "resource": { "pattern": "^billing:[^:]+$" } } }, "then": { "properties": { "actions": { "if": { "type": "array" }, "then": { "minItems": 1, "items": { "type": "string", "enum": [ "billing:paymentMethod:update", "billing:contact:update", "billing:address:update", "billing:subscription:changePlan", "billing:spendingLimit:update", "billing:view", "billing:invoices:view" ] } }, "else": { "const": "*" } } } } }, { "if": { "required": ["resource"], "properties": { "resource": { "pattern": "^oauthApplication:[^:]+$" } } }, "then": { "properties": { "actions": { "if": { "type": "array" }, "then": { "minItems": 1, "items": { "type": "string", "enum": [ "oauthApplication:create", "oauthApplication:update", "oauthApplication:delete", "oauthApplication:view", "oauthApplication:generateClientSecret" ] } }, "else": { "const": "*" } } } } }, { "if": { "required": ["resource"], "properties": { "resource": { "pattern": "^sso:[^:]+$" } } }, "then": { "properties": { "actions": { "if": { "type": "array" }, "then": { "minItems": 1, "items": { "type": "string", "enum": [ "sso:enable", "sso:disable", "sso:update", "sso:view" ] } }, "else": { "const": "*" } } } } }, { "if": { "required": ["resource"], "properties": { "resource": { "pattern": "^integration:[^:]+$" } } }, "then": { "properties": { "actions": { "if": { "type": "array" }, "then": { "minItems": 1, "items": { "type": "string", "enum": [ "integration:view", "integration:create", "integration:update", "integration:delete", "team:auditLog:view" ] } }, "else": { "const": "*" } } } } }, { "if": { "required": ["resource"], "properties": { "resource": { "pattern": "^project:[^:]+:defaultEnvironmentVariable:[^:]+$" } } }, "then": { "properties": { "actions": { "if": { "type": "array" }, "then": { "minItems": 1, "items": { "type": "string", "enum": [ "defaultEnvironmentVariable:create", "defaultEnvironmentVariable:update", "defaultEnvironmentVariable:delete", "defaultEnvironmentVariable:view" ] } }, "else": { "const": "*" } } } } } ] }, "actionPattern": { "if": { "type": "array" }, "then": { "minItems": 1, "items": { "type": "string" } }, "else": { "const": "*" } }, "resourceSpecifier": { "type": "string", "minLength": 1, "pattern": "^(team:\\*(:token:(\\*|creator=(self|[0-9]+))(,(\\*|creator=(self|[0-9]+)))*)?|project:(\\*|id=[^,:]+|slug=[^,:]+)(,(\\*|id=[^,:]+|slug=[^,:]+))*(:token:(\\*|creator=(self|[0-9]+))(,(\\*|creator=(self|[0-9]+)))*|:deployment:(\\*|id=[^,:]+|type=[^,:]+|creator=(self|[0-9]+))(,(\\*|id=[^,:]+|type=[^,:]+|creator=(self|[0-9]+)))*(:token:(\\*|creator=(self|[0-9]+))(,(\\*|creator=(self|[0-9]+)))*)?|:defaultEnvironmentVariable:\\*)?|member:\\*|customRole:\\*|billing:\\*|oauthApplication:\\*|sso:\\*|integration:\\*)$" } } } ``` --- # Team Management Convex provides administrative features for controlling how members access your team, projects, and deployments: * **[Single Sign-On (SSO)](/team-management/sso.md)** — authenticate team members through your organization's identity provider. * **[Custom Roles](/team-management/custom-roles.md)** — define fine-grained permission policies beyond the built-in Admin and Developer roles. * **[Role Actions](/team-management/role-actions.md)** — reference for every action a role can grant, and which built-in roles cover which actions. For an overview of the built-in team and project roles, see [Roles and permissions](/dashboard/teams/teams.md#roles-and-permissions). --- # Role Actions Convex represents every permission you can grant on a team, project, or deployment as a named **role action**. Both the built-in team roles (Admin and Developer) and [custom roles](/team-management/custom-roles.md) are defined in terms of the same set of role actions, so this page works as a reference for both: * If you're using built-in roles, scan the columns below to see which permissions each role gets. * If you're writing a [custom role](/team-management/custom-roles.md), pick the action names you want to allow or deny. ## Conventions[​](#conventions "Direct link to Conventions") Each table lists role actions for one kind of resource, with a column per built-in role: * **Team Admin** is granted to any team member with the built-in Admin role. * **Team Developer** is granted to any team member with the built-in Developer role. Members assigned custom roles do **not** receive Developer-level access. * **Project Admin** is granted to any team member who additionally holds the Project Admin role on the specific project that owns the resource. Project Admin sits alongside the member's built-in or custom role; Team Admins implicitly have Project Admin on every project. Cells use these markers: * ✓ - the role grants this action. * ✗ - the role does not grant this action. * ✓ *non-prod* - the role grants this action only on non-production deployments. Granting the action on a production deployment requires Team Admin or Project Admin on that project. * N/A - the action does not apply to that role (e.g. Project Admin on team-scoped actions). ## Team[​](#team "Direct link to Team") Resource leaf: `team:*`. | Action | Description | Team Admin | Team Developer | | -------------------- | ------------------------------ | ---------- | -------------- | | `team:update` | Change the team name and slug. | ✓ | ✗ | | `team:delete` | Delete the team. | ✓ | ✗ | | `team:auditLog:view` | View the team's audit log. | ✓ | ✓ | | `team:usage:view` | View the team's usage page. | ✓ | ✓ | info Both `team:auditLog:view` and `team:usage:view` reveal the existence of every project on the team. The audit log contains entries that reference projects and deployments across the whole team, and the usage page breaks down consumption per project. Grant these actions only to members who should know what projects the team has, even if they cannot otherwise access those projects. ## Billing[​](#billing "Direct link to Billing") Resource leaf: `billing:*`. | Action | Description | Team Admin | Team Developer | | ---------------------------------------------------------------------------------- | --------------------------------------------------------------- | ---------- | -------------- | | `billing:paymentMethod:update`, `billing:contact:update`, `billing:address:update` | Change billing details. | ✓ | ✗ | | `billing:subscription:changePlan` | Create, resume, cancel, or change the team's subscription plan. | ✓ | ✗ | | `billing:spendingLimit:update` | Set warning and disable spending limits. | ✓ | ✗ | | `billing:view` | Read billing details. | ✓ | ✓ | | `billing:invoices:view` | Read invoices. | ✓ | ✗ | ## OAuth applications[​](#oauth-applications "Direct link to OAuth applications") Resource leaf: `oauthApplication:*`. | Action | Description | Team Admin | Team Developer | | ------------------------------------------------------------------------------- | ------------------------------------ | ---------- | -------------- | | `oauthApplication:create`, `oauthApplication:update`, `oauthApplication:delete` | Manage OAuth applications. | ✓ | ✗ | | `oauthApplication:generateClientSecret` | Generate a client secret for an app. | ✓ | ✗ | | `oauthApplication:view` | View OAuth applications. | ✓ | ✓ | ## SSO[​](#sso "Direct link to SSO") Resource leaf: `sso:*`. | Action | Description | Team Admin | Team Developer | | ----------------------------------------- | ----------------------------- | ---------- | -------------- | | `sso:enable`, `sso:disable`, `sso:update` | Manage the SSO configuration. | ✓ | ✗ | | `sso:view` | View the SSO configuration. | ✓ | ✓ | ## Team integrations[​](#team-integrations "Direct link to Team integrations") Resource leaf: `integration:*`. | Action | Description | Team Admin | Team Developer | | ---------------------------------------------------------------- | ------------------------------- | ---------- | -------------- | | `integration:create`, `integration:update`, `integration:delete` | Manage team-level integrations. | ✓ | ✗ | | `integration:view` | View team-level integrations. | ✓ | ✓ | ## Members[​](#members "Direct link to Members") Resource leaf: `member:*`. | Action | Description | Team Admin | Team Developer | | ----------------------------------------------------------- | --------------------------------- | ---------- | -------------- | | `member:view` | View the team's members. | ✓ | ✓ | | `member:invite`, `member:cancelInvitation`, `member:remove` | Manage team membership. | ✓ | ✗ | | `member:updateRole` | Change a team member's team role. | ✓ | ✗ | ## Custom roles[​](#custom-roles "Direct link to Custom roles") Resource leaf: `customRole:*`. | Action | Description | Team Admin | Team Developer | | ----------------- | ---------------------------------------- | ---------- | -------------- | | `customRole:view` | View the team's custom role definitions. | ✓ | ✓ | `customRole:create`, `customRole:update`, and `customRole:delete` are reserved for Team Admins and cannot be granted through a custom role. ## Projects[​](#projects "Direct link to Projects") Resource leaf: `project:*` (or `project:slug=…`, `project:id=…`). Project Admin applies on the specific project the action targets. | Action | Description | Team Admin | Team Developer | Project Admin | | ------------------------------------- | ----------------------------------------------------- | ---------- | -------------- | ------------- | | `project:create` | Create new projects. | ✓ | ✓ | N/A | | `project:view` | View projects in the team. | ✓ | ✓ | ✓ | | `project:update`, `project:delete` | Update or delete a project. | ✓ | ✗ | ✓ | | `project:updateMemberRole` | Assign or remove the Project Admin role on a project. | ✓ | ✗ | ✓ | | `project:transfer`, `project:receive` | Transfer projects between teams. | ✓ | ✗ | ✗ | ## Default project environment variables[​](#default-project-environment-variables "Direct link to Default project environment variables") Resource leaf: `project:…:defaultEnvironmentVariable:*`. | Action | Description | Team Admin | Team Developer | Project Admin | | ------------------------------------------------------------------------------------------------------------- | --------------------------------------------- | ---------- | -------------- | ------------- | | `defaultEnvironmentVariable:view` | View default project environment variables. | ✓ | ✓ | ✓ | | `defaultEnvironmentVariable:create`, `defaultEnvironmentVariable:update`, `defaultEnvironmentVariable:delete` | Manage default project environment variables. | ✓ | ✗ | ✓ | ## Deployments[​](#deployments "Direct link to Deployments") Resource leaf: `project:…:deployment:*` (optionally filtered with selectors like `:type=prod`). Most deployment-modifying actions are gated by whether the deployment is production. Team Developers can perform them on dev, preview, and custom deployments via team membership, but production deployments additionally require Team Admin or Project Admin on the owning project. The same split applies to data-plane actions: on a production deployment, a Team Developer gets a read-only deployment identity unless they're also Project Admin on that project. ### Lifecycle and configuration[​](#lifecycle-and-configuration "Direct link to Lifecycle and configuration") | Action | Description | Team Admin | Team Developer | Project Admin | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------- | ---------- | -------------- | ------------- | | `deployment:view` | View deployments. | ✓ | ✓ | ✓ | | `deployment:create` | Create deployments. | ✓ | ✓ *non-prod* | ✓ | | `deployment:delete` | Delete a deployment. | ✓ | ✓ *non-prod* | ✓ | | `deployment:transfer`, `deployment:receive` | Transfer a deployment between projects. | ✓ | ✓ *non-prod* | ✓ | | `deployment:updateReference`, `deployment:updateDashboardEditConfirmation`, `deployment:updateExpiresAt`, `deployment:updateSendLogsToClient`, `deployment:updateClass`, `deployment:updateIsDefault`, `deployment:updateType` | Update individual deployment settings. Each gates a single field on the deployment update API. | ✓ | ✓ *non-prod* | ✓ | | `deployment:customDomain:view` | View custom domains. | ✓ | ✓ | ✓ | | `deployment:customDomain:create`, `deployment:customDomain:delete` | Manage custom domains. | ✓ | ✓ *non-prod* | ✓ | | `deployment:insights:view` | View deployment insights. | ✓ | ✓ | ✓ | | `deployment:integrations:view` | View deployment-scoped integrations. | ✓ | ✓ | ✓ | | `deployment:integrations:write` | Modify deployment-scoped integrations. | ✓ | ✓ *non-prod* | ✓ | ### Data plane and runtime[​](#data-plane-and-runtime "Direct link to Data plane and runtime") These actions run against the deployment itself. On production deployments, a Team Developer who isn't also Project Admin gets a read-only deployment identity. | Action | Description | Team Admin | Team Developer | Project Admin | | -------------------------------------------------------------------------------------- | ------------------------------------------------------------ | ---------- | -------------- | ------------- | | `deployment:deploy` | Push code to a deployment. | ✓ | ✓ *non-prod* | ✓ | | `deployment:pause`, `deployment:unpause` | Pause or resume function execution. | ✓ | ✓ *non-prod* | ✓ | | `deployment:logs:view`, `deployment:metrics:view`, `deployment:auditLog:view` | Read deployment logs, metrics, and audit log. | ✓ | ✓ | ✓ | | `deployment:env:view` | Read the deployment's environment variables. | ✓ | ✓ | ✓ | | `deployment:env:write` | Modify the deployment's environment variables. | ✓ | ✓ *non-prod* | ✓ | | `deployment:data:view` | Read the deployment's database tables. | ✓ | ✓ | ✓ | | `deployment:data:write` | Modify the deployment's database tables. | ✓ | ✓ *non-prod* | ✓ | | `deployment:functions:runInternalQueries`, `deployment:functions:runTestQuery` | Run internal queries or test queries against the deployment. | ✓ | ✓ | ✓ | | `deployment:functions:runInternalMutations`, `deployment:functions:runInternalActions` | Run internal mutations or actions against the deployment. | ✓ | ✓ *non-prod* | ✓ | | `deployment:functions:actAsUser` | Run functions as another authenticated user. | ✓ | ✓ *non-prod* | ✓ | | `deployment:usage:view`, `deployment:usageLimits:view` | Read the deployment's current usage and its usage limits. | ✓ | ✓ | ✓ | | `deployment:usageLimits:write` | Create, update, or delete the deployment's usage limits. | ✓ | ✓ *non-prod* | ✓ | ### Backups[​](#backups "Direct link to Backups") | Action | Description | Team Admin | Team Developer | Project Admin | | ------------------------------------------------------------------------------------- | -------------------------------------- | ---------- | -------------- | ------------- | | `deployment:backups:view`, `deployment:backups:download` | View and download deployment backups. | ✓ | ✓ | ✓ | | `deployment:backups:create`, `deployment:backups:import`, `deployment:backups:delete` | Create, restore, or delete backups. | ✓ | ✓ *non-prod* | ✓ | | `deployment:backups:configurePeriodic`, `deployment:backups:disablePeriodic` | Configure or disable periodic backups. | ✓ | ✓ *non-prod* | ✓ | ## Access tokens[​](#access-tokens "Direct link to Access tokens") Access tokens nest under their owning resource. The actions follow the same prefix as the owner; `team:token:*` for team-scoped tokens, `project:token:*` for project-scoped, and `deployment:token:*` for deployment-scoped. ### Team-scoped tokens (resource leaf: `team:*:token:*`)[​](#team-scoped-tokens-resource-leaf-teamtoken "Direct link to team-scoped-tokens-resource-leaf-teamtoken") | Action | Description | Team Admin | Team Developer | | -------------------------------------------------------------------------------- | ------------------------------------------------------------- | ---------- | -------------- | | `team:token:create`, `team:token:view`, `team:token:update`, `team:token:delete` | Create, view, update, and delete your own team-scoped tokens. | ✓ | ✓ | All of these actions are scoped to tokens **you personally created**. A team access token can only perform actions its creator is allowed to perform. If the creator has [custom roles](/team-management/custom-roles.md), the token is limited to the actions those roles allow, so issuing a token never escalates the creator's privileges. ### Project-scoped tokens (resource leaf: `project:…:token:*`)[​](#project-scoped-tokens-resource-leaf-projecttoken "Direct link to project-scoped-tokens-resource-leaf-projecttoken") | Action | Description | Team Admin | Team Developer | Project Admin | | -------------------------------------------------------------------------------------------- | ------------------------------------ | ---------- | -------------- | ------------- | | `project:token:create`, `project:token:update`, `project:token:delete`, `project:token:view` | Manage project-scoped access tokens. | ✓ | ✓ | ✓ | ### Deployment-scoped tokens (resource leaf: `project:…:deployment:…:token:*`)[​](#deployment-scoped-tokens-resource-leaf-projectdeploymenttoken "Direct link to deployment-scoped-tokens-resource-leaf-projectdeploymenttoken") | Action | Description | Team Admin | Team Developer | Project Admin | | -------------------------------------------------------------------------------------------------------- | --------------------------------------- | ---------- | -------------- | ------------- | | `deployment:token:create`, `deployment:token:update`, `deployment:token:delete`, `deployment:token:view` | Manage deployment-scoped access tokens. | ✓ | ✓ *non-prod* | ✓ | Deploy keys and preview deploy keys are service tokens. Once issued, they carry their own permissions independent of the creator's current role: if a team member has already created a deploy key or preview deploy key, that key continues to work with its original permissions even if the member's team role or custom role later changes. To revoke a key's access, delete the key from the deployment or project settings page. --- # Single Sign-On (SSO) info Single Sign-On is only available on Convex Business and Enterprise. Single Sign-On (SSO) allows your team to authenticate with Convex using your organization's identity provider (IdP). Once configured, team members can sign in to Convex through your IdP instead of using individual credentials. ## Finding SSO settings[​](#finding-sso-settings "Direct link to Finding SSO settings") SSO settings are located in your team settings. To access them: 1. Click on "Team Settings" at the top of the project list page 2. Select the **Single Sign-On** tab Or navigate directly to the [SSO settings page](https://dashboard.convex.dev/team/settings/sso). ## Setting up SSO[​](#setting-up-sso "Direct link to Setting up SSO") To configure SSO for your team: ### 1. Enable SSO[​](#1-enable-sso "Direct link to 1. Enable SSO") On the Single Sign-On settings page, click **Enable SSO** to begin the setup process. ### 2. Verify your domain[​](#2-verify-your-domain "Direct link to 2. Verify your domain") Click **Manage Domains** to verify the domain used for SSO login. Follow the domain verification wizard to confirm ownership of your domain. ### 3. Configure your identity provider[​](#3-configure-your-identity-provider "Direct link to 3. Configure your identity provider") After verifying your domain, click **Manage SSO Configuration** to set up SSO with your identity provider of choice. Follow the instructions in the wizard to complete the configuration. ### Renewing certificates[​](#renewing-certificates "Direct link to Renewing certificates") The SSO configuration page also allows you to renew your configuration's certificate when it approaches expiration. ## Require Single Sign-On[​](#require-single-sign-on "Direct link to Require Single Sign-On") Once SSO is enabled, you can optionally choose to **require** SSO for all team members. When this setting is turned on: * All team members must authenticate through your identity provider to access this team. This applies to both access via the dashboard and CLI. * Members will not be able to sign in using other authentication methods to access the team This only applies to the specific team that has SSO enabled. Members can still use other login methods to access any other Convex teams they belong to. To enable this, toggle the **Require SSO** option on the Single Sign-On settings page. ## Customizing your domain policy[​](#customizing-your-domain-policy "Direct link to Customizing your domain policy") By default, all Convex users that sign in with your verified SSO domain will be required to log in with SSO to use Convex If they are signing in with an email address that uses your verified domain. To configure a custom domain policy, such as allowing users to login with other sign-on methods, contact Convex support. These settings will be available for self-serve configuration in the future. --- # Continuous Integration Continuous integration allows your team to move fast by combining changes from all team members and automatically testing them on a remote machine. ## Testing in GitHub Actions[​](#testing-in-github-actions "Direct link to Testing in GitHub Actions") It's easy if you're using [GitHub](https://docs.github.com/en/actions) to set up [CI](https://docs.github.com/en/actions/automating-builds-and-tests/about-continuous-integration) workflow for running your test suite: .github/workflows/test.yml ``` name: Run Tests on: [pull_request, push] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 - run: npm ci - run: npm run test ``` After you commit and push this file to your repository, GitHub will run `npm run test` every time you create a pull request or push a new commit. --- # Testing Local Backend Alternatively to [`convex-test`](/testing/convex-test.md) you can test your functions using the [open-source version of the Convex backend](https://github.com/get-convex/convex-backend). ## Getting Started[​](#getting-started "Direct link to Getting Started") Follow [this guide](https://stack.convex.dev/testing-with-local-oss-backend) for the instructions. Compared to `convex-test`, which uses a JS mock of the backend, running your tests against the real backend has these advantages: * Your tests will run against the same code as your Convex production (as long you keep the local backend up-to-date). * Limits on argument, data, query sizes are enforced. * You can bootstrap a large test dataset from a data import. * You can test your client code in combination with your backend logic. ## Limitations[​](#limitations "Direct link to Limitations") Note that testing against the local backend also has some drawbacks: * It requires setting up the local backend, which is more involved. * No control over time and any scheduled functions will run as scheduled. * Crons will also run unless disabled via [`IS_TEST`](https://stack.convex.dev/testing-with-local-oss-backend#setting-up-a-local-backend). * No way to mock `fetch` calls. * No way to mock dependencies or parts of the codebase. * No way to control randomness (tests may not be deterministic). * No way to set environment variable values from within tests. To test your functions in JS with a mocked Convex backend, check out [convex-test](/testing/convex-test.md). ## CI[​](#ci "Direct link to CI") See [Continuous Integration](/testing/ci.md) to run your tests on a shared remote machine. --- # convex-test The [`convex-test`](https://www.npmjs.com/package/convex-test) library provides a mock implementation of the Convex backend in JavaScript. It enables fast automated testing of the logic in your [functions](/functions/overview.md). ## Example[​](#example "Direct link to Example") convex/posts.test.ts ``` import { convexTest } from "convex-test"; import { describe, it, expect } from "vitest"; import { api, internal } from "./_generated/api"; import schema from "./schema"; describe("posts.list", () => { it("returns empty array when no posts exist", async () => { const t = convexTest(schema, modules); // Initially, there are no posts, so `list` returns an empty array const posts = await t.query(api.posts.list); expect(posts).toEqual([]); }); it("returns all posts ordered by creation time when there are posts", async () => { const t = convexTest(schema, modules); // Create some posts await t.mutation(internal.posts.add, { title: "First Post", content: "This is the first post", author: "Alice", }); await t.mutation(internal.posts.add, { title: "Second Post", content: "This is the second post", author: "Bob", }); // `list` returns all posts ordered by creation time const posts = await t.query(api.posts.list); expect(posts).toHaveLength(2); expect(posts[0].title).toBe("Second Post"); expect(posts[1].title).toBe("First Post"); }); }); const modules = import.meta.glob("./**/*.ts"); ``` You can see more examples in the [test suite](https://github.com/get-convex/convex-test/tree/main/convex) of the convex-test library. ## Get started[​](#get-started "Direct link to Get started") 1. Install test dependencies Install [Vitest](https://vitest.dev/) and the [`convex-test`](https://www.npmjs.com/package/convex-test) library. ``` npm install --save-dev convex-test vitest @edge-runtime/vm ``` 2. Setup NPM scripts Add these scripts to your `package.json` package.json ``` "scripts": { "test": "vitest", "test:once": "vitest run", "test:debug": "vitest --inspect-brk --no-file-parallelism", "test:coverage": "vitest run --coverage --coverage.reporter=text", } ``` 3. Configure Vitest Add `vitest.config.ts` file to configure the test environment to better match the Convex runtime. If your Convex functions are in a directory other than `convex` If your project has a [different name or location configured](/production/project-configuration.md#changing-the-convex-folder-name-or-location) for the `convex/` folder in `convex.json`, you need to call [`import.meta.glob`](https://vitejs.dev/guide/features#glob-import) and pass the result as the second argument to `convexTest`. The argument to `import.meta.glob` must be a glob pattern matching all the files containing your Convex functions. The paths are relative to the test file in which `import.meta.glob` is called. It's best to do this in one place in your custom functions folder: src/convex/test.setup.ts ``` /// export const modules = import.meta.glob( "./**/!(*.*.*)*.*s" ); ``` This example glob pattern includes all files with a single extension ending in `s` (like `js` or `ts`) in the `src/convex` folder and any of its children. Use the result in your tests: src/convex/messages.test.ts ``` import { convexTest } from "convex-test"; import { test } from "vitest"; import schema from "./schema"; import { modules } from "./test.setup"; test("some behavior", async () => { const t = convexTest(schema, modules); // use `t`... }); ``` Set up multiple test environments (e.g. Convex + frontend) If you want to use Vitest to test both your Convex functions and your React frontend: * With Vitest 4, use the [`projects`](https://vitest.dev/guide/projects) array to define separate configurations per environment: vitest.config.ts ``` import { defineConfig } from "vitest/config"; export default defineConfig({ test: { projects: [ { extends: true, test: { name: "convex", include: ["convex/**/*.test.{ts,js}"], environment: "edge-runtime", }, }, { extends: true, test: { name: "frontend", include: ["**/*.test.{ts,tsx,js,jsx}"], exclude: ["convex/**"], environment: "jsdom", }, }, ], }, }); ``` * With Vitest 3, use [`environmentMatchGlobs`](https://v3.vitest.dev/config/#environmentmatchglobs): vitest.config.ts ``` import { defineConfig } from "vitest/config"; export default defineConfig({ test: { environmentMatchGlobs: [ // all tests in convex/ will run in edge-runtime ["convex/**", "edge-runtime"], // all other tests use jsdom ["**", "jsdom"], ], }, }); ``` vitest.config.ts ``` import { defineConfig } from "vitest/config"; export default defineConfig({ test: { environment: "edge-runtime", }, }); ``` 4. Add a test file In your `convex` folder add a file ending in `.test.ts` The example test calls the `api.messages.send` mutation twice and then asserts that the `api.messages.list` query returns the expected results. convex/messages.test.ts ``` import { convexTest } from "convex-test"; import { expect, test } from "vitest"; import { api } from "./_generated/api"; import schema from "./schema"; test("sending messages", async () => { const t = convexTest(schema); await t.mutation(api.messages.send, { body: "Hi!", author: "Sarah" }); await t.mutation(api.messages.send, { body: "Hey!", author: "Tom" }); const messages = await t.query(api.messages.list); expect(messages).toMatchObject([ { body: "Hi!", author: "Sarah" }, { body: "Hey!", author: "Tom" } ]); }); ``` 5. Run tests Start the tests with `npm run test`. When you change the test file or your functions the tests will rerun automatically. ``` npm run test ``` If you're not familiar with Vitest, read the [Vitest Getting Started docs](https://vitest.dev/guide) first. ## Using convex-test[​](#using-convex-test "Direct link to Using convex-test") ### Initialize `convexTest`[​](#initialize-convextest "Direct link to initialize-convextest") The library exports a `convexTest` function which should be called at the start of each of your tests. The function returns an object which is by convention stored in the `t` variable and which provides methods for exercising your Convex functions. If your project uses a [schema](/database/schemas.md) you should pass it to the `convexTest` function: convex/myFunctions.test.ts ``` import { convexTest } from "convex-test"; import { test } from "vitest"; import schema from "./schema"; test("some behavior", async () => { const t = convexTest(schema); // use `t`... }); ``` Passing in the schema is required for the tests to correctly implement schema validation and for correct typing of [`t.run`](#modify-data-outside-of-functions). If you don't have a schema, call `convexTest()` with no argument. ### Call functions[​](#call-functions "Direct link to Call functions") Your test can call public and internal Convex [functions](/functions/overview.md) in your project: convex/myFunctions.test.ts ``` import { convexTest } from "convex-test"; import { test } from "vitest"; import { api, internal } from "./_generated/api"; test("functions", async () => { const t = convexTest(); const x = await t.query(api.myFunctions.myQuery, { a: 1, b: 2 }); const y = await t.query(internal.myFunctions.internalQuery, { a: 1, b: 2 }); const z = await t.mutation(api.myFunctions.mutateSomething, { a: 1, b: 2 }); const w = await t.mutation(internal.myFunctions.mutateSomething, { a: 1 }); const u = await t.action(api.myFunctions.doSomething, { a: 1, b: 2 }); const v = await t.action(internal.myFunctions.internalAction, { a: 1, b: 2 }); }); ``` ### Modify data outside of functions[​](#modify-data-outside-of-functions "Direct link to Modify data outside of functions") Sometimes you might want to directly [write](/database/writing-data.md) to the mock database or [file storage](/file-storage/overview.md) from your test, without needing a declared function in your project. You can use the `t.run` method which takes a handler that is given a `ctx` that allows reading from and writing to the mock backend: convex/tasks.test.ts ``` import { convexTest } from "convex-test"; import { expect, test } from "vitest"; import schema from "./schema"; test("functions", async () => { const t = convexTest(schema, modules); const firstTask = await t.run(async (ctx) => { await ctx.db.insert("tasks", { text: "Eat breakfast" }); return await ctx.db.query("tasks").first(); }); expect(firstTask).toMatchObject({ text: "Eat breakfast" }); }); const modules = import.meta.glob("./**/*.ts"); ``` ### Test helper functions with inline queries, mutations, and actions[​](#test-helper-functions-with-inline-queries-mutations-and-actions "Direct link to Test helper functions with inline queries, mutations, and actions") Often your code will have helper functions that take in `QueryCtx`, `MutationCtx`, and `ActionCtx` as an argument. With version `0.0.42` and later, you can pass an inline function to `t.query`, `t.mutation`, and `t.action`, similar to `t.run`, but with a `ctx` argument matching the function type. ``` test("helper functions", async () => { const t = convexTest(); const threadId = await t.mutation(async (ctx) => { const threadId = await ctx.db.insert("threads", {}); // insertThreadMessage takes a MutationCtx argument. await insertThreadMessage(ctx, threadId, "Hello"); return threadId; }); const text = await t.action(async (ctx) => { // searchForMessages takes an ActionCtx argument. const messages = await searchForMessages(ctx, threadId); const response = await promptLLM(ctx, threadId, messages); }); }); ``` ### HTTP actions[​](#http-actions "Direct link to HTTP actions") Your test can call [HTTP actions](/functions/http-actions.md) registered by your router: convex/http.test.ts ``` import { convexTest } from "convex-test"; import { expect, test } from "vitest"; import schema from "./schema"; test("functions", async () => { const t = convexTest(schema, modules); const response = await t.fetch("/some/path", { method: "POST" }); expect(response.status).toBe(200); }); const modules = import.meta.glob("./**/*.ts"); ``` Mocking the global `fetch` function doesn't affect `t.fetch`, but you can use `t.fetch` in a `fetch` mock to route to your HTTP actions. ### Scheduled functions[​](#scheduled-functions "Direct link to Scheduled functions") One advantage of using a mock implementation running purely in JavaScript is that you can control time in the Vitest test environment. To test implementations relying on [scheduled functions](/scheduling/scheduled-functions.md) use [Vitest's fake timers](https://vitest.dev/guide/mocking.html#timers) in combination with `t.finishInProgressScheduledFunctions`: convex/scheduling.test.ts ``` import { convexTest } from "convex-test"; import { expect, test, vi } from "vitest"; import { api } from "./_generated/api"; import schema from "./schema"; test("mutation scheduling action", async () => { // Enable fake timers vi.useFakeTimers(); const t = convexTest(schema, modules); // Call a function that schedules a mutation or action const scheduledFunctionId = await t.mutation( api.scheduler.mutationSchedulingAction, { delayMs: 10000 }, ); // Advance the mocked time vi.advanceTimersByTime(5000); // Advance the mocked time past the scheduled time of the function vi.advanceTimersByTime(6000); // Or run all currently pending timers vi.runAllTimers(); // At this point the scheduled function will be `inProgress`, // now wait for it to finish await t.finishInProgressScheduledFunctions(); // Assert that the scheduled function succeeded or failed const scheduledFunctionStatus = await t.run(async (ctx) => { return await ctx.db.system.get("_scheduled_functions", scheduledFunctionId); }); expect(scheduledFunctionStatus).toMatchObject({ state: { kind: "success" } }); // Reset to normal `setTimeout` etc. implementation vi.useRealTimers(); }); const modules = import.meta.glob("./**/*.ts"); ``` If you have a chain of several scheduled functions, for example a mutation that schedules an action that schedules another action, you can use `t.finishAllScheduledFunctions` to wait for all scheduled functions, including recursively scheduled functions, to finish: convex/chainedScheduling.test.ts ``` import { convexTest } from "convex-test"; import { expect, test, vi } from "vitest"; import { api } from "./_generated/api"; import schema from "./schema"; test("mutation scheduling action scheduling action", async () => { // Enable fake timers vi.useFakeTimers(); const t = convexTest(schema, modules); // Call a function that schedules a mutation or action await t.mutation(api.scheduler.mutationSchedulingActionSchedulingAction); // Wait for all scheduled functions, repeatedly // advancing time and waiting for currently in-progress // functions to finish await t.finishAllScheduledFunctions(vi.runAllTimers); // Assert the resulting state after all scheduled functions finished const createdTask = await t.run(async (ctx) => { return await ctx.db.query("tasks").first(); }); expect(createdTask).toMatchObject({ author: "AI" }); // Reset to normal `setTimeout` etc. implementation vi.useRealTimers(); }); const modules = import.meta.glob("./**/*.ts"); ``` Check out more examples in [this file](https://github.com/get-convex/convex-test/blob/main/convex/scheduler.test.ts). ### Authentication[​](#authentication "Direct link to Authentication") To test functions which depend on the current [authenticated](/auth/overview.md) user identity you can create a version of the `t` accessor with given [user identity attributes](/api/interfaces/server.UserIdentity.md). If you don't provide them, `issuer`, `subject` and `tokenIdentifier` will be generated automatically: convex/tasks.test.ts ``` import { convexTest } from "convex-test"; import { expect, test } from "vitest"; import { api } from "./_generated/api"; import schema from "./schema"; test("authenticated functions", async () => { const t = convexTest(schema, modules); const asSarah = t.withIdentity({ name: "Sarah" }); await asSarah.mutation(api.tasks.create, { text: "Add tests" }); const sarahsTasks = await asSarah.query(api.tasks.list); expect(sarahsTasks).toMatchObject([{ text: "Add tests" }]); const asLee = t.withIdentity({ name: "Lee" }); const leesTasks = await asLee.query(api.tasks.list); expect(leesTasks).toEqual([]); }); const modules = import.meta.glob("./**/*.ts"); ``` ## Vitest tips[​](#vitest-tips "Direct link to Vitest tips") ### Asserting results[​](#asserting-results "Direct link to Asserting results") See Vitest's [Expect](https://vitest.dev/api/expect.html) reference. [`toMatchObject()`](https://vitest.dev/api/expect.html#tomatchobject) is particularly helpful when asserting the shape of results without needing to list every object field. ### Asserting errors[​](#asserting-errors "Direct link to Asserting errors") To assert that a function throws, use [`.rejects.toThrowError()`](https://vitest.dev/api/expect.html#tothrowerror): convex/messages.test.ts ``` import { convexTest } from "convex-test"; import { expect, test } from "vitest"; import { api } from "./_generated/api"; import schema from "./schema"; test("messages validation", async () => { const t = convexTest(schema, modules); await expect(async () => { await t.mutation(api.messages.send, { body: "", author: "James" }); }).rejects.toThrowError("Empty message body is not allowed"); }); const modules = import.meta.glob("./**/*.ts"); ``` ### Mocking `fetch` calls[​](#mocking-fetch-calls "Direct link to mocking-fetch-calls") You can use Vitest's [vi.stubGlobal](https://vitest.dev/guide/mocking.html#globals) method: convex/ai.test.ts ``` import { expect, test, vi } from "vitest"; import { api } from "./_generated/api"; import schema from "./schema"; import { convexTest } from "convex-test"; test("ai", async () => { const t = convexTest(schema, modules); vi.stubGlobal( "fetch", vi.fn(async () => ({ text: async () => "I am the overlord" }) as Response), ); const reply = await t.action(api.messages.sendAIMessage, { prompt: "hello" }); expect(reply).toEqual("I am the overlord"); vi.unstubAllGlobals(); }); const modules = import.meta.glob("./**/*.ts"); ``` ### Measuring test coverage[​](#measuring-test-coverage "Direct link to Measuring test coverage") You can get a printout of the code coverage provided by your tests. Besides answering the question "how much of my code is covered by tests" it is also helpful to check that your test is actually exercising the code that you want it to exercise. Run `npm run test:coverage`. It will ask you to install a required dependency the first time you run it. ![example coverage printout](/screenshots/testing_coverage.png) ### Debugging tests[​](#debugging-tests "Direct link to Debugging tests") You can attach a debugger to the running tests. Read the Vitest [Debugging docs](https://vitest.dev/guide/debugging.html) and then use `npm run test:debug`. ## Limitations[​](#limitations "Direct link to Limitations") Since `convex-test` is only a mock implementation, it doesn't have many of the behaviors of the real Convex backend. Still, it should be helpful for testing the logic in your functions, and catching regressions caused by changes to your code. Some of the ways the mock differs: * Error messages content. You should not write product logic that relies on the content of error messages thrown by the real backend, as they are always subject to change. * Limits. The mock doesn't enforce size and time [limits](/production/state/limits.md). * ID format. Your code should not depend on the document or storage ID format. * Runtime built-ins. Most of your functions are written for the [Convex default runtime](/functions/runtimes.md), while Vitest uses a mock of Vercel's Edge Runtime, which is similar but might differ from the Convex runtime. You should always test new code manually to make sure it doesn't use built-ins not available in the Convex runtime. * Some features have only simplified semantics, namely: * [Text search](/search/overview.md) returns all documents that include a word for which at least one word in the searched string is a prefix. It does not sort the results by relevance. * [Vector search](/search/vector-search.md) returns results sorted by cosine similarity, but doesn't use an efficient vector index in its implementation. * There is no support for [cron jobs](/scheduling/cron-jobs.md), you should trigger your functions manually from the test. To test your functions running on a real Convex backend, check out [Testing Local Backend](/testing/convex-backend.md). ## CI[​](#ci "Direct link to CI") See [Continuous Integration](/testing/ci.md) to run your tests on a shared remote machine. --- # Testing Convex makes it easy to test your app via automated tests running in JS or against a real backend, and manually in dev, preview and staging environments. ## Automated tests[​](#automated-tests "Direct link to Automated tests") ### `convex-test` library[​](#convex-test-library "Direct link to convex-test-library") [Use the `convex-test` library](/testing/convex-test.md) to test your functions in JS via the excellent Vitest testing framework. ### Testing against a real backend[​](#testing-against-a-real-backend "Direct link to Testing against a real backend") Convex open source builds allow you to test all of your backend logic running on a real [local Convex backend](/testing/convex-backend.md). ### Set up testing in CI[​](#set-up-testing-in-ci "Direct link to Set up testing in CI") It's a good idea to test your app continuously in a controlled environment. No matter which way automated method you use, it's easy to run them with [GitHub Actions](/testing/ci.md). ## Manual tests[​](#manual-tests "Direct link to Manual tests") ### Running a function in dev[​](#running-a-function-in-dev "Direct link to Running a function in dev") Manually run a function in dev to quickly see if things are working: * [Run functions from the command line](/cli/reference/run.md) * [Run functions from the dashboard](/dashboard/deployments/functions.md#running-functions) ### Preview deployments[​](#preview-deployments "Direct link to Preview deployments") [Use preview deployments](/production/multiple-deployments.md#preview) to get early feedback from your team for your in-progress features. ### Staging environment[​](#staging-environment "Direct link to Staging environment") You can set up a separate project as a staging environment to test against. See [Deploying Your App to Production](/production/overview.md#staging-environment). --- # Convex Tutorial: Calling external services In the [previous step](/tutorial/overview.md), you built a fully self-contained chat app. Data in, data out. In order to power the automatic reactivity we just saw while providing strong database transactions, query and mutation functions in Convex are not allowed to make `fetch` calls to the outside world. Real apps aren't this simple. They often need to talk to the rest of the internet directly from the backend. Convex lets you do this too via **action** functions. Action functions let the sync engine access the external world by scheduling out work that can then write data back via mutations. Let's make our chat app a bit smarter by letting anyone in the chat get the Wikipedia summary of a topic using the Wikipedia API. [YouTube video player](https://www.youtube.com/embed/0bn9RcwOwOQ?si=C5Gvz2Us2H1KIAQu) ## Your first `action`[​](#your-first-action "Direct link to your-first-action") **Add the following action to your `convex/chat.ts` file.** ``` // Update your server import like this: import { query, mutation, internalAction } from "./_generated/server"; //... export const getWikipediaSummary = internalAction({ args: { topic: v.string() }, handler: async (ctx, args) => { const response = await fetch( "https://en.wikipedia.org/w/api.php?format=json&action=query&prop=extracts&exintro&explaintext&redirects=1&titles=" + args.topic, ); return getSummaryFromJSON(await response.json()); }, }); function getSummaryFromJSON(data: any) { const firstPageId = Object.keys(data.query.pages)[0]; return data.query.pages[firstPageId].extract; } ``` Let's walk through it: 1. First, we created a new Convex action function called `getWikipediaSummary`. We used `internalAction` because we want this function to be private to the Convex backend and not exposed as a public API. This function does a simple fetch to the Wikipedia API with our topic. 2. Next, we have a helper TypeScript function called `getSummaryFromJSON` to pull out the summary text from the JSON response. 3. The `getWikipediaSummary` function calls our helper function like any other TypeScript function. This is great and all, but how do I use it? To quickly test this function in the Convex dashboard, go to [https://dashboard.convex.dev](https://dashboard.convex.dev/deployment/functions) and navigate to your project. Click on the Functions in the left nav, and then click on the `getWikipediaSummary` function. Click "Run Function". The function runner UI will pop up. Try making a few searches. Running a few Wikipedia queries ## Hooking it up to your app[​](#hooking-it-up-to-your-app "Direct link to Hooking it up to your app") It's awesome that we can call Wikipedia, but we still need to show up in our chat. So, let's hook it all up. **Update your existing `sendMessage` mutation like this:** ``` // Import the api reference import { api, internal } from "./_generated/api"; //... export const sendMessage = mutation({ args: { user: v.string(), body: v.string(), }, handler: async (ctx, args) => { console.log("This TypeScript function is running on the server."); await ctx.db.insert("messages", { user: args.user, body: args.body, }); // Add the following lines: if (args.body.startsWith("/wiki")) { // Get the string after the first space const topic = args.body.slice(args.body.indexOf(" ") + 1); await ctx.scheduler.runAfter(0, internal.chat.getWikipediaSummary, { topic, }); } }, }); ``` Wait a second! What's with this `ctx.scheduler` stuff? Convex comes with a powerful durable function scheduler. It's a fundamental part of the sync engine, and it's the way you coordinate asynchronous functions in Convex. In the case of mutations, it's the only way to call an action to fetch from the outside world. The really cool part is, if for some reason your mutation throws an exception, then nothing is scheduled. This is because mutations are transactions, and scheduling is just a write in the database to tell Convex to run this function at a future time. Ok so, we can schedule our action, but we still need to write the summary back to the chat. **Let's go back and update our `getWikipediaSummary` action:** ``` export const getWikipediaSummary = internalAction({ args: { topic: v.string() }, handler: async (ctx, args) => { const response = await fetch( "https://en.wikipedia.org/w/api.php?format=json&action=query&prop=extracts&exintro&explaintext&redirects=1&titles=" + args.topic, ); // Replace the `return ...` with the following. const summary = getSummaryFromJSON(await response.json()); await ctx.scheduler.runAfter(0, api.chat.sendMessage, { user: "Wikipedia", body: summary, }); }, }); ``` Just like scheduling the action, we're now scheduling our `sendMessage` mutation to send the result of our Wikipedia lookup to our chat. Go ahead, now play with your app! Chat with Wikipedia ## The scheduler, actions, and the sync engine[​](#the-scheduler-actions-and-the-sync-engine "Direct link to The scheduler, actions, and the sync engine") ![Sync engine with actions](/assets/images/ConvexSyncAction-29b050dc3377673c0d3d21cc60efd709.png) Queries and mutations are the only ways to interact with the database and the scheduler enables building sophisticated workflows with actions in between. [Actions](/functions/actions.md) are normal serverless functions like AWS Lambda and Google Cloud Run. They help model flows like calling AI APIs and using the Vector Store. They serve as an escape hatch. They deal with the reality of the messy outside world with few guarantees. Actions are not part of the sync engine. To talk to the database they have to talk through query and mutation functions. This restriction lets Convex enforce transactional guarantees in the database and keep the sync engine fast and nimble. The best way to structure your application for scale is to minimize the work that happens in an action. Only the part that needs the [non-determinism](https://en.wikipedia.org/wiki/Deterministic_algorithm), like making the external `fetch` call should use them. Keeping them as small as possible is the most scalable way to build Convex apps, enabling the highest throughput. The scheduler allows your app to keep most of its important logic in queries and mutations and structure your code as workflows in and out of actions. ## What you built[​](#what-you-built "Direct link to What you built") In this section of the tutorial, you built an action to talk to the outside world and used the scheduler to trigger this work. You learned that keeping our actions small and keeping most of our work in queries and mutations are fundamental to building scalable Convex backends. ## Next up[​](#next-up "Direct link to Next up") You've now learned the most important concepts in Convex. As a full-featured backend, Convex is capable of many things such as [authentication](/auth/overview.md), [file storage](/file-storage/overview.md) and [search](/search/overview.md). You can add those features as needed by following the documentation. We touched a little bit on setting your app up for success. As your application scales, you will run into new challenges. Let's learn how to deal with some of these challenges in the [next section →](/tutorial/scale.md). [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.](/tutorial/scale.md) --- # Convex Tutorial: A chat app Convex provides you with a fully featured backend with cloud functions, database, scheduling, and a sync engine that keeps your frontend and backend up to date in real-time. Today, in about **10 lines of code,** we'll build a backend that reads and writes to the database and automatically updates all users in a chat app. After that we'll see how to connect to external services and setup your product for success and scale. [YouTube video player](https://www.youtube.com/embed/608khv7qqOI?si=ce-M8pt6EWDZ8tfd) ## Start developing with Convex[​](#start-developing-with-convex "Direct link to Start developing with Convex") Before you begin: You'll need Node.js 18+ and Git Ensure you have Node.js version 18 or greater installed on your computer. You can check your version of Node.js by running `node --version` in your terminal. If you don't have the appropriate version of Node.js installed, [install it from the Node.js website.](https://nodejs.org/en) In addition, this walkthrough requires Git, so verify you have it installed by running `git -v` in your terminal. If not, head over to the [Git website](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) for installation instructions. First, clone the example project repo from GitHub and install the dependencies: ``` git clone https://github.com/get-convex/convex-tutorial.git cd convex-tutorial npm install ``` This app's `dev` npm command sets up Convex and then runs the web app: ``` npm run dev ``` During setup, you'll see that Convex uses your GitHub account for authentication. Sign into Convex with GitHub and then accept the default project setup prompts. This will **automatically create your backend** and a folder called `convex/` in your project, where you'll write your backend code. **Make sure you keep this command (`npm run dev`) running in the background throughout this tutorial.** It's running both the dev web server for the frontend as well as the `convex` command in the background to keep your backend in sync with your local codebase. Once your server is up and running, open [localhost:5173](http://localhost:5173) and check it out: ![Chat UI](/assets/images/tut_chat_ui-9ab95f331e3132c9c61a0e2fc4eaf16c.png) If you try sending a message now, you'll see an alert telling you the mutation is not yet implemented. We'll do that in a bit, but first here's a quick summary of how Convex works. ## How Convex works[​](#how-convex-works "Direct link to How Convex works") ![Overview of the sync engine](/assets/images/ConvexSyncEngine-3271d28868180073da72479d72a5d93e.png) **Database.** The Convex database is a document-relational database, which means you have tables with JSON like documents in them. All documents have an auto-generated `_id` that can be used to create relations between documents. You interact with the database through mutation and query functions that are written entirely in TypeScript. **Mutation functions.** Mutations are TypeScript functions that update the database. All mutation functions in Convex run as a database transaction. So either all the changes are committed, or none are. **Query functions.** Queries are TypeScript functions that can only read from the database. As we'll see in a bit, you subscribe to them from your frontend to keep your app automatically up to date. Your frontend registers to listen to query updates through the **client library**. The client libraries talk to Convex via WebSockets for fast realtime updates. The **sync engine** reruns query functions when any input to the function changes, including any changes to the documents in the database that the query reads. It then updates every app listening to the query. The sync engine is the combination of queries, mutations and the database. Now, let's dive into the code! ## Your first `mutation`[​](#your-first-mutation "Direct link to your-first-mutation") Create a new file in your `convex/` folder called `chat.ts`. This is where you'll write your Convex backend functions for this application. **Add the following to your `convex/chat.ts` file.** ``` import { mutation } from "./_generated/server"; import { v } from "convex/values"; export const sendMessage = mutation({ args: { user: v.string(), body: v.string(), }, handler: async (ctx, args) => { console.log("This TypeScript function is running on the server."); await ctx.db.insert("messages", { user: args.user, body: args.body, }); }, }); ``` Let's break this down: 1. You've added a new backend `mutation` function called `sendMessage` and exposed it as a public api. 2. The whole function automatically runs as a transaction that will roll back if an exception is thrown. 3. Since this is just a TypeScript function you can drop `console.log` lines to do simple debugging on the server. 4. `args:` ensures the function arguments are two strings named `user` and `body`, both as types and runtime values. 5. `ctx.db.insert` tells Convex to insert a new message document into the table. Now, let's connect this mutation to your web app. **Update your `src/App.tsx` file like so:** ``` // Import `useMutation` and `api` from Convex. import { useMutation } from "convex/react"; import { api } from "../convex/_generated/api"; //... export default function App() { // Replace the "TODO: Add mutation hook here." with: const sendMessage = useMutation(api.chat.sendMessage); //... return (
{/* ... */}
{ e.preventDefault(); // Replace "alert("Mutation not implemented yet");" with: await sendMessage({ user: NAME, body: newMessageText }); setNewMessageText(""); }} > {/* ... */}
); } ``` There are two steps to call a mutation in your frontend: 1. `const sendMessage = useMutation(api.chat.sendMessage);` gives your frontend app a handle to the mutation function 2. `await sendMessage({ user: NAME, body: newMessageText });` calls the mutation with the proper parameters. This is a good time to **open up the Convex dashboard**. Open a new browser window and go to and find new `convex-tutorial` project. **Go to the "Data" screen**. So far, there is no data in your database. **Keep your chat app and dashboard windows open side by side**. Now try to send some messages from your chat app. Mutations hooked up to the Convex backend and database. You'll notice new chat messages showing up live in the `messages` table. Convex automatically created a `messages` table when you sent the first message. In Convex, [schemas](/database/schemas.md) are optional. Eventually, you'll want to enforce the structure of your tables, but for the purposes of the tutorial we'll skip this. In the dashboard you can also go to the [logs screen](https://dashboard.convex.dev/deployment/logs) and see every call to the mutation as you ran with the log line we added earlier. The logs screen is a critical part of debugging your backend in development. You've successfully created a `mutation` function, which is also a database transaction, and connected it to your UI. Now, let's make sure your app can update live the same way the dashboard is updating live. ## Your first `query`[​](#your-first-query "Direct link to your-first-query") **Update your `convex/chat.ts` file like this:** ``` // Update your server import like this: import { query, mutation } from "./_generated/server"; // ... // Add the following function to the file: export const getMessages = query({ args: {}, handler: async (ctx) => { // Get most recent messages first const messages = await ctx.db.query("messages").order("desc").take(50); // Reverse the list so that it's in a chronological order. return messages.reverse(); }, }); ``` Let's break this down: 1. You've added a new backend `query` function called `getMessages` and exposed it as a public api. 2. Since this is a query function, the `ctx.db` in this function only lets you read data. 3. In the first line of the `handler` you are querying the most recent 50 messages from newest to oldest. 4. In the second line you're reversing the list using plain old TypeScript. **Now update `src/App.tsx` to read from your query:** ``` // Update your convex/react import like this: import { useQuery, useMutation } from "convex/react"; //... export default function App() { // Replace the `const messages = ...` line with the following const messages = useQuery(api.chat.getMessages); //... } ``` That one `useQuery` line is doing a lot of work automatically for you. It's telling the Convex client library to subscribe to your `getMessages` function. Anytime there are new messages to show the query function is automatically rerun. The result is put in `const messages` variable and React rerenders your UI component to show the latest messages. That's it. Now go back to your app and try sending messages. Your app should be showing live updates as new messages arrive: Queries hooked up and live updating to the app.

Don't believe it? Try opening two chat windows side by side and send some messages: Live syncing chat app. ## What you built[​](#what-you-built "Direct link to What you built") With just a few lines of code you've built a live updating chat app. 1. You created a `mutation` TypeScript function that, in a transaction, adds new chat messages to your database. 2. You created a `query` TypeScript function updates your app with the latest data. 3. You used the client library that keeps your frontend in live sync with the backend. You've learned the fundamentals of Convex and the sync engine that powers everything. ## Next up[​](#next-up "Direct link to Next up") In this tutorial we just touched on the very basics. It's ok to just stop here and go explore the rest of the docs, including [efficient queries via indexes](/database/reading-data/indexes/.md) and traversing [relationships through joins](/database/reading-data/.md#join). If you're deeply curious about how Convex works, you can read this [excellent deep dive](https://stack.convex.dev/how-convex-works). But if you want to see how to call external services and build sophisticated backend workflows, jump into the [next section →](/tutorial/actions.md). [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.](/tutorial/actions.md) --- # Convex Tutorial: Scaling your app Convex was designed from the ground up for scale. In the previous section we already talked about how keeping your actions small and most of your logic in queries and mutations are crucial to building fast scalable backends. Let's talk about a few other ways to keep your app fast and scalable. [YouTube video player](https://www.youtube.com/embed/7lOGqFHnEsA) ## Indexed queries[​](#indexed-queries "Direct link to Indexed queries") Indexes tell the database to create a lookup structure to make it really fast to filter data. If, in our chat app we wanted to build a way to look up `messages` from just one user, we'd tell Convex to index the `user` field in the `messages` table and write the query with the `withIndex` syntax. [Learn how to use indexes](/database/reading-data/indexes/.md). ## Too many writes on the same document[​](#too-many-writes-on-the-same-document "Direct link to Too many writes on the same document") Let's say you decide to show a counter in your app. You may write a mutation that reads a number field, adds 1, and updates the same field in the database. At some point, this pattern may cause an [optimistic concurrency control conflict](/error.md#1). That means that the database isn't able to handle updating the document that fast. All databases have trouble with this sort of pattern. There are a [few ways to deal with this](/error.md#remediation), including building something called a sharded counter... But before you go learn advanced scaling techniques on your own, there is a better way with [Convex Components](/components/overview.md). ## Scaling best practices with Convex Components[​](#scaling-best-practices-with-convex-components "Direct link to Scaling best practices with Convex Components") In the case of the counter above, the Convex team has already built a [scalable counter](https://www.convex.dev/components/sharded-counter) Convex component for you to use. Convex Components are deployed along with your Convex backend but have their own tables and functions. As you build more complicated features like [AI agents](/agents/overview.md), [workflows](https://www.convex.dev/components/workflow), [leaderboards](https://www.convex.dev/components/aggregate), [feature flags](https://www.convex.dev/components/launchdarkly) or [rate limiters](https://www.convex.dev/components/rate-limiter), you may find that there is already a Convex Component that solves this problem. [Learn more about Convex Components here](/components/overview.md). [Components directory](https://www.convex.dev/components) ## Wrap up[​](#wrap-up "Direct link to Wrap up") We've covered a lot of ground in this tutorial. We started by [building a chat app](/tutorial/overview.md) with queries, mutations and the database that form the fundamental building blocks of the Convex sync engine. We then called an [external API](/tutorial/actions.md) from our backend, using the scheduler to coordinate the work. Finally, we learned that [Convex Components](/components/overview.md) give you scaling best practices in neat packages. If you are looking for more tips, read our [best practices](/understanding/best-practices/.md) and join the [community](https://www.convex.dev/community). Convex enables you to build your MVP fast and then scale to new heights. Many great products have already done so. You're in good company. --- # Best Practices This is a list of best practices and common anti-patterns around using Convex. We recommend going through this list before broadly releasing your app to production. You may choose to try using all of these best practices from the start, or you may wait until you've gotten major parts of your app working before going through and adopting the best practices here. ## Await all Promises[​](#await-all-promises "Direct link to Await all Promises") ### Why?[​](#why "Direct link to Why?") Convex functions use async / await. If you don't await all your promises (e.g. `await ctx.scheduler.runAfter`, `await ctx.db.patch`), you may run into unexpected behavior (e.g. failing to schedule a function) or miss handling errors. ### How?[​](#how "Direct link to How?") We recommend the [no-floating-promises](https://typescript-eslint.io/rules/no-floating-promises/) rule of typescript-eslint. ## Avoid `.filter` on database queries[​](#avoid-filter-on-database-queries "Direct link to avoid-filter-on-database-queries") ### Why?[​](#why-1 "Direct link to Why?") Filtering in code instead of using the `.filter` syntax has the same performance, and is generally easier code to write. Conditions in `.withIndex` or `.withSearchIndex` are more efficient than `.filter` or filtering in code, so almost all uses of `.filter` should either be replaced with a `.withIndex` or `.withSearchIndex` condition, or written as TypeScript code. Read through the [indexes documentation](/database/reading-data/indexes/indexes-and-query-perf.md) for an overview of how to define indexes and how they work. ### Examples[​](#examples "Direct link to Examples") convex/messages.ts ``` // ❌ const tomsMessages = ctx.db .query("messages") .filter((q) => q.eq(q.field("author"), "Tom")) .collect(); // ✅ // Option 1: Use an index const tomsMessages = await ctx.db .query("messages") .withIndex("by_author", (q) => q.eq("author", "Tom")) .collect(); // Option 2: Filter in code const allMessages = await ctx.db.query("messages").collect(); const tomsMessages = allMessages.filter((m) => m.author === "Tom"); ``` ### How?[​](#how-1 "Direct link to How?") Search for `.filter` in your Convex codebase — a regex like `\.filter\(\(?q` will probably find all the ones on database queries. You can also check automatically that your functions don’t use `.filter` with the [`@convex-dev/no-filter-in-query` ESLint rule](/eslint.md#no-filter-in-query). Decide whether they should be replaced with a `.withIndex` condition — per [this section](/understanding/best-practices/.md#only-use-collect-with-a-small-number-of-results), if you are filtering over a large (1000+) or potentially unbounded number of documents, you should use an index. If not using a `.withIndex` / `.withSearchIndex` condition, consider replacing them with a filter in code for more readability and flexibility. See [this article](https://stack.convex.dev/complex-filters-in-convex) for more strategies for filtering. ### Exceptions[​](#exceptions "Direct link to Exceptions") Using `.filter` on a paginated query (`.paginate`) has advantages over filtering in code. The paginated query will return the number of documents requested, including the `.filter` condition, so filtering in code afterwards can result in a smaller page or even an empty page. Using `.withIndex` on a paginated query will still be more efficient than a `.filter`. ## Only use `.collect` with a small number of results[​](#only-use-collect-with-a-small-number-of-results "Direct link to only-use-collect-with-a-small-number-of-results") ### Why?[​](#why-2 "Direct link to Why?") All results returned from `.collect` count towards database bandwidth (even ones filtered out by `.filter`). It also means that if any document in the result changes, the query will re-run or the mutation will hit a conflict. If there's a chance the number of results is large (say 1000+ documents), you should use an index to filter the results further before calling `.collect`, or find some other way to avoid loading all the documents such as using pagination, denormalizing data, or changing the product feature. ### Example[​](#example "Direct link to Example") **Using an index:** convex/movies.ts ``` // ❌ -- potentially unbounded const allMovies = await ctx.db.query("movies").collect(); const moviesByDirector = allMovies.filter( (m) => m.director === "Steven Spielberg", ); // ✅ -- small number of results, so `collect` is fine const moviesByDirector = await ctx.db .query("movies") .withIndex("by_director", (q) => q.eq("director", "Steven Spielberg")) .collect(); ``` **Using pagination:** convex/movies.ts ``` // ❌ -- potentially unbounded const watchedMovies = await ctx.db .query("watchedMovies") .withIndex("by_user", (q) => q.eq("user", "Tom")) .collect(); // ✅ -- using pagination, showing recently watched movies first const watchedMovies = await ctx.db .query("watchedMovies") .withIndex("by_user", (q) => q.eq("user", "Tom")) .order("desc") .paginate(paginationOptions); ``` **Using a limit or denormalizing:** convex/movies.ts ``` // ❌ -- potentially unbounded const watchedMovies = await ctx.db .query("watchedMovies") .withIndex("by_user", (q) => q.eq("user", "Tom")) .collect(); const numberOfWatchedMovies = watchedMovies.length; // ✅ -- Show "99+" instead of needing to load all documents const watchedMovies = await ctx.db .query("watchedMovies") .withIndex("by_user", (q) => q.eq("user", "Tom")) .take(100); const numberOfWatchedMovies = watchedMovies.length === 100 ? "99+" : watchedMovies.length.toString(); // ✅ -- Denormalize the number of watched movies in a separate table const watchedMoviesCount = await ctx.db .query("watchedMoviesCount") .withIndex("by_user", (q) => q.eq("user", "Tom")) .unique(); ``` ### How?[​](#how-2 "Direct link to How?") Search for `.collect` in your Convex codebase (a regex like `\.collect\(` will probably find these). And think through whether the number of results is small. This function health page in the dashboard can also help surface these. You can also check automatically that `.collect()` is avoided by enabling the [`@convex-dev/no-collect-in-query` ESLint rule](/eslint.md#no-collect-in-query). The [aggregate component](https://www.npmjs.com/package/@convex-dev/aggregate) or [database triggers](https://stack.convex.dev/triggers) can be helpful patterns for denormalizing data. ### Exceptions[​](#exceptions-1 "Direct link to Exceptions") If you're doing something that requires loading a large number of documents (e.g. performing a migration, making a summary), you may want to use an action to load them in batches via separate queries / mutations. ## Check for redundant indexes[​](#check-for-redundant-indexes "Direct link to Check for redundant indexes") ### Why?[​](#why-3 "Direct link to Why?") Indexes like `by_foo` and `by_foo_and_bar` are usually redundant (you only need `by_foo_and_bar`). Reducing the number of indexes saves on database storage and reduces the overhead of writing to the table. convex/teams.ts ``` // ❌ const allTeamMembers = await ctx.db .query("teamMembers") .withIndex("by_team", (q) => q.eq("team", teamId)) .collect(); const currentUserId = /* get current user id from `ctx.auth` */ const currentTeamMember = await ctx.db .query("teamMembers") .withIndex("by_team_and_user", (q) => q.eq("team", teamId).eq("user", currentUserId), ) .unique(); // ✅ // Just don't include a condition on `user` when querying for results on `team` const allTeamMembers = await ctx.db .query("teamMembers") .withIndex("by_team_and_user", (q) => q.eq("team", teamId)) .collect(); const currentUserId = /* get current user id from `ctx.auth` */ const currentTeamMember = await ctx.db .query("teamMembers") .withIndex("by_team_and_user", (q) => q.eq("team", teamId).eq("user", currentUserId), ) .unique(); ``` ### How?[​](#how-3 "Direct link to How?") Look through your indexes, either in your `schema.ts` file or in the dashboard, and look for any indexes where one is a prefix of another. ### Exceptions[​](#exceptions-2 "Direct link to Exceptions") `.index("by_foo", ["foo"])` is really an index on the properties `foo` and `_creationTime`, while `.index("by_foo_and_bar", ["foo", "bar"])` is an index on the properties `foo`, `bar`, and `_creationTime`. If you have queries that need to be sorted by `foo` and then `_creationTime`, then you need both indexes. For example, `.index("by_channel", ["channel"])` on a table of messages can be used to query for the most recent messages in a channel, but `.index("by_channel_and_author", ["channel", "author"])` could not be used for this since it would first sort the messages by `author`. ## Use argument validators for all public functions[​](#use-argument-validators-for-all-public-functions "Direct link to Use argument validators for all public functions") ### Why?[​](#why-4 "Direct link to Why?") Public functions can be called by anyone, including potentially malicious attackers trying to break your app. [Argument validators](/functions/validation.md) (as well as return value validators) help ensure you're getting the traffic you expect. ### Example[​](#example-1 "Direct link to Example") convex/movies.ts ``` // ❌ -- `id` and `update` are not validated, so a client could pass // any Convex value (the type at runtime could mismatch the // TypeScript type). In particular, `update` could contain // fields other than `title` and `director`. export const updateMovie = mutation({ handler: async ( ctx, { id, update, }: { id: Id<"movies">; update: Pick, "title" | "director">; }, ) => { await ctx.db.patch("movies", id, update); }, }); // ✅ -- This can only be called with an ID from the movies table, // and an `update` object with only the `title`/`director` fields export const updateMovie = mutation({ args: { id: v.id("movies"), update: v.object({ title: v.string(), director: v.string(), }), }, handler: async (ctx, { id, update }) => { await ctx.db.patch("movies", id, update); }, }); ``` ### How?[​](#how-4 "Direct link to How?") Search for `query`, `mutation`, and `action` in your Convex codebase, and ensure that all of them have argument validators (and optionally return value validators). You can also check automatically that your functions have argument validators with the [`@convex-dev/require-argument-validators` ESLint rule](/eslint.md#require-argument-validators). If you use HTTP actions, you may want to use an argument validation library like [Zod](https://zod.dev) to validate that the HTTP request is the shape you expect. ## Use some form of access control for all public functions[​](#use-some-form-of-access-control-for-all-public-functions "Direct link to Use some form of access control for all public functions") ### Why?[​](#why-5 "Direct link to Why?") Public functions can be called by anyone, including potentially malicious attackers trying to break your app. If portions of your app should only be accessible when the user is signed in, make sure all these Convex functions check that `ctx.auth.getUserIdentity()` is set. You may also have specific checks, like only loading messages that were sent to or from the current user, which you'll want to apply in every relevant public function. Favoring more granular functions like `setTeamOwner` over `updateTeam` allows more granular checks for which users can do what. Access control checks should either use `ctx.auth.getUserIdentity()` or a function argument that is unguessable (e.g. a UUID, or a Convex ID, provided that this ID is never exposed to any client but the one user). In particular, don't use a function argument which could be spoofed (e.g. email) for access control checks. ### Example[​](#example-2 "Direct link to Example") convex/teams.ts ``` // ❌ -- no checks! anyone can update any team if they get the ID export const updateTeam = mutation({ args: { id: v.id("teams"), update: v.object({ name: v.optional(v.string()), owner: v.optional(v.id("users")), }), }, handler: async (ctx, { id, update }) => { await ctx.db.patch("teams", id, update); }, }); // ❌ -- checks access, but uses `email` which could be spoofed export const updateTeam = mutation({ args: { id: v.id("teams"), update: v.object({ name: v.optional(v.string()), owner: v.optional(v.id("users")), }), email: v.string(), }, handler: async (ctx, { id, update, email }) => { const teamMembers = /* load team members */ if (!teamMembers.some((m) => m.email === email)) { throw new Error("Unauthorized"); } await ctx.db.patch("teams", id, update); }, }); // ✅ -- checks access, and uses `ctx.auth`, which cannot be spoofed export const updateTeam = mutation({ args: { id: v.id("teams"), update: v.object({ name: v.optional(v.string()), owner: v.optional(v.id("users")), }), }, handler: async (ctx, { id, update }) => { const user = await ctx.auth.getUserIdentity(); if (user === null) { throw new Error("Unauthorized"); } const isTeamMember = /* check if user is a member of the team */ if (!isTeamMember) { throw new Error("Unauthorized"); } await ctx.db.patch("teams", id, update); }, }); // ✅ -- separate functions which have different access control export const setTeamOwner = mutation({ args: { id: v.id("teams"), owner: v.id("users"), }, handler: async (ctx, { id, owner }) => { const user = await ctx.auth.getUserIdentity(); if (user === null) { throw new Error("Unauthorized"); } const isTeamOwner = /* check if user is the owner of the team */ if (!isTeamOwner) { throw new Error("Unauthorized"); } await ctx.db.patch("teams", id, { owner: owner }); }, }); export const setTeamName = mutation({ args: { id: v.id("teams"), name: v.string(), }, handler: async (ctx, { id, name }) => { const user = await ctx.auth.getUserIdentity(); if (user === null) { throw new Error("Unauthorized"); } const isTeamMember = /* check if user is a member of the team */ if (!isTeamMember) { throw new Error("Unauthorized"); } await ctx.db.patch("teams", id, { name: name }); }, }); ``` ### How?[​](#how-5 "Direct link to How?") Search for `query`, `mutation`, `action`, and `httpAction` in your Convex codebase, and ensure that all of them have some form of access control. [Custom functions](https://github.com/get-convex/convex-helpers/blob/main/packages/convex-helpers/README.md#custom-functions) like [`authenticatedQuery`](https://stack.convex.dev/custom-functions#modifying-the-ctx-argument-to-a-server-function-for-user-auth) can be helpful. Some apps use Row Level Security (RLS) to check access to each document automatically whenever it's loaded, as described in [this article](https://stack.convex.dev/row-level-security). Alternatively, you can check access in each Convex function instead of checking access for each document. Helper functions for common checks and common operations can also be useful -- e.g. `isTeamMember`, `isTeamAdmin`, `loadTeam` (which throws if the current user does not have access to the team). ## Only schedule and `ctx.run*` internal functions[​](#only-schedule-and-ctxrun-internal-functions "Direct link to only-schedule-and-ctxrun-internal-functions") ### Why?[​](#why-6 "Direct link to Why?") Public functions can be called by anyone, including potentially malicious attackers trying to break your app, and should be carefully audited to ensure they can't be used maliciously. Functions that are only called within Convex can be marked as internal, and relax these checks since Convex will ensure that internal functions can only be called within Convex. ### How?[​](#how-6 "Direct link to How?") Search for `ctx.runQuery`, `ctx.runMutation`, and `ctx.runAction` in your Convex codebase. Also search for `ctx.scheduler` and check the `crons.ts` file. Ensure all of these use `internal.foo.bar` functions instead of `api.foo.bar` functions. If you have code you want to share between a public Convex function and an internal Convex function, create a helper function that can be called from both. The public function will likely have additional access control checks. Alternatively, make sure that `api` from `_generated/api.ts` is never used in your Convex functions directory. ### Examples[​](#examples-1 "Direct link to Examples") convex/teams.ts ``` // ❌ -- using `api` export const sendMessage = mutation({ args: { body: v.string(), author: v.string(), }, handler: async (ctx, { body, author }) => { // add message to the database }, }); // crons.ts crons.daily( "send daily reminder", { hourUTC: 17, minuteUTC: 30 }, api.messages.sendMessage, { author: "System", body: "Share your daily update!" }, ); // ✅ Using `internal` import { MutationCtx } from './_generated/server'; async function sendMessageHelper( ctx: MutationCtx, args: { body: string; author: string }, ) { // add message to the database } export const sendMessage = mutation({ args: { body: v.string(), }, handler: async (ctx, { body }) => { const user = await ctx.auth.getUserIdentity(); if (user === null) { throw new Error("Unauthorized"); } await sendMessageHelper(ctx, { body, author: user.name ?? "Anonymous" }); }, }); export const sendInternalMessage = internalMutation({ args: { body: v.string(), // don't need to worry about `author` being spoofed since this is an internal function author: v.string(), }, handler: async (ctx, { body, author }) => { await sendMessageHelper(ctx, { body, author }); }, }); // crons.ts crons.daily( "send daily reminder", { hourUTC: 17, minuteUTC: 30 }, internal.messages.sendInternalMessage, { author: "System", body: "Share your daily update!" }, ); ``` ## Use helper functions to write shared code[​](#use-helper-functions-to-write-shared-code "Direct link to Use helper functions to write shared code") ### Why?[​](#why-7 "Direct link to Why?") Most logic should be written as plain TypeScript functions, with the `query`, `mutation`, and `action` wrapper functions being a thin wrapper around one or more helper function. Concretely, most of your code should live in a directory like `convex/model`, and your public API, which is defined with `query`, `mutation`, and `action`, should have very short functions that mostly just call into `convex/model`. Organizing your code this way makes several of the refactors mentioned in this list easier to do. See the [TypeScript page](/understanding/best-practices/typescript.md) for useful types. ### Example[​](#example-3 "Direct link to Example") **❌** This example overuses `ctx.runQuery` and `ctx.runMutation`, which is discussed more in the [Avoid sequential `ctx.runMutation` / `ctx.runQuery` from actions](/understanding/best-practices/.md#avoid-sequential-ctxrunmutation--ctxrunquery-calls-from-actions) section. convex/users.ts ``` export const getCurrentUser = query({ args: {}, handler: async (ctx) => { const userIdentity = await ctx.auth.getUserIdentity(); if (userIdentity === null) { throw new Error("Unauthorized"); } const user = /* query ctx.db to load the user */ const userSettings = /* load other documents related to the user */ return { user, settings: userSettings }; }, }); ``` convex/conversations.ts ``` export const listMessages = query({ args: { conversationId: v.id("conversations"), }, handler: async (ctx, { conversationId }) => { const user = await ctx.runQuery(api.users.getCurrentUser); const conversation = await ctx.db.get("conversations", conversationId); if (conversation === null || !conversation.members.includes(user._id)) { throw new Error("Unauthorized"); } const messages = /* query ctx.db to load the messages */ return messages; }, }); export const summarizeConversation = action({ args: { conversationId: v.id("conversations"), }, handler: async (ctx, { conversationId }) => { const messages = await ctx.runQuery(api.conversations.listMessages, { conversationId, }); const summary = /* call some external service to summarize the conversation */ await ctx.runMutation(api.conversations.addSummary, { conversationId, summary, }); }, }); ``` **✅** Most of the code here is now in the `convex/model` directory. The API for this application is in `convex/conversations.ts`, which contains very little code itself. convex/model/users.ts ``` import { QueryCtx } from '../_generated/server'; export async function getCurrentUser(ctx: QueryCtx) { const userIdentity = await ctx.auth.getUserIdentity(); if (userIdentity === null) { throw new Error("Unauthorized"); } const user = /* query ctx.db to load the user */ const userSettings = /* load other documents related to the user */ return { user, settings: userSettings }; } ``` convex/model/conversations.ts ``` import { QueryCtx, MutationCtx } from '../_generated/server'; import * as Users from './users'; export async function ensureHasAccess( ctx: QueryCtx, { conversationId }: { conversationId: Id<"conversations"> }, ) { const user = await Users.getCurrentUser(ctx); const conversation = await ctx.db.get("conversations", conversationId); if (conversation === null || !conversation.members.includes(user._id)) { throw new Error("Unauthorized"); } return conversation; } export async function listMessages( ctx: QueryCtx, { conversationId }: { conversationId: Id<"conversations"> }, ) { await ensureHasAccess(ctx, { conversationId }); const messages = /* query ctx.db to load the messages */ return messages; } export async function addSummary( ctx: MutationCtx, { conversationId, summary, }: { conversationId: Id<"conversations">; summary: string }, ) { await ensureHasAccess(ctx, { conversationId }); await ctx.db.patch("conversations", conversationId, { summary }); } export async function generateSummary( messages: Doc<"messages">[], conversationId: Id<"conversations">, ) { const summary = /* call some external service to summarize the conversation */ return summary; } ``` convex/conversations.ts ``` import * as Conversations from './model/conversations'; export const addSummary = internalMutation({ args: { conversationId: v.id("conversations"), summary: v.string(), }, handler: async (ctx, { conversationId, summary }) => { await Conversations.addSummary(ctx, { conversationId, summary }); }, }); export const listMessages = internalQuery({ args: { conversationId: v.id("conversations"), }, handler: async (ctx, { conversationId }) => { return Conversations.listMessages(ctx, { conversationId }); }, }); export const summarizeConversation = action({ args: { conversationId: v.id("conversations"), }, handler: async (ctx, { conversationId }) => { const messages = await ctx.runQuery(internal.conversations.listMessages, { conversationId, }); const summary = await Conversations.generateSummary( messages, conversationId, ); await ctx.runMutation(internal.conversations.addSummary, { conversationId, summary, }); }, }); ``` ## Use `runAction` only when using a different runtime[​](#use-runaction-only-when-using-a-different-runtime "Direct link to use-runaction-only-when-using-a-different-runtime") ### Why?[​](#why-8 "Direct link to Why?") Calling `runAction` has more overhead than calling a plain TypeScript function. It counts as an extra function call with its own memory and CPU usage, while the parent action is doing nothing except waiting for the result. Therefore, `runAction` should almost always be replaced with calling a plain TypeScript function. However, if you want to call code that requires Node.js from a function in the Convex runtime (e.g. using a library that requires Node.js), then you can use `runAction` to call the Node.js code. ### Example[​](#example-4 "Direct link to Example") convex/scrape.ts ``` // ❌ -- using `runAction` export const scrapeWebsite = action({ args: { siteMapUrl: v.string(), }, handler: async (ctx, { siteMapUrl }) => { const siteMap = await fetch(siteMapUrl); const pages = /* parse the site map */ await Promise.all( pages.map((page) => ctx.runAction(internal.scrape.scrapeSinglePage, { url: page }), ), ); }, }); ``` convex/model/scrape.ts ``` import { ActionCtx } from '../_generated/server'; // ✅ -- using a plain TypeScript function export async function scrapeSinglePage( ctx: ActionCtx, { url }: { url: string }, ) { const page = await fetch(url); const text = /* parse the page */ await ctx.runMutation(internal.scrape.addPage, { url, text }); } ``` convex/scrape.ts ``` import * as Scrape from './model/scrape'; export const scrapeWebsite = action({ args: { siteMapUrl: v.string(), }, handler: async (ctx, { siteMapUrl }) => { const siteMap = await fetch(siteMapUrl); const pages = /* parse the site map */ await Promise.all( pages.map((page) => Scrape.scrapeSinglePage(ctx, { url: page })), ); }, }); ``` ### How?[​](#how-7 "Direct link to How?") Search for `runAction` in your Convex codebase, and see if the function it calls uses the same runtime as the parent function. If so, replace the `runAction` with a plain TypeScript function. You may want to structure your functions so the Node.js functions are in a separate directory so it's easier to spot these. ## Avoid sequential `ctx.runMutation` / `ctx.runQuery` calls from actions[​](#avoid-sequential-ctxrunmutation--ctxrunquery-calls-from-actions "Direct link to avoid-sequential-ctxrunmutation--ctxrunquery-calls-from-actions") ### Why?[​](#why-9 "Direct link to Why?") Each `ctx.runMutation` or `ctx.runQuery` runs in its own transaction, which means if they're called separately, they may not be consistent with each other. If instead we call a single `ctx.runQuery` or `ctx.runMutation`, we're guaranteed that the results we get are consistent. ### How?[​](#how-8 "Direct link to How?") Audit your calls to `ctx.runQuery` and `ctx.runMutation` in actions. If you see multiple in a row with no other code between them, replace them with a single `ctx.runQuery` or `ctx.runMutation` that handles both things. Refactoring your code to use helper functions will make this easier. ### Example: Queries[​](#example-queries "Direct link to Example: Queries") convex/teams.ts ``` // ❌ -- this assertion could fail if the team changed between running the two queries const team = await ctx.runQuery(internal.teams.getTeam, { teamId }); const teamOwner = await ctx.runQuery(internal.teams.getTeamOwner, { teamId }); assert(team.owner === teamOwner._id); ``` convex/teams.ts ``` import * as Teams from './model/teams'; import * as Users from './model/users'; export const sendBillingReminder = action({ args: { teamId: v.id("teams"), }, handler: async (ctx, { teamId }) => { // ✅ -- this will always pass const teamAndOwner = await ctx.runQuery(internal.teams.getTeamAndOwner, { teamId, }); assert(teamAndOwner.team.owner === teamAndOwner.owner._id); // send a billing reminder email to the owner }, }); export const getTeamAndOwner = internalQuery({ args: { teamId: v.id("teams"), }, handler: async (ctx, { teamId }) => { const team = await Teams.load(ctx, { teamId }); const owner = await Users.load(ctx, { userId: team.owner }); return { team, owner }; }, }); ``` ### Example: Loops[​](#example-loops "Direct link to Example: Loops") convex/teams.ts ``` import * as Users from './model/users'; export const importTeams = action({ args: { teamId: v.id("teams"), }, handler: async (ctx, { teamId }) => { // Fetch team members from an external API const teamMembers = await fetchTeamMemberData(teamId); // ❌ This will run a separate mutation for inserting each user, // which means you lose transaction guarantees like atomicity. for (const member of teamMembers) { await ctx.runMutation(internal.teams.insertUser, member); } }, }); export const insertUser = internalMutation({ args: { name: v.string(), email: v.string() }, handler: async (ctx, { name, email }) => { await Users.insert(ctx, { name, email }); }, }); ``` convex/teams.ts ``` import * as Users from './model/users'; export const importTeams = action({ args: { teamId: v.id("teams"), }, handler: async (ctx, { teamId }) => { // Fetch team members from an external API const teamMembers = await fetchTeamMemberData(teamId); // ✅ This action runs a single mutation that inserts all users in the same transaction. await ctx.runMutation(internal.teams.insertUsers, teamMembers); }, }); export const insertUsers = internalMutation({ args: { users: v.array(v.object({ name: v.string(), email: v.string() })) }, handler: async (ctx, { users }) => { for (const { name, email } of users) { await Users.insert(ctx, { name, email }); } }, }); ``` ### Exceptions[​](#exceptions-3 "Direct link to Exceptions") If you're intentionally trying to process more data than fits in a single transaction, like running a migration or aggregating data, then it makes sense to have multiple sequential `ctx.runMutation` / `ctx.runQuery` calls. Multiple `ctx.runQuery` / `ctx.runMutation` calls are often necessary because the action does a side effect in between them. For example, reading some data, feeding it to an external service, and then writing the result back to the database. ## Use `ctx.runQuery` and `ctx.runMutation` sparingly in queries and mutations[​](#use-ctxrunquery-and-ctxrunmutation-sparingly-in-queries-and-mutations "Direct link to use-ctxrunquery-and-ctxrunmutation-sparingly-in-queries-and-mutations") ### Why?[​](#why-10 "Direct link to Why?") While these queries and mutations run in the same transaction, and will give consistent results, they have extra overhead compared to plain TypeScript functions. Wanting a TypeScript helper function is much more common than needing `ctx.runQuery` or `ctx.runMutation`. ### How?[​](#how-9 "Direct link to How?") Audit your calls to `ctx.runQuery` and `ctx.runMutation` in queries and mutations. Unless one of the exceptions below applies, replace them with a plain TypeScript function. ### Exceptions[​](#exceptions-4 "Direct link to Exceptions") * If you're using components, these require `ctx.runQuery` or `ctx.runMutation`. * If you want partial rollback on an error, you will want `ctx.runMutation` instead of a plain TypeScript function. convex/messages.ts ``` export const trySendMessage = mutation({ args: { body: v.string(), author: v.string(), }, handler: async (ctx, { body, author }) => { try { await ctx.runMutation(internal.messages.sendMessage, { body, author }); } catch (e) { // Record the failure, but rollback any writes from `sendMessage` await ctx.db.insert("failures", { kind: "MessageFailed", body, author, error: `Error: ${e}`, }); } }, }); ``` ## Always include the table name when calling `ctx.db` functions[​](#always-include-the-table-name-when-calling-ctxdb-functions "Direct link to always-include-the-table-name-when-calling-ctxdb-functions") ### Why?[​](#why-11 "Direct link to Why?") Since version 1.31.0 of the `convex` NPM package, the `ctx.db` functions accept a table name as the first argument. While this first argument is currently optional, passing the table name adds an additional safeguard which will be required for custom ID generation in the future. ### Example[​](#example-5 "Direct link to Example") convex/movies.ts ``` // ❌ await ctx.db.get(movieId); await ctx.db.patch(movieId, { title: "Whiplash" }); await ctx.db.replace(movieId, { title: "Whiplash", director: "Damien Chazelle", votes: 0, }); await ctx.db.delete(movieId); // ✅ vvvvvvvv await ctx.db.get("movies", movieId); await ctx.db.patch("movies", movieId, { title: "Whiplash" }); await ctx.db.replace("movies", movieId, { title: "Whiplash", director: "Damien Chazelle", votes: 0, }); await ctx.db.delete("movies", movieId); ``` ### How?[​](#how-10 "Direct link to How?") Search for calls of `db.get`, `db.patch`, `db.replace` and `db.delete` in your Convex codebase, and ensure that all of them pass a table name as the first argument. You can also check automatically that a table name argument is passed with the [`@convex-dev/explicit-table-ids` ESLint rule](/eslint.md#explicit-table-ids). You can migrate existing code automatically by using the autofix in the ESLint rule, or with the `@convex-dev/codemod` standalone tool. [Learn more on news.convex.dev →](https://news.convex.dev/db-table-name/) ## Don’t use `Date.now()` in queries[​](#date-in-queries "Direct link to date-in-queries") ### Why?[​](#why-12 "Direct link to Why?") When you subscribe to a query, Convex [will automatically run it again](/realtime.md) if the data that it accesses in the database change. The query is not re-run when `Date.now()` changes, because it wouldn’t be desirable to re-run a query every millisecond. So, if your query depends on the current time, it might return stale results. Also, using `Date.now()` in a query can cause the Convex query cache to be invalidated more frequently than necessary. In general, Convex will automatically re-use Convex query results if the query is called with the same arguments. However, when using `Date.now()` in a query, the query cache will be invalidated frequently in order to avoid showing results that are too old. This will unnecessarily increase the work that the database has to do. ### Example[​](#example-6 "Direct link to Example") convex/posts.ts ``` // ❌ const releasedPosts = await ctx.db .query("posts") .withIndex("by_released_at", (q) => q.lte("releasedAt", Date.now())) .take(100); // ✅ const releasedPosts = await ctx.db .query("posts") // `isReleased` is set to `true` by a scheduled function after `releasedAt` is reached .withIndex("by_is_released", (q) => q.eq("isReleased", true)) .take(100); ``` ### How?[​](#how-11 "Direct link to How?") Search for usages of `Date.now()` in your Convex queries, or in functions that are called from a Convex query. If you want to compare the current time with a timestamp stored in a database document, consider adding a coarser field to the document that you update from a [scheduled function](/scheduling/scheduled-functions.md) (see the example above). This way, the query cache is only invalidated explicitly when data changes. Alternatively, you can pass in the target time in as an explicit argument from the client. For best caching results, the client should avoid changing this argument frequently, for instance by rounding the time down to the most recent minute, so all client requests within that minute use the same arguments. --- # TypeScript Convex provides end-to-end type support when Convex functions are written in [TypeScript](https://www.typescriptlang.org/). You can gradually add TypeScript to a Convex project: the following steps provide progressively better type support. For the best support you'll want to complete them all. **Example:** [TypeScript and Schema](https://github.com/get-convex/convex-demos/tree/main/typescript) ## Writing Convex functions in TypeScript[​](#writing-convex-functions-in-typescript "Direct link to Writing Convex functions in TypeScript") The first step to improving type support in a Convex project is to writing your Convex functions in TypeScript by using the `.ts` extension. If you are using [argument validation](/functions/validation.md), Convex will infer the types of your functions arguments automatically: convex/sendMessage.ts ``` import { mutation } from "./_generated/server"; import { v } from "convex/values"; export default mutation({ args: { body: v.string(), author: v.string(), }, // Convex knows that the argument type is `{body: string, author: string}`. handler: async (ctx, args) => { const { body, author } = args; await ctx.db.insert("messages", { body, author }); }, }); ``` Otherwise you can annotate the arguments type manually: convex/sendMessage.ts ``` import { internalMutation } from "./_generated/server"; export default internalMutation({ // To convert this function from JavaScript to // TypeScript you annotate the type of the arguments object. handler: async (ctx, args: { body: string; author: string }) => { const { body, author } = args; await ctx.db.insert("messages", { body, author }); }, }); ``` This can be useful for [internal functions](/functions/internal-functions.md) accepting complicated types. If TypeScript is installed in your project `npx convex dev` and `npx convex deploy` will typecheck Convex functions before sending code to the Convex backend. Convex functions are typechecked with the `tsconfig.json` in the Convex folder: you can modify some parts of this file to change typechecking settings, or delete this file to disable this typecheck. You'll find most database methods have a return type of `Promise` until you add a schema. ## Adding a schema[​](#adding-a-schema "Direct link to Adding a schema") Once you [define a schema](/database/schemas.md) the type signature of database methods will be known. You'll also be able to use types imported from `convex/_generated/dataModel` in both Convex functions and clients written in TypeScript (React, React Native, Node.js etc.). The types of documents in tables can be described using the [`Doc`](/generated-api/data-model.md#doc) type from the generated data model and references to documents can be described with parametrized [Document IDs](/database/document-ids.md). convex/messages.ts ``` import { query } from "./_generated/server"; export const list = query({ args: {}, // The inferred return type of `handler` is now `Promise[]>` handler: (ctx) => { return ctx.db.query("messages").collect(); }, }); ``` ## Type annotating server-side helpers[​](#type-annotating-server-side-helpers "Direct link to Type annotating server-side helpers") When you want to reuse logic across Convex functions you'll want to define helper functions, and these might need some of the provided context, to access the database, authentication and any other Convex feature. Convex generates types corresponding to documents and IDs in your database, `Doc` and `Id`, as well as `QueryCtx`, `MutationCtx` and `ActionCtx` types based on your schema and declared Convex functions: convex/helpers.ts ``` // Types based on your schema import { Doc, Id } from "./_generated/dataModel"; // Types based on your schema and declared functions import { QueryCtx, MutationCtx, ActionCtx, DatabaseReader, DatabaseWriter, } from "./_generated/server"; // Types that don't depend on schema or function import { Auth, StorageReader, StorageWriter, StorageActionWriter, } from "convex/server"; // Note that a `MutationCtx` also satisfies the `QueryCtx` interface export function myReadHelper(ctx: QueryCtx, id: Id<"channels">) { /* ... */ } export function myActionHelper(ctx: ActionCtx, doc: Doc<"messages">) { /* ... */ } ``` ### Inferring types from validators[​](#inferring-types-from-validators "Direct link to Inferring types from validators") Validators can be reused between [argument validation](/functions/validation.md) and [schema validation](/database/schemas.md). You can use the provided [`Infer`](/api/modules/values.md#infer) type to get a TypeScript type corresponding to a validator: convex/helpers.ts ``` import { Infer, v } from "convex/values"; export const courseValidator = v.union( v.literal("appetizer"), v.literal("main"), v.literal("dessert"), ); // The corresponding type can be used in server or client-side helpers: export type Course = Infer; // is inferred as `'appetizer' | 'main' | 'dessert'` ``` ### Document types without system fields[​](#document-types-without-system-fields "Direct link to Document types without system fields") All documents in Convex include the built-in `_id` and `_creationTime` fields, and so does the generated `Doc` type. When creating or updating a document you might want use the type without the system fields. Convex provides [`WithoutSystemFields`](/api/modules/server.md#withoutsystemfields) for this purpose: convex/helpers.ts ``` import { MutationCtx } from "./_generated/server"; import { WithoutSystemFields } from "convex/server"; import { Doc } from "./_generated/dataModel"; export async function insertMessageHelper( ctx: MutationCtx, values: WithoutSystemFields>, ) { // ... await ctx.db.insert("messages", values); // ... } ``` ## Writing frontend code in TypeScript[​](#writing-frontend-code-in-typescript "Direct link to Writing frontend code in TypeScript") All Convex JavaScript clients, including React hooks like [`useQuery`](/api/modules/react.md#usequery) and [`useMutation`](/api/modules/react.md#usemutation) provide end to end type safety by ensuring that arguments and return values match the corresponding Convex functions declarations. For React, install and configure TypeScript so you can write your React components in `.tsx` files instead of `.jsx` files. Follow our [React](/quickstart/react.md) or [Next.js](/quickstart/nextjs.md) quickstart to get started with Convex. ### Type annotating client-side code[​](#type-annotating-client-side-code "Direct link to Type annotating client-side code") When you want to pass the result of calling a function around your client codebase, you can use the generated types `Doc` and `Id`, just like on the backend: src/App.tsx ``` import { Doc, Id } from "../convex/_generated/dataModel"; function Channel(props: { channelId: Id<"channels"> }) { // ... } function MessagesView(props: { message: Doc<"messages"> }) { // ... } ``` You can also declare custom types inside your backend codebase which include `Doc`s and `Id`s, and import them in your client-side code. You can also use `WithoutSystemFields` and any types inferred from validators via `Infer`. #### Using inferred function return types[​](#using-inferred-function-return-types "Direct link to Using inferred function return types") Sometimes you might want to annotate a type on the client based on whatever your backend function returns. Beside manually declaring the type (on the backend or on the frontend), you can use the generic `FunctionReturnType` and `UsePaginatedQueryReturnType` types with a function reference: src/Components.tsx ``` import { FunctionReturnType } from "convex/server"; import { UsePaginatedQueryReturnType } from "convex/react"; import { api } from "../convex/_generated/api"; export function MyHelperComponent(props: { data: FunctionReturnType; }) { // ... } export function MyPaginationHelperComponent(props: { paginatedData: UsePaginatedQueryReturnType< typeof api.myFunctions.getSomethingPaginated >; }) { // ... } ``` ## Turning `string`s into valid document IDs[​](#turning-strings-into-valid-document-ids "Direct link to turning-strings-into-valid-document-ids") See [Serializing IDs](/database/document-ids.md#serializing-ids). ## Required TypeScript version[​](#required-typescript-version "Direct link to Required TypeScript version") Convex requires TypeScript version [5.0.3](https://www.npmjs.com/package/typescript/v/5.0.3) or newer. Related posts from [![Stack](/img/stack-logo-dark.svg)![Stack](/img/stack-logo-light.svg)](https://stack.convex.dev/) --- # Convex Overview Convex is the open source, reactive database where queries are TypeScript code running right in the database. Just like React components react to state changes, Convex queries react to database changes. Convex provides a database, a place to write your server functions, and client libraries. It makes it easy to build and scale dynamic live-updating apps. The following diagram shows the standard three-tier app architecture that Convex enables. We'll start at the bottom and work our way up to the top of this diagram. ![Convex in your app](/assets/images/basic-diagram-8ad312f058c3cf7e15c3396e46eedb48.png) ## Database[​](#database "Direct link to Database") The [database](/database/overview.md) is at the core of Convex. The Convex database is automatically provisioned when you create your project. There is no connection setup or cluster management. info In Convex, your database queries are just [TypeScript code](/database/reading-data/.md) written in your [server functions](/functions/overview.md). There is no SQL to write. There are no ORMs needed. The Convex database is reactive. Whenever any data on which a query depends changes, the query is rerun, and client subscriptions are updated. Convex is a "document-relational" database. "Document" means you put JSON-like nested objects into your database. "Relational" means you have tables with relations, like `tasks` assigned to a `user` using IDs to reference documents in other tables. The Convex cloud offering runs on top of PlanetScale using MySQL as its persistence layer. The Open Source version uses SQLite, Postgres and MySQL. The database is ACID-compliant and uses [serializable isolation and optimistic concurrency control](/database/advanced/occ.md). All that to say, Convex provides the strictest possible transactional guarantees, and you never see inconsistent data. ## Server functions[​](#server-functions "Direct link to Server functions") When you create a new Convex project, you automatically get a `convex/` folder where you write your [server functions](/functions/overview.md). This is where all your backend application logic and database query code live. Example TypeScript server functions that read (query) and write (mutation) to the database. convex/tasks.ts ``` // A Convex query function export const getAllOpenTasks = query({ args: {}, handler: async (ctx, args) => { // Query the database to get all items that are not completed const tasks = await ctx.db .query("tasks") .withIndex("by_completed", (q) => q.eq("completed", false)) .collect(); return tasks; }, }); // A Convex mutation function export const setTaskCompleted = mutation({ args: { taskId: v.id("tasks"), completed: v.boolean() }, handler: async (ctx, { taskId, completed }) => { // Update the database using TypeScript await ctx.db.patch("tasks", taskId, { completed }); }, }); ``` You read and write to your database through query or mutation functions. [Query functions](/functions/query-functions.md) are pure functions that can only read from the database. [Mutation functions](/functions/mutation-functions.md) are transactions that can read or write from the database. These two database functions are [not allowed to take any non-deterministic](/functions/runtimes.md#restrictions-on-queries-and-mutations) actions like network requests to ensure transactional guarantees. info The entire Convex mutation function is a transaction. There are no `begin` or `end` transaction statements to write. Convex automatically retries the function on conflicts, and you don't have to manage anything. Convex also provides standard general-purpose serverless functions called actions. [Action functions](/functions/actions.md) can make network requests. They have to call query or mutation functions to read and write to the database. You use actions to call LLMs or send emails. You can also durably schedule Convex functions via the [scheduler](/scheduling/scheduled-functions.md) or [cron jobs](/scheduling/cron-jobs.md). Scheduling lets you build workflows like emailing a new user a day later if they haven't performed an onboarding task. You call your Convex functions via [client libraries](/client/react/overview.md) or directly via [HTTP](/http-api/.md#functions-api). ## Client libraries[​](#client-libraries "Direct link to Client libraries") Convex client libraries keep your frontend synced with the results of your server functions. ``` // In your React component import { useQuery } from "convex/react"; import { api } from "../convex/_generated/api"; export function TaskList() { const data = useQuery(api.tasks.getAllOpenTasks); return data ?? "Loading..."; } ``` Like the `useState` hook that updates your React component when local state changes, the Convex `useQuery` hook automatically updates your component whenever the result of your query changes. There's no manual subscription management or state synchronization needed. When calling query functions, the client library subscribes to the results of the function. Convex tracks the dependencies of your query functions, including what data was read from the database. Whenever relevant data in the database changes, the Convex automatically reruns the query and sends the result to the client. The client library also queues up mutations in memory to send to the server. As mutations execute and cause query results to update, the client library keeps your app state consistent. It updates all subscriptions to the same logical moment in time in the database. Convex provides client libraries for nearly all popular web and native app frameworks. Client libraries connect to your Convex deployment via WebSockets. You can then call your public Convex functions [through the library](/client/react/overview.md#fetching-data). You can also use Convex with [HTTP directly](/http-api/.md#functions-api), you just won't get the automatic subscriptions. ## Putting it all together[​](#putting-it-all-together "Direct link to Putting it all together") Let's return to the `getAllOpenTasks` Convex query function from earlier that gets all tasks that are not marked as `completed`: convex/tasks.ts ``` export const getAllOpenTasks = query({ args: {}, handler: async (ctx, args) => { // Query the database to get all items that are not completed const tasks = await ctx.db .query("tasks") .withIndex("by_completed", (q) => q.eq("completed", false)) .collect(); return tasks; }, }); ``` Let's follow along what happens when you subscribe to this query: ![Convex data flow](/assets/images/convex-query-subscription-945e7990515e438ab4385f9b4803bbd4.png) The web app uses the `useQuery` hook to subscribe to this query, and the following happens to get an initial value: * The Convex client sends a message to the Convex server to subscribe to the query * The Convex server runs the function, which reads data from the database * The Convex server sends a message to the client with the function's result In this case the initial result looks like this (1): ``` [ { _id: "e4g", title: "Grocery shopping", complete: false }, { _id: "u9v", title: "Plant new flowers", complete: false }, ]; ``` Then you use a mutation to mark an item as completed (2). Convex then reruns the query (3) to get an updated result. And pushes the result to the web app via the WebSocket connection (4): ``` [ { _id: "e4g", title: "Grocery shopping", complete: false }, ]; ``` ## Beyond reactivity[​](#beyond-reactivity "Direct link to Beyond reactivity") Beyond reactivity, Convex's architecture is crucial for a deeper reason. Convex does not let your app have inconsistent state at any layer of the stack. To illustrate this, let's imagine you're building a shopping cart for an e-commerce store. ![Convex in your app](/assets/images/convex-swaghaus-dcc9919685db6a7f34378afc500f68cd.png) On the product listing page, you have two numbers, one showing the number of items remaining in stock and another showing the number of items in your shopping cart. Each number is a result of a different query function. Every time you press the "Add to Cart" button, a mutation is called to remove one item from the stock and add it to the shopping cart. The mutation to change the cart runs in a transaction, so your database is always in a consistent state. The reactive database knows that the queries showing the number of items in stock and the number of items in the shopping cart both need to be updated. The queries are invalidated and rerun. The results are pushed to the web app via the WebSocket connection. The client library makes sure that both queries update at the same time in the web app since they reflect a singular moment in time in your database. You never have a moment where those numbers don't add up. Your app always shows consistent data. You can see this example in action in the [Swaghaus sample app](https://swaghaus.biz/). ## For human and AI generated code[​](#for-human-and-ai-generated-code "Direct link to For human and AI generated code") Convex is designed around a small set of composable abstractions with strong guarantees that result in code that is not only faster to write, it’s 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. ## Learn more[​](#learn-more "Direct link to Learn more") [YouTube video player](https://www.youtube.com/embed/3d29eKJ2Vws) If you are intrigued about the details of how Convex pulls this all off, you can read Convex co-founder Sujay's excellent [How Convex Works](https://stack.convex.dev/how-convex-works) blog post. Now that you have a good sense of how Convex fits in your app. Let's walk through the overall workflow of setting up and launching a Convex app. --- # Dev workflow Let's walk through everything that needs to happen from creating a new project to launching your app in production. This doc assumes you are building an app with Convex and React and you already have a basic React app already up and running. You can follow one of our [quickstarts](/quickstart/overview.md) to set this up. ## Installing and running Convex[​](#installing-and-running-convex "Direct link to Installing and running Convex") You install Convex adding the npm dependency to your app: ``` npm i convex ``` Then you create your Convex project and start the backend dev loop: ``` npx convex dev ``` The first time you run the `npx convex dev` command you'll be asked whether you want start developing locally without an account or create an account. ### Developing without an account[​](#developing-without-an-account "Direct link to Developing without an account") `npx convex dev` will prompt you for the name of your project, and then start running the open-source Convex backend locally on your machine (this is also called a "deployment"). The data for your project will be saved in the `~/.convex` directory. 1. The name of your project will get saved to your `.env.local` file so future runs of `npx convex dev` will know to use this project. 2. A `convex/` folder will be created (if it doesn't exist), where you'll write your Convex backend functions. You can run `npx convex login` in the future to create an account and link any existing projects. ### Developing with an account[​](#developing-with-an-account "Direct link to Developing with an account") `npx convex dev` will prompt you through creating an account if one doesn't exist, and will add your credentials to `~/.convex/config.json` on your machine. You can run `npx convex logout` to log you machine out of the account in the future. Next, `npx convex dev` will create a new project and provision a new personal development deployment for this project: 1. Deployment details will automatically be added to your `.env.local` file so future runs of `npx convex dev` will know which dev deployment to connect to. 2. A `convex/` folder will be created (if it doesn't exist), where you'll write your Convex backend functions. ![Convex directory in your app](/assets/images/convex-directory-1ede9882007bf42d249b0561f2892c54.png) ## Running the dev loop[​](#running-the-dev-loop "Direct link to Running the dev loop") Keep the `npx convex dev` command running while you're working on your Convex app. This continuously pushes backend code you write in the `convex/` folder to your deployment. It also keeps the necessary TypeScript types up-to-date as you write your backend code. When you're developing with a locally running deployment, `npx convex dev` is also responsible for running your deployment. You can then add new server functions to your Convex backend: convex/tasks.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") .withIndex("taskListId", (q) => q.eq("taskListId", args.taskListId)) .order("desc") .take(100); return tasks; }, }); ``` When you write and save this code in your editor, several things happen: 1. The `npx convex dev` command typechecks your code and updates the `convex/_generated` directory. 2. The contents of your `convex/` directory get uploaded to your dev deployment. 3. Your Convex dev deployment analyzes your code and finds all Convex functions. In this example, it determines that `tasks.getTaskList` is a new public query function. 4. If there are any changes to the [schema](/database/schemas.md), the deployment will automatically enforce them. 5. The `npx convex dev` command updates generated TypeScript code in the `convex/_generated` directory to provide end to end type safety for your functions. tip Check in everything in your `convex/_generated/` directory. This it ensures that your code immediately type checks and runs without having to first run `npx convex dev`. It's particularly useful when non-backend developers are writing frontend code and want to ensure their code type checks against currently deployed backend code. Once this is done you can use your new server function in your frontend: src/App.tsx ``` import { useQuery } from "convex/react"; import { api } from "../convex/_generated/api"; export function App() { const data = useQuery(api.tasks.getTaskList); return data ?? "Loading..."; } ``` If you have other configuration like [crons](/scheduling/cron-jobs.md) or [auth](/auth/overview.md) in your `convex/` folder, Convex ensures that they are applied and enforced on your backend. ## Convex dashboard[​](#convex-dashboard "Direct link to Convex dashboard") The [Convex dashboard](/dashboard/deployments/.md) will be a trusty helper throughout your dev, debug and deploy workflow in Convex. `npx convex dashboard` will open a link to the dashboard for your deployment. ### Logs[​](#logs "Direct link to Logs") Since Convex functions are TypeScript functions you can always use the standard `console.log` and `console.time` functions to debug your apps. Logs from your functions show up [in your dashboard](/dashboard/deployments/logs.md). ![Logs Dashboard Page](/assets/images/logs-ed208103a42edfb005e9089a8edad58e.png) ### Health, Data, Functions and more[​](#health-data-functions-and-more "Direct link to Health, Data, Functions and more") * [Health](/dashboard/deployments/health.md) - provides invaluable information on how your app is performing in production, with deep insights on how your Convex queries are doing. * [Data](/dashboard/deployments/data.md) - gives you a complete data browser to spot check your data. * [Functions](/dashboard/deployments/functions.md) - gives you stats and run functions to debug them. There is a lot more to to the dashboard. Be sure to click around or [check out the docs](/dashboard/overview.md). ## Deploying your app[​](#deploying-your-app "Direct link to Deploying your app") So far you've been working on your app against your personal dev deployment. All Convex projects have one production deployment running in the cloud. It has separate data and has a separate push process from personal dev deployments, which allows you and your teammates to work on new features using personal dev deployments without disrupting your app running in production. If you have not created a Convex account yet, you will need to do so with `npx convex login`. This will automatically link any projects you've started with your new account, and enable using your production deployment. To push your code to your production deployment for your project you run the deploy command: ``` npx convex deploy ``` info If you're running this command for the first time, it will automatically provision the prod deployment for your project. ### Setting up your deployment pipeline[​](#setting-up-your-deployment-pipeline "Direct link to Setting up your deployment pipeline") It's rare to run `npx convex deploy` directly. Most production applications run an automated workflow that runs tests and deploys your backend and frontend together. You can see detailed deployment and frontend configuration instructions in the [Hosting and Deployment](/production/hosting/.md) doc. For most React meta-frameworks Convex [automatically sets the correct environment variable](/production/hosting/vercel.md#how-it-works) to connect to the production deployment. ## Up next[​](#up-next "Direct link to Up next") You now know the basics of how Convex works and fits in your app. Go head and explore the docs further to learn more about the specific features you want to use. Whenever you're ready be sure the read the [Best Practices](/understanding/best-practices/.md), and then the [Zen of Convex](/understanding/zen.md) once you are ready to "think in Convex." --- # The Zen of Convex [YouTube video player](https://www.youtube.com/embed/dyEWQ9s2ji4?si=ce-M8pt6EWDZ8tfd) Convex is an opinionated framework, with every element designed to pull developers into [the pit of success](https://blog.codinghorror.com/falling-into-the-pit-of-success/). The Zen of Convex is a set of guidelines & best practices developers have discovered that keep their projects falling into this wonderful pit. ## Performance ### Double down on the [sync engine](/tutorial/overview.md#how-convex-works) There's a reason why a deterministic, reactive database is the beating heart of Convex: the more you center your apps around its properties, the better your projects will fare over time. Your projects will be easier to understand and refactor. Your app's performance will stay screaming fast. You won't have any consistency or state management problems. Use a query for nearly every app read Queries are the reactive, automatically cacheable, consistent and resilient way to propagate data to your application and its jobs. With very few exceptions, every read operation in your app should happen via a query function. Keep sync engine functions light & fast In general, your mutations and queries should be working with less than a few hundred records and should aim to finish in less than 100ms. It's nearly impossible to maintain a snappy, responsive app if your synchronous transactions involve a lot more work than this. Use actions sparingly and incrementally Actions are wonderful for batch jobs and/or integrating with outside services. They're very powerful, but they're slower, more expensive, and Convex provides a lot fewer guarantees about their behavior. So never use an action if a query or mutation will get the job done. ### Don't over-complicate client-side state management Convex builds in a ton of its own caching and consistency controls into the app's client library. Rather than reinvent the wheel, let your client-side code take advantage of these built-in performance boosts. Let Convex handle caching & consistency You might be tempted to quickly build your own local cache or state aggregation layer in Convex to sit between your components and your Convex functions. With Convex, most of the time, you won't end up needing this. More often than not, you can bind your components to Convex functions in pretty simple ways and things will Just Work and be plenty fast. Be thoughtful about the return values of mutations Mutation return values can be useful to trigger state changes in your app, but it's rarely a good idea to use them to set in-app state to update the UI. Let queries and the sync engine do that. ## Architecture ### Create server-side frameworks using "just code" Convex's built-in primitives are pretty low level! They're just functions. What about authentication frameworks? What about object-relational mappings? Do you need to wait until Convex ships some in-built feature to get those? Nope. In general, you should solve composition and encapsulation problems in your server-side Convex code using the same methods you use for the rest of your TypeScript code bases. After all, this is why Convex is "just code!" [Stack](https://stack.convex.dev) always has [great](https://stack.convex.dev/functional-relationships-helpers) [examples](https://stack.convex.dev/wrappers-as-middleware-authentication) of ways to tackle [these needs](https://stack.convex.dev/row-level-security). ### Don't misuse actions Actions are powerful, but it's important to be intentional in how they fit into your app's data flow. Don't invoke actions directly from your app In general, it's an anti-pattern to call actions from the browser. Usually, actions are running on some dependent record that should be living in a Convex table. So it's best trigger actions by invoking a mutation that both *writes* that dependent record and *schedules* the subsequent action to run in the background. Don't think 'background jobs', think 'workflow' When actions are involved, it's useful to write chains of effects and mutations, such as: action code → mutation → more action code → mutation. Then apps or other jobs can follow along with queries. Record progress one step at a time While actions *could* work with thousands of records and call dozens of APIs, it's normally best to do smaller batches of work and/or to perform individual transformations with outside services. Then record your progress with a mutation, of course. Using this pattern makes it easy to debug issues, resume partial jobs, and report incremental progress in your app's UI. ## Development workflow ### Keep the dashboard by your side Working on your Convex project without using the dashboard is like driving a car with your eyes closed. The dashboard lets you view logs, give mutations/queries/actions a test run, make sure your configuration and codebase are as you expect, inspect your tables, generate schemas, etc. It's an invaluable part of your rapid development cycle. ### Don't go it alone Between these [docs](https://docs.convex.dev), [Stack](https://stack.convex.dev), and [our community](https://convex.dev/community), someone has *probably* encountered the design or architectural issue you're facing. So why try to figure things out the hard way, when you can take advantage of a whole community's experience? Leverage Convex developer search With so many great resources from the Convex team & community, it can be hard to know where to look first. If you want a quick way to search across all of these, [we have a portal for that](https://search.convex.dev)! Join the Convex community Whether you're stuck on a tricky use case, you have a question or feature request for the Convex team, or you're excited to share the amazing app(s) you've built and help others learn, the Convex community is there for you! Join the party on [Discord](https://convex.dev/community). ---