showcase_

Lawfty CMS

tools used

next.js, typescript, sanity.io, graphql, tailwind, redis, new relic

year

2025/2026

front-end, back-end, ui/ux

View Project

available for freelance work

social_

twitter / instagram / facebook

Lawfty CMS website image

I built a Sanity/Next.js project, essentially one CMS that powers multiple landing pages across different campaigns and law firms.

It features a schema architecture that separates environments into distinct “datasets” for production and staging.

When a new page is created in a collection, it’s automatically routed to the correct campaign based on the selected configuration.

This was my first time building a CMS designed to handle multiple page deployments from a single content source. The system was built using Next.js App Router, with GraphQL, Redis, and New Relic integrations to ensure performance, observability, and scalability.


Replacing the legacy templates

Every campaign site used to be its own hardcoded template. Adding a firm meant another page in the codebase, and any copy change had to go through a developer.

Lawfty CMS legacy campaign page

Now a page is just a list of modules, so the marketing team can build and rebrand a campaign on their own.

Lawfty CMS modular campaign page Lawfty CMS Pracht campaign hero


Modules

I wrote a set of reusable modules that editors can drag, drop and reorder: Navigation, Hero, Form, Testimonials, Grid, Bios, Carousel, Fifty-Fifty, Floating CTA, Pop-up, Text, WYSIWYG and Footer.

Lawfty CMS module list

The old templates did not disappear on day one. The schema still carries a legacy set of field groups alongside the modern blocks, so pages built the old way keep working while anything new gets assembled from modules. Those two sets are exactly what the control and variant in the experiment screenshot below are being tested against each other.

Content is modelled as firms, campaigns, collections and pages, with bios and testimonials attached to a campaign. Colours come from a colour palette document on the firm, so the same module renders as a different brand depending on which firm the page belongs to.

Lawfty CMS Pracht process module Lawfty CMS Pracht footer module

Pages are also written in English and Spanish from the same document.

Lawfty CMS Pracht pop-up module


Validation

Pages made of modules are easy to break, so I put the rules in the schema where they get enforced. An editor sees the problem in the Studio before publishing. Only one Pop-up module per page, for example.

Lawfty CMS module validation


Experiments

I also added an experiments layer, so a page can show different content based on the experiment returned for that visit.

An editor sets up variants on a page, say Control - Legacy (a) and Variant - Modular (b), and gives each one its own modules. The visit resolves to a variant and the matching modules get rendered. That meant the team could A/B test a whole page layout, not just the copy.

Lawfty CMS experiment variants

The experiments themselves are not defined in Sanity. They live in the internal admin dashboard, and I wrote custom Studio inputs that pull the experiment list and its variants from that API, so an editor picks a real experiment from a dropdown and never types an ID. The schema catches the rest: adding more variants than the experiment actually has is rejected, and so is pointing two variants at the same one. Each experiment also needs a default variant, which is what gets served when the experiment is switched off.

Visits that should not count, like internal traffic, are filtered out before a variant is assigned.


Delivery

Every firm page comes off one catch-all route, so the CMS decides which pages exist and the file system stays out of it. Sanity responses go through an Apollo link I wrote that caches them in Redis, with an authenticated endpoint the CMS calls to clear the cache when content is published, so editors are not waiting on a deploy to see their change. New Relic covers both the browser and the server side, and the app logs through Winston and Pino.

The two sites share a monorepo. Middleware, the Apollo and Redis setup, logging, env handling and the Sanity layouts sit in a shared workspace both apps import, so a fix lands in both at once.

Results

One content source now runs the campaign sites for several firms, with staging and production kept apart by dataset. Launching a new campaign is now a content job, and any page can be put behind an experiment.


Live sites

injuryfirmstl.com | socarolinainjuryfirm.com | alabamanegligencefirm.com etc.

Happy to send more links on request.


View Lawfty D2C case study | View Lawfty 2.0 case study | Contact Me

work

Case study incoming

Flatmately project image, click to view more details.

Flatmately

js, html, tailwind, figma

Flatmately is a flatmate finder app, built for New Zealand and Australian market. I was tasked to design and develop their website, and also helped with branding and marketing.

Case study incoming

NxtStep project image, click to view more details.

NxtStep

js, html, bootstrap, sketch, ai, psd

NxtStep is a job board for students and graduates. I was tasked to design and develop their website, and also helped with branding and marketing.

Case study incoming

Yoga With Kassandra project image, click to view more details.

Yoga With Kassandra

js, html, sass, wordpress, ai, psd

Yoga With Kassandra is a yoga teacher and content creator. I was tasked to design and develop her website and courses platform while I was working at VidApp.

Case study incoming

Tourism New Zealand project image, click to view more details.

Tourism New Zealand

js, html5, css3, sass, bootstrap, sketch

Tourism New Zealand is a website I've built to showcase my skills utilising JavaScript, HTML5, CSS3, SASS, Bootstrap, Sketch. I was tasked to design and develop their website.

Case study incoming

Renkon project image, click to view more details.

Renkon

js, html5, css3, sass, bootstrap, handlebars, sketch

Renkon is a Japanese restaurant, I've pitched the new website and design for the ordering app. I used JavaScript, HTML5, CSS3, SASS, Handlebars and Bootstrap to build the website.

Case study incoming

DotaPopQuiz project image, click to view more details.

DotaPopQuiz

js, html5, css3, sass, php, bootstrap, sketch

DotaPopQuiz is a quiz app built with JavaScript, HTML5, SASS, PHP. It was built as a fun project to make a game to increase brand awareness and to learn more about JavaScript and PHP.

Case study incoming

VidApp project image, click to view more details.

VidApp

wordpress, js, html, sass, ai, psd

VidApp is a video streaming platform. I was tasked to design and develop their website and the platform where users would publish their customised app for iOS and Android.