Library / SDK
pmndrs/react-three-fiber avatar
pmndrs/react-three-fiber

react-three-fiber: a React renderer for Three.js, and what it costs you

🇨🇭 A React renderer for Three.js

32,422 stars1,978 forksTypeScriptMIT

At a glance

What is it?
react-three-fiber lets you build Three.js scenes as React components, with React 19 support in v9 and a v10 alpha already shipping. The trade-off is a version pairing rule with React that you have to plan around.
Who is it for?
Adopt react-three-fiber if your application is already React and the 3D view has to share state, events and lifecycle with the rest of the UI. Do not adopt it if you are shipping a standalone WebGL experience with no React tree, or if you cannot pin a React major: the README states that @react-three/fiber@8 pairs with react@18 and @react-three/fiber@9 pairs with react@19, and that is the first thing to verify before you install.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 8 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem react-three-fiber solves for React applications

Three.js is an imperative scene graph library. You construct objects, attach them to parents, mutate transforms and dispose of GPU resources by hand. React is a declarative tree with a reconciler that decides when components mount, update and unmount. Putting the two together by hand means writing the same glue every time: create the object on mount, update it when props change, dispose it on unmount, and keep a reference around so the render loop can touch it.

react-three-fiber is a React renderer for Three.js. The README describes the intent directly: build your scene declaratively with re-usable, self-contained components that react to state, are readily interactive and can participate in React's ecosystem. That last clause is the actual selling point. A mesh can read from a context provider, respond to a click handler, and unmount with the route that owns it, using the same patterns as the rest of your application.

The audience is narrow but real. If you have a React application and you want a product configurator, a data visualisation in 3D, or an embedded scene that shares state with forms and navigation, this removes a category of manual bookkeeping. If you are writing a standalone WebGL demo with no React tree, you are paying for a reconciler you will not use.

How the reconciler maps JSX onto Three.js objects

The README states the mechanism plainly: it merely expresses Threejs in JSX, and `<mesh />` dynamically turns into `new THREE.Mesh()`. Lowercase JSX tags are treated as Three.js constructors, so `<boxGeometry args={[1, 1, 1]} />` becomes a `THREE.BoxGeometry` constructed with those arguments, and nesting in JSX becomes parenting in the scene graph. There is no wrapper component per Three.js class to wait for. New Three.js versions are available immediately, because the mapping is by name rather than by hand-written binding.

The `Canvas` component is the root. It sets up the renderer and the scene, and everything inside it is part of the Three.js tree rather than the DOM tree. `useFrame` subscribes a component to the render loop; in the README example it receives `state` and `delta` and rotates a mesh by `delta` each frame. `useRef` gives direct access to the underlying Three.js object, which is how you escape the declarative layer when you need to.

Events are handled on the components themselves. The example attaches `onClick`, `onPointerOver` and `onPointerOut` to a `<mesh>` and uses them to toggle React state, which then changes `scale` and `color`. That is the whole architecture in miniature: React state drives props, props drive Three.js objects, and pointer events come back through the React tree.

Installing react-three-fiber and rendering a first interactive box

The README gives a single install command covering the runtime and its types. Run it in your project root.

bash
npm install three @types/three @react-three/fiber

Before you go further, check the pairing rule. The README carries a warning: three-fiber is a React renderer, it must pair with a major version of React, just like react-dom, react-native, etc. It states that `@react-three/fiber@8` pairs with `react@18` and `@react-three/fiber@9` pairs with `react@19`. Installing the wrong major will not be fixed by a config change.

The README's basic example mounts a `Canvas` through `createRoot` and renders two boxes with lights. A trimmed version of it looks like this.

jsx
import { createRoot } from 'react-dom/client'
import React, { useRef, useState } from 'react'
import { Canvas, useFrame } from '@react-three/fiber'

function Box(props) {
  const ref = useRef()
  const [hovered, hover] = useState(false)
  const [clicked, click] = useState(false)
  useFrame((state, delta) => (ref.current.rotation.x += delta))
  return (
    <mesh {...props} ref={ref} scale={clicked ? 1.5 : 1} onClick={() => click(!clicked)}
      onPointerOver={() => hover(true)} onPointerOut={() => hover(false)}>
      <boxGeometry args={[1, 1, 1]} />
      <meshStandardMaterial color={hovered ? 'hotpink' : 'orange'} />
    </mesh>
  )
}

createRoot(document.getElementById('root')).render(
  <Canvas>
    <ambientLight intensity={Math.PI / 2} />
    <Box position={[-1.2, 0, 0]} />
    <Box position={[1.2, 0, 0]} />
  </Canvas>,
)

What you should see is two boxes rotating on the x axis, turning hotpink when the pointer is over them and growing to 1.5 scale when clicked. Note the props on `Box`: `position` is passed straight through to the mesh, because the component spreads `...props` onto it. That is the pattern the README is demonstrating, a component that owns its own state and participates in the render loop.

For TypeScript, the README adds `npm install @types/three` and types the component as `props: ThreeElements['mesh']` with `useRef<THREE.Mesh>(null!)`. There is also a React Native path through `@react-three/fiber/native`, which the README shows with `expo init` and a `metro.config.js` that adds `glb`, `png` and `jpg` to `assetExts` so the bundler can resolve model and texture assets.

