Configuration Reference

Every module option, every resource registration field and every authorization key in one place. The guides explain when to use them; this page lists what exists.

Configuration Reference

Every module option, every resource registration field and every authorization key in one place. The guides explain when to use them; this page lists what exists.

Module options (autoApi in nuxt.config.ts)

export default defineNuxtConfig({
  modules: ['@websideproject/nuxt-auto-api'],
  autoApi: {
    prefix: '/api',
    plugins: '~/server/autoapi-plugins',
    pagination: { defaultLimit: 20, maxLimit: 100 },
    multiTenancy: { enabled: true, tenantIdField: 'organizationId' },
  },
})
OptionDefaultDescription
prefix'/api'Route prefix for every generated route; the composables follow it
plugins—Path to a server file exporting an array of plugins (recommended), or an inline array. Plugin System
pagination.defaultLimit20Page size when ?limit is absent
pagination.maxLimit100Largest ?limit; also caps ?include= and M2M pages. Pagination
multiTenancy.enabledfalseScope tenant tables to the caller's tenant; fail closed without one. Multi-Tenancy
multiTenancy.tenantIdField'organizationId'Tenant column (property key) on scoped tables
multiTenancy.userTenantFieldtenantIdFieldProperty of ctx.user holding the active tenant
multiTenancy.scopedResources'*''*' = every resource whose table has the column, or a list
multiTenancy.excludedResources[]Never scoped (global tables that happen to have the column)
authorization—Per-resource overrides of a module's auth config — strings/arrays only (serialized). Auth
relations.maxDepth3Deepest ?include= nesting
relations.maxIncludes20Relations per request
relations.allowFieldSelectiontrue?include=author[id,name]
relations.allowFilteringtrueFilters on to-many includes
relations.allowPaginationtruelimit / offset on to-many includes
bulk.enabledtrue/:resource/bulk routes
bulk.maxBatchSize100Items per bulk request
bulk.transactionaltrueAll-or-nothing (not atomic on D1). Bulk Operations
aggregations.enabledtrue/:resource/aggregate and ?aggregate=
aggregations.allowGroupBytruegroupBy
aggregations.maxGroupByFields5Group-by columns per request
hookConfig.errorHandling'log' for after-hooks'throw' surfaces after-hook errors. Before-hooks always throw
hookConfig.timeout5000Milliseconds per hook
hookConfig.parallelfalseRun a hook's handlers concurrently
hiddenFields.global[]Columns never returned or queryable on any resource (e.g. passwordHash)
hiddenFields.resources{}Same, per resource
m2mauto-detectJunction detection and explicit relations. M2M
debugfalseLog registration and plugin details at build time

Not options: the database engine is the second argument of initializeDatabase(db, engine) in a server plugin. database is accepted for older configs but not read. hooks, exclude, include and multiTenancy.getTenantId / allowCrossTenantAccess / requireTenant were removed and fail the build — see Upgrading.

Registering a resource

Resources are registered at build time, from a Nuxt module, through the autoApi:registerSchema hook:

// modules/blog/index.ts
import { createResolver, defineNuxtModule } from '@nuxt/kit'
import { createModuleImport } from '@websideproject/nuxt-auto-api'

export default defineNuxtModule({
  meta: { name: 'blog' },
  setup(_, nuxt) {
    const { resolve } = createResolver(import.meta.url)
    nuxt.hook('autoApi:registerSchema', (registry) => {
      registry.register('posts', {
        schema: createModuleImport(resolve('./schema'), 'posts'),
        authorization: createModuleImport(resolve('./auth'), 'postsAuth'),
        validation: createModuleImport(resolve('./validation'), 'postsValidation'),
        hooks: createModuleImport(resolve('./hooks'), 'postsHooks'),
        hiddenFields: ['internalNotes'],
        protectedFields: ['authorId'],
      })
    })
  },
})
FieldRequiredDescription
schema✅The Drizzle table, as createModuleImport(path, exportName)
authorizationeffectively ✅ResourceAuthConfig (below). Without it every request is refused and the build warns
validation—{ create?, update?, query? } Zod schemas; parts left out are generated from the table. Validation
hooks—before* / after* lifecycle hooks. Lifecycle Hooks
hiddenFields—Columns never returned and never usable in filter/sort/include
protectedFields—Columns a request body can never set (silently dropped) — on top of the always-protected pk, tenant, soft-delete and audit columns
metadata—Free-form, JSON-serializable data for tooling (the admin module reads it)

