How to change export paths
Modify where a cloned generator writes its output files.
When to use this
Stock generator paths don't match your project's conventions.
Common cases: you want schemas/ not models/, you want
per-tag subdirectories, or you want to flatten everything into
one directory.
Prerequisites
- The generator cloned into your project (tutorial: cloning a generator).
Steps
Open gen-x/src/base.ts
toExportPath lives there for stock generators. For
model generators it takes { refName, enrichments, variant };
for operation generators it takes { operation, enrichments, variant } (and similar for GraphQL).
Edit toExportPath
Return whatever path you want. The path is relative to the
project's configured basePath.
// Stock gen-zod / gen-typescript default (decapitalized name under @/types)
toExportPath: ({ refName }) => {
const name = decapitalize(camelCase(refName))
return join('@', 'types', `${decapitalize(name)}.generated.ts`)
}
// Per-tag subdirectory
toExportPath: ({ operation }) => {
const tag = operation.tags?.[0] ?? 'misc'
return `/api/${tag}/${toEndpointName(operation)}.ts`
}
// Flat
toExportPath: ({ refName }) => `/${refName}.ts`The function must be pure — same input → same path. If it
isn't, cross-generator coordination
breaks because the cache key includes exportPath.
Branch on enrichments for per-operation overrides (optional)
For per-operation path control, add an enrichment field:
// In enrichments.ts — the per-operation override lives under `subject`.
export const pathsSubject = v.optional(
v.object({
paths: v.optional(v.object({ override: v.optional(v.string()) }))
})
)
export const enrichmentSchema = v.object({
subject: pathsSubject,
generator: v.undefined(),
stack: v.undefined()
})
export const toEnrichmentSchema = () => enrichmentSchema
// In base.ts — toExportPath receives the parsed umbrella; read `subject`.
toExportPath: ({ operation, enrichments }) => {
const override = enrichments?.subject?.paths?.override
if (override) return override
return `/api/${toEndpointName(operation)}.ts`
}Users now set per-operation path overrides in client.json.
Rebundle and regenerate
skmtc bundle my-project
skmtc generate my-projectOutput appears at the new paths. Old files at the old paths
persist — skmtc generate doesn't delete (see how to update a
schema).
Verification
ls <basePath>/<your-new-path-prefix>/Files appear at the new location. Other generators that
reference these files (e.g., a hook generator referencing a Zod
schema) follow automatically — they discover the path via
insertModel's return value, not by hardcoding.
Troubleshooting
- Other generators register imports to the OLD path. They're
reading from a stale bundle. Run
skmtc bundle my-projectagain.skmtc doctorflags stale bundles. - Same path produced for multiple schemas. Your
toExportPathlost uniqueness. Driver-path inserts (the usual case viainsertModel/insertOperation) detect the mismatch and throwRegistered definition mismatch; bareregister()collisions discard silently. Re-check that the path is unique per input. - TypeScript errors about missing imports. A consumer file imports from the old location. The consumer-side code needs updating; the engine doesn't know about it.
Related
- Tutorial: Cloning a generator
- API: ContentSettings —
what
exportPathflows into - How to change identifier conventions — the sibling task (changing the name)