Skip to content

Type Mapping

This page is a comprehensive reference for how Strapi schema types are converted to TypeScript types during code generation.

Scalar Type Mapping

Strapi TypeTypeScript TypeNotes
stringstringShort text field
textstringLong text field
richtextstringMarkdown rich text (Strapi v4 style)
emailstringEmail field
uidstringUnique identifier field
integernumber
bigintegernumber
floatnumber
decimalnumber
booleanboolean
datestringISO date string (YYYY-MM-DD)
datetimestringISO datetime string
timestringTime string (HH:mm:ss)
jsonunknownArbitrary JSON data

Complex Type Mapping

Strapi TypeTypeScript TypeNotes
enumeration<['a', 'b', 'c']>'a' | 'b' | 'c'Union of literal string types
blocks (Rich Text v2)BlocksContentStructured block array; see Media & Blocks
media (single)MediaFile | nullSee MediaFile
media (multiple)MediaFile[]Array of media objects
component (single)ComponentNameTyped interface for the component
component (repeatable)ComponentName[]Array of component objects
dynamiczone(CompA | CompB | ...)[]Union type array of all allowed components
passwordexcludedPrivate fields are not generated

Relation Mapping

Relations are mapped differently depending on whether they are populated or not.

Base Types (without populate)

Relations are not included in base types. When you query without populate, Strapi does not return relation data, so the generated base interface only contains scalar fields.

Populated Types (with populate)

When you use the populate parameter, the return type automatically includes the related entities:

Relation TypePopulated TypeScript Type
oneToOneRelatedType | null
manyToOneRelatedType | null
oneToManyRelatedType[]
manyToManyRelatedType[]
ts
// Without populate — only scalar fields
const article = await strapi.articles.findOne('abc123')
// article: Article  (no relations)

// With populate — relations are included in the type
const article = await strapi.articles.findOne('abc123', {
    populate: { category: true, tags: true },
})
// article: Article & { category?: Category | null; tags?: Tag[] }

Input Types (create/update)

In input types, relations are always referenced by ID:

Relation TypeInput TypeScript Type
oneToOnenumber | null
manyToOnenumber | null
oneToManynumber[]
manyToManynumber[]

Base Fields

The following fields are automatically added to every generated content type interface:

FieldTypeDescription
idnumberAuto-incremented database ID
documentIdstringStrapi v5 document identifier
createdAtstringISO datetime of creation
updatedAtstringISO datetime of last update

Component types receive only id: number as a base field.

INFO

A readonly __typename field is also added to content type interfaces for nominal typing. This ensures TypeScript treats structurally similar types as distinct. You do not need to use this field directly.

Excluded Fields

The following fields from the Strapi schema are not included in generated types:

Field / AttributeReason
createdByAdmin-only field
updatedByAdmin-only field
publishedAtManaged by Strapi internally
localei18n internal field
localizationsi18n internal field
passwordPrivate attribute
Admin relations (admin::*)Admin panel internals
Non-user plugin relationsPlugin internals (except users-permissions)

TIP

Any attribute marked as private in the Strapi schema is automatically excluded from generated types. The password type is the most common example.

Nullable and Optional Behavior

Nullability depends on the required setting in your Strapi schema and the type category:

Base Types (reading)

  • Required fields are generated as their plain type (e.g., title: string).
  • Non-required fields are generated with | null (e.g., description: string | null).
  • Relations already encode nullability in their type (| null for singular, [] for plural).

Input Types (writing)

  • All fields are optional (?:) because input types are used for both create and partial update operations.
  • Scalar fields use | null to allow clearing a value (e.g., title?: string | null).
  • Relation fields accept IDs: category?: number | null or tags?: number[].
  • Media fields accept IDs: avatar?: number | null or gallery?: number[].
  • Component fields accept objects: seo?: SeoComponentInput | null.
ts
// All input fields are optional for partial updates
interface ArticleInput {
    title?: string | null
    body?: string | null
    category?: number | null // relation by ID
    cover?: number | null // media by ID
    seo?: SeoComponentInput | null // component as object
    tags?: number[] // many relation by IDs
}

Released under the MIT License.