Three.js GLTFLoader: Loading 3D Models the Right Way

GLTFLoader is the standard way to load 3D models into Three.js: instantiate it, call loader.load(url, onLoad), and add gltf.scene to your Three.js scene. glTF (.gltf/.glb) is the recommended interchange format because it maps directly onto Three.js's own scene graph, materials and animations with no manual conversion.

Last updated . Verified against three.js r181.

Read the FAQJump to code

Loading a model

GLTFLoader is asynchronous and callback- or promise-based. The loaded gltf object contains scene (the root object to add to your scene graph), animations (an array ready for AnimationMixer), cameras, and asset metadata.

Prefer the binary .glb format over .gltf+separate files where possible: it bundles geometry, textures and materials into a single file, which means one HTTP request instead of several and no risk of a missing texture reference.

Draco compression for large models

Geometry-heavy models (dense scans, sculpts, CAD exports) can be enormous as raw glTF. Draco compression shrinks geometry data dramatically, often 10x or more, at the cost of a decode step at load time.

To use it, set a DRACOLoader on your GLTFLoader pointing at the Draco decoder files (Three.js ships them in examples/jsm/libs/draco/, or you can self-host them). Models must be Draco-compressed at export time; this is a checkbox in Blender's glTF exporter and most other export pipelines.

Exporting clean glTF from Blender

Blender's built-in glTF exporter (File → Export → glTF 2.0) is generally reliable, but a few settings avoid the most common problems:

  • Apply transforms before exporting (Object → Apply → All Transforms), or scale/rotation can come through wrong.
  • +Y Up is glTF's convention; Blender is Z-up internally, and the exporter handles the conversion automatically. Don't fight it by pre-rotating your scene.
  • Combine materials where possible; every unique material becomes a separate draw call in the loaded scene.
  • Enable Draco compression in the exporter if the model is geometry-heavy (see above).
  • Export animations only if you actually need them; they add file size and loader complexity for static models that don't.

Code

GLTFLoader with Draco (r181)
1import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
2import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js'
3
4const dracoLoader = new DRACOLoader()
5dracoLoader.setDecoderPath('/draco/') // self-hosted or the CDN path
6
7const loader = new GLTFLoader()
8loader.setDRACOLoader(dracoLoader)
9
10loader.load(
11 '/models/scene.glb',
12 (gltf) => {
13 scene.add(gltf.scene)
14 if (gltf.animations.length) {
15 const mixer = new THREE.AnimationMixer(gltf.scene)
16 mixer.clipAction(gltf.animations[0]).play()
17 }
18 },
19 (progress) => console.log(`${(progress.loaded / progress.total * 100).toFixed(0)}%`),
20 (error) => console.error('Failed to load model:', error)
21)
Loaded materials in WebGPU (r181)
1// GLTFLoader produces standard MeshStandardMaterial/MeshPhysicalMaterial
2// instances, which WebGPURenderer renders natively, no conversion step.
3// You only touch TSL if you want to modify the loaded material afterward:
4import { color } from 'three/tsl'
5
6gltf.scene.traverse((child) => {
7 if (child.isMesh && child.material.isMeshStandardMaterial) {
8 const nodeMaterial = new THREE.MeshStandardNodeMaterial()
9 nodeMaterial.colorNode = color(child.material.color)
10 nodeMaterial.map = child.material.map
11 child.material = nodeMaterial
12 }
13})

Learn this properly

Learn Practical TSL

Your First Node Material

Understand node materials before customizing materials on a loaded glTF scene.

Start the lesson (6 minutes)

Frequently asked questions

What's the difference between .gltf and .glb?

.gltf is a JSON file that typically references separate binary and texture files. .glb packs everything (geometry, textures, materials) into a single binary file. .glb is usually preferred: one HTTP request, no risk of missing references.

How do I use Draco-compressed models with GLTFLoader?

Create a DRACOLoader, point it at the Draco decoder files with setDecoderPath(), and attach it to your GLTFLoader with loader.setDRACOLoader(dracoLoader). The model itself must have been Draco-compressed at export time.

Why does my Blender model look wrong when loaded in Three.js?

The most common cause is unapplied transforms in Blender. Apply all transforms (Object → Apply → All Transforms) before exporting. Rotation issues are usually not an axis-convention bug, since Blender's glTF exporter handles the Z-up to Y-up conversion automatically.

Keep reading