---
title: 'Performance'
excerpt: 'Compositor properties, will-change, stagger vs N tweens, and cleanup.'
icon: 'BookOpen'
---

## Animate transform and opacity

Smooth UI hangs on **what** you animate. Prefer `x` / `y` / `scale` / `rotation` / `autoAlpha` — compositor-friendly. Animating `left`, `top`, `width`, or `height` forces layout every frame unless you truly need reflow (accordion, Flip).

Same travel, two costs: top uses transform; bottom uses `left`. Prefer the top pattern by default.

<ComponentPreview>
  <GsapTransformVsLayout />

  <DocsFileTabs title="Gpu only">

```tsx title="gpu-only.tsx"
// ✓ compositor
gsap.to(el, { x: 100, autoAlpha: 0 });
// ✗ layout every frame
gsap.to(el, { left: 100, width: 200 });
```

```html title="gpu-only-markup.html"
<div>
  <div class="gsap-good absolute size-8 rounded"></div>
  <div class="gsap-bad absolute size-8 rounded"></div>
</div>
```

  </DocsFileTabs>
</ComponentPreview>

## Stagger vs many tweens

One staggered tween beats N separate tweens with manual `delay`. Fewer instances, one ease, easier overwrite and cleanup. Reach for many tweens only when each target truly needs different vars or timelines.

## quickTo for frequent updates

Pointer followers and scrubbed values should not call `gsap.to` every event. See [Utils](/learn/gsap-react/production/utils) — `quickTo` retargets one property without allocating a new tween per frame.

## Cleanup checklist

- **`useGSAP`** reverts context on unmount
- **`ScrollTrigger.getAll().forEach(t => t.kill())`** on SPA route change if needed
- **`split.revert()`** for SplitText
- **`Draggable.get(...).kill()`** when removing drag targets
- Pause or kill off-screen animations

## will-change

Hint the browser only on elements that **will** animate:

```css
.will-animate {
  will-change: transform;
}
```

Do not set on every element preemptively — it costs memory and can create unnecessary layers.
