Research

React Three Fiber in Production

Field Note

React Three Fiber is how we ship most of our 3D web work now. Not because it renders anything vanilla Three.js cannot, it uses the same renderer underneath, but because it changes the shape of the code from a script into components.

These are the lessons that survived contact with real sites: when R3F is the right call, where memory leaks hide, and how to make a scene look expensive on a phone that refuses to pay for it.

Short answer

React Three Fiber is production-ready and is how we ship most of our 3D web work. It is a React renderer for Three.js, so it draws exactly what vanilla Three.js draws, but as reusable components with automatic disposal when they unmount. Choose react three fiber whenever React or framework islands are already in the stack, and reserve vanilla Three.js for isolated single-scene pages where bundle size rules.

Chalk illustration of a stick figure assembling nested component brackets into a glowing blue wireframe cube on a phone screen, with a clean drain at the base
The same renderer, reshaped into components.

What Is React Three Fiber?

React Three Fiber is a React renderer for Three.js. You declare a scene as JSX components instead of writing imperative setup code, and props map directly to Three.js properties. It produces identical output to vanilla Three.js because it uses the same renderer underneath, with no meaningful overhead added.

Instead of imperatively creating a scene, a camera, a renderer, and a loop, you declare the scene as JSX: a Canvas component, meshes as children, lights as siblings. A useFrame hook replaces the hand-rolled animation loop. The official documentation puts it flatly: everything that works in Three.js works here without exception, and components render outside of React with no added overhead.

The practical win is composition. A product viewer, a particle field, or a baked hero scene becomes a component you can drop into any React tree, pass props to, and reuse across pages. For the sites we build on Astro islands or Next.js, that maps exactly to how the rest of the page is already structured, and it pairs naturally with the scroll-driven patterns we cover in how scroll animation websites work.

When Should You Choose R3F Over Vanilla Three.js?

Choose R3F when the site is React-based, the 3D work must be reused across pages, or more than one person will maintain it. Choose vanilla Three.js when there is no React in the stack, when bundle size for a single isolated scene matters most, or when you are doing renderer-level work where the abstraction gets in the way.

The ecosystem tips the scale further toward R3F. The drei helper library covers controls, model loading, environment lighting, text, and staging in a few lines each. Physics, post-processing, and scroll controls all have maintained React bindings. You write meaningfully less code, and less code that touches disposal by hand.

The adoption numbers say the React path is now the mainstream one, not the exotic one. Roughly one in three weekly installs of three arrives alongside the React renderer:

PackageWeekly npm downloadsGitHub stars
three10.1M113k
@react-three/fiber3.5M31.1k
@react-three/drei2.7M9.7k
Source: npm registry download counts and GitHub, June 2026

Why Does Disposal Make or Break Memory in Single-Page Apps?

Three.js never frees GPU memory automatically. Geometries, materials, and textures persist until you call dispose, so every revisit to a 3D route in a single-page app can stack another copy of the scene in GPU memory. R3F disposes the objects it created when a component unmounts, which removes the most common production leak.

The three.js manual is explicit that this is by design: the library cannot clean these resources up automatically, and a single 1024-pixel texture can hold four to six megabytes of GPU memory. On a traditional page load that never matters: navigate away and the whole context dies. On a single-page app it matters enormously, because users navigate to your 3D page, leave, and come back, and every visit that does not clean up stacks another copy of your scene in GPU memory until mobile Safari kills the tab.

This is the strongest single argument for R3F. In vanilla Three.js you must write that teardown yourself, traversing the scene, disposing geometries and materials, unbinding events, and stopping the loop. We have audited sites where the missing dispose path was the entire performance complaint.

Chalk illustration of a dripping faucet labeled GPU memory slowly filling a phone-shaped bucket to overflowing
Every revisit without a dispose path adds another copy to the bucket.

How Should You Structure a Production Scene?

Give the scene one entry point that owns the renderer, camera, sizing, and time, then split the world into modules or components that each own their own assets and cleanup. One owner for the render loop, one owner per asset, and no module reaching across to mutate another module's mesh.

