The 10-Line Architecture That Scaled to 50+ Pages

“The best architecture is invisible to the developer using it” – This principle led us to create something that fundamentally changed how we build web applications.

Six months ago, our Next.js application at Kreate Technologies was drowning in techn…


This content originally appeared on DEV Community and was authored by Sachin Maurya

"The best architecture is invisible to the developer using it" - This principle led us to create something that fundamentally changed how we build web applications.

Six months ago, our Next.js application at Kreate Technologies was drowning in technical debt. 50+ pages, 300+ components, and a team struggling to maintain consistency. Every new page took 2 hours to build. Every bug fix risked breaking three other features.

Today, creating a new page takes 18 minutes. Our bundle size dropped 65%. Performance scores hit 95+. Developer productivity increased 300%.

The secret? We treat pages as data structures, not code.

Table of Contents

  • The Problem: Component Soup
  • The Breakthrough Moment
  • The Architecture Deep Dive
  • Real Implementation Examples
  • Performance Impact
  • Developer Experience Revolution
  • Lessons Learned

The Problem: Component Soup {#the-problem}

Picture this typical Next.js page:

// homepage.tsx - The old way (200+ lines)
import HeroSection from '@/components/sections/HeroSection';
import ServicesSection from '@/components/sections/ServicesSection';
import TestimonialsSection from '@/components/sections/TestimonialsSection';
import ClientsSection from '@/components/sections/ClientsSection';
import FAQSection from '@/components/sections/FAQSection';
import CTASection from '@/components/sections/CTASection';
// ... 20 more imports

export default function HomePage() {
  const [heroData, setHeroData] = useState(null);
  const [servicesData, setServicesData] = useState(null);
  // ... 10 more state variables

  useEffect(() => {
    fetchHeroData().then(setHeroData);
    fetchServicesData().then(setServicesData);
    // ... 10 more API calls
  }, []);

  if (!heroData || !servicesData /* ... */) {
    return <PageLoader />;
  }

  return (
    <>
      <HeroSection 
        title={heroData.title}
        subtitle={heroData.subtitle}
        image={heroData.image}
        ctaText={heroData.ctaText}
        ctaLink={heroData.ctaLink}
      />
      <ServicesSection 
        services={servicesData}
        layout="grid"
        columns={3}
      />
      {/* ... 15 more sections */}
    </>
  );
}

Problems everywhere:

  • đź”´ Code duplication across 50+ pages
  • đź”´ No lazy loading (450KB initial bundle)
  • đź”´ Prop drilling nightmare
  • đź”´ Error cascading (one failure = page crash)
  • đź”´ Inconsistent patterns
  • đź”´ 2+ weeks for new developer onboarding

The Breakthrough Moment {#the-breakthrough}

During a code review, I noticed something shocking: 80% of our pages were just different arrangements of the same 30 components.

What if we could define pages as configurations instead of code?

// The same page - revolutionary approach (10 lines)
import { PageRenderer } from '@/components/common/PageRenderer';
import { HOMEPAGE_SECTIONS } from '@/config/sectionsConfig';

export default function HomePage() {
  return <PageRenderer sections={HOMEPAGE_SECTIONS} pagelink="home" />;
}
// sectionsConfig.ts - The magic happens here
export const HOMEPAGE_SECTIONS: Section[] = [
  createSection('hero', () => import('./HeroSection'), { type: 'banner' }),
  createSection('services', () => import('./ServicesSection'), { type: 'grid', cols: 3 }),
  createSection('testimonials', () => import('./TestimonialsSection'), { type: 'carousel' }),
  createSection('clients', () => import('./ClientsSection'), { type: 'logos' }),
  createSection('faq', () => import('./FAQSection'), { type: 'accordion' }),
];

This simple shift unleashed a cascade of innovations.

The Architecture Deep Dive {#the-architecture}

The Section Factory Pattern

interface Section {
  id: string;
  Component: React.LazyExoticComponent<React.ComponentType<any>>;
  skeleton: SkeletonConfig;
  defaultProps?: Record<string, unknown>;
}

interface SkeletonConfig {
  type: 'banner' | 'grid' | 'carousel' | 'list' | 'card';
  cols?: number;
  rows?: number;
  animated?: boolean;
}

const createSection = (
  id: string,
  importer: () => Promise<{ default: React.ComponentType<any> }>,
  skeleton: SkeletonConfig,
  defaultProps?: Record<string, unknown>
): Section => {
  return {
    id,
    Component: React.lazy(importer),
    skeleton,
    defaultProps
  };
};

The Orchestrator: PageRenderer

The magic happens in our PageRenderer component:

export const PageRenderer: React.FC<PageRendererProps> = ({
  sections,
  globalProps = {},
  sectionProps = {},
  pagelink
}) => {
  const renderSection = useCallback((section: Section, index: number) => {
    const mergedProps = {
      ...globalProps,
      ...section.defaultProps,
      ...sectionProps[section.id],
      pagelink
    };

    return (
      <SectionErrorBoundary key={section.id} sectionName={section.id}>
        <LazySection
          Component={() => <section.Component {...mergedProps} />}
          skeleton={section.skeleton}
          sectionName={section.id}
        />
      </SectionErrorBoundary>
    );
  }, [globalProps, sectionProps, pagelink]);

  return (
    <div className="page-container">
      {sections.map(renderSection)}
    </div>
  );
};

Intelligent Lazy Loading

Our LazySection component uses Intersection Observer for viewport-aware loading:

const LazySection: React.FC<LazySectionProps> = ({ 
  Component, 
  skeleton, 
  sectionName 
}) => {
  const [shouldRender, setShouldRender] = useState(false);
  const targetRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (!targetRef.current) return;

    const observer = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          setShouldRender(true);
          performance.mark(`section-${sectionName}-start`);
        }
      },
      {
        threshold: 0.1,
        rootMargin: '50px' // Start loading 50px before visible
      }
    );

    observer.observe(targetRef.current);
    return () => observer.disconnect();
  }, [sectionName]);

  return (
    <div ref={targetRef} data-section={sectionName}>
      {shouldRender ? (
        <Suspense fallback={<SectionSkeleton config={skeleton} />}>
          <Component />
        </Suspense>
      ) : (
        <SectionSkeleton config={skeleton} />
      )}
    </div>
  );
};

