Best headless CMS for Next.js - Typescript support comparison
Introduction to Best Headless CMS for Next.js - TypeScript Support Comparison As TypeScript adoption continues to grow in modern web development, developers are increasingly seeking Headless CMS platforms that integrate seamlessly with TypeScript. TypeScript enhances productivity with features like static typing, type inference, and code autocompletion, while reducing errors in development workflows. When building with Next.js, choosing a CMS with strong TypeScript support and TypeScript resources can significantly streamline development. In this comparison, we analyzed three popular Headless CMS platforms: Strapi, Contentful, and Flotiq. We examined their strengths and limitations, focusing on developer experience, integration complexity, and maintenance concerns. For each of these solutions - we looked through the official documentation and available tutorials and examples, to find out how to make it work with Typescript. Let’s dive into the details! Strapi Strapi is a popular open-source Headless CMS known for its flexibility and self-hosting capabilities. It provides a REST API and optional GraphQL support, making it a versatile choice for developers. Content Types Setup in Strapi First you need to create Content-Types which you plan to use: Once you define the data model, content editors can immediately start their content management work using the generated forms (this is true only for the Strapi Cloud version). If self-hosting, additional steps are required: you must deploy Strapi to a publicly accessible server and configure appropriate access permissions for editors to interact with the system. This means you need to have devops/dbaAdmin engineers available in your organisation. The development team gets access to the generated REST API, which reflects the data model. Specific endpoints allow access to different types of data, which is natural for developers with experience in RESTful APIs: curl localhost:1337/api/products -H "Authorization:bearer $STRAPI\_TOKEN" This request queries the products API for all objects and produces a response similar to this: { "data": \[ { "id": 1, "attributes": { "Name": "Test", "enabled": true, "createdAt": "2023-12-08T08:26:17.828Z", "updatedAt": "2025-01-06T18:58:33.421Z", "publishedAt": "2025-01-06T18:58:33.420Z", "locale": "en", "description": null, "price": null } } \], "meta": { "pagination": { "page": 1, "pageSize": 25, "pageCount": 1, "total": 1 } } } Typescript support in Strapi The standard way of accessing the Strapi API in a Typescript project, as shown in Strapi tutorials (see links [1], [2], [3], [4], [5]), requires manual setup of interfaces for the IDE to understand the data model, so you can utilize the advantages offered by Typescript: Build a blog with Next (React.js) and Strapi Getting Started With Next.js and Strapi 5: beginner's guide Build a Developer Blog with Strapi 5 and Next.js How to build a To-do App using Next.js and Strapi Improve Your Frontend Experience With Strapi Types And TypeScript Once you define these interfaces, the IDE will start suggesting proper attributes and Typescript will verify type correctness: Unfortunately, hand-crafting these interfaces is error-prone, tedious, and not suited for long-term maintenance as any change in the data model will have to be manually adjusted in the interfaces. For those with direct access to the Strapi backend project, you can access type definitions generated by Strapi. Deep down in the file, you can find interfaces for all content types. You can import these files into the client/frontend project, but there are some caveats: The file might need tidying up as it contains many interfaces that will not be used (for internal Strapi types). When you copy the file into the frontend, it will get out of sync with the data model once changes are made to the content type structure. Typescript interfaces are generated in development mode, so someone working on the Strapi backend side of things has to generate them and pass them to you. While this may be a problem in larger, enterprise projects, it's likely not an issue in smaller builds. With that, you can finally utilize Typescript in the client application: Note how the IDE autocompletes the property names available in the Product content type. Unfortunately, some additional concerns arise: The Product content type definition is exported with a rather odd name - ApiProductProduct. With the default setup, the IDE might not be able to properly interpret the types on all attributes (in the screenshot above, the description field is interpreted as any, which is a sort of failover for missing type definition in Typescript). Conclusions Most tutorials and code samples for Strapi
Introduction to Best Headless CMS for Next.js - TypeScript Support Comparison
As TypeScript adoption continues to grow in modern web development, developers are increasingly seeking Headless CMS platforms that integrate seamlessly with TypeScript. TypeScript enhances productivity with features like static typing, type inference, and code autocompletion, while reducing errors in development workflows.
When building with Next.js, choosing a CMS with strong TypeScript support and TypeScript resources can significantly streamline development. In this comparison, we analyzed three popular Headless CMS platforms: Strapi, Contentful, and Flotiq. We examined their strengths and limitations, focusing on developer experience, integration complexity, and maintenance concerns. For each of these solutions - we looked through the official documentation and available tutorials and examples, to find out how to make it work with Typescript.
Let’s dive into the details!
Strapi
Strapi is a popular open-source Headless CMS known for its flexibility and self-hosting capabilities. It provides a REST API and optional GraphQL support, making it a versatile choice for developers.
Content Types Setup in Strapi
First you need to create Content-Types which you plan to use:
Once you define the data model, content editors can immediately start their content management work using the generated forms (this is true only for the Strapi Cloud version). If self-hosting, additional steps are required: you must deploy Strapi to a publicly accessible server and configure appropriate access permissions for editors to interact with the system. This means you need to have devops/dbaAdmin engineers available in your organisation.
The development team gets access to the generated REST API, which reflects the data model. Specific endpoints allow access to different types of data, which is natural for developers with experience in RESTful APIs:
curl localhost:1337/api/products -H "Authorization:bearer $STRAPI\_TOKEN"
This request queries the products API for all objects and produces a response similar to this:
{
"data": \[
{
"id": 1,
"attributes": {
"Name": "Test",
"enabled": true,
"createdAt": "2023-12-08T08:26:17.828Z",
"updatedAt": "2025-01-06T18:58:33.421Z",
"publishedAt": "2025-01-06T18:58:33.420Z",
"locale": "en",
"description": null,
"price": null
}
}
\],
"meta": {
"pagination": {
"page": 1,
"pageSize": 25,
"pageCount": 1,
"total": 1
}
}
}
Typescript support in Strapi
The standard way of accessing the Strapi API in a Typescript project, as shown in Strapi tutorials (see links [1], [2], [3], [4], [5]), requires manual setup of interfaces for the IDE to understand the data model, so you can utilize the advantages offered by Typescript:
-
Build a blog with Next (React.js) and Strapi
-
Getting Started With Next.js and Strapi 5: beginner's guide
-
Build a Developer Blog with Strapi 5 and Next.js
-
How to build a To-do App using Next.js and Strapi
-
Improve Your Frontend Experience With Strapi Types And TypeScript
Once you define these interfaces, the IDE will start suggesting proper attributes and Typescript will verify type correctness:
Unfortunately, hand-crafting these interfaces is error-prone, tedious, and not suited for long-term maintenance as any change in the data model will have to be manually adjusted in the interfaces.
For those with direct access to the Strapi backend project, you can access type definitions generated by Strapi. Deep down in the file, you can find interfaces for all content types. You can import these files into the client/frontend project, but there are some caveats:
- The file might need tidying up as it contains many interfaces that will not be used (for internal Strapi types).
- When you copy the file into the frontend, it will get out of sync with the data model once changes are made to the content type structure.
- Typescript interfaces are generated in development mode, so someone working on the Strapi backend side of things has to generate them and pass them to you. While this may be a problem in larger, enterprise projects, it's likely not an issue in smaller builds.
With that, you can finally utilize Typescript in the client application:
Note how the IDE autocompletes the property names available in the Product content type.
Unfortunately, some additional concerns arise:
- The Product content type definition is exported with a rather odd name - ApiProductProduct.
- With the default setup, the IDE might not be able to properly interpret the types on all attributes (in the screenshot above, the description field is interpreted as any, which is a sort of failover for missing type definition in Typescript).
Conclusions
- Most tutorials and code samples for Strapi do not make full use of Typescript or require manual crafting of interfaces. Creating interfaces by hand is not acceptable for professional projects built with long-term support in mind, but it may be fine for small, pet projects under full control.
- If you can copy generated type definitions from the Strapi backend to client applications, it provides a simple way to get (limited) benefits of Typescript in the client app.
- Manual synchronization of type definitions from the backend will be required whenever a change is made in the data model. This may require a complicated human-based process or automation that may also create problems.
- Type definitions imported in a client app may not provide full support for typing on all object properties, and you have to accept that the *.d.ts files will contain definitions for Strapi internals, as well as the fact that type names may not be very friendly (the ApiProductProduct case).
One more thing: What if you do not have access to the generated type definitions files?
This can easily happen when the project is in maintenance mode and updates are needed without access to the development team. It's also common in large enterprise builds, where separate teams are responsible for maintaining the CMS backend and building client frontend applications.
The Strapi community understands this problem and has come up with solutions based on either OpenAPI or GraphQL (both carry type information), but these solutions are not exactly out-of-the-box or trivial to use.
The OpenAPI approach has been thoroughly described on the Strapi Blog and, although quite complex, it offers a good and standards-based solution to the problem.
However, the GraphQL-based setup (which should be simpler) is only referenced in a Strapi forum thread from 2021:
But since the dotansimha/graphql-code-generator library is hugely popular, this approach is likely to be successful.
Contentful
Contentful is a cloud-hosted Headless CMS, known for its intuitive content editor interface and robust API options (GraphQL and REST).
Content Type Setup in Contentful
In order to compare with Strapi and Flotiq - we start with the same content-type built in Contentful:
Once you define the model, content editors get a graphical interface to enter content:
Developers have access to generic Contentful GraphQL and REST APIs, like this:
It's easy to see that the API described in Contentful docs is not very friendly to use. Strapi and Flotiq have an easier way of accessing content, where API endpoints reflect the content types which are created in your account.
Typescript support in Contentful
Contentful publishes an interesting blog post, highest ranking for "contentful nextjs typescript", How to use TypeScript in your Next.js project. Unfortunately, the post seems mainly SEO-oriented and only briefly mentions how Typescript, Contentful, and Next.js can improve developer experience:
Not very useful.
The official Contentful + next.js starter does not seem to provide any support for Typescript on the content management side of things, either. Furthermore, it uses hardcoded GraphQL queries and content models to fetch the data:
As indicated by the wide use of the any TS type, it does not support any integration with the IDE:
A blog post by Max Schmitt is an improvement, as it shows how adding hand-crafted Typescript interfaces to the code can provide TS support:
The contentful.js v10 announcement promised improved Typescript support, but manually created interfaces can still be seen in the demo code.
Fortunately, when digging deeper into the contentful.js SDK, the Typescript readme file provides a list of 3rd party open-source packages that can help with type generation.
Out of 4 packages, only 2 seem noteworthy.
intercom/contentful-typescript-codegen
Using the intercom/contentful-typescript-codegen package (most starred among the 4 packages listed by Contentful) actually yields promising results, including type information on individual fields:
However, you still need to manually edit the GraphQL query.
To get around this, you can use the contentful.sdk, which should be able to understand the data model in the Contentful account. Unfortunately, it turns out that types generated from the Intercom package do not support the Skeleton types used by the official Contentful SDK.
contentful-userland/cf-content-types-generator
Although the contentful-userland/cf-content-types-generator package seems to be less popular than the Intercom one, it seems to provide better compatibility with the Contentful Typescript SDK.
After running
yarn add cf-content-types-generator
the package is installed and ready to generate types compatible with the current Contentful SDK
yarn run cf-content-types-generator -s $CONTENTFUL_SPACE_ID -t $CONTENTFUL_MANAGEMENT_ACCESS_TOKEN --out @types --response -X
This produces a clean set of type definitions, like this one:
… so much better than what was obtained with Strapi.
With this in place, the IDE is finally ready to work with Typescript and Contentful:
Conclusion for Contentful
Contentful offers partial TypeScript support through third-party tools, but the integration process is cumbersome. The basic setup relies on manually crafted GraphQL queries and and hardcoded interfaces, which limits its appeal for TypeScript-driven workflows. On the other hand, when fully setup with the 3rd party tools - Contentful offers a better experience than Strapi, it also allows content editors to start working immediately after the content types are setup.
Flotiq
Flotiq stands out for its simplicity, developer-first design, and comprehensive tools for content editors and developers.
Content Type Setup in Flotiq
Adding a content type definition in Flotiq is very similar to the process seen in Contentful or Strapi.
When you define the model, as with any other headless CMS, content editors working with Flotiq can start creating content using an easy-to-use form:
Similar to other cloud-hosted systems, like Contentful or Strapi Cloud, Flotiq provides the editors with immediate access to data. Self-hosted systems, in contrast, require a significant (sometimes) effort to deploy and host the system in a way that it’s available to the entire team.
What makes Flotiq stand out, compared to Contentful and Strapi, is the amount of options and easy-to-use tools it gives to the development team:
- API documentation - generated and always up-to-date with your content model
- SDKs - downloadable for several popular languages
- OpenAPI support - for easy integration with other systems
- Scoped APIs - to easily generate subsets of the content API for different purposes
- Hosted webhooks - for quickly adding extensions without worrying about hosting code
- Lifecycle webhooks - synchronous webhooks which let developers modify content before it’s persisted in the CMS
- UI plugins - for extending the look and function of the GUI.
You can find more about these features in the Flotiq developer documentation.
Typescript integration in Flotiq
Flotiq’s native support for OpenAPI makes it easy to generate client code for different languages - Java, Python, Dart (for Flutter), Typescript and several more. The Typescript SDK has received much love in the recent months and provides the easiest and most comprehensive method of accessing CMS content among all compared systems.
Install the flotiq/flotiq-codegen-ts sdk
npx flotiq-codegen-ts generate
During the installation you will be asked to provide your Flotiq API key and a few seconds later - the types will be generated. The resulting integration is, by far, the easiest to use and provides full support for types on all attributes in your content model:
This level of integration provides developers with the best most convenient access to the data stored in their CMS.
Conclusions for Flotiq
- Flotiq’s SDK for Typescript is easier to configure and install than what Contentful or Strapi has to offer
- Flotiq-codegen-ts supports information about types of attributes, return types on API methods as well as field descriptions (same that content editors see in their forms)
- Flotiq API is reflecting the content types defined in the system (like Strapi) and does not force developers to learn any system-specific content API (which is what Contentful does)
- Ease of use and Typescript support make Flotiq a great choice for Next.js projects.
- Flotiq TypeScript resources and integration information is available here: https://flotiq.com/docs/Deep-Dives/nextjs-react-typescript-openapi/#flotiq-codegen-ts
Final Thoughts
Choosing the right Headless CMS for your Next.js project depends on your priorities. Here’s a quick summary of TypeScript CMS support with our ranging, from most compatible to lowest compatible:
1. Flotiq
- Provides native TypeScript SDK generation with flotiq-codegen-ts.
- Fully typed models ensure complete type safety and IDE autocompletion.
- Automatically synchronizes with content model changes, requiring no additional configuration.
- Offers the most streamlined and developer-friendly experience, especially for large or dynamic projects.
- Is a fully managed product, with a generous free tier.
2. Contentful
- Lacks native TypeScript integration; relies on third-party tools like contentful-typescript-codegen or cf-content-types-generator.
- Generated types often require manual adjustments to work seamlessly with the SDK.
- If opting for GraphQL-based approach - it may require hardcoding of queries, reducing flexibility.
- Has a fully managed free tier (very limited), but the paid tiers have a steep price point.
3. Strapi
- Requires manual creation of TypeScript interfaces or syncing generated definitions from the backend.
- Limited type coverage; some attributes default to any.
- Synchronization issues arise when content models change, increasing maintenance overhead.
- Best suited for small projects or setups where developers have full backend access.
- Managed offering does not include a free tier, but it can be self-hosted, if you have the expertise.
What's Your Reaction?