Strapi + Next.js - Blueprint
Headless CMS website with Strapi 5, Next.js 16, PostgreSQL, and S3 media
A content website built with Strapi 5 and Next.js 16, managed as a Turborepo monorepo. One repository, two services, a database, and a media bucket, all wired up on deploy.
Tech stack:
| Layer | Technology |
|---|---|
| CMS | Strapi 5 (TypeScript), port 1337 |
| Frontend | Next.js 16 App Router, Turbopack, standalone output, port 3000 |
| Styling | Tailwind v4 + shadcn/ui |
| Database | PostgreSQL via DATABASE_URL |
| Media | S3-compatible object storage |
Content model: a Page collection with dynamic-zone blocks, plus Navbar and Footer single types.
What You Get
- A private clone of the monorepo in your GitHub account, one repo for both services
- Two Rock8Cloud services: the Strapi admin and the Next.js site
- A managed PostgreSQL database, pre-wired via
DATABASE_URL - A managed S3 bucket for media, pre-wired via the
S3_*variables - A seeded, published Home page that renders at your site URL as soon as the first deploy finishes
- SEO metadata,
sitemap.xml,robots.txt, and ISR with webhook revalidation
Strapi runtime secrets (APP_KEYS, JWT_SECRET, ENCRYPTION_KEY and friends) are generated per deploy. The two services learn each other's URLs automatically, so there is no manual URL or CORS setup.
Create your admin user at /admin on the Strapi service.
Media Uploads
An S3-compatible bucket is provisioned and wired into Strapi automatically (S3_ENDPOINT, S3_BUCKET, S3_REGION, S3_ACCESS_KEY, S3_SECRET_KEY, S3_PUBLIC_URL). Uploads survive redeploys with no setup. See S3 Storage.
Live Preview
Works out of the box. A shared PREVIEW_SECRET is generated and set on both services automatically, so the Preview button in the Strapi admin renders drafts through the real Next.js frontend with no setup.
Instant Revalidation
Optional. Published pages already refresh within about five minutes through ISR. For instant updates on publish:
- Set
REVALIDATE_SECRETon the web service - In Strapi admin go to Settings > Webhooks and add a webhook to
<web-url>/api/revalidatewith headerAuthorization: bearer <REVALIDATE_SECRET>, triggered on entry publish
See Environment Variables for how to set these.
Customizing
- Content models live under
apps/strapi/src/api/* - Blocks render from
apps/web/src/components/blocks/*
Each service builds from its own Dockerfile (apps/strapi/Dockerfile and apps/web/Dockerfile) with the repository root as the build context.