What worked, what did not, and what I would do differently when building a logistics platform with a headless CMS backend and SSR frontend.
A supply chain web app is not the obvious use case for a headless CMS. Most people reach for Strapi when they are building a blog or a marketing site. But for this project — a package delivery and logistics platform — Strapi with PostgreSQL turned out to be a surprisingly good fit, with a few painful exceptions.
The client needed the ability to define and modify logistics entity types — shipment categories, warehouse zone configurations, carrier profiles — without touching code. A traditional REST API with hard-coded schemas would have required a developer every time a business rule changed. Strapi's content-type builder gave the ops team a UI to manage that themselves, with the API generated automatically.
The PostgreSQL integration was solid. Strapi's relational field types mapped cleanly to the domain model — shipments belonged to carriers, carriers had depot locations, depot locations had operating zones. The auto-generated REST API handled the basic CRUD operations, and the Next.js frontend consumed them with TanStack Query for caching and background sync. SSR on the tracking pages meant fast initial loads and correct Open Graph previews when customers shared tracking links.
Real-time updates. Strapi does not have built-in WebSocket support. For delivery status updates, I had to implement a webhook trigger system where external carriers pushed status changes to a custom Strapi endpoint, which then fanned out to connected clients via Server-Sent Events in the Next.js API layer. It worked, but it was more plumbing than I expected.
The other pain point was performance on complex relational queries. Strapi's populate mechanism can generate deeply nested SQL joins that become slow fast. I ended up writing raw SQL for the most complex reports and exposing them through custom Strapi controllers.
For the real-time requirement, I would separate concerns earlier — a dedicated event-streaming service (a simple Node.js process with Redis pub/sub) rather than bolting it onto Strapi. And I would add a database query analysis step during development to catch slow populate queries before they hit production.