Development
Generators
@nestledjs/generators contains the generators you use during normal development. They handle workspace setup, code generation from your Prisma schema, and additive scaffolding for new models.
The current release is 3.0.3 and exposes six generators:
workspace-setupcrudmodelscustommodel-extensionAdded in 2.0.0sdk
This page documents the latest release
Nestled keeps one always-current documentation set rather than a separate copy per version. Anything whose behavior depends on which version you are on carries an inline badge — Added in 2.0.0 or Changed in 3.0.0 — so you can tell at a glance whether a section applies to your workspace. Full history lives in the changelog.
You rarely run these individually
In day-to-day development, pnpm db-update runs the schema-driven generators automatically. The full pipeline is: prisma:generate → @nestledjs/generators:crud → @nestledjs/generators:models → @nestledjs/generators:custom → @nestledjs/generators:sdk. You usually run generators directly only for first-time workspace setup or when regenerating one layer while debugging.
model-extension is intentionally not part of that pipeline — you run it by hand when you want a resolver module for a specific model.
Upgrading to 3.x — security migration required
3.0.0 makes every generated CRUD operation admin-only and removes @crudAuth. Before deleting the old annotations, replace every user, public, or custom-level operation with an explicit application resolver using a purpose-built input and a user- or tenant-scoped query.
Follow the Migrating to 3.0 guide before running pnpm db-update. Generator 3 rejects a schema that still contains @crudAuth rather than silently ignoring it.
Coming from 1.1.x?
2.0.0 also has an ordered migration: it changes how generated resolvers are registered and removes the per-model shells the custom generator used to emit. Complete Migrating to 2.0 before the 3.0 security migration.
Security fixes in 1.1.3 and 1.1.5 — audit required for deployed workspaces
If you are upgrading from an older line, two releases carry exposure that upgrading alone does not resolve:
- Before 1.1.3, the
modelsgenerator ignored@graphqlOmit, so annotated fields (commonly secrets likeencryptedAccessToken) stayed queryable. See the 1.1.3 audit steps. - Before 1.1.5, generated list queries accepted an untyped
filtersblob that reached Prisma'swhereclause verbatim, making every database column filterable — including@graphqlOmitcolumns — and usable as an oracle to recover tokens. See the 1.1.5 audit steps.
Both require rotating affected secrets, not just regenerating.
@nestledjs/generators:workspace-setup
nx g @nestledjs/generators:workspace-setup --name my-app
Run this once, immediately after cloning the starter template. It bootstraps a fresh workspace in order:
- Renames the project — replaces
nestled-templatewith your--nameacross every file - Preserves updater metadata — deliberately skips
.nestled/and.nestled-updates/so upgrade and doctor workflows keep working - Ensures
.envexists — copies.env.exampleif.envis missing - Validates
DATABASE_URL— refuses non-localhost database URLs as a safety guard - Starts infrastructure — ensures Docker and Docker Compose are running, then waits for the database
- Applies Prisma migrations — runs the template's Prisma apply command
- Generates the Prisma client — runs
pnpm prisma:generatebefore anything imports Prisma - Generates GraphQL types — runs the template's GraphQL generation command
- Seeds the database — creates initial development data
Options: --name (required) — your project name. It must match ^[a-z][a-z0-9-]*$, for example my-app, acme-saas, or todo-pro. This becomes the @name/ namespace for all imports, so keep it short.
Requires Docker and a local database. The generator intentionally refuses production or hosted database URLs.
@nestledjs/generators:crud
Part of pnpm db-update
nx g @nestledjs/generators:crud
Reads your Prisma schema via DMMF and generates a complete admin CRUD API:
- Data access module at
libs/api/generated-crud/data-access/— model metadata and pagination config - Feature module at
libs/api/generated-crud/feature/— one resolver per model with full CRUD operations
For each model, generates:
{model}query (read one){models}query (read many with pagination){models}Countquerycreate{Model},update{Model},delete{Model}mutations
Handles BigInt IDs with the GraphQLBigInt scalar. List operations use typed, bounded-depth filters that omit fields marked @graphqlOmit.
Admin-only security boundary
Changed in 3.0.0Every generated resolver class declares both @AdminOnly() and @UseGuards(GqlAuthAdminGuard). The guard cannot be lowered per model or per operation: @crudAuth was removed in 3.0.0, and the crud, sdk, models, and model-extension generators fail before writing if any model still carries it.
Generated create/update inputs, administrative filters, and recursive relation selection exist for the admin data browser. Do not reuse them as a user-facing API. Application workflows belong in additive custom resolvers with:
- purpose-built inputs containing only allowed fields;
- an explicit access decorator and guard;
- user or tenant scope derived from authenticated server context; and
- explicit Prisma
whereandselectclauses.
The recursive GraphQL-to-Prisma selection compiler is now a private, non-exported implementation detail inside the generated ApiCrudDataAccessService. It resolves relation metadata through the generated DATABASE_MODELS_BY_NAME map instead of repeatedly scanning the model array. See Migrating to 3.0 for replacing lower-privilege operations and removing the old createSelect/viewer-context machinery.
Typed admin filters
Changed in 3.0.1Filter fields and operators are derived from the visible Prisma model:
- all supported scalar filters provide
equals,in, andnot; - strings also provide
contains,startsWith, andendsWith; - numbers and dates also provide
lt,lte,gt, andgte; - list relations provide
some,every, andnone; and - to-one relations provide
isandisNot, including null checks, while retaining the direct nested shorthand from 1.1.5.
@graphqlOmit fields never enter the filter types. Json columns and scalar lists remain unfilterable.
AND, OR, and NOT are bounded rather than self-referencing: each relation or logical operator points only to the next generated input depth. The default --filterDepth is 3, and the deepest level contains scalars only. Generated data access normalizes the compatible to-one shorthand into Prisma's relation-filter form and rejects a contradictory is: null plus direct predicate before it reaches Prisma.
3.0.2 also makes this normalization compile when noPropertyAccessFromIndexSignature is enabled. See the 3.0.1 and 3.0.2 entries for patch-specific upgrade notes.
How generated resolvers get registered
Changed in 2.0.0The feature library exports a single module, ApiGeneratedCrudFeatureModule, written to api-generated-crud-feature.module.ts. The generator imports it into coreModules in apps/api/src/app.module.ts, and that import is the registration — it's what puts every generated resolver into the running schema. Re-running the generator is safe: the module is only added if it isn't already listed.
Before 2.0.0, generated resolvers reached the schema indirectly, by having each per-model custom resolver extend its generated counterpart. That's gone. If you are upgrading, see Migrating to 2.0 — importing this module while inherited custom resolvers are still registered will register every generated field twice.
@nestledjs/generators:models
Part of pnpm db-update
nx g @nestledjs/generators:models
Reads your Prisma schema and generates TypeScript classes with GraphQL decorators at libs/api/core/models/. These models are used by generated CRUD resolvers and by your custom API code.
This generator replaces the older template-local model generation script. Keeping model generation in @nestledjs/generators means fixes ship with the generator package instead of requiring template file changes.
Prisma Json fields are emitted as GraphQLJSON, which supports objects, arrays, and scalar JSON values. If you upgraded from a version that emitted GraphQLJSONObject, regenerate models after installing @nestledjs/[email protected].
Fields annotated with @graphqlOmit in the Prisma schema are dropped from the generated models (both the @Field() decorator and the property). Because the emitted @ObjectType() is the server GraphQL schema, this makes models.ts the single authoritative enforcement point — an omitted field never reaches api-schema.graphql and is not queryable through the API. This behavior was fixed in 1.1.3; see the changelog for the security audit steps if you built with an earlier version.
model OAuthAccount {
id String @id
/// @graphqlOmit
encryptedAccessToken String // not emitted to the GraphQL schema
}
@nestledjs/generators:custom
Part of pnpm db-update
nx g @nestledjs/generators:custom
Creates and maintains the custom API library at libs/api/custom/ — the library itself plus its stable barrel files:
src/index.ts— the library barrel, re-exporting the two belowsrc/lib/default/index.ts— created empty if missing; where your model-specific modules are exported fromsrc/lib/plugins/index.ts— created withexport const customPlugins = []if missing or empty
It does not read your Prisma schema and does not create per-model code. Running it is safe and effectively idempotent: existing extensions under src/lib/default/ are left untouched.
Changed in 2.0.0
Through 1.1.x this generator emitted a {model}.service.ts / {model}.resolver.ts / {model}.module.ts shell for every Prisma model, because generated CRUD relied on those custom resolvers inheriting from the generated ones in order to be registered at all. 2.0.0 registers generated CRUD directly through ApiGeneratedCrudFeatureModule, so the shells are no longer needed and are no longer produced.
To add a module for one specific model, use model-extension — it is explicit and on-demand rather than blanket-generated. See Migrating to 2.0 for what to do with shells you already have.
Options: --name (default: custom), --directory, --overwrite (default: false)
--overwrite removes and recreates the library. It is destructive — everything under libs/api/custom/ goes, including your own extensions — so it is only for rebuilding a broken library from scratch.
@nestledjs/generators:model-extension
Added in 2.0.0Run on demand — not part of pnpm db-update
nx g @nestledjs/generators:model-extension Post
Scaffolds an additive, model-specific resolver module for a single Prisma model. Use it when a model needs behavior beyond generated CRUD — a computed field, a domain-specific mutation, an extra guard.
In 3.0.0, this is also the starting point for any application workflow that used to lower generated CRUD through @crudAuth. Define a new, non-colliding GraphQL operation with its own input and explicitly scoped database query; do not inject ApiCrudDataAccessService or import generated CRUD inputs into the user-facing module.
This is the deliberate replacement for the blanket per-model shells that custom used to emit: you get a module for the models that actually need one, when they need one, instead of a directory of empty classes for every model in the schema.
It writes two files to libs/api/custom/src/lib/default/{name}/:
{name}.resolver.ts— an empty@Resolver(() => Model)class for you to fill in{name}.module.ts— a NestJS module providing and exporting that resolver
It then adds the export to libs/api/custom/src/lib/default/index.ts and registers the module in the defaultModules array in apps/api/src/app.module.ts. No service is generated — inject what you need.
Options:
model(required, first positional) — the Prisma model to target. Matched case-insensitively; an unknown name fails listing the available models.--name— artifact name; defaults to the model name
--name changes what the generated files and class are called without changing the GraphQL type they target — the resolver is always @Resolver(() => Model) for the model you passed. So Post can carry a PostPublishing extension alongside a plain Post one, both resolving Post fields:
nx g @nestledjs/generators:model-extension Post --name PostPublishing
It refuses rather than overwrites. If the target folder already exists and is non-empty, the generator errors instead of touching your code. It also requires the custom library to exist first — run @nestledjs/generators:custom if you see "The custom API library is not initialized" — and rejects models marked @skipCrud, since those have no generated GraphQL model to target.
@nestledjs/generators:sdk
Part of pnpm db-update
nx g @nestledjs/generators:sdk
Reads your Prisma schema and maintains the GraphQL client SDK. As of 3.0.3, it has a strict ownership boundary:
- Generated admin documents at
libs/shared/sdk/src/__admin/<model>/— recreated for every visible Prisma model, including fragments, read/count queries, create/update/delete mutations, nested relation IDs, and_countfields - Application documents under
libs/shared/sdk/src/graphql/<feature>/— preserved exactly; never created or deleted based on Prisma models - Shared SDK source — updates
database-models.ts, the core uptime/paging document, SDK exports, and GraphQL Code Generator setup
Write purpose-built queries, mutations, and fragments under src/graphql/<feature>/ only after their explicit application resolver exists. Do not copy the generated admin root operations into this tree, and do not add empty .graphql placeholders.
The generator adds sdk / sdk:watch scripts. It creates codegen.yml when missing and preserves an existing file unless you opt into replacing it.
Options: --forceCodegen (default: false) — overwrite codegen.yml even if it exists
Looking for older scaffolders?
The old split-package commands such as @nestledjs/api:plugin, @nestledjs/api:integrations, and @nestledjs/shared:sdk are legacy template-build commands, not active @nestledjs/generators commands. See Generators (Legacy) only if you are studying how the template was originally assembled.