schema, authorization, validation and hooks must be createModuleImport() references: the registry is generated as code, so an inline function or Zod schema cannot be carried into it — passing one fails the build.

The resource name is the URL segment (/api/posts) and the key used everywhere else: in permissions.m2m, in autoApi.authorization, in hiddenFields.resources, in the composables (useAutoApiList('posts')).

Files loaded through createModuleImport (auth.ts, hooks.ts, validation.ts and everything they import) are not processed by Nitro's auto-imports: import what you use explicitly, read config from ctx.runtimeConfig rather than useRuntimeConfig(), and avoid extensionless relative runtime imports — import from package subpaths or use import type.

Authorization (ResourceAuthConfig)

export const postsAuth: ResourceAuthConfig = {
  permissions: {
    read, create, update, delete, // PermissionValue — undeclared = denied
    aggregate, // → read
    restore, purge, viewDeleted, // → update / delete / restore
    m2m: { requireUpdateOnRelated, requireUpdateToLink, relations: { [relation]: { check } } },
  },
  listFilter: (table, ctx) => SQL | undefined, // row visibility, every route
  objectLevel: (row, ctx) => boolean, // per row; list rows failing it are dropped
  fields: { [column]: { read?: PermissionValue, write?: PermissionValue } },
  softDelete: { cascade: 'auto' | 'off', retentionDays: number, restore, purge, viewDeleted },
  custom: { [endpointName]: { permissions: { read, create, update, delete } } },
}

PermissionValue = true · false · 'perm' · ['a', 'b'] · (ctx) => boolean | Promise<boolean> · an object handled by a registered evaluator. Recipes: Permissions Cookbook.

Generated routes

For a resource posts (prefix /api):

RouteOperation → permission
GET /api/postslist → read
GET /api/posts/:idget → read
POST /api/postscreate → create
PATCH /api/posts/:idupdate → update
DELETE /api/posts/:iddelete → delete (?force=true → purge)
POST /api/posts/:id/restore→ restore
POST · PATCH · DELETE /api/posts/bulk→ create · update · delete per item
GET /api/posts/aggregate→ aggregate
GET /api/posts/:id/relations/:relation→ read on both
POST /api/posts/:id/relations/:relation (sync), /add, DELETE …/remove, POST /api/posts/:id/relations/batch→ update here, read (or update) on the related resource
GET /api/posts/permissions, GET /api/permissionsthe caller's permissions
GET /api/_m2m/junctions, /is-junction/:table, /detect/:resourcesigned-in callers

Package entry points

ImportContents
@websideproject/nuxt-auto-apithe Nuxt module, createModuleImport, types (ResourceAuthConfig, HandlerContext, …)
@websideproject/nuxt-auto-api/utilsserver utils — also auto-imported in server code. Custom Endpoints
@websideproject/nuxt-auto-api/pluginsbuilt-in plugins, defineAutoApiPlugin, addContextExtender, addResourceHook, addGlobalHook, registerPermissionEvaluator
@websideproject/nuxt-auto-api/databaseinitializeDatabase, getDatabaseAdapter, adapters
@websideproject/nuxt-auto-api/composablesclient composables and their types — also auto-imported. Frontend Composables
@websideproject/nuxt-auto-api/schema/{sqlite,pg,mysql}schema presets

Need a Landing Page?

Modern landing pages with optional modules (blog, docs, forms, i18n). Let's discuss your project.

Build Your MVP

Full-stack SaaS development. Expert in database design, multi-tenancy, and scalable architecture.

Deployment Help

Dockerize your backend, set up CI/CD pipelines, deploy to Cloudflare or Hetzner. Early-stage setup.

Suggest a SaaS Tool

Missing a calculator or tool? Suggest what you'd like to see on our site.