How to Optimize GLB Models for Fast Web Loading

Interactive 3D Brain Model

Written by

at

A 3D model that takes ten seconds to appear is worse than no 3D at all. If you are putting GLB models on a WooCommerce store, a portfolio, or any web page, file size is the difference between an interactive product viewer and a blank loading spinner that visitors abandon. This guide walks through how to optimize GLB models for fast web loading — starting with the simple wins anyone can run, then going deep into geometry compression, texture handling, and a real before-and-after from a model we optimized for production.

Everything here uses glTF-Transform, a free command-line tool and library for processing GLB and glTF files. It is the standard tool for this job and runs anywhere Node.js does.

Why GLB file size matters

GLB is the binary form of glTF — geometry, materials, and textures packed into a single file. It is the right format for the web, but exported models are almost always far larger than they need to be. A model straight out of Blender, a scan, or a marketplace download commonly carries duplicate vertices, unused data, oversized textures, and full 32-bit precision the browser does not need.

Large GLB files cost you three ways: slower first render, more mobile data, and higher bounce rates on the exact interactive feature you added to increase engagement. The goal is the smallest file that still looks correct.

The quick win: one command

If you do nothing else, run the optimize command. It bundles the safe, lossless cleanup steps into a single pass — removing duplicate data, merging vertices, pruning unused nodes, and more.

Install the CLI globally:

npm install -g @gltf-transform/cli

Or run it once without installing, using npx:

npx @gltf-transform/cli optimize model.glb model.opt.glb

That single command will, on most exported models, cut file size noticeably before you touch any advanced settings. For many store owners, this is enough. The sections below are for when you need more, or when you are integrating GLB into a custom viewer that has specific requirements.

What the optimize command actually does

It helps to know the individual operations, because you will sometimes want to run them selectively. The main ones:

  • dedup — removes duplicated meshes, materials, textures, and accessors.
  • weld — merges vertices that share the same position, shrinking geometry data. This is often one of the biggest single savings.
  • simplify — decimates the mesh, reducing triangle count. Powerful, but the one step you must visually verify (more on this below).
  • prune — strips unused nodes, materials, and data left behind by exporters.
  • flatten and join — collapse the scene hierarchy and merge meshes to reduce draw calls.
  • textureCompress — re-encodes textures (covered in its own section).

Geometry compression: Meshopt and Draco

The largest savings on geometry-heavy models come from compression. glTF-Transform supports two schemes, and choosing between them depends on one thing: what will render the file.

Meshopt

Meshopt compresses vertex and index data and decodes extremely fast in the browser. It is the modern default for most web use, and it compresses both geometry and animation well. Apply it with:

gltf-transform meshopt model.glb model.opt.glb

Draco

Draco typically achieves smaller geometry than Meshopt, at the cost of slower decoding and a larger decoder library the browser must load. It is a strong choice when the absolute smallest file is the priority and a slightly heavier decode is acceptable:

gltf-transform draco model.glb model.opt.glb

On typical product models, geometry compression can reduce the mesh portion of a file substantially — often well over half — but the exact result depends entirely on the model’s complexity. The key point is the tradeoff, not a universal percentage: Meshopt for speed and broad support, Draco for the smallest file.

The catch: your renderer must support it

This is the step most guides skip, and it is the one that breaks things. Both Meshopt and Draco require the rendering engine to load a matching decoder. Three.js and Babylon.js support both out of the box. But if you are using a lighter library — or a viewer that does not bundle the decoder — a compressed GLB will simply fail to load, often silently. That leads directly to the next section, which is the part of this guide built on a real production run.

A real example: optimizing without compression

Not every viewer can decode Meshopt or Draco. We hit exactly this case optimizing a model for a lightweight WebGL renderer that had no decoder available. Compression was off the table, so the savings had to come entirely from cleanup and geometry reduction. Here is the actual run.

