We've implemented a style objects approach that provides the best balance of maintainability and simplicity for OG image generation.
- No Dependencies: Works immediately with Vercel OG
- Type Safety: Full TypeScript support
- Reusability: Shared style objects across components
- Performance: No runtime overhead
- Maintainability: Centralized design system
src/config/
├── constants.ts # Colors, dimensions, paths
└── styles.ts # Reusable style objects
import { styles } from '../config/styles';
// Before (inline styles)
<div style={{
display: 'flex',
gap: '40px',
padding: '40px',
background: 'linear-gradient(-22deg, #5b23e1 0%, #a22feb 100%)',
}}>
// After (style objects)
<div style={styles.header}>Pros:
- Clean JSX
- Familiar CSS syntax
Cons:
- Requires CSS file management
- Need to ensure CSS is available in OG context
- Potential for style conflicts
- More complex build setup
Pros:
- Design system consistency with web app
- Type-safe styles
- Component-based styling
- Reusable theme
Cons:
- Additional bundle size (~15-20KB)
- Build complexity
- Runtime overhead
- SSR compatibility concerns
For your OG image generator, continue with the style objects approach for these reasons:
- OG Images are Simple: Limited styling needs compared to full web apps
- Performance Critical: Every KB matters for edge computing
- Self-Contained: No external dependencies to manage
- Reliable: Works consistently across all environments
Only consider adding Emotion if:
- Design System Grows: You need complex theming/variants
- Component Library Integration: You want to share components with web app
- Team Preference: Developers strongly prefer CSS-in-JS
- Bundle Size Acceptable: The 15-20KB overhead is acceptable
If you decide to add Emotion later:
- Phase 1: Keep style objects, add Emotion alongside
- Phase 2: Gradually migrate components to Emotion
- Phase 3: Remove style objects once migration is complete
- Use style objects for common patterns
- Keep styles close to components
- Use TypeScript for type safety
- Document design tokens in constants
- Mix inline styles with style objects
- Duplicate styles across components
- Use magic numbers (use constants)
- Over-abstract simple styles
// src/config/styles.ts
export const styles = {
// ... existing styles
// New component styles
card: {
background: '#FFF',
borderRadius: '12px',
padding: '24px',
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.1)',
},
// Variant styles
cardVariants: {
primary: {
background: 'linear-gradient(-22deg, #5b23e1 0%, #a22feb 100%)',
color: '#FFF',
},
secondary: {
background: '#F5F5F5',
color: '#333',
},
},
} as const;The current style objects approach is optimal for OG image generation. It provides:
- ✅ Maintainability through reusable styles
- ✅ Performance with zero overhead
- ✅ Reliability with no external dependencies
- ✅ Type Safety with full TypeScript support
Recommendation: Continue with style objects. Only consider Emotion if you need complex theming or want to share components with your web app.