Cron jobs are here! You can now schedule recurring functions right within Convex.

We’ve also made a ton of other improvements to the platform. The full list of changes in this release is:

  • Cron Jobs
  • Running Functions in the Dashboard
  • File Storage with HTTP Endpoints
  • Delete Tables in the Dashboard
  • Breaking: Rename Document<TableName>Doc<TableName>
  • Breaking: ConvexProviderWithAuth0 Upgrade
  • Breaking: Removed Support for Node.js 14
  • undefined  in Objects
  • Minor Improvements

You can read more about all of these changes below.

Cron Jobs

Convex now has support for cron jobs! Cron jobs allow you to schedule functions to run on a recurring basis.

You could use a cron job to clean up data at regular intervals, send a reminder email at the same time every month, or schedule a backup every Saturday.

To define a cron job, put the job definition in convex/crons.ts:

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

const crons = cronJobs();

  "clear messages table",
  { minutes: 1 }, // every minute

  "payment reminder",
  { day: 1, hourUTC: 16, minuteUTC: 0 }, // Every month on the 1st at 8:00am PST
  "" // argument to sendPaymentEmail

// An alternate way to create the same schedule as above
  "payment reminder duplicate",
  "0 16 1 * *",
  "" // argument to sendPaymentEmail

export default crons

To learn more, read the docs.

Running Functions in the Dashboard

Ever wish you could test a Convex function you've written before integrating it into your code? Well, wait no longer, because testing functions in the dashboard is here! :Hype:

You can find this feature on the "Functions" page in the Convex dashboard (docs :


File Storage with HTTP Endpoints

Convex now supports File Storage via HTTP Endpoints, in addition to the existing support using queries and mutations.

Files can be uploaded via HTTP endpoints like this:

// e.g.
const sendImageUrl = new URL(`${convexSiteUrl}/sendImage`);
sendImageUrl.searchParams.set("author", name);

await fetch(sendImageUrl, {
    method: "POST",
    headers: { "Content-Type": selectedImage.type },
    body: selectedImage,
  path: "/sendImage",
  method: "POST",
  handler: httpEndpoint(async ({ storage, runMutation }, request) => {
    // Store the image
    const storageId = await;
    const author = new URL(request.url).searchParams.get("author");

    // Save the storage ID to the messages table via a mutation
    await runMutation("sendMessage:sendImage", storageId, author);
    return new Response(null, {
      status: 200,

Files can be fetched and rendered like this:

function Image({ storageId }) {
  // e.g. <>
  const getImageUrl = new URL(`${convexSiteUrl}/getImage`);
  getImageUrl.searchParams.set("storageId", storageId);

  return <img src={getImageUrl.href} height="300px" width="auto" />;
  path: "/getImage",
  method: "GET",
  handler: httpEndpoint(async ({ storage }, request) => {
    const storageId = new URL(request.url).searchParams.get("storageId");
    const responseOrNull = await storage.get(storageId);
    if (responseOrNull === null) {
      return new Response("Image not found", {
        status: 404,
    return responseOrNull;

To learn more, check out the documentation or the file storage with http demo.

Delete Tables in the Dashboard

Have a pesky old table hanging around from an early version of your code? It’s time to say goodbye. The “Clear table” button in the Convex dashboard has been replaced by a “Delete table” button, and the size restriction has been lifted so tables of any size can be deleted.


In order to clear a table, you can delete the table and create a new one with the same name.

Breaking: Rename Document<TableName>Doc<TableName>

We’ve renamed the Document<TableName> TypeScript type to Doc<TableName>. You can use this type like:

import { Doc } from "../convex/_generated/dataModel";

function MessageView(props: { message: Doc<"messages"> }) {

The reason for the change is that TypeScript’s DOM types already include a type named Document. This made Convex’s Document<TableName> type difficult to import.

Breaking: ConvexProviderWithAuth0 Upgrade

We’ve upgraded the version of @auth0/auth0-react needed to use the ConvexProviderWithAuth0 component. Please upgrade @auth0/auth0-react to at least 2.0.1.

Additionally, ConvexProviderWithAuth0 now accepts an optional authorizationParams argument that corresponds to Auth0’s authorizationParams.

Breaking: Removed Support for Node.js 14

We’re removed support for using the Convex CLI with Node.js 14. Node.js 14 is scheduled to reach its end of live on April 30, 2023. Please upgrade to a newer version to continue using Convex.

undefined in Objects

Convex now supports creating objects in Convex with undefined as a value. When you define an object, the corresponding key will be ignored if a value is undefined. This applies to function arguments, return values, and documents.

For example, if you store a document like:

export default mutation(async ({ db }) => {
  await db.insert("myTable", {
    property1: "value1",
    property2: undefined

Then this will be stored in Convex as:

  property1: "value1",

This matches how JSON.stringify handles undefined and makes it easier to conditionally add fields to objects.

Minor Improvements

  • We’ve revamped the structure of the Convex docs! It’s now easier to find what you’re looking for and understand how the pieces fit together.
  • We’ve added new quickstart guides for using Convex with React, Next.js, Python, and React Native.
  • We’ve improved the support for using npm libraries in actions.
  • Convex now prints a clear warning if you are using an unsupported TypeScript version.
  • We’ve changed our recommended deployment command in our deployment documentation from npx convex deploy && npm run build to npm run build && npx convex deploy. This ensures that your Convex functions are only deployed if your project builds.