Convex authentication just got even simpler! We now support authentication with Clerk and our Auth0 support is more flexible and extendable.

The full list of changes in the release is:

  • Support for Clerk Authentication
  • Breaking: Updated Auth0 Authentication Integration
  • Internal Functions

Full details below.

If you need a hand updating your Convex app to 0.12.0, let us know in Discord. We’re happy to help!

Support for Clerk Authentication

Convex now has built-in support for authentication with Clerk. Clerk is a modern authentication provider with good Next.js and React Native support.

The convex npm package has a new ConvexProviderWithClerk component that makes it simple to add Clerk to your Convex app:

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

    <ClerkProvider publishableKey="pk_test_....">
      <ConvexProviderWithClerk client={convex}>
        <App />

For the full instructions to integrate Clerk, check out the Convex Clerk documentation.

Breaking: Updated Auth0 Authentication Integration

We’ve updated the integration between Auth0 and Convex to have a new API. If you have an existing app using the ConvexProviderWithAuth0 component, you now need to:

1. Nest the ConvexProviderWithAuth0 underneath the Auth0Provider from @auth0/auth0-react.

All of your Auth0 configuration should now be passed to the Auth0Provider directly.

2. Use the new Authenticated, Unauthenticated, and AuthLoading to control which portions of your app appear for users when they are logged in, logged out, and loading their authentication respectively.

For example your “Log In” button should be nested under Unauthenticated.

A Convex app using Auth0 now might look like:

import { ConvexProviderWithAuth0 } from "convex/react-auth0";
import { Auth0Provider } from "@auth0/auth0-react";

        redirect_uri: window.location.origin
      <ConvexProviderWithAuth0 client={convex} >
        <App />

We’ve made these changes to make ConvexProviderWithAuth0 more flexible. It’s now easier to build apps with a mix of logged in and logged out content. It’s also easier to adjust the parameters passed to auth0-react.

For more information, see the Convex Auth0 documentation.

Internal Functions

Convex now supports internal functions. An internal function is a query, mutation, or action function that is not publicly accessible. Internal functions can still be called from other Convex functions or run directly on the Convex dashboard.

Some example use cases are:

To define an internal function, use the internalQuery, internalMutation, or internalAction wrappers like:

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

// Internal mutation to mark a plan as professional.
export default internalMutation(async ({ db }, { planId }) => {
  await db.patch(planId, { planType: "professional" });


Then you can call this internal function as you normally would. In this example, markPlanAsProfessional is called within the upgrade action, but shouldn’t be accessible from the client.

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

export default action(async ({ runMutation }, { planId, ... }) => {
  // Call out to payment provider (e.g. Stripe) to charge customer
  const response = await fetch(...);
  if (response.ok) {
    // Mark the plan as "professional" in the Convex DB
    await runMutation("markPlanAsProfessional", { planId });


By making markPlanAsProfessional an internal function, we ensure that no user can directly mark their plan as premium without getting charged.

To learn more, check out the Internal Functions documentation!

Minor Improvements

  • ConvexReactClient now accepts a verbose parameter in its options object. Turning on verbose will add a lot of console logs about the internal state of the client. This is useful for debugging WebSocket issues.
  • npx convex dev no longer retries on HTTP 400 errors.
  • There’s now documentation on building a Custom Authentication Integration with Convex.