# How to change identifier conventions



## When to use this [#when-to-use-this]

You want the generated identifiers to match your team's naming
conventions instead of the stock generator's defaults.

## Prerequisites [#prerequisites]

* The generator cloned into your project ([tutorial: cloning](/docs/authoring/tutorials/01-cloning-a-generator)).
* Light understanding of [identifiers and entity types](/docs/reference/api/dsl-identifier).

## Steps [#steps]

### Open `gen-x/src/base.ts` [#open-gen-xsrcbasets]

The naming convention lives there, split across two config fields
on the `toTsModelProjectionBase({...})` (or operation-equivalent)
call: `toIdentifierName` returns the name string, and
`toIdentifierType` declares whether the name is a variable
(a `const` declaration) or a type declaration.

### Edit `toIdentifierName` [#edit-toidentifiername]

```ts
// gen-zod default
toIdentifierName: ({ refName }) => decapitalize(refName)
// → "user", "order", "pet"

// Your house style: PascalCase with suffix
toIdentifierName: ({ refName }) => `${refName}Schema`
// → "UserSchema", "OrderSchema", "PetSchema"
```

For a type generator, have `toIdentifierType` return
`{ type: 'type' }` instead of `{ type: 'variable' }`:

```ts
import type { TsIdentifierType } from '@skmtc/lang-typescript'

toIdentifierType: (): TsIdentifierType => ({ type: 'type' })
// → rendered as `export type User = ...` and imports as `import { type User }`
```

The `variable` vs `type` choice determines:

* The declaration shape (`export const` vs `export type`)
* The import shape under `verbatimModuleSyntax: true`
  (`import { X }` vs `import { type X }`)

See [identifier reference](/docs/reference/api/dsl-identifier)
for the entity-type semantics.

### Preserve uniqueness across operations [#preserve-uniqueness-across-operations]

The `(identifier.name, exportPath)` pair is the cache key. If
two operations within your generator produce the same name in
the same file, the Driver's `affirmDefinition` detects the
mismatch (different `generatorKey` per operation) and throws
`Registered definition mismatch`. Re-inserting the same operation
is idempotent (same key → cache hit).

Make sure your naming function produces unique names per
operation/refName so the throw never fires. Helpers like
`toEndpointName(operation)` handle the OAS-spec quirks (missing
`operationId`, identical paths with different methods).

### Rebundle and regenerate [#rebundle-and-regenerate]

```bash
skmtc bundle my-project
skmtc generate my-project
```

## Verification [#verification]

Open an generated file and check the declarations:

```bash
cat src/generated/Pet.generated.ts | head -3
# export const PetSchema = z.object({...})    ← new naming
```

Cross-generator references (e.g., a form generator importing the
Zod schema) follow the new name automatically — they discover
it via `insertModel(...).toName()`, not by hardcoded reference.

## Troubleshooting [#troubleshooting]

* **Imports break under `verbatimModuleSyntax`** — A type
  declaration whose `toIdentifierType` returns `{ type: 'variable' }`
  (or vice versa) causes TS errors. Audit which generators produce
  values vs types and make sure each is right.
* **Same identifier name across operations** — naming function
  isn't unique enough. Common bug: derivation from `operation.summary`
  rather than `operationId` (summaries are free text and not
  required to be unique).

## Related [#related]

* [API: Identifier](/docs/reference/api/dsl-identifier) —
  including the entity-type discussion
* [How to change export paths](/docs/authoring/how-to/change-export-paths) — the
  sibling task
* [How idempotency works](/docs/explanation/how-idempotency-works) —
  why uniqueness matters