Content-Aware Skeleton System

Each section defines its own loading state:

const SectionSkeleton: React.FC<{ config: SkeletonConfig }> = ({ config }) => {
  switch (config.type) {
    case 'grid':
      const items = (config.cols || 3) * (config.rows || 2);
      return (
        <div className={`grid grid-cols-${config.cols} gap-4`}>
          {Array.from({ length: items }).map((_, i) => (
            <Skeleton key={i} className="h-32" delay={i * 50} />
          ))}
        </div>
      );

    case 'carousel':
      return (
        <div className="flex gap-4 overflow-hidden">
          {Array.from({ length: 3 }).map((_, i) => (
            <Skeleton key={i} className="flex-shrink-0 w-80 h-48" />
          ))}
        </div>
      );

    // ... more skeleton types
  }
};

Real Implementation Examples {#implementation}

Our GenAI Document Analyzer Page

export const GENAI_SECTIONS: Section[] = [
  createSection(
    'hero',
    () => import('@/components/sections/genai/HeroSection'),
    { type: 'banner', height: '600px' }
  ),

  createSection(
    'processing-modes',
    () => import('@/components/sections/genai/AIProcessingModes'),
    { type: 'grid', cols: 2, rows: 4 }
  ),

  createSection(
    'industry-solutions',
    () => import('@/components/sections/genai/IndustrySolutions'),
    { type: 'carousel', items: 4 }
  ),

  createSection(
    'testimonials',
    () => import('@/components/sections/common/ClientTestimonials'),
    { type: 'carousel', autoPlay: true }
  )
];

// The entire page
export default function GenAIPage() {
  return (
    <PageRenderer 
      sections={GENAI_SECTIONS}
      pagelink="genai"
      globalProps={{ theme: 'dark' }}
    />
  );
}

Dynamic Configuration with Feature Flags

const getPageSections = (page: string, user?: User): Section[] => {
  const baseSections = PAGE_CONFIGS[page] || [];

  // A/B testing through configuration
  if (user?.experimentGroup === 'B') {
    return [
      baseSections[1], // Move features first for group B
      baseSections[0],
      ...baseSections.slice(2)
    ];
  }

  // Feature flags
  if (featureFlags.newTestimonials) {
    const newSections = [...baseSections];
    const testimonialIndex = newSections.findIndex(s => s.id === 'testimonials');

    if (testimonialIndex !== -1) {
      newSections[testimonialIndex] = createSection(
        'testimonials-v2',
        () => import('./TestimonialsV2'),
        { type: 'masonry', cols: 3 }
      );
    }
  }

  return baseSections;
};

Performance Impact {#performance}

The results speak for themselves:

Metric Before After Improvement
Bundle Size 450KB 157KB -65%
Time to Interactive 3.8s 2.3s -40%
First Contentful Paint 1.6s 0.8s -50%
Lighthouse Score 68 95+ +40%
Page Creation Time 2 hours 18 min -85%

Bundle Analysis Deep Dive

# Before - One massive chunk
main.js          450KB
vendors.js       1.2MB
Total Initial:   1.65MB

# After - Intelligent splitting  
main.js          157KB
framework.js     45KB
commons.js       89KB
sections/hero.js    23KB (loaded on demand)
sections/services.js 34KB (loaded on demand)
Total Initial:   291KB

Real User Metrics

  • Bounce Rate: Decreased from 34% to 21%
  • Session Duration: Increased from 2.3min to 3.8min
  • Conversion Rate: Improved by 45%
  • Time to Interactive: 40% faster across all devices

Developer Experience Revolution {#dx-revolution}

Before vs After: New Developer Onboarding

Before (2 weeks):

  • Day 1-3: Understanding component architecture
  • Day 4-7: Learning data fetching patterns
  • Day 8-10: Understanding error handling
  • Day 11-14: First page creation

After (3 days):

  • Day 1: Configuration pattern explanation (2 hours)
  • Day 2: Practice with existing sections
  • Day 3: Create first page independently

Code Review Time Reduction

// Old way - 200+ line page file
// - Check imports
// - Verify data fetching
// - Validate error handling  
// - Review prop passing
// Average review time: 45 minutes

// New way - 10 line configuration
const SECTIONS = [
  createSection('hero', heroImport, heroSkeleton),
  createSection('features', featuresImport, featuresSkeleton)
];
// Average review time: 5 minutes

Developer Happiness Metrics

We surveyed our development team:

  • "I enjoy working on pages": 23% → 89%
  • "I understand the codebase": 45% → 91%
  • "I can work independently": 34% → 87%
  • "Code reviews are helpful": 56% → 94%

Lessons Learned {#lessons}

1. Configuration > Code for Repetitive Patterns

When you find yourself copying code, ask: "Can this be configuration?"

2. Performance Should Be Automatic

Developers shouldn't think about:

  • Lazy loading (automatic with sections)
  • Code splitting (handled by dynamic imports)
  • Loading states (defined in skeleton config)

3. Error Boundaries at Every Level

// Section-level errors don't crash pages
<SectionErrorBoundary sectionName="testimonials">
  <TestimonialsSection />
</SectionErrorBoundary>

4. Developer Experience Drives Product Quality

Happy developers → Better code → Better user experience

5. Migration Strategy: One Page at a Time

We migrated our entire application over 3 months:

  • Week 1-4: Build PageRenderer system
  • Week 5-8: Convert homepage + 2 key pages
  • Week 9-12: Migrate remaining pages
  • Zero downtime, minimal risk

Advanced Patterns

Context-Aware Data Fetching

// Components automatically get the right data
const TestimonialsSection = ({ pagelink }) => {
  // Automatically selects correct API based on pagelink
  const { data } = useTestimonials(pagelink);
  return <TestimonialCarousel data={data} />;
};

// Hook mapping
const useTestimonials = createHookMap({
  'genai': useGenAiTestimonials,
  'mobile-app': useMobileAppTestimonials,
  'default': useGeneralTestimonials
}, 'default');

Multi-Level Error Recovery

// Automatic retry for transient errors
const SectionErrorBoundary = ({ children, sectionName }) => {
  const [retryCount, setRetryCount] = useState(0);

  const handleError = (error) => {
    const errorType = classifyError(error);

    if (errorType.autoRetry && retryCount < 3) {
      setTimeout(() => {
        setRetryCount(prev => prev + 1);
        // Component automatically retries
      }, errorType.retryDelay);
    }
  };

  return (
    <ErrorBoundary onError={handleError}>
      {children}
    </ErrorBoundary>
  );
};

Future Innovations

AI-Powered Page Optimization

We're exploring ML models that optimize page configurations based on user behavior:

// Future: AI suggests optimal section arrangements
const optimizedSections = await optimizePageLayout({
  baseSections: HOMEPAGE_SECTIONS,
  userSegment: currentUser.segment,
  conversionGoal: 'signup',
  timeOfDay: new Date().getHours()
});

Real-Time Configuration Updates

// Deploy new page layouts without code changes
const sections = await fetchSectionsFromCMS(pageName);
return <PageRenderer sections={sections} />;

Conclusion

Configuration-driven architecture isn't just a pattern—it's a paradigm shift. By treating pages as data structures, we unlocked:

  • Unprecedented flexibility (A/B testing through config)
  • Automatic performance (lazy loading built-in)
  • Developer happiness (simple mental model)
  • Business agility (rapid iteration)

The best part? You can start small. Convert one page to this pattern, measure the impact, then expand.

Remember: The goal isn't to build software. It's to solve problems efficiently.

Resources

Connect with me:

What patterns have transformed your development experience? Share in the comments below!


This content originally appeared on DEV Community and was authored by Sachin Maurya


Print Share Comment Cite Upload Translate Updates
APA

Sachin Maurya | Sciencx (2025-09-02T03:08:59+00:00) The 10-Line Architecture That Scaled to 50+ Pages. Retrieved from https://www.scien.cx/2025/09/02/the-10-line-architecture-that-scaled-to-50-pages/

MLA
" » The 10-Line Architecture That Scaled to 50+ Pages." Sachin Maurya | Sciencx - Tuesday September 2, 2025, https://www.scien.cx/2025/09/02/the-10-line-architecture-that-scaled-to-50-pages/
HARVARD
Sachin Maurya | Sciencx Tuesday September 2, 2025 » The 10-Line Architecture That Scaled to 50+ Pages., viewed ,<https://www.scien.cx/2025/09/02/the-10-line-architecture-that-scaled-to-50-pages/>
VANCOUVER
Sachin Maurya | Sciencx - » The 10-Line Architecture That Scaled to 50+ Pages. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2025/09/02/the-10-line-architecture-that-scaled-to-50-pages/
CHICAGO
" » The 10-Line Architecture That Scaled to 50+ Pages." Sachin Maurya | Sciencx - Accessed . https://www.scien.cx/2025/09/02/the-10-line-architecture-that-scaled-to-50-pages/
IEEE
" » The 10-Line Architecture That Scaled to 50+ Pages." Sachin Maurya | Sciencx [Online]. Available: https://www.scien.cx/2025/09/02/the-10-line-architecture-that-scaled-to-50-pages/. [Accessed: ]
rf:citation
» The 10-Line Architecture That Scaled to 50+ Pages | Sachin Maurya | Sciencx | https://www.scien.cx/2025/09/02/the-10-line-architecture-that-scaled-to-50-pages/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.