First, a note on what didn’t help. Running quantize on its own did nothing useful:

gltf-transform quantize brain.glb brain.opt.glb
# 104.85 KB → 104.94 KB  (no gain)

That is expected. Without a compression scheme to consume it, quantization just rewrites the same float data with extra metadata the renderer would have to decode anyway. Quantize is a partner to Meshopt/Draco, not a standalone win.

The real reduction came from optimize with compression explicitly disabled:

gltf-transform optimize brain.glb brain.opt.glb --no-compress --join false
# ✔ dedup ✔ instance ✔ palette ✔ flatten ✔ weld
# ✔ simplify ✔ resample ✔ prune ✔ sparse ✔ textureCompress
# 104.85 KB → 65.23 KB  (38% reduction)

A 38% cut with no compression and full renderer compatibility. The savings came almost entirely from weld (merging duplicate vertices) and simplify (reducing triangle count) — proof that lossless and near-lossless cleanup alone is worth running even when you cannot compress.

The gotcha that cost us a second look

Because simplify ran, it decimated the mesh — and on a low-poly model, default simplification can shave geometry you wanted to keep. The model in this run was only about 4,400 triangles to begin with, where aggressive simplification risks visible quality loss. Always open the optimized file and compare it to the original before shipping. If simplify went too far, turn it off and keep the rest:

gltf-transform optimize brain.glb brain.opt.glb --no-compress --join false --simplify false

This is the single most common way an “optimized” model ends up looking wrong. Verify visually, every time.

Textures are usually the real problem

For most product models, textures — not geometry — are the largest part of the file. A single 4K base-color map can dwarf the entire mesh. Two levers matter here.

Resize

Most product textures do not need to be 4096px. Downscaling to 2048 or 1024 often cuts file size dramatically with no visible difference at typical viewing sizes:

gltf-transform resize model.glb model.opt.glb --width 1024 --height 1024

Re-encode to WebP or KTX2

Converting PNG and JPEG textures to WebP reduces size while keeping wide browser support:

gltf-transform webp model.glb model.opt.glb

For the smallest GPU-friendly textures, KTX2 (Basis Universal) compresses textures into a form the GPU reads directly, reducing both file size and video memory — though, like Meshopt and Draco, it requires renderer support:

gltf-transform etc1s model.glb model.opt.glb

On texture-heavy models, resizing and re-encoding routinely deliver bigger wins than anything done to the geometry. If your file is large and you are unsure why, check the textures first.

The final lever: serve it compressed

Optimization does not stop at the file. How you serve it matters. Precompress the optimized GLB with Brotli and serve the compressed version:

brotli -q 11 brain.opt.glb

Serve the resulting brain.opt.glb.br with a Content-Encoding: br header. On a binary GLB this typically saves another 10–20% over the wire, and it near-fully compresses the JSON portion of the file. Combined with the cleanup above, the brain model in our run transferred at roughly 50–55 KB — less than half its original size, with no renderer compatibility cost. Most hosts and CDNs can be configured to apply Brotli automatically; if yours does, you may not need to precompress manually.

A practical optimization order

Putting it together, here is a sensible sequence:

  1. Run optimize first and measure the result.
  2. Resize and re-encode textures — usually the biggest single win.
  3. Apply Meshopt (or Draco) if your renderer supports it. If it does not, rely on cleanup and skip compression.
  4. Open the result and verify it visually, especially after simplify.
  5. Serve with Brotli compression at the transport layer.

Match the aggressiveness to your renderer. The fastest-loading file in the world is useless if your viewer cannot display it.

From optimized model to live product

Optimizing the GLB is half the job — the other half is getting it in front of customers. If you are selling configurable or visual products on WordPress, our 3D Product Customizer for WooCommerce lets you upload a GLB straight from the product editor and turn it into an interactive, customizable 3D viewer with AR — no developer handoff. See the full plugin features and live demos to watch optimized models running in a real store.