The React major pairing rule is the real constraint

The README's FAQ answers are confident to the point of being unhelpful. Asked whether it has limitations, it says none, and that everything that works in Threejs will work here without exception. Asked whether it is slower than plain Threejs, it says there is no overhead, that components render outside of React, and that it outperforms Threejs in scale due to React's scheduling abilities. None of those claims come with a caveat, a measurement or a condition. Treat them as positioning rather than as engineering guidance.

The documented constraint that does matter is the React major pairing. A renderer sits between React and the host environment, so it depends on internals that change between React majors. The README states the mapping explicitly for versions 8 and 9. If your application is on React 18 you take the v9 line only after upgrading React, and if you are on React 19 you cannot stay on fiber 8. A monorepo with several React versions in it will feel this immediately.

The second thing to check is which line you are installing. The most recent stable release listed is v9.7.0 from 2026-07-31. The v10 line is in alpha: v10.0.0-alpha.4 on 2026-08-28 and v10.0.0-alpha.5 on 2026-09-08. The last push to the repository was on 2026-09-08, so work is ongoing, but an alpha is an alpha. If you need a stable dependency for a production application, v9.7.0 is the release to target, and the README's React Native example, which pins `@react-three/fiber@beta` alongside `react@rc`, is a reminder that the beta channel is not the stable one.

There is also a build consideration in the repository itself. The root `package.json` runs `preconstruct dev` and a `patch-react-reconciler` script as a `postinstall` step. That is a build-tooling detail of this repository, not of your application, but it tells you the library does patch the reconciler, which is consistent with the React-major sensitivity.

react-three-fiber against plain Three.js and Threlte

The comparison people actually search for is Three.js versus react-three-fiber, and the honest answer is that they are not competitors. Three.js is the engine. react-three-fiber is a renderer that drives it. Choosing fiber means choosing React as your scene description language, and everything follows from that. You get component composition, hooks, context and React's scheduling. You also get React's constraints: a reconciler in your bundle, a version pairing rule, and a mental model where the scene graph is a function of props.

If your application is not React, the answer is plain Three.js. There is no version of this that pays off without a React tree around it.

Among React-based alternatives, Threlte is the Svelte equivalent, and it is the comparison worth making because it isolates the variable. Threlte expresses Three.js in Svelte components, so the difference is not the rendering strategy but the framework underneath. If your project is Svelte, Threlte is the natural fit and react-three-fiber is not on the table. If your project is React, the reverse holds. The choice is made by your existing frontend, not by the 3D layer.

Maintenance, licence and the cost of upgrading

The repository is not archived, and the last push was on 2026-09-08. Releases are managed with changesets: the root `package.json` exposes `changeset:add`, `vers` and `release` scripts, and there is a `.changeset/` directory at the top level. That is a reasonable signal about how versions are cut, though it says nothing about how quickly issues are answered.

The upgrade path is the thing to budget for. Because fiber pairs with a React major, upgrading React is not a background dependency bump. Moving from React 18 to React 19 means moving from fiber 8 to fiber 9 in the same change, and any component in your scene that relies on behaviour tied to the old reconciler has to be checked at the same time. The v10 alpha adds a third line to track. If you pin v9.7.0 and stay there, you are stable but you are also on the previous React pairing whenever your application moves.

On licensing, the repository declares MIT in both the root `package.json` and the `LICENSE` file. MIT is permissive and imposes no source-disclosure obligation on your application. That is a statement about the licence text, not legal advice; if you are redistributing the library as part of a product, have your own counsel read the terms rather than this article.

Editorial conclusion

Adopt react-three-fiber if your application is already React and the 3D view has to share state, events and lifecycle with the rest of the UI. Do not adopt it if you are shipping a standalone WebGL experience with no React tree, or if you cannot pin a React major: the README states that @react-three/fiber@8 pairs with react@18 and @react-three/fiber@9 pairs with react@19, and that is the first thing to verify before you install. Check that pairing, then check whether you need the stable v9 line or the v10 alpha, which was at v10.0.0-alpha.5 on 2026-09-08. If neither React major fits your application, plain Three.js is the smaller dependency.

Frequently asked questions

What is react-three-fiber used for?

It is a React renderer for Three.js, used to build 3D scenes declaratively as reusable React components that react to state and can participate in React's ecosystem. Typical use is a 3D view inside a React application that needs to share state and events with the rest of the UI.

How do I install react-three-fiber?

The README gives one command: npm install three @types/three @react-three/fiber. Before running it, check the pairing rule, because @react-three/fiber@8 pairs with react@18 and @react-three/fiber@9 pairs with react@19.

Is react-three-fiber compatible with React 19?

Yes. The README states that @react-three/fiber@9 pairs with react@19, in the same way react-dom and react-native pair with a React major. The v8 line is the one that pairs with react@18.

Is react-three-fiber free?

Yes. The repository declares the MIT licence in its package.json and includes a LICENSE file. MIT is permissive and does not require you to publish your own application's source.

Official sources

  1. License: MIT
  2. pmndrs/react-three-fiber on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/pmndrs-react-three-fiber.svg)](https://hysenlabs.com/projects/pmndrs-react-three-fiber)