- Sanity CMS
- Architecture
- ISR + Webhooks
From Static JSON to Scalable CMS Architecture
Transforming a developer-dependent, SSR-based content system into a flexible headless CMS architecture using Sanity, ISR, and webhooks — enabling rapid campaign launches and powering both the IPO platform and the marketing website.
- Company
- PrimaryBid
- Role
- Senior React Engineer
- Scope
- Full ownership
- <5 min
Content updates time reduced
- Zero
Developer involvement for copy changes
- 2+ Products
IPO app + marketing website powered
Context
The Problem
After the successful Deliveroo campaign launch, we identified a major operational bottleneck. The IPO platform relied on an SSR architecture and consumed campaign data from static JSON files — a pragmatic choice during the 6-week sprint, but one that created serious friction and operational risk in production.
The JSON Bottleneck
Every content update—even simple copy adjustments—required a full development cycle:
- 1Designer or product manager requests change
- 2Developer creates feature branch
- 3Updates JSON file
- 4Pushes to repository
- 5Waits for code review
- 6Merges to main
- 7CI/CD pipeline runs
- 8Deploy to production
Result: Simple copy changes took hours and required developer intervention.
Objective
The Task
Brendan (Technical Director) asked me to research and recommend a headless CMS solution that would eliminate this bottleneck and scale with our growing needs.
The requirements were clear: enable non-technical teams to manage content independently, support multiple simultaneous campaigns, maintain performance, and provide enough flexibility for our component-based architecture.
Solution
Choosing Sanity
After evaluating several headless CMS options, I recommended Sanity for the following reasons:
Developer Experience
- Schema as code (TypeScript-friendly)
- Powerful query language (GROQ)
- Excellent documentation
- Real-time collaboration features
Flexibility
- Custom field types and validation
- Block content for rich text
- Structured content modeling
- No prescriptive content model
Performance
- Global CDN for assets
- Webhook support for ISR
- Fast API responses
- Efficient caching strategies
Editor Experience
- Intuitive Studio interface
- Real-time preview
- Custom input components
- Version history built-in
Execution
Implementation Approach
1. Schema Design with Design Team
I worked closely with Andy (Design) to transform our JSON structure into a component-based schema. This required establishing a common vocabulary and thinking differently about content:
- Identified reusable content patterns across campaigns
- Created document types for core entities (Issuer, Campaign, Phase)
- Built component schemas matching our React components
- Established naming conventions and content rules
- Ensured mobile-first approach in content structure
2. Studio Creation
I created and configured the Sanity Studio—the content editing interface:
- Custom input components for complex fields
- Validation rules to prevent invalid content
- Preview configurations for editors
- Organized document structure for usability
3. ISR + Webhook Architecture
To maintain performance while enabling real-time updates, I implemented Incremental Static Regeneration (ISR) triggered by Sanity webhooks:
This approach gave us the best of both worlds: static site performance with near-instant content updates.
4. Migration from JSON
I transformed existing JSON data into Sanity documents and updated the React application to fetch from Sanity's API instead of static imports:
- Created migration scripts for existing campaign data
- Updated GraphQL queries to fetch from Sanity
- Maintained backward compatibility during transition
- Tested thoroughly across all campaign phases
Constraints
Key Challenges
Different campaigns needed different layouts and content structures while maintaining consistency.
Solution:
Created flexible component schemas with optional fields and variants. Editors could compose pages from components, choosing which to use and how to configure them, without requiring developer intervention.
Some campaigns needed to support multiple languages (e.g., UK English, French).
Solution:
Implemented Sanity's internationalization pattern with language-specific fields and a language selector in the Studio. Content could be translated without duplicating entire documents.
Financial content needed strict validation to prevent errors (wrong dates, invalid prices, broken workflows).
Solution:
Built custom validation rules in the schema, conditional field visibility, and preview warnings. Editors got immediate feedback before publishing.
Outcome
The Impact
From 6-week sprint to enterprise platform:
- Content updates went from hours to minutes with zero developer involvement
- Enabled rapid campaign launches as content could be prepared in parallel with development
- Scaled to multiple simultaneous campaigns with different configurations
- Became the foundation for the marketing website showing the architecture's versatility
- Enabled the DSP2.0 evolution by providing a flexible, scalable content layer
Reflection
Lessons Learned
Schema design is product design.
The schema determines what's possible for editors.Investing time upfront with the design team to establish patterns and vocabulary paid dividends in usability.
Start with constraints, add flexibility later.
I initially made schemas too flexible, which confused editors.Adding constraints and sensible defaults made the system easier to use, then we added flexibility where needed.
Performance architecture matters.
ISR + webhooks gave us static site performance with dynamic content.This wouldn't have worked with pure SSR or pure static generation.
Good architecture enables new use cases.
Building the CMS for the IPO app created an architecture that naturally extended to the marketing website and eventually supported DSP2.0's more complex requirements.
Stack