Skip to main content
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
 * 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:
Strapi TypeTypeScript TypeExample
stringstringtitle: string
textstringdescription: string
richtextstringcontent: string (v4)
blocksBlocksContentcontent: BlocksContent (v5)
emailstringemail: string
passwordstringpassword: string
uidstringslug: string
integernumberviews: number
bigintegernumberlargeNumber: number
floatnumberrating: number
decimalnumberprice: number
booleanbooleanfeatured: boolean
datestringpublishDate: string
datetimestringpublishedAt: string
timestringeventTime: string
jsonunknownmetadata: unknown

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;
}
Type definition for media files (images, videos, etc.)
export interface StrapiMedia {
  id: number;
  documentId: string;  // v5 only
  name: string;
  alternativeText: string | null;
  caption: string | null;
  width: number;
  height: number;
  formats: {
    thumbnail?: StrapiMediaFormat;
    small?: StrapiMediaFormat;
    medium?: StrapiMediaFormat;
    large?: StrapiMediaFormat;
  } | null;
  hash: string;
  ext: string;
  mime: string;
  size: number;
  url: string;
  previewUrl: string | null;
  provider: string;
  createdAt: string;
  updatedAt: string;
}

export interface StrapiMediaFormat {
  name: string;
  hash: string;
  ext: string;
  mime: string;
  width: number;
  height: number;
  size: number;
  url: string;
}
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[];
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

pages/blog/[slug].astro
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

utils/blog.ts
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