---
title: "Headless CMS - Strapi Evaluation Notes"
description: "Practical notes on evaluating and adopting the headless CMS Strapi, covering installation, Swagger integration, API permission configuration, image response troubleshooting, and feature walkthroughs."
canonical_url: "https://blog.markkulab.net/en/post/headless-cms-note"
author: "Mark Ku"
author_url: "https://blog.markkulab.net/en/author/mark-ku"
site: "Mark Ku's Tech Notes"
date_published: "2022-09-08 01:01:01 +0800"
category: "Infra"
tags: ["headless", "cms", "strapi", "swagger", "node.js", "api", "content management"]
language: "en"
license: "CC BY 4.0"
license_url: "https://creativecommons.org/licenses/by/4.0/"
attribution: "when reusing or quoting, credit the author and link back to the original"
---

# Headless CMS - Strapi Evaluation Notes

## The Problem to Solve

My manager asked me to evaluate a CMS solution so the product team could maintain an FAQ and product knowledge base. Backend development capacity was limited, so the goal was to find something with a friendly UI that could quickly generate admin maintenance pages and frontend APIs — reducing the burden on frontend developers who would consume those APIs.

## Why Strapi?

![Headless CMS feature comparison with Markdown and article editor examples](https://blog.markkulab.net/content/markku/posts/headless-cms-note/images/ONXbTAJ.jpg)

After trialing several mainstream CMS options, I landed on Strapi for the following reasons. It's flexible and lightweight, well-suited for long-term enterprise use, and can be repurposed for other needs down the road.

- **End users**: friendly UI, draggable field layout.
- **Admins**: field validation, permission management, workflow control.
- **Developers**: open source, developer-friendly API integration, built-in Swagger docs, extensibility via plugin marketplace, rich endpoints, and the project itself is built with React and Node.js — very approachable for frontend developers.

## How It Works

Strapi uses a friendly admin UI to generate code from configuration.

![Windows File Explorer showing Strapi project API folders](https://blog.markkulab.net/content/markku/posts/headless-cms-note/images/M6RfjZ8.png)

## Installation Constraints

- Node version: `>=10.16.0 <=14.x.x` (use nvm to manage multiple Node versions)
- Cloud-hosted version is paid; self-hosted is open source and permanently free

## [Install Strapi](https://docs.strapi.io/developer-docs/latest/getting-started/quick-start.html#_1-install-strapi-and-create-a-new-project)

```
npx create-strapi-app@latest my-project --quickstart
```

## Install [Swagger](https://docs.strapi.io/developer-docs/latest/plugins/documentation.html#installation)

```
cd my-project
npm run strapi install documentation
n﻿pm run build // 裝完一定要按 build 才會跑出按鈕
```

## Common Issues After Installation

## API Doesn't Return Images

By default, Strapi API responses don't include image fields. You need to add a `populate` query parameter to explicitly request the image fields you want returned.

![Strapi API endpoint parameters with populate set to image1](https://blog.markkulab.net/content/markku/posts/headless-cms-note/images/6gfNF29.png)
![Swagger UI demonstrating Strapi API image field population](https://blog.markkulab.net/content/markku/posts/headless-cms-note/images/eF34HEH.png)

## API Permissions

By default, all API access requires a token. If you don't need authentication for a particular collection, go to Settings > USERS & PERMISSIONS PLUGIN > Roles, find your collection, and grant `find` and `findOne` permissions.

![Strapi Public role permissions for Article collection with findOne and update](https://blog.markkulab.net/content/markku/posts/headless-cms-note/images/ovdumL9.png)

## Rich Text Images Can't Be Previewed in Real Time

`.env`

```
HOST=0.0.0.0
PORT=1337
APP_KEYS=p285lmxQN6bZ90Dh870eIg==,twHIadFFnSgVKyGgzcpnIQ==,jgn83CaVHIPPnpSqsZPWGw==,s2lTboydFrhkPRHJp4omQw==
API_TOKEN_SALT=9LGnsz1zt4UpaKfCCQxEZQ==
ADMIN_JWT_SECRET=l7gG6CTUeK0502ns9FAKkw==
JWT_SECRET=mJg/1OqVkOeCiZcxiQfG5w==
WEBSITE=http://127.0.0.1:1337/
```

`config/server.js`

```
module.exports = ({ env }) => ({
  host: env('HOST', '0.0.0.0'),
  port: env.int('PORT', 1337),
  ------
  url: env('WEBSITE', 'http://127.0.0.1'), 
  ------
  app: {
    keys: env.array('APP_KEYS'),
  },  
});
```

## Data Backup

- **Database**: defaults to SQLite, located at `.tmp/data.db` (also supports MySQL and MongoDB).
- **Static files**: uploaded files are stored in `/public/uploads`.

## Feature Walkthrough

### Dynamically Generated Admin Panel

![Strapi Content-Type Builder defining Article fields: title, content, images](https://blog.markkulab.net/content/markku/posts/headless-cms-note/images/0f0BjwY.png)

### Multi-image Upload

![Strapi Content-Type Builder editing 'images' field, multiple media option](https://blog.markkulab.net/content/markku/posts/headless-cms-note/images/jXmzMbk.png)

### Upload Format Restrictions

![Strapi Content-Type Builder editing Article, configuring allowed media types](https://blog.markkulab.net/content/markku/posts/headless-cms-note/images/PunbK7f.png)

## Data Entry Screen

![Strapi admin panel creating an article entry with image upload](https://blog.markkulab.net/content/markku/posts/headless-cms-note/images/lLcJ5rp.png)

### Dynamic Layout Adjustment

![Strapi admin panel configuring article content type displayed fields](https://blog.markkulab.net/content/markku/posts/headless-cms-note/images/hGjLnld.png)

### Webhooks

![Strapi UI showing the Create a webhook form with event options](https://blog.markkulab.net/content/markku/posts/headless-cms-note/images/DAuWE1D.png)

### Roles

![Strapi admin panel displaying user roles, descriptions, and assigned users](https://blog.markkulab.net/content/markku/posts/headless-cms-note/images/i1fy4kz.png)

## Permissions

![Strapi UI for editing author role permissions](https://blog.markkulab.net/content/markku/posts/headless-cms-note/images/gEvb3eh.png)

## Related Links

[ckeditor](https://market.strapi.io/plugins/@_sh-strapi-plugin-ckeditor)
[strapi provider upload ftp v2](https://www.npmjs.com/package/strapi-provider-upload-ftp-v2)

---

## About this article and its author

Originally published on [Mark Ku's Tech Notes](https://blog.markkulab.net/en/post/headless-cms-note)

License: [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) — when reusing or quoting, credit the author and link back to the original

### About the author

**[Mark Ku](https://blog.markkulab.net/en/author/mark-ku)** — Software Solution Provider

- 10+ years senior software engineer, now an AI Builder
- Focused on large-platform architecture — North-American e-commerce, AI SaaS subscription billing
- Combining AI Agents and automation to build evolvable product foundations

### Free tools built by the author

All of these are free to use:

- [Free PDF Sign Tool](https://blog.markkulab.net/en/tools/pdf-sign): Online PDF sign tool — draw, type, or upload a signature, then drag, resize, and download. Everything runs in your browser; nothing is uploaded.
- [VS Code Refactory](https://blog.markkulab.net/en/tools/refactory): Refactory is a VS Code refactoring extension: 34 actions plus a 37-rule code-smell inspection layer with a Code Health dashboard, across 18 languages, backed by 534 tests. It learns your repo's conventions: where interfaces live, where DI is registered, whether 'use client' belongs. It ranks files by git churn × complexity so you know what to fix first, and hands any smell to the Claude Code already on your machine. Free to use, and your source never leaves your computer.
- [DB-Kit Database Manager](https://blog.markkulab.net/en/tools/db-kit): DB-Kit is a lightweight, cross-platform database manager built with Tauri + Rust + React. Manage MySQL, MariaDB, PostgreSQL, SQL Server, Oracle, SQLite, MongoDB, Redis, Kafka, Elasticsearch and RabbitMQ from one consistent interface: passwords encrypted in the OS keychain, SSH tunnels, full CRUD, a visual query builder, stacked multi-statement result sets, cross-connection data transfer and compare/sync, Excel / CSV import & export, visualized execution plans, ER diagrams, scheduled backups, SQL stress testing with p50–p99 latency percentiles, a 15-rule SQL review engine, Kafka message browsing with monitoring & alerts, a bilingual UI (Traditional Chinese / English), a built-in AI assistant (natural-language SQL, AI review and tuning advice) and the dbk CLI. Free and open source (MIT), with installers for Windows, macOS and Linux.
- [VS Code Super Mermaid](https://blog.markkulab.net/en/tools/super-mermaid): Super Mermaid is a VS Code extension for beautiful Mermaid diagrams out of the box: auto-colored live preview, mouse pan & zoom, high-res PNG / SVG export, 21 templates and multiple themes. Free and open source (MIT).
- [React Super Mermaid](https://blog.markkulab.net/en/tools/react-super-mermaid): react-super-mermaid is an open-source React component library: render beautiful Mermaid diagrams with a single <MermaidViewer>, with built-in colorful / sketch themes, pan & zoom, in-diagram search, and high-res SVG / PNG export. Lightweight, SSR-safe, fully typed. Free and open source (MIT).
- [Jira / Confluence Super Mermaid](https://blog.markkulab.net/en/tools/jira-super-mermaid): An Atlassian Forge app: write Mermaid syntax directly inside a Jira issue or a Confluence page and get flowcharts, sequence diagrams, state machines and Gantt charts. 11 diagram types, SVG / PNG export, light and dark themes, full CJK support. Runs on Atlassian: your diagrams live in your own site and the app calls no third-party service. Free, coming soon to the Atlassian Marketplace.
- [Mermaid Live Preview](https://blog.markkulab.net/en/tools/mermaid-preview): Write Mermaid in your browser, see it render instantly, and share the whole diagram as a single link. No sign-up, nothing uploaded to a server, and mermaid.live share links work as-is.
- [React Intl Phone Number](https://blog.markkulab.net/en/tools/react-intl-phone-number): react-intl-phone-number is an open-source React component: framework-agnostic and antd-free, with E.164 in/out, a searchable flag / country-code dropdown, configurable validation levels (strict / mobile-strict / loose), themeable CSS, and i18n — phone logic powered by google-libphonenumber. Lightweight and fully typed. Free and open source (MIT).
- [Uptime Kuma Cluster](https://blog.markkulab.net/en/tools/uptime-kuma-cluster): Turn single-node Uptime Kuma into a highly available cluster: OpenResty + Lua smart load balancing, shared MariaDB state, health checks and automatic failover, plus cluster-management REST APIs. One Docker Compose command to start. Free and open source (MIT).
- [Special Education](https://blog.markkulab.net/en/education): Learning materials crafted for special education students

### Daily podcasts

- [Mark's Tech Insights — Daily AI News](https://blog.markkulab.net/en/category/tech-news): Daily curated AI and tech trends. Catch the latest developments via audio summaries — covering AI applications, software architecture, DevOps, and engineering practice. — RSS: https://blog.markkulab.net/feed.xml
- [AI股市蝦聊](https://blog.markkulab.net/en/category/ai-stock-chat): Every trading day, an AI-analyzed take on the Taiwan stock market, delivered as a two-host conversation covering the session and the next-day outlook. — RSS: https://blog.markkulab.net/ai-stock-chat/feed.xml
- [開源好物週報](https://blog.markkulab.net/en/category/open-source-weekly): A weekly two-host pick of free open-source tools surfaced from real Hacker News, GitHub, and Reddit buzz — what pain they solve and the fastest way to get started. — RSS: https://blog.markkulab.net/open-source-weekly/feed.xml

### Newsletter

[Subscribe to the newsletter](https://blog.markkulab.net/en/subscribe) — Be the first to know about new posts. No spam, unsubscribe anytime.
