strapi2front generates complete TypeScript type definitions from your Strapi content types, providing full type safety for your frontend application.
What Gets Generated
When you run npx strapi2front sync, the generator creates:
Collection Types TypeScript interfaces with full type safety for all your collection types
Single Types Interfaces for single types like homepage, settings, etc.
Components Reusable component interfaces referenced by your content types
Utility Types Helper types for media, pagination, responses, and more
Generated File Structure
src/strapi/
├── collections/
│ ├── article.ts
│ ├── category.ts
│ └── author.ts
├── components/
│ ├── seo.ts
│ └── content-block.ts
└── utils.ts
Collection Type Example
For a Blog Article collection type in Strapi, the generator creates:
article.ts
Single Type Example
/**
* Article
* Blog article with author and categories
* Generated by strapi2front
*/
import type { StrapiBaseEntity , StrapiMedia , BlocksContent } from '../utils' ;
import type { Author } from './author' ;
import type { Category } from './category' ;
import type { Seo } from '../components/seo' ;
export interface Article extends StrapiBaseEntity {
/** Required, Min length: 1, Max length: 255 */
title : string ;
slug : string ;
/** Rich text content (Strapi v5) */
content : BlocksContent ;
excerpt ?: string ;
coverImage : StrapiMedia | null ;
/** Published status */
status : 'draft' | 'published' | 'archived' ;
/** View count */
views : number ;
/** Reading time in minutes */
readingTime ?: number ;
/** Article author */
author : Author | null ;
/** Article categories */
categories : Category [];
/** SEO metadata */
seo ?: Seo | null ;
}
export interface ArticleFilters {
id ?: number | { $eq ?: number ; $ne ?: number ; $in ?: number []; $notIn ?: number [] };
documentId ?: string | { $eq ?: string ; $ne ?: string };
title ?: string | { $eq ?: string ; $contains ?: string };
status ?: 'draft' | 'published' | 'archived' ;
createdAt ?: string | { $eq ?: string ; $gt ?: string ; $gte ?: string ; $lt ?: string ; $lte ?: string };
publishedAt ?: string | null | { $eq ?: string ; $ne ?: string ; $null ?: boolean };
$and ?: ArticleFilters [];
$or ?: ArticleFilters [];
$not ?: ArticleFilters ;
}
export interface ArticleSort {
field : keyof Article ;
order : 'asc' | 'desc' ;
}
Attribute Type Mappings
strapi2front maps Strapi field types to TypeScript types:
Basic Types
Advanced Types
Strapi Type TypeScript Type Example stringstringtitle: stringtextstringdescription: stringrichtextstringcontent: string (v4)blocksBlocksContentcontent: BlocksContent (v5)emailstringemail: stringpasswordstringpassword: stringuidstringslug: stringintegernumberviews: numberbigintegernumberlargeNumber: numberfloatnumberrating: numberdecimalnumberprice: numberbooleanbooleanfeatured: booleandatestringpublishDate: stringdatetimestringpublishedAt: stringtimestringeventTime: stringjsonunknownmetadata: unknown
Strapi Type TypeScript Type Example enumerationUnion of literals status: 'draft' | 'published'media (single)StrapiMedia | nullcover: StrapiMedia | nullmedia (multiple)StrapiMedia[]gallery: StrapiMedia[]relation (to-one)RelatedType | nullauthor: Author | nullrelation (to-many)RelatedType[]tags: Tag[]componentComponentType | nullseo: Seo | nullcomponent (repeatable)ComponentType[]sections: Section[]dynamiczone(CompA | CompB)[]content: (TextBlock | ImageBlock)[]
Utility Types
The generator also creates utility types in utils.ts:
Base interface that all content types extend. Contains system fields. export interface StrapiBaseEntity {
id : number ;
documentId : string ; // New in v5
createdAt : string ;
updatedAt : string ;
publishedAt : string | null ;
}
BlocksContent (Strapi v5)
Rich text blocks for Strapi v5’s new blocks editor. For full type support and rendering, install @strapi/blocks-react-renderer then re-run npx strapi2front sync.
// With @strapi/blocks-react-renderer installed
export type { BlocksContent } from '@strapi/blocks-react-renderer' ;
// Without package (fallback)
export type BlocksContent = unknown [];
StrapiResponse & StrapiListResponse
Wrapper types for API responses with metadata. export interface StrapiResponse < T > {
data : T ;
meta : {
pagination ?: StrapiPagination ;
};
}
export interface StrapiListResponse < T > {
data : T [];
meta : {
pagination : StrapiPagination ;
};
}
export interface StrapiPagination {
page : number ;
pageSize : number ;
pageCount : number ;
total : number ;
}
Using Generated Types
Import Types in Your Components
import type { Article } from '@/strapi/collections/article' ;
import { articleService } from '@/strapi/collections/article/service' ;
const { slug } = Astro . params ;
const article = await articleService . findBySlug ( slug );
// TypeScript knows the exact shape of 'article'
const title : string = article . title ;
const coverUrl : string | null = article . coverImage ?. url ?? null ;
Type-Safe Data Fetching
import type { Article , ArticleFilters } from '@/strapi/collections/article' ;
import { articleService } from '@/strapi/collections/article/service' ;
export async function getFeaturedArticles () : Promise < Article []> {
const filters : ArticleFilters = {
status: 'published' ,
featured: true ,
};
const { data } = await articleService . findMany ({
filters ,
sort: [ '-publishedAt' ],
pagination: { pageSize: 6 },
});
return data ;
}
Working with Relations
components/ArticleCard.tsx
import type { Article } from '@/strapi/collections/article' ;
interface Props {
article : Article ;
}
export function ArticleCard ({ article } : Props ) {
// TypeScript knows author is Author | null
const authorName = article . author ?. name ?? 'Anonymous' ;
// TypeScript knows categories is Category[]
const categoryNames = article . categories . map ( cat => cat . name );
return (
< div >
< h2 >{article. title } </ h2 >
< p > By { authorName } </ p >
< div >{categoryNames.join( ', ' )}</div>
</div>
);
}
Field Validation Attributes
The generator includes validation constraints from your Strapi schema as JSDoc comments:
export interface Product extends StrapiBaseEntity {
/** Required, Min length: 3, Max length: 100 */
name : string ;
/** Min: 0, Max: 999999 */
price : number ;
/** Required, Min length: 10 */
description : string ;
}
Dynamic Zones
For dynamic zones (flexible content areas), the generator creates discriminated unions:
import type { TextBlock } from '../components/text-block' ;
import type { ImageBlock } from '../components/image-block' ;
import type { VideoBlock } from '../components/video-block' ;
export interface Page extends StrapiBaseEntity {
title : string ;
// Dynamic zone with multiple component types
content : ( TextBlock | ImageBlock | VideoBlock )[];
}
You can use TypeScript’s type narrowing:
function renderContent ( blocks : ( TextBlock | ImageBlock | VideoBlock )[]) {
return blocks . map ( block => {
// Check the __component field to narrow the type
if ( block . __component === 'content.text-block' ) {
// TypeScript knows this is TextBlock
return < TextRenderer text ={ block . text } />;
}
if ( block . __component === 'content.image-block' ) {
// TypeScript knows this is ImageBlock
return < ImageRenderer image ={ block . image } />;
}
// etc...
});
}
Types are automatically regenerated when you run npx strapi2front sync. Make sure to sync after changing your Strapi schema.
Next Steps