Skip to main content

Internal Functions

Internal functions can only be called by other functions and cannot be called directly from a Convex client.

By default your Convex functions are public and accessible to clients. Public functions may be called by malicious users in ways that cause surprising results. Internal functions help you mitigate this risk. We recommend using internal functions any time you're writing logic that should not be called from a client.

Security Note - While internal functions help mitigate risk by reducing the public surface area of your application, always consider using argument validation and/or authentication to validate internal invariants.

Use cases for internal functions

Leverage internal functions by:

  • Calling them from actions via runQuery and runMutation
  • Calling them from HTTP actions via runQuery, runMutation, and runAction
  • Scheduling them from other functions to run in the future
  • Scheduling them to run periodically from cron jobs
  • Testing them using the Dashboard

Defining internal functions

An internal function is defined using internalQuery, internalMutation, or internalAction. For example:

convex/markPlanAsProfessional.js
import { internalMutation } from "./_generated/server";

export default internalMutation(async ({ db }, { planId }) => {
await db.patch(planId, { planType: "professional" });
});

Calling internal functions

Internal functions can be called from other functions using the same hooks that are used for public functions:

For example, consider this public upgrade action that calls the internal markPlanAsProfessional mutation we defined above:

convex/upgrade.js
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 });
}
});

In this example a user should not be able to directly call markPlanAsProfessional without going through the upgrade action — if they did, then they would get a free upgrade.