Skip to main content

Module configuration

Every option under the convex key in nuxt.config.ts, and the convexAuth page metadata.

Configure the module under the convex key. The type is ModuleOptions.

nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@lupinum/better-convex-nuxt'],
  convex: {},
})

Core

OptionTypeDefault
urlstringNUXT_PUBLIC_CONVEX_URL, then CONVEX_URL
siteUrlstringNUXT_PUBLIC_CONVEX_SITE_URL, then CONVEX_SITE_URL, then the .convex.site URL for url
authfalse | ConvexAuthOptionsNot set: authentication is off
loggingfalse | 'info' | 'debug'false
clientobjectSee browser client
serverobjectSee server limits

url is the Convex deployment URL, for example https://happy-otter-123.convex.cloud. siteUrl is the URL of the deployment's HTTP actions, for example https://happy-otter-123.convex.site. The module uses siteUrl to exchange the session for a Convex session token.

logging: 'info' logs short messages. logging: 'debug' adds timings and details.

Authentication

Authentication is off until you add an auth object:

nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@lupinum/better-convex-nuxt'],
  convex: {
    auth: {
      origin: process.env.SITE_URL ?? 'http://localhost:3000',
      trustedClientIpHeader: process.env.BCN_AUTH_TRUSTED_CLIENT_IP_HEADER,
    },
  },
})
OptionTypeDefaultEffect
originstringRequiredThe public origin of the Nuxt application
clientstringNot setPath to a file that exports defineConvexAuthClient(...)
trustedClientIpHeaderstring''The request header that your proxy or host sets to the client IP
redirectTostring'/auth/signin'The sign-in page for anonymous visitors on a protected page
guestRedirectTostring'/'Where a signed-in visitor goes from a convexAuth: 'guest' page
defaultQueryAuth'optional' | 'required' | 'none''optional'The auth mode of a query that does not set one
routes'public' | 'protected''public'Whether a page without convexAuth metadata needs a signed-in user

origin is one exact origin, such as https://app.example.com. It must not contain a path, query, or fragment.

client is read only at build time. Use it to add Better Auth client plugins. The module does not copy it into the runtime configuration.

trustedClientIpHeader names a header that contains exactly one client IP address. Your proxy or host must overwrite this header on every request. It must not append to a list, such as X-Forwarded-For. The module uses the IP address for rate limiting. You may leave it empty only when origin is localhost, 127.0.0.1, or [::1]. Make sure that public traffic cannot reach Nuxt without passing through that proxy. See environment variables.

redirectTo and guestRedirectTo must be local paths that start with one /. The module rejects other values at build time and at runtime.

defaultQueryAuth applies to useConvexQuery and useConvexPaginatedQuery. The auth option of a call always wins. The server render and the browser use the same value. It does not apply to serverConvex.

The auth proxy path is always /api/auth on your own origin. You cannot change it.

Set auth: false only in a Nuxt layer that must turn off an auth object from another layer. There is no enabled flag.

Page metadata

With authentication on, each page can set convexAuth in definePageMeta:

app/pages/dashboard.vue
<script setup lang="ts">
definePageMeta({ convexAuth: true })
</script>
ValueEffect
trueThe page needs a signed-in user. Anonymous visitors go to redirectTo.
{ redirectTo: '/login' }The page needs a signed-in user. Anonymous visitors go to this route.
'guest'The page is for signed-out visitors, such as a sign-in page. Signed-in visitors go to the ?redirect= path or to guestRedirectTo.
falseThe page is public, even when routes is 'protected'
Not setThe page follows routes

The route middleware adds the current path as ?redirect= when it sends a visitor to the sign-in page. Read it with useConvexAuthReturnTo.

Route middleware only controls navigation. It does not protect data. Check the user in every Convex function that returns private data.

Browser client

client passes options to every browser ConvexClient that the module creates. This includes the client for auth: 'none' queries.

ts
client: {
  verbose: false,
  skipConvexDeploymentUrlCheck: false,
  unsavedChangesWarning: false,
}
OptionTypeDefaultEffect
verbosebooleanfalseLog Convex client debug output in the browser console
skipConvexDeploymentUrlCheckbooleanfalseAccept a self-hosted deployment URL that does not end in .convex.cloud
unsavedChangesWarningbooleanfalseAsk before the page closes while mutations are still pending

The build fails for any other client option. The module controls authentication, logging, and client replacement. In Vue without Nuxt, pass the same options, plus webSocketConstructor, as createBetterConvex({ convexUrl, clientOptions }).

Server limits

server limits the Convex HTTP calls during server rendering and from serverConvex.

ts
server: {
  maxResponseBytes: 1_048_576,
  queryTimeoutMs: 8_000,
}
OptionTypeDefaultEffect
maxResponseBytesnumber1048576Largest accepted Convex HTTP response body, in bytes
queryTimeoutMsnumber8000Time limit for one Convex HTTP query, in milliseconds

Both values must be positive integers. A larger response fails with a transport error and code RESPONSE_TOO_LARGE. A query that takes longer fails with code TIMEOUT. Mutations have a fixed 15-second limit, and actions a fixed 60-second limit.

To change the limits at deploy time, set NUXT_PUBLIC_CONVEX_SERVER_MAX_RESPONSE_BYTES and NUXT_PUBLIC_CONVEX_SERVER_QUERY_TIMEOUT_MS. These values are public runtime configuration, not secrets. An invalid value fails the build. An invalid deploy-time value fails every request that reads the configuration.

Full example

nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@lupinum/better-convex-nuxt'],
  convex: {
    url: process.env.NUXT_PUBLIC_CONVEX_URL,
    siteUrl: process.env.NUXT_PUBLIC_CONVEX_SITE_URL,
    auth: {
      origin: process.env.SITE_URL ?? 'http://localhost:3000',
      trustedClientIpHeader: process.env.BCN_AUTH_TRUSTED_CLIENT_IP_HEADER,
      redirectTo: '/auth/signin',
    },
    logging: process.env.NODE_ENV === 'development' ? 'info' : false,
    server: {
      queryTimeoutMs: 5_000,
    },
  },
})