Skip to content

Content types ​

strapi-client generate writes the interfaces and the registry augmentation. The installed binary is strapi-client, so npx @fbritoferreira/strapi generate and strapi-client generate run the same command.

It takes exactly one source, or a config file for all of them: --dir or --url for content types (this page), --openapi for route types, or --graphql for GraphQL schema types. Each writes its own file. They are meant to be used side by side.

sh
# From a Strapi project checked out next to your app
npx @fbritoferreira/strapi generate --dir ../my-strapi -o src/strapi-types.ts

# From a running instance (admin user credentials, not an API token)
STRAPI_ADMIN_EMAIL=me@example.com STRAPI_ADMIN_PASSWORD=... \
  npx @fbritoferreira/strapi generate --url https://cms.example.com -o src/strapi-types.ts

# In CI: fail when the committed file is stale
npx @fbritoferreira/strapi generate --dir ../my-strapi -o src/strapi-types.ts --check

Import the generated file once (import "./strapi-types") and strapi.collection("articles") returns CollectionClient<Article>.

The first line of the generated file records its source, with local paths relative to the output file's directory:

ts
// Generated by @fbritoferreira/strapi generate from dir ../../my-strapi. Do not edit.

There is no timestamp, so regenerating an unchanged schema leaves the file as it was, and the same checkout produces the same file on every machine. --check ignores that line.

What is generated ​

  • One interface per api:: content type, extending StrapiDocument. Localized types get a required locale.
  • One interface per component, with id: number.
  • Relations, media, components and dynamic zones are optional (they appear only when populated). media is StrapiMedia | null or StrapiMedia[]. Relations to plugin::users-permissions.user are StrapiUser.
  • Dynamic zones are Array<(BlocksHero & { __component: "blocks.hero" }) | ...>.
  • enumeration becomes a union of string literals. json is unknown. biginteger is string. blocks is StrapiBlock[].
  • A __relations marker listing the fields written by reference: relations and media, not components or dynamic zones.
  • A __populatable marker listing the fields populate accepts. It exists only in the type system. It is what lets fields, sort and populate be told apart, and what lets results be narrowed.
  • private attributes are skipped. Plugin content types are skipped unless --include-plugins is passed.
  • --include-plugins registers plugin content types under their pluralName even when the plugin does not expose a matching /api/<pluralName> route.

The output augments StrapiContentTypes and StrapiSingleTypes. Once that file is imported, a uid it does not declare is a compile error, which catches strapi.collection("aritcles"). An explicit type argument still overrides the registry and accepts any uid.

Admin credentials ​

--url calls POST /admin/login and the Content-Type Builder routes. That needs an admin user with plugin::content-type-builder.read. Strapi does not accept API tokens on admin routes. --email and --password override STRAPI_ADMIN_EMAIL and STRAPI_ADMIN_PASSWORD.

Add --watch to regenerate as schemas change. See Watch mode.

Released under the MIT License.