convex-js

IndexedCommit: e9a01980 pullsUpdated Jan 31, 2026

TypeScript backend SDK and client libraries for the Convex cloud platform, providing a fully managed backend with database, file storage, authentication, and reactive real-time updates.

Install this reference
Reference

Convex

TypeScript backend SDK and client libraries for the Convex cloud platform, providing a fully managed backend with database, file storage, authentication, and reactive real-time updates.

Quick References

FilePurpose
src/server/index.tsServer-side SDK entry point
src/react/index.tsReact integration entry point
src/browser/index.tsBrowser client entry point
src/nextjs/index.tsNext.js SSR helpers
README.mdOfficial documentation
src/values/index.tsValue utilities for Convex data

When to Use

  • Building full-stack applications with a managed backend without DevOps
  • Need reactive real-time data synchronization between server and client
  • Integrating with React applications for live query subscriptions
  • Server-side rendering with Next.js or other frameworks
  • Custom authentication flows with Auth0 or Clerk
  • Vector search for AI-powered features

Installation

npm install convex

Best Practices

  1. Always use the generated API after running npx convex dev for type safety instead of manual function references
  2. Separate read and write operations - use queries for data fetching, mutations for writes
  3. Prefer pagination for large datasets using paginate() instead of loading all results
  4. Validate function arguments using validators from convex/values to ensure type safety
  5. Set up proper authentication using Auth0 or Clerk integrations for secure apps

Common Patterns

Defining a Database Schema:

// 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(),
    emailVerified: v.optional(v.boolean()),
  }).index("by_email", ["email"]),
  
  messages: defineTable({
    body: v.string(),
    userId: v.id("users"),
  }).searchIndex("search_body", {
    searchField: "body",
    filterFields: ["userId"],
  }),
});

Server Query and Mutation Functions:

// convex/myFile.ts
import { query, mutation } from "./_generated/server";

export const getUser = query({
  args: { id: v.id("users") },
  handler: async ({ db }, { id }) => {
    return await db.get(id);
  },
});

export const createUser = mutation({
  args: { name: v.string(), email: v.string() },
  handler: async ({ db }, { name, email }) => {
    const userId = await db.insert("users", { name, email });
    return userId;
  },
});

React Client Setup and Hooks:

// _app.tsx or layout.tsx
import { ConvexProvider, ConvexReactClient } from "convex/react";

const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL);

export default function App() {
  return (
    <ConvexProvider client={convex}>
      <YourComponent />
    </ConvexProvider>
  );
}

Using React Hooks:

import { useQuery, useMutation } from "convex/react";
import { api } from "../convex/_generated/api";

function MessagesList() {
  const messages = useQuery(api.messages.list);
  const addMessage = useMutation(api.messages.create);
  
  if (messages === undefined) return null;
  
  return (
    <div>
      {messages.map(msg => <div key={msg._id}>{msg.body}</div>)}
    </div>
  );
}

Paginated Queries:

export const listMessages = query({
  args: { paginationOpts: paginationOptsValidator },
  handler: async ({ db }, { paginationOpts }) => {
    return await db.query("messages")
      .order("desc")
      .paginate(paginationOpts);
  },
});

// React usage
const { results, status, loadMore } = usePaginatedQuery(
  api.messages.list,
  { paginationOpts: { numItems: 10, cursor: null } },
);

Vector Search:

export const searchEmbeddings = query({
  args: { 
    query: v.array(v.float64()),
    limit: v.optional(v.number()),
  },
  handler: async ({ vectorSearch }, { query, limit }) => {
    return await vectorSearch(
      "documents",
      "byEmbedding",
      { vector: query, limit: limit ?? 10 }
    );
  },
});

Browser HTTP Client:

import { ConvexHttpClient } from "convex/browser";
import { api } from "../convex/_generated/api";

const client = new ConvexHttpClient(process.env.CONVEX_URL);

// In a serverless function or API route
export async function GET() {
  const data = await client.query(api.users.list);
  return Response.json(data);
}

Next.js SSR with Preloading:

// app/page.tsx (Server Component)
import { preloadQuery } from "convex/nextjs";
import { api } from "@/convex/_generated/api";

export default async function Page() {
  const preloaded = await preloadQuery(api.counter.get, {});
  return <Counter preloaded={preloaded} />;
}

// components/Counter.tsx (Client Component)
import { usePreloadedQuery } from "convex/react";
import { Preloaded } from "convex/react";

export default function Counter({ preloaded }: { preloaded: Preloaded<typeof api.counter.get> }) {
  const count = usePreloadedQuery(preloaded);
  return <div>{count}</div>;
}

Authentication with Clerk:

import { ConvexProviderWithClerk } from "convex/react-clerk";
import { ClerkProvider, useAuth } from "@clerk/clerk-react";

export default function App() {
  return (
    <ClerkProvider publishableKey={import.meta.env.VITE_CLERK_PUB_KEY}>
      <ConvexProviderWithClerk client={convex} useAuth={useAuth}>
        <YourApp />
      </ConvexProviderWithClerk>
    </ClerkProvider>
  );
}

File Storage:

import { mutation } from "./_generated/server";

export const uploadUrl = mutation({
  handler: async ({ storage }) => {
    return await storage.generateUploadUrl();
  },
});

export const finalizeUpload = mutation({
  args: { storageId: v.id("_storage") },
  handler: async ({ storage }, { storageId }) => {
    return await storage.getUrl(storageId);
  },
});

Scheduled Functions:

import { cronJobs } from "convex/server";

export default cronJobs()
  .daily({
    hour: 2,
    minute: 0,
    handler: async ({ db }) => {
      // Run cleanup tasks
    },
  });

HTTP Actions:

import { httpRouter } from "convex/server";
import { httpAction } from "./_generated/server";

const http = httpRouter();

http.route({
  path: "/webhook",
  method: "POST",
  handler: httpAction(async ({ request }, action) => {
    const { data } = await request.json();
    await action(api.webhooks.process, { data });
    return new Response(null, { status: 200 });
  }),
});

export default http;

API Quick Reference

ExportTypeDescription
queryFunction builderDefine read-only server functions
mutationFunction builderDefine server functions that write data
actionFunction builderDefine server functions with external I/O access
defineSchemaFunctionDefine your database schema with tables and indexes
defineTableFunctionDefine a single table with validators and indexes
vValidator builderDefine value validators for function arguments
ConvexReactClientClassWebSocket-based client for React with real-time sync
ConvexProviderComponentProvider to store ConvexReactClient in React context
useQueryHookSubscribe to query results in React components
useMutationHookExecute mutations from React components
useActionHookExecute actions from React components
usePaginatedQueryHookHandle paginated queries in React
useQueriesHookExecute multiple queries in a single React render
ConvexHttpClientClassHTTP-based client for server-side code or non-React apps
preloadQueryFunctionPreload query data for Next.js SSR
fetchQueryFunctionFetch query data in Next.js server components
vectorSearchFunctionPerform vector similarity search
cronJobsFunctionDefine scheduled functions
httpRouterFunctionDefine HTTP endpoints for webhooks
ConvexProviderWithClerkComponentConvex provider integrated with Clerk auth
ConvexProviderWithAuth0ComponentConvex provider integrated with Auth0

“Explore distant worlds.”

© 2026 Oscar Gabriel