docs: add background tasks (#8395)

This commit is contained in:
Jonathan Samines
2026-03-05 18:25:20 -08:00
committed by Maxwell
parent 11c3959e15
commit d2fe0463eb
3 changed files with 120 additions and 0 deletions
+46
View File
@@ -250,6 +250,52 @@ This may be useful to use instead of using your db directly to get access to `da
You can use `ctx.context.generateId` to generate Id for various reasons.
#### runInBackground
Schedules a task to run after the response is sent. Use for fire-and-forget operations (cleanup, analytics, rate limit counter updates). Configure the handler in [advanced.backgroundTasks](/docs/reference/options#backgroundtasks).
```ts title="auth.ts"
import { betterAuth } from "better-auth";
import { createAuthMiddleware } from "better-auth/api";
export const auth = betterAuth({
hooks: {
after: createAuthMiddleware(async (ctx) => {
if (ctx.path.startsWith("/sign-up")) {
const newSession = ctx.context.newSession;
if (newSession) {
ctx.context.runInBackground(sendAnalyticsEvent(newSession.user.id));
}
}
}),
},
});
```
#### runInBackgroundOrAwait
Defers the task when a handler is configured, otherwise awaits it. Use for operations that must complete (e.g. sending emails) but benefit from not blocking when a handler exists. Configure the handler in [advanced.backgroundTasks](/docs/reference/options#backgroundtasks).
```ts title="auth.ts"
import { betterAuth } from "better-auth";
import { createAuthMiddleware } from "better-auth/api";
export const auth = betterAuth({
hooks: {
after: createAuthMiddleware(async (ctx) => {
if (ctx.path.startsWith("/sign-up")) {
const newSession = ctx.context.newSession;
if (newSession) {
await ctx.context.runInBackgroundOrAwait(
sendWelcomeEmail(newSession.user)
);
}
}
}),
},
});
```
## Reusable Hooks
If you need to reuse a hook across multiple endpoints, consider creating a plugin. Learn more in the [Plugins Documentation](/docs/concepts/plugins).
@@ -121,6 +121,31 @@ Here are examples of how you can do caching in different frameworks and environm
</Tab>
</Tabs>
## Background Tasks
On serverless platforms (Vercel, Cloudflare Workers), you can improve response times by deferring non-critical work—cleanup, analytics, rate limit updates, email sending—to run after the response is sent. Configure [`advanced.backgroundTasks`](/docs/reference/options#backgroundtasks) and use `ctx.context.runInBackground` or `ctx.context.runInBackgroundOrAwait` in hooks.
```ts title="auth.ts"
import { betterAuth } from "better-auth";
import { createAuthMiddleware } from "better-auth/api";
import { waitUntil } from "@vercel/functions";
export const auth = betterAuth({
advanced: {
backgroundTasks: { handler: waitUntil },
},
hooks: {
after: createAuthMiddleware(async (ctx) => {
if (ctx.path === "/sign-up/email") {
ctx.context.runInBackground(logSignUp(ctx.context.newSession?.user.id));
}
}),
},
});
```
See the [Context documentation](/docs/concepts/hooks#runinbackground) for more examples.
## SSR Optimizations
If you're using a framework that supports server-side rendering, it's usually best to pre-fetch the user session on the server and use it as a fallback on the client.
+49
View File
@@ -585,6 +585,9 @@ export const auth = betterAuth({
defaultFindManyLimit: 100,
experimentalJoins: false,
},
backgroundTasks: {
handler: (promise) => { /* e.g. waitUntil(promise) */ }
},
skipTrailingSlashes: true
},
})
@@ -599,9 +602,55 @@ export const auth = betterAuth({
- `defaultCookieAttributes`: Default attributes for all cookies
- `cookiePrefix`: Prefix for cookies
- `database`: Database configuration options
- `backgroundTasks`: Configure background task handling for deferred operations
- `skipTrailingSlashes`: Skip trailing slash validation in route matching. (default: `false`)
- OAuth state configuration options (`storeStateStrategy`, `skipStateCookieCheck`) are now part of the `account` option
### `backgroundTasks`
Configure background task handling for deferred operations. Background tasks allow non-critical operations (like cleanup, analytics, timing-attack mitigation, or rate limit counter updates) to run after the response is sent. This can significantly improve response times on serverless platforms.
Some examples are: `waitUntil` from `@vercel/functions` on Vercel, or `ctx.waitUntil` on Cloudflare Workers. See the examples below for more details.
<Callout type="warn">
Enabling this introduces eventual consistency where the response returns optimistic data before the database is updated. Only enable if your application can tolerate this trade-off for improved latency.
</Callout>
<Tabs items={["Vercel", "Cloudflare Workers"]}>
<Tab value="Vercel">
```ts
import { betterAuth } from "better-auth";
import { waitUntil } from "@vercel/functions";
export const auth = betterAuth({
advanced: {
backgroundTasks: {
handler: waitUntil,
},
},
});
```
</Tab>
<Tab value="Cloudflare Workers">
```ts
import { betterAuth } from "better-auth";
import { AsyncLocalStorage } from "node:async_hooks";
const execCtxStorage = new AsyncLocalStorage<ExecutionContext>();
export const auth = betterAuth({
advanced: {
backgroundTasks: {
handler: (p) => execCtxStorage.getStore()?.waitUntil(p),
},
},
});
// In your request handler, wrap with execCtxStorage.run(ctx, ...)
```
</Tab>
</Tabs>
## `logger`
Logger configuration for Better Auth.