Strapi
Open-source headless CMS built with Node.js/TypeScript. Provides REST/GraphQL APIs with high customizability and developer-friendly features.
CMS
Strapi
Overview
Strapi is an open-source headless CMS designed for modern web application development.
Details
Strapi is a content management system that adopts a headless (decoupled) architecture, separating frontend and backend. Built on Node.js and Koa.js, it provides developers with a flexible API development environment. It supports both REST and GraphQL APIs and can be combined with any frontend technology (React, Vue.js, Angular, Next.js, etc.). The admin panel is intuitive and user-friendly, allowing visual management of content types, user management, permission settings, and plugin management. It supports PostgreSQL, MySQL, SQLite, and MariaDB, and offers Docker deployment and cloud deployment to AWS/GCP/Azure. The enterprise version provides advanced permission management, RBAC, SSO, and workflow features.
Pros and Cons
Pros
- Headless Design: Rich choice of frontends enables flexible development
- REST and GraphQL: Supports both API types
- Self-hosted: Complete data control on-premises
- Intuitive Admin Panel: Easy-to-use UI even for non-technical users
- Rich Plugins: Easy functionality extension
- Open Source: Free to use with active community
- Multi-language Support: Built-in internationalization features
Cons
- Self-management: Infrastructure management and maintenance required
- Learning Curve: Understanding headless design is necessary
- Resource Consumption: Server resources as Node.js application
- Complex Configuration: Technical knowledge required for advanced customization
- Scalability: Additional configuration needed for large-scale traffic
Key Links
- Strapi Official Site
- Strapi Documentation
- Strapi GitHub Repository
- Strapi Blog
- Strapi Community
- Strapi Market
Usage Examples
Installation and Initial Setup
# Create Strapi project
npx create-strapi-app@latest my-project --quickstart
# Start development server
npm run develop
# Access admin panel: http://localhost:1337/admin
Content Type Definition
// config/api/article/models/article.settings.json
{
"kind": "collectionType",
"collectionName": "articles",
"info": {
"name": "article"
},
"options": {
"increments": true,
"timestamps": true
},
"attributes": {
"title": {
"type": "string",
"required": true
},
"content": {
"type": "richtext"
},
"author": {
"type": "relation",
"relation": "manyToOne",
"target": "plugin::users-permissions.user"
},
"published_at": {
"type": "datetime"
},
"slug": {
"type": "uid",
"targetField": "title"
}
}
}
API Usage
// Data fetching with REST API
const response = await fetch('http://localhost:1337/api/articles');
const data = await response.json();
// Data fetching with GraphQL
const ARTICLES_QUERY = `
query GetArticles {
articles {
data {
id
attributes {
title
content
published_at
author {
data {
attributes {
username
}
}
}
}
}
}
}
`;
const response = await fetch('http://localhost:1337/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ query: ARTICLES_QUERY }),
});
Custom API Endpoint
// api/article/controllers/article.js
'use strict';
const { createCoreController } = require('@strapi/strapi').factories;
module.exports = createCoreController('api::article.article', ({ strapi }) => ({
// Custom endpoint
async findPublished(ctx) {
const entries = await strapi.entityService.findMany('api::article.article', {
filters: {
published_at: {
$notNull: true,
},
},
populate: {
author: true,
},
});
return entries;
},
// Get popular articles
async findPopular(ctx) {
const entries = await strapi.entityService.findMany('api::article.article', {
sort: { views: 'desc' },
limit: 10,
});
return entries;
}
}));
Plugin Creation
// plugins/custom-plugin/server/controllers/my-controller.js
'use strict';
module.exports = {
index(ctx) {
ctx.body = strapi
.plugin('custom-plugin')
.service('myService')
.getWelcomeMessage();
},
};
// plugins/custom-plugin/server/services/my-service.js
'use strict';
module.exports = {
getWelcomeMessage() {
return 'Welcome to Strapi 🚀';
},
};
Docker Configuration
# Dockerfile
FROM node:18-alpine
WORKDIR /opt/app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
EXPOSE 1337
CMD ["npm", "start"]
# docker-compose.yml
version: '3'
services:
strapi:
container_name: strapi
build: .
image: strapi:latest
restart: unless-stopped
env_file: .env
environment:
DATABASE_CLIENT: postgres
DATABASE_HOST: strapiDB
DATABASE_PORT: 5432
DATABASE_NAME: strapi
DATABASE_USERNAME: strapi
DATABASE_PASSWORD: strapi
ports:
- '1337:1337'
networks:
- strapi
depends_on:
- strapiDB
strapiDB:
container_name: strapiDB
platform: linux/amd64
restart: unless-stopped
env_file: .env
image: postgres:14.5-alpine
environment:
POSTGRES_USER: strapi
POSTGRES_PASSWORD: strapi
POSTGRES_DB: strapi
ports:
- '5432:5432'
networks:
- strapi
networks:
strapi:
name: Strapi
driver: bridge