Rebuilding capptions.com - with next.js
Context
My journey to rebuilding Capptions.com started in an unexpected place: creating internal automation tools. As the Director of Marketing but also a passionate self-taught-developer at Capptions, I had been working on streamlining our internal processes through small automation projects. These projects, combined with my self-driven completion of CS50 (Harvard University), The Odin Project, and the Full Stack Open (FSO - University of Helsinki) courses, caught our CTO's attention. When the opportunity arose to rebuild our marketing website, I saw it as a chance to apply modern web development practices at scale.
The existing website was outdated and bloated – it wasn't serving our core audience of EHS (Environmental, Health, and Safety) directors and managers effectively. We needed a platform that could evolve quickly with our product offerings and market positioning, while maintaining top-tier performance and SEO standards.
What I Built
I created a modern, component-driven website using Next.js 14, with a focus on Server Components and optimal performance. The site serves as both our marketing platform and a technical showcase of our capabilities. Here's what makes it special:
- Component Library: A comprehensive collection of 50+ reusable components, from simple UI elements to complex interactive features
- Performance-First Architecture: Leveraging Next.js Server Components and static generation where possible
- Content Management: Integration with Sanity CMS (though that's a story for another post!)
- Design System: Custom implementation using TailwindCSS and ShadcnUI
- SEO Optimization: Built-in SEO features with dynamic meta tags and structured data
Technical Breakdown
Stack Selection
// Example of our tech stack configuration
{
framework: "Next.js 14",
styling: "TailwindCSS",
ui: "ShadCN + Custom Components",
deployment: "Vercel",
cms: "Sanity",
analytics: "Posthog",
typeChecking: "TypeScript",
}
Key Architectural Decisions
-
Folder Structure I implemented a feature-based architecture that scales with our growing needs:
-
Performance Optimizations
One of my proudest achievements was implementing efficient component loading:
// components/lazy-loading-wrapper.tsx
export const LazyLoadingWrapper = ({ children, threshold = 0.1 }) => {
const [isVisible, setIsVisible] = useState(false);
const ref = useRef(null);
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setIsVisible(true);
observer.disconnect();
}
},
{ threshold },
);
if (ref.current) {
observer.observe(ref.current);
}
return () => observer.disconnect();
}, [threshold]);
return (
<div ref={ref}>
{isVisible ? children : <div className="h-[200px] animate-pulse" />}
</div>
);
};
- Component Architecture
I developed a system of composable components that could be mixed and matched for different page layouts. Here's an example of our hero component structure:
// Simplified version of our hero component architecture
interface HeroProps {
variant: "default" | "centered" | "split";
title: string;
description: string;
cta?: {
text: string;
href: string;
};
}
export const Hero: React.FC<HeroProps> = ({
variant,
title,
description,
cta,
}) => {
// Component logic
};
Challenges and Solutions
- Performance vs. Rich Interactions
One of the biggest challenges was balancing rich interactive features with performance. I solved this through strategic code splitting and lazy loading:
// Example of how we handle dynamic imports
const DynamicWorkflowBuilder = dynamic(
() =>
import("@/components/workflow-builder-drawer").then(
(mod) => mod.WorkflowBuilder,
),
{
loading: () => <LoadingSpinner />,
ssr: false,
},
);
- SEO Optimization
I implemented a robust SEO strategy using Next.js's metadata API:
// app/(main)/layout.tsx
export const metadata: Metadata = {
metadataBase: new URL("https://capptions.com"),
title: {
default: "Capptions - EHS & ESG Compliance Software",
template: "%s | Capptions",
},
// ... other metadata
};
What I Learned
-
Server Components Are Game-Changing Moving from a client-heavy approach to Server Components dramatically improved our initial page load times and SEO capabilities.
-
Type Safety Pays Off TypeScript's strict mode caught countless potential issues before they hit production. The initial investment in proper typing saved hours of debugging.
-
Component Architecture Evolution I learned to start with smaller, more focused components and compose them into larger features, rather than building monolithic components that are hard to maintain.
-
Userflow Monitoring is Crucial Setting up Posthog early helped us identify and fix userflow bottlenecks before they impacted users.
-
Performance Monitoring is Crucial Running Lighthouse tests on the website helped me identify and fix performance bottlenecks before they impacted users.
What's Next
The website is never "done" – it's a living project that evolves with our business needs. Here's what's on the horizon:
- A/B Testing Infrastructure: Building a system to test different messaging and layouts
- Enhanced Personalization: Implementing user-specific content based on industry, role, and use-case.
- Performance Optimization: Continuing to optimize for Core Web Vitals
- Internationalization: Expanding our language support beyond English
Impact and Results
The rebuild has had significant business impact:
- 90% improvement in Core Web Vitals scores
- 10x faster deployment cycles (previously we were limited to only content changes, now we can rapidly deploy new features, pages, layouts etc.)
- 30% increase in lead generation form submissions
- Significantly improved developer experience for content updates
(I'm now able to make changes to the website without having to wait for an external developer to do it for me: as I am the developer)
Honestly, this project wasn't just about "building a website" – it was about creating a solid foundation for Capptions' digital presence that could scale and evolve. It's a strong (single handed) mix of design, content (visual and written), and development. The trust placed in me by our CTO to take on this project has led to even more opportunities to innovate and improve our technical infrastructure.
This is part one of a two-part series. Stay tuned for a deep dive into our Sanity CMS implementation and content management strategy.