Hero-scene code rots fast when everything lives in one file. In vanilla projects we use a single Experience entry point with the world split into modules behind it. In R3F the same structure falls out of the component tree naturally: the Canvas is the boundary, and each child component loads, animates, and cleans up its own slice of the world.

What Belongs in a Mobile Performance Budget?

Set the budget before you build: pixel ratio capped at 2, draw calls held to the low hundreds with instancing, one or two real-time lights with shadows baked or off, textures sized to what is actually visible, and a frame-time check on a mid-range Android phone before launch, not just the development Mac.

Every scene we ship gets a performance budget up front, because retrofitting one is miserable. The numbers we hold to:

Why Does Baked Lighting Look Premium for Almost Nothing?

Baking moves the lighting cost out of the browser entirely. You light the scene properly in Blender, bake the result into a single texture, and ship the model with a basic unlit material wearing it. The scene shows soft global illumination that real-time rendering cannot afford, at the render cost of a textured cube.

The best-looking scenes we ship are usually the cheapest to render. The workflow: model the scene low-poly in Blender, light it properly there, then bake all of that lighting into a single texture. In the browser, the model loads with a basic unlit material wearing the baked texture. No real-time lights, no shadow maps, no lighting math per frame.

R3F handles this pattern well: load the model with useGLTF inside Suspense, apply the baked texture, add a couple of shader-driven accents like animated particles, and the whole hero runs smoothly on a four-year-old phone. It is the core technique behind most of our 3D website design work, and we wrote more about where it fits in our note on Three.js for business sites.

What Are the Honest Tradeoffs of R3F?

R3F adds React as a dependency, which is wrong for a one-canvas brochure page. The abstraction can hide per-frame allocations created inside render functions, and debugging spans two layers, React and Three.js, a real tax on developers who only know one. On multi-page production work the maintainability win has outweighed all three.

The allocation trap is the sneakiest of the three. Creating a new vector, material, or geometry inside a render function or a useFrame callback allocates every frame, and nothing warns you. The fix is old React discipline: memoize what persists, mutate what changes, and profile on real hardware instead of trusting the development machine.

Where Did We Land on R3F Versus Vanilla?

R3F by default for any site with React or Astro islands in the stack, vanilla Three.js for isolated single-scene pages where bundle size rules. The four lessons travel either way: dispose deliberately, structure the scene like an app, set the mobile budget before modeling starts, and bake lighting whenever the scene allows it.

The framework choice matters less than the discipline, but R3F makes the discipline easier to keep. If you want a hero scene built to these budgets rather than retrofitted to them, that is exactly the kind of project we take on. See how we work with clients for the shape of an engagement.

Chalk illustration of layered website panels stacked behind a glowing browser frame
The same budgets and discipline sit behind every site we ship.

Common Questions

Is React Three Fiber slower than plain Three.js?
Not meaningfully. R3F is a thin reconciler over the same renderer, and its overhead sits outside the hot render loop. Performance problems in R3F apps come from the same places as vanilla ones: draw calls, texture sizes, lights, and allocations inside the frame loop.
Can we use R3F if our site is not a React app?
Yes, through islands. Frameworks like Astro let one component hydrate as React while the rest of the page stays static HTML. The 3D scene ships as an isolated island, so you get R3F's component model without converting the whole site.
Do we need a 3D artist to get a good-looking scene?
For baked-lighting work, someone needs Blender competence for modeling, lighting, and baking. For configurators and data visualization built from primitives and purchased models, a developer with the right references can carry it alone.

Sources

SourcePublisherLink
React Three Fiber: IntroductionPoimandres (pmndrs)r3f.docs.pmnd.rs
Three.js Manual: Cleanupthree.jsthreejs.org
pmndrs/react-three-fiberGitHubgithub.com
pmndrs/dreiGitHubgithub.com
npm registry download counts: three (last week)npmapi.npmjs.org

Keep Exploring

Chalk stick figure in a hard hat presenting a little machine of blue gears it just built

Bring us the bottleneck.
We’ll build the system.

No Dreaming. Just Building.