#How can I call convex functions from the server in tanstack start?
1 messages · Page 1 of 1 (latest)
Hi @echo skiff. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
You can call Convex from TanStack Start server code, but you don’t use the browser client (WebSocket) or the Next.js helpers. You have two main patterns, depending on whether you need auth or not.
1. Server → Convex without auth (simple / internal use)
For “server-only” or internal calls where you don’t care about end‑user auth, the recommended pattern is:
-
Expose a public Convex function that:
- Verifies a shared secret (e.g. from an env var).
- Calls your internal functions via
ctx.runQuery/Mutation/Action. [Internal funcs; Discord internal-from-backend]
-
Call that public function from your TanStack Start server code using a plain HTTP client (e.g.
ConvexHttpClientor rawfetch), passing the shared secret. [Discord server-only; Discord internal-from-backend]
High‑level flow:
// convex/secureTasks.ts
import { action, internalMutation } from "./_generated/server";
import { internal } from "./_generated/api";
import { v } from "convex/values";
export const _doSensitiveThing = internalMutation({
args: { taskId: v.id("tasks") },
handler: async (ctx, { taskId }) => {
// ... sensitive logic ...
},
});
export const doSensitiveThing = action({
args: {
secret: v.string(),
taskId: v.id("tasks"),
},
handler: async (ctx, { secret, taskId }) => {
if (secret !== process.env.SERVER_SHARED_SECRET) {
throw new Error("Unauthorized");
}
await ctx.runMutation(internal.secureTasks._doSensitiveThing, { taskId });
},
});
Then in TanStack Start server code (e.g. createServerFn handler), call that action via HTTP. The exact code isn’t in the sources, but this is the pattern described in the Discord threads: use a shared secret and a public entrypoint that only calls internal functions. [Discord server-only; Discord internal-from-backend]
2. Server → Convex with end‑user auth (TanStack Start)
Here things are more limited today:
- Convex Auth does not currently support server‑side auth with TanStack Start (no cookie helpers like in Next.js). [Discord auth-on-server]
- That means you can’t easily run a Convex function on the TanStack Start server “as the current user” using Convex Auth alone.
If you need server‑side auth with TanStack Start, the recommended approach in the docs is to use Better Auth + Convex:
- Use Better Auth for session cookies and server‑side auth.
- Call Convex from TanStack Start server code via helpers like
fetchAuthMutation/fetchAuthQuery, which forward the Better Auth cookies to Convex. [Better Auth TanStack guide]
Example from the Better Auth + TanStack Start guide (server function calling a Convex mutation):
// convex/users.ts
import { mutation } from "./_generated/server";
import { v } from "convex/values";
import { createAuth, authComponent } from "./auth";
export const updateUserPassword = mutation({
args: {
currentPassword: v.string(),
newPassword: v.string(),
},
handler: async (ctx, args) => {
const { auth, headers } = await authComponent.getAuth(createAuth, ctx);
await auth.api.changePassword({
body: {
currentPassword: args.currentPassword,
newPassword: args.newPassword,
},
headers,
});
},
});
```ts
// src/routes/users.ts (TanStack Start)
import { createServerFn } from "@tanstack/react-start";
import { fetchAuthMutation } from "@/lib/auth-server";
import { api } from "../../convex/_generated/api";
export const updatePassword = createServerFn({ method: "POST" }).handler(
async ({ data: { currentPassword, newPassword } }) => {
await fetchAuthMutation(api.users.updatePassword, {
currentPassword,
newPassword,
});
}
);
3. SSR data loading (read‑only) with TanStack Query
For SSR reads (no auth or handled separately), you can:
- Use
convexQuery+ensureQueryDatain route loaders. - Use
useSuspenseQuery(convexQuery(...))in components. [TanStack Start SSR]
Example:
export const Route = createFileRoute("/posts")({
loader: async (opts) => {
await opts.context.queryClient.ensureQueryData(
convexQuery(api.messages.list, {})
);
},
component: () => {
const { data } = useSuspenseQuery(convexQuery(api.messages.list, {}));
return <div>{/* render data */}</div>;
},
});
Summary
- There is no “server-side Convex client” for TanStack Start exactly like orpc.
- For internal / server-only calls: expose a public Convex function that checks a shared secret and calls internal functions; call it from TanStack Start via HTTP. [Internal funcs; Discord internal-from-backend]
- For server-side, user-authenticated calls in TanStack Start: Convex Auth doesn’t support this yet; use Better Auth + Convex if you need full server-side auth. [Discord auth-on-server; Better Auth TanStack guide]
If you describe your exact use case (SSR reads, protected mutations, background jobs, etc.), I can map it more concretely onto one of these patterns using the docs we have.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@echo skiff Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@tardy knot
Lets say I want to do the following
I want to use Better Auth to set the session by converting a token query to a custom createAuthEndpoint in better Auth. right now this fails because I am trying to use fernet which relies on crypto. I cannot set "use node" either since it is directly consumed and bundled by convex.
What should I do here? I cannot use the setSessionCookie items without this
Let me check the knowledge base for you again. One moment! :books:
There isn’t anything in the docs that describes using Fernet specifically with Convex + Better Auth, but there is clear guidance on how to use crypto inside Convex functions and how Better Auth is expected to be wired.
Key points from the sources:
-
Node
cryptois not meant to be imported in Convex-bundled code.In Convex runtimes,
cryptois available as a global, but importingnode:crypto(orcrypto) from a file that Convex bundles will fail, even with"use node". [Crypto thread]The workaround from that thread:
// ❌ This breaks: // import { createHash } from "node:crypto"; // ✅ Use the global: const digest = crypto.createHash("sha256")...So if your Fernet implementation is doing
import crypto from "crypto"or similar in a Convex-bundled file, that’s the root problem. -
"use node"cannot be used in code that Convex Better Auth bundles.You’ve already hit this: the Better Auth component code is consumed and bundled by Convex, so you can’t mark those files
"use node"and rely on Node‑only APIs there. -
Better Auth + Convex is designed to work without you wiring your own crypto for sessions.
The Convex Better Auth plugin already handles JWT generation, cookies, and JWKS for you. [Convex plugin] The recommended setup is:
convex/auth.config.tswithgetAuthConfigProvider()[TanStack install]convex/auth.tsusingbetterAuth+convex({ authConfig })plugin. [TanStack install]
In that model, you don’t need to implement your own token → session logic or custom setSessionCookie—the plugin and Better Auth handle it.
Given those constraints, here are your viable options:
Option A: Avoid Fernet in Convex‑bundled Better Auth code
If your goal is “convert a token query to a custom createAuthEndpoint and then call setSessionCookie”, but the only blocker is Fernet:
- Remove Fernet from the Convex side and instead:
- Use the built‑in Better Auth + Convex plugin for session handling (recommended).
- Or, if you must use Fernet, do the Fernet work outside Convex (e.g. in your framework server) and only pass the result (e.g. a verified user id or JWT) into Convex.
Inside Convex / Better Auth integration code, stick to what the plugin already supports (JWT, cookies, JWKS). [Convex plugin]
Option B: If you absolutely must use Fernet inside Convex
The knowledge sources don’t show a supported pattern for plugging a custom crypto scheme like Fernet into Better Auth’s Convex integration. They only show:
- Using the Convex plugin’s built‑in JWT handling. [Convex plugin]
- Using global
crypto(orcrypto.subtle) directly in Convex functions, without imports. [Crypto thread]
So the only thing we can say with confidence is:
- If you write any Convex function or helper that needs crypto, you must:
- Not import
node:crypto/crypto. - Use
cryptoorcrypto.subtleas globals.
- Not import
Example pattern (from the Discord thread, adapted):
// In a Convex function file (no "use node", no imports from "crypto")
export function encryptSomething(data: string) {
// Use global crypto
const hash = crypto.createHash("sha256").update(data).digest("hex");
return hash;
}
If your Fernet library requires a Node import, it won’t be compatible in this environment. You’d need a Fernet implementation that can run on top of the Web Crypto API (crypto.subtle) or plain JS, without importing Node’s crypto.
The docs do not show how to integrate such a custom scheme with setSessionCookie or createAuthEndpoint, so anything beyond “use global crypto, not imports” would be speculation.
Option C: Let Better Auth + Convex own the session, and keep Fernet elsewhere
Given the docs, the most “supported” path is:
- Use Better Auth + Convex plugin as documented (no custom Fernet in Convex).
- If you need Fernet for some other part of your system (e.g. external API tokens), keep that logic in your framework server (TanStack Start, Next, etc.), where Node crypto is available and not bundled by Convex.
- Use Convex only for:
- Calling
auth.api.*from Convex functions viaauthComponent.getAuth(createAuth, ctx)when needed. [Basic usage / auth.api] - Normal Convex queries/mutations/actions.
- Calling
Direct answer to “What should I do here?”
Based on the docs we have:
- You cannot safely use a Fernet implementation that depends on
node:cryptoinside Convex‑bundled Better Auth code. - You can use
crypto/crypto.subtleas globals in Convex functions, but the docs do not show a supported way to plug a custom crypto scheme into Better Auth’s Convex integration orsetSessionCookie. - The supported path is to let the Convex Better Auth plugin manage sessions and cookies, and avoid custom Fernet logic in that layer. [Convex plugin]
If you describe exactly why you need Fernet (e.g. migrating from an existing system, sharing tokens with another service), I can help map that requirement onto the documented Better Auth + Convex patterns, but I can’t give a fully worked Fernet + createAuthEndpoint example because it’s not covered in the sources.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@echo skiff Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@tardy knot how can I call better auths setSessionCookie method from inside a httpAction?
Let me check the knowledge base for you again. One moment! :books:
I’m sorry, but the provided knowledge sources don’t show any example or API reference for calling Better Auth’s setSessionCookie (or any cookie‑setting helper) directly from inside a Convex httpAction.
What is documented for Convex + Better Auth is:
- How to register the Better Auth component and Convex plugin (
convex/auth.config.ts,convex/auth.ts). [Next guide; React/Vite guide; TanStack guide] - How to use the component client (
authComponent) to:- Get a DB adapter (
adapter(ctx)), - Get an authenticated
authinstance + headers (getAuth(createAuth, ctx)), - Call
auth.api.*methods from Convex functions. [Component client; Basic usage / auth.api]
- Get a DB adapter (
- How the Convex plugin handles JWT generation, cookies, and JWKS endpoints for you when wired into
betterAuth({ plugins: [convex({ authConfig, ... })] }). [Convex plugin]
None of these docs expose or mention a setSessionCookie helper you can call yourself from Convex code, nor do they show any pattern for wiring Better Auth directly into a Convex httpAction.
Given that:
- I can’t point to a supported way (in the docs) to call
setSessionCookiefrom anhttpAction. - The documented integration model is: let the Convex Better Auth plugin own cookie/JWT handling, and interact with Better Auth from Convex via
authComponent.getAuth(...).auth.api.*, not by manually setting cookies. [Convex plugin; Basic usage / auth.api]
So, with the information available:
- There is no documented, supported pattern for calling Better Auth’s
setSessionCookiefrom inside a ConvexhttpAction. - The recommended approach is to rely on the Convex Better Auth plugin’s built‑in cookie/JWT handling instead of manually setting session cookies from
httpActions.