Both GSAP and Framer Motion are excellent animation libraries, but they solve different problems. We use both in the same projects and have developed clear guidelines for when to reach for each.
Framer Motion for Component Animations
Framer Motion shines for component-level interactions: mount and unmount transitions, hover and tap states, drag gestures, and layout animations. Its declarative API integrates naturally with React's component model. AnimatePresence handles exit animations more elegantly than any alternative.
GSAP ScrollTrigger for Scroll-Driven Sequences
GSAP excels at complex scroll-driven animations: pinned sections with progress-based timelines, batch reveals where dozens of elements stagger into view, and parallax effects that need precise scroll synchronization. ScrollTrigger's batch method is uniquely efficient for staggering large numbers of elements.
Using Both Together
In our portfolio site, Framer Motion handles card tilts, hover effects, and page transitions. GSAP handles the scroll-driven story intro sequence and blog card batch reveals. They coexist without conflicts as long as you follow one rule: never animate the same CSS property with both libraries simultaneously.
Performance Comparison
GSAP's requestAnimationFrame loop runs outside React's render cycle, making it more efficient for complex sequences with many elements. Framer Motion integrates with React's lifecycle, which is cleaner for component state but adds re-render overhead. For most applications, both perform well — the choice is about API preference and use case fit.
Bundle Size
GSAP core plus ScrollTrigger is approximately 36KB gzipped. Framer Motion tree-shakes to around 30KB for typical usage. Both are reasonable additions. GSAP requires careful setup in Next.js to avoid SSR issues — we use a custom useGSAP hook that registers plugins client-side only.