Loading skill
Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Only schedule internal functions, never api functions
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 26% | 0% |
| case-02 | ✗→✓ | ▲ Improved | -32% | 0% |
| case-04 | ✗→✓ | ▲ Improved | -44% | 0% |
| case-21 | ✓→✗ | ▼ Worse | -15% | 0% |
| case-05 | ✓→✓ | = Same ✓ | -24% | 0% |
Always schedule internal functions with ctx.scheduler, ctx.runAfter, ctx.runAt, and ctx.run* methods. Never schedule public api functions.
Scheduled functions bypass authentication and argument validation that public APIs expect to receive from clients.
Bad:
typescriptimport { api } from "./_generated/api"; export const processPayment = action({ handler: async (ctx, args) => { // ❌ Don't schedule api functions await ctx.scheduler.runAfter(0, api.users.chargeUser, { userId: args.userId, amount: args.amount, }); }, });
Good:
typescriptimport { internal } from "./_generated/api"; // Define an internal function export const chargeUserInternal = internalMutation({ args: { userId: v.id("users"), amount: v.number() }, handler: async (ctx, args) => { // ... charging logic ... }, }); export const processPayment = action({ handler: async (ctx, args) => { // ✅ Schedule internal functions await ctx.scheduler.runAfter(0, internal.users.chargeUserInternal, { userId: args.userId, amount: args.amount, }); }, });
Use internalQuery, internalMutation, and internalAction for functions that should only be called from backend code:
typescriptexport const internalHelper = internalMutation({ args: { /* ... */ }, handler: async (ctx, args) => { // No auth check needed - only callable from backend }, });
Other measured skills in the registry, with their headline benchmark lift.