Strapi + Next.js Full Stack
Headless CMS with Strapi backend and Next.js frontend.
Overview
Strapi is an open-source headless Content Management System (CMS) that provides a flexible, developer-first approach to content management. Built entirely in JavaScript, Strapi separates content management from presentation, offering both RESTful and GraphQL APIs out of the box. This architecture allows developers to manage content through Strapi's intuitive admin panel while delivering that content to any frontend framework or platform.
This stack combines Strapi's powerful content management capabilities with Next.js, React's production-ready framework that excels at both static site generation and server-side rendering. PostgreSQL serves as the robust relational database for Strapi's content storage, while Redis provides high-performance caching and session management. NGINX acts as the reverse proxy, handling SSL termination, load balancing, and routing between the frontend and backend services. Together, these components create a modern JAMstack architecture that can scale from startup MVPs to enterprise-grade applications.
Development teams building content-heavy applications, marketing websites, e-commerce platforms, or multi-channel digital experiences will find this stack particularly valuable. The headless approach means content creators can work independently in Strapi while developers have complete freedom to build custom frontends in Next.js. This separation enables faster development cycles, better performance through static generation, and the flexibility to deliver content to web, mobile, and IoT applications from a single source.
Key Features
- Visual content-type builder in Strapi for creating custom data models without code
- Next.js static site generation (SSG) and server-side rendering (SSR) for optimal performance
- RESTful and GraphQL APIs automatically generated from Strapi content models
- Role-based access control with customizable permissions for content editors
- PostgreSQL JSONB support for flexible content structures alongside relational data
- Redis-powered session storage and API response caching
- Strapi's plugin ecosystem for extending functionality (SEO, internationalization, media)
- Next.js incremental static regeneration for updating static content without full rebuilds
Common Use Cases
- 1Marketing websites requiring frequent content updates by non-technical team members
- 2E-commerce platforms needing product catalogs with complex attributes and relationships
- 3Multi-brand companies delivering content to multiple websites from a centralized CMS
- 4SaaS applications requiring user-generated content management and admin dashboards
- 5News and publishing platforms with editorial workflows and content scheduling
- 6Mobile app backends providing structured content through Strapi's REST/GraphQL APIs
- 7International websites leveraging Strapi's i18n plugin for multi-language content management
Prerequisites
- Docker and Docker Compose installed with at least 3GB available RAM
- Ports 80, 443, 1337, and 3000 available on the host system
- Basic understanding of React/Next.js development for frontend customization
- Familiarity with REST APIs or GraphQL for connecting frontend to Strapi backend
- Node.js development environment for building custom Strapi plugins if needed
- SSL certificates for production deployment with NGINX HTTPS configuration
For development & testing. Review security settings, change default credentials, and test thoroughly before production use. See Terms
docker-compose.yml
docker-compose.yml
1services: 2 strapi: 3 image: strapi/strapi:latest4 ports: 5 - "1337:1337"6 environment: 7 DATABASE_CLIENT: postgres8 DATABASE_HOST: postgres9 DATABASE_PORT: 543210 DATABASE_NAME: ${POSTGRES_DB}11 DATABASE_USERNAME: ${POSTGRES_USER}12 DATABASE_PASSWORD: ${POSTGRES_PASSWORD}13 JWT_SECRET: ${JWT_SECRET}14 ADMIN_JWT_SECRET: ${ADMIN_JWT_SECRET}15 APP_KEYS: ${APP_KEYS}16 volumes: 17 - strapi_app:/srv/app18 depends_on: 19 postgres: 20 condition: service_healthy21 networks: 22 - strapi-net23 restart: unless-stopped2425 nextjs: 26 build: 27 context: ./frontend28 dockerfile: Dockerfile29 ports: 30 - "3000:3000"31 environment: 32 STRAPI_URL: http://strapi:133733 depends_on: 34 - strapi35 networks: 36 - strapi-net37 restart: unless-stopped3839 postgres: 40 image: postgres:16-alpine41 environment: 42 POSTGRES_USER: ${POSTGRES_USER}43 POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}44 POSTGRES_DB: ${POSTGRES_DB}45 volumes: 46 - postgres_data:/var/lib/postgresql/data47 healthcheck: 48 test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]49 interval: 10s50 timeout: 5s51 retries: 552 networks: 53 - strapi-net54 restart: unless-stopped5556 redis: 57 image: redis:7-alpine58 volumes: 59 - redis_data:/data60 networks: 61 - strapi-net62 restart: unless-stopped6364 nginx: 65 image: nginx:alpine66 ports: 67 - "80:80"68 - "443:443"69 volumes: 70 - ./nginx.conf:/etc/nginx/nginx.conf:ro71 depends_on: 72 - strapi73 - nextjs74 networks: 75 - strapi-net76 restart: unless-stopped7778volumes: 79 strapi_app: 80 postgres_data: 81 redis_data: 8283networks: 84 strapi-net: 85 driver: bridge.env Template
.env
1# PostgreSQL2POSTGRES_USER=strapi3POSTGRES_PASSWORD=secure_postgres_password4POSTGRES_DB=strapi56# Strapi Secrets7JWT_SECRET=$(openssl rand -base64 32)8ADMIN_JWT_SECRET=$(openssl rand -base64 32)9APP_KEYS=$(openssl rand -base64 32),$(openssl rand -base64 32)Usage Notes
- 1Strapi Admin at http://localhost:1337/admin
- 2Next.js frontend at http://localhost:3000
- 3Create Dockerfile for Next.js frontend
- 4Configure nginx.conf for production routing
Individual Services(5 services)
Copy individual services to mix and match with your existing compose files.
strapi
strapi:
image: strapi/strapi:latest
ports:
- "1337:1337"
environment:
DATABASE_CLIENT: postgres
DATABASE_HOST: postgres
DATABASE_PORT: 5432
DATABASE_NAME: ${POSTGRES_DB}
DATABASE_USERNAME: ${POSTGRES_USER}
DATABASE_PASSWORD: ${POSTGRES_PASSWORD}
JWT_SECRET: ${JWT_SECRET}
ADMIN_JWT_SECRET: ${ADMIN_JWT_SECRET}
APP_KEYS: ${APP_KEYS}
volumes:
- strapi_app:/srv/app
depends_on:
postgres:
condition: service_healthy
networks:
- strapi-net
restart: unless-stopped
nextjs
nextjs:
build:
context: ./frontend
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
STRAPI_URL: http://strapi:1337
depends_on:
- strapi
networks:
- strapi-net
restart: unless-stopped
postgres
postgres:
image: postgres:16-alpine
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test:
- CMD-SHELL
- pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}
interval: 10s
timeout: 5s
retries: 5
networks:
- strapi-net
restart: unless-stopped
redis
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
networks:
- strapi-net
restart: unless-stopped
nginx
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- strapi
- nextjs
networks:
- strapi-net
restart: unless-stopped
Quick Start
terminal
1# 1. Create the compose file2cat > docker-compose.yml << 'EOF'3services:4 strapi:5 image: strapi/strapi:latest6 ports:7 - "1337:1337"8 environment:9 DATABASE_CLIENT: postgres10 DATABASE_HOST: postgres11 DATABASE_PORT: 543212 DATABASE_NAME: ${POSTGRES_DB}13 DATABASE_USERNAME: ${POSTGRES_USER}14 DATABASE_PASSWORD: ${POSTGRES_PASSWORD}15 JWT_SECRET: ${JWT_SECRET}16 ADMIN_JWT_SECRET: ${ADMIN_JWT_SECRET}17 APP_KEYS: ${APP_KEYS}18 volumes:19 - strapi_app:/srv/app20 depends_on:21 postgres:22 condition: service_healthy23 networks:24 - strapi-net25 restart: unless-stopped2627 nextjs:28 build:29 context: ./frontend30 dockerfile: Dockerfile31 ports:32 - "3000:3000"33 environment:34 STRAPI_URL: http://strapi:133735 depends_on:36 - strapi37 networks:38 - strapi-net39 restart: unless-stopped4041 postgres:42 image: postgres:16-alpine43 environment:44 POSTGRES_USER: ${POSTGRES_USER}45 POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}46 POSTGRES_DB: ${POSTGRES_DB}47 volumes:48 - postgres_data:/var/lib/postgresql/data49 healthcheck:50 test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]51 interval: 10s52 timeout: 5s53 retries: 554 networks:55 - strapi-net56 restart: unless-stopped5758 redis:59 image: redis:7-alpine60 volumes:61 - redis_data:/data62 networks:63 - strapi-net64 restart: unless-stopped6566 nginx:67 image: nginx:alpine68 ports:69 - "80:80"70 - "443:443"71 volumes:72 - ./nginx.conf:/etc/nginx/nginx.conf:ro73 depends_on:74 - strapi75 - nextjs76 networks:77 - strapi-net78 restart: unless-stopped7980volumes:81 strapi_app:82 postgres_data:83 redis_data:8485networks:86 strapi-net:87 driver: bridge88EOF8990# 2. Create the .env file91cat > .env << 'EOF'92# PostgreSQL93POSTGRES_USER=strapi94POSTGRES_PASSWORD=secure_postgres_password95POSTGRES_DB=strapi9697# Strapi Secrets98JWT_SECRET=$(openssl rand -base64 32)99ADMIN_JWT_SECRET=$(openssl rand -base64 32)100APP_KEYS=$(openssl rand -base64 32),$(openssl rand -base64 32)101EOF102103# 3. Start the services104docker compose up -d105106# 4. View logs107docker compose logs -fOne-Liner
Run this command to download and set up the recipe in one step:
terminal
1curl -fsSL https://docker.recipes/api/recipes/strapi-nextjs-stack/run | bashTroubleshooting
- Strapi 'Database connection refused': Ensure PostgreSQL health check passes before Strapi starts using depends_on condition
- Next.js build failing with 'STRAPI_URL not found': Verify environment variable points to http://strapi:1337 for container-to-container communication
- NGINX 502 Bad Gateway: Check that both Strapi (port 1337) and Next.js (port 3000) containers are running and responsive
- Strapi admin panel shows 'Application configuration error': Generate proper JWT_SECRET, ADMIN_JWT_SECRET, and APP_KEYS in environment variables
- PostgreSQL data loss after container restart: Ensure postgres_data volume is properly mounted to /var/lib/postgresql/data
- Redis connection timeout in Strapi: Configure Strapi's Redis session store to use redis:6379 as the connection string
Community Notes
Loading...
Loading notes...
Download Recipe Kit
Get all files in a ready-to-deploy package
Includes docker-compose.yml, .env template, README, and license
Components
strapinextjspostgresqlredisnginx
Tags
#strapi#nextjs#headless-cms#react#fullstack
Category
Full Web StacksAd Space
Shortcuts: C CopyF FavoriteD Download