Generate TypeScript types from your Contentful content model, either from a local contentful space export JSON file or by fetching the model directly from Contentful.
Use the generated types with contentful.js v10+ for safer queries, autocomplete, and less schema drift between Contentful and your app.
As of v3.x, pre-v10 output is removed. If you are upgrading from
2.x, moderncontentful.jstyping is now the default and only output model.
import type { TypeAnimal } from './@types/generated';npm install --save-dev cf-content-types-generatorYou can generate types in two ways:
- from a local export JSON file in the exact Input shape, usually created with
contentful space export - by providing Contentful credentials and letting the CLI fetch the same model data on the fly
Export your space model:
contentful space export --config ./export-config.jsonGenerate types:
cf-content-types-generator ./contentful-export.json -o src/@types/generatedUse the generated type:
import type { TypeAnimal } from './@types/generated';cf-content-types-generator \
-s <space-id> \
-t <management-token> \
-e <environment> \
--proxy https://user:password@proxy.example:8443 \
-o src/@types/generatedIf your network requires a proxy, you can also add --rawProxy to pass the proxy config straight to Axios.
- turn a Contentful content model into generated TypeScript types
- use those generated types in apps built with
contentful.jsv10+ - optionally add JSDoc, type guards, and response aliases
- you keep Contentful schema in source control and want generated app types
- you use
contentful.jsin TypeScript and want typed entries based on your real model - you want type generation in CI from either exports or live space data
Further reading: if you want broader context on typing Contentful projects with TypeScript, see Contentful’s guide to TypeScript and Contentful.
cf-content-types-generator [FILE]
Common tasks:
- generate from a local export JSON file:
cf-content-types-generator ./contentful-export.json -o src/@types/generated - generate by fetching live data:
cf-content-types-generator -s <space-id> -t <management-token> -e <environment> -o src/@types/generated - add optional helpers:
cf-content-types-generator ./contentful-export.json -o src/@types/generated --jsdoc --typeguard --response
Key flags:
-o, --outoutput directory-p, --preservepreserve existing output folder-d, --jsdocadd JSDoc comments-g, --typeguardadd modern type guards-r, --responseadd response aliases-s, --spaceIdContentful space id-t, --tokenContentful management token-e, --environmentContentful environment-a, --hostManagement API host--proxyproxy URL in HTTP auth format--rawProxypass proxy config to Axios directly
Removed in v3.x:
--v10--localized
Both now error with explicit migration hints.
All examples below use the same generated base type:
export interface TypeAnimalFields {
breed?: EntryFieldTypes.Symbol;
}
export type TypeAnimalSkeleton = EntrySkeletonType<TypeAnimalFields, 'animal'>;
export type TypeAnimal<
Modifiers extends ChainModifiers,
Locales extends LocaleCode = LocaleCode,
> = Entry<TypeAnimalSkeleton, Modifiers, Locales>;Adds generated comments to fields, skeletons, and entries.
/**
* Fields type definition for content type 'TypeAnimal'
* @name TypeAnimalFields
* @type {TypeAnimalFields}
* @memberof TypeAnimal
*/
export interface TypeAnimalFields {
/**
* Field type definition for field 'breed' (Breed)
* @name Breed
* @localized false
*/
breed?: EntryFieldTypes.Symbol;
}Adds a runtime predicate for the generated entry type.
export function isTypeAnimal<Modifiers extends ChainModifiers, Locales extends LocaleCode>(
entry: Entry<EntrySkeletonType, Modifiers, Locales>,
): entry is TypeAnimal<Modifiers, Locales> {
return entry.sys.contentType.sys.id === 'animal';
}Adds aliases for common response modifier combinations.
export type TypeAnimalWithoutLinkResolutionResponse = TypeAnimal<'WITHOUT_LINK_RESOLUTION'>;
export type TypeAnimalWithAllLocalesResponse<Locales extends LocaleCode = LocaleCode> = TypeAnimal<
'WITH_ALL_LOCALES',
Locales
>;These aliases are convenience aliases for the top-level entry type only. Linked entries still stay typed as Entry<LinkedSkeleton, Modifiers, Locales>, which is expected and matches contentful.js.
If you want resolved assets and entries without unresolved-link unions, call the client with the matching chain modifier:
const articles = await client.withoutUnresolvableLinks.getEntries<TypeBlogArticleSkeleton>({
content_type: 'blogArticle',
include: 4,
});
articles.items[0]?.fields.image?.fields.file?.url;
articles.items[0]?.fields.category?.[0]?.fields;If a reference field allows multiple content types, generate type guards with --typeguard and narrow linked entries where you use them.
import {
CFDefinitionsBuilder,
ContentTypeRenderer,
ResponseTypeRenderer,
TypeGuardRenderer,
} from 'cf-content-types-generator';
const builder = new CFDefinitionsBuilder([
new ContentTypeRenderer(),
new TypeGuardRenderer(),
new ResponseTypeRenderer(),
]);If you want custom output, extend BaseContentTypeRenderer or implement the Renderer interface.
This tool accepts either:
- a local JSON file in the exact shape produced by
contentful space export - or enough CLI credentials for the generator to fetch equivalent model data live
Typical export command:
contentful space export --config ./export-config.jsonIf you pass a local file, that exported JSON shape is the exact shape this tool expects.
When you fetch the model remotely, this tool intentionally skips entry data and only reads schema data. A log line about skipping content entries is expected and does not mean generation is incomplete.
At minimum, this generator needs a JSON object with a contentTypes field. A full contentful space export dump usually also contains keys such as entries, assets, locales, roles, webhooks, and editorInterfaces, but this generator mainly reads contentTypes and editorInterfaces.
Example shape:
{
"contentTypes": [
{
"sys": {
"id": "animal",
"type": "ContentType"
},
"name": "Animal",
"fields": [
{
"id": "breed",
"type": "Symbol",
"required": false,
"localized": false,
"omitted": false,
"disabled": false,
"validations": []
}
]
}
]
}3.x removes all pre-v10 output behavior. If you are upgrading from 2.x, use this migration path:
- Remove
--v10from CLI usage. - Remove
--localized; no replacement needed. - Rename programmatic imports:
V10ContentTypeRenderer->ContentTypeRendererV10TypeGuardRenderer->TypeGuardRenderercreateV10Context()->createContext() - Regenerate all generated types.
- Update downstream code that still assumes classic
Entry<TypeFields>output.
CLI before:
cf-content-types-generator ./contentful-export.json -o src/@types/generated --v10 --responseCLI after:
cf-content-types-generator ./contentful-export.json -o src/@types/generated --responseProgrammatic before:
import {
CFDefinitionsBuilder,
V10ContentTypeRenderer,
V10TypeGuardRenderer,
} from 'cf-content-types-generator';
const builder = new CFDefinitionsBuilder([
new V10ContentTypeRenderer(),
new V10TypeGuardRenderer(),
]);Programmatic after:
import {
CFDefinitionsBuilder,
ContentTypeRenderer,
TypeGuardRenderer,
} from 'cf-content-types-generator';
const builder = new CFDefinitionsBuilder([new ContentTypeRenderer(), new TypeGuardRenderer()]);If downstream code still expects classic output, regenerate and adapt those types in the same change.
pnpm test
pnpm buildRelated app: cf-content-types-generator-app