Convert STL to glTF

Converting STL to glTF turns a print file into something a web viewer handles well: coincident vertices are welded into a real index buffer, and the bounds three.js and model-viewer use to frame the shot are written into the file. Two things to plan for — glTF measures in metres where STL means millimetres, and the model will render flat-shaded.

  • Where it runs In your browser. The file is never uploaded.
  • Rebuilt GLTF works differently from an STL, so this is not the gradual degradation a lossy codec applies. What GLTF can express is reproduced faithfully; what it has no equivalent for does not survive at all.
  • File size limit Up to 100 MB per file, free, without an account.
  • Worth knowing Geometry only. Materials, colours, textures and animation are not carried across, and a model placed several times comes back with each copy baked into its own position.

Up to 100 files at once. Mixed formats are fine.

Putting an STL in front of a visitor means converting it first

No browser renders an STL and no browser renders a glTF either — both need a runtime. What differs is the quality of the path. three.js ships an STL loader, so the naive answer is to serve the STL directly and be done, and for a one-off internal tool that is a reasonable answer.

It stops being reasonable when the page is public and the model is the content. An STL is the least efficient way to move a mesh over a connection that exists, it carries no bounds so the camera has to be computed after parsing, and every triangle arrives with its own three vertices for the GPU to deduplicate or not. glTF was designed for this exact transfer and fixes all three.

Welding is where the STL to glTF size win comes from

A binary STL is exactly 84 + 50n bytes for n triangles, regardless of the shape. Fifty of those bytes are twelve for a face normal, thirty-six for three full vertices, and two unused. Nothing is shared: a cube is thirty-six vertex records for eight distinct corners.

The conversion rounds coordinates to six decimal places to build a key and collapses every corner at the same position into one vertex. On a closed surface each vertex typically serves five or six triangles, so the vertex data falls by roughly that factor before it is written as float32. Add twelve bytes of uint32 indices per triangle and the glTF geometry lands well under the STL for any mesh that is actually closed.

What the glTF contains and how a viewer frames it

One scene, one node, one mesh, one primitive in triangle mode, a float32 VEC3 position accessor and a uint32 SCALAR index accessor. The asset block declares version 2.0. The buffer is embedded as a base64 data URI, so the file is self-contained.

The POSITION accessor carries min and max, which the specification requires and which is the practical difference between a model that appears and one that does not. model-viewer and three.js both derive their initial camera distance from those six numbers; a file written without them opens zoomed to nothing, and that failure is indistinguishable from a broken load until you inspect the JSON.

Flat shading is the correct look for a converted STL

No NORMAL attribute is written, and the glTF specification instructs viewers to compute flat face normals when a mesh has none. On an organic model imported from a sculpting tool that is a defect and people ask how to fix it. On a part that came out of CAD as an STL it is the truth.

An STL has no curved surfaces. It has the triangles the exporter produced at whatever chord tolerance was set, and a smooth-shaded render of them is a flattering lie about the geometry a printer will actually reproduce. If you want the preview to look smoother, the honest fix is upstream — re-export the STL with a finer tolerance so there are more triangles — rather than averaging normals to hide the ones you have.

Millimetres against metres: the scale trap in STL to glTF

STL declares no unit and the engineering and printing worlds read its numbers as millimetres. glTF 2.0 defines its linear unit as the metre. The conversion copies the coordinates through unchanged, because rescaling by a factor the source never stated would be a guess.

So a 60 mm bracket becomes a 60-metre bracket in glTF terms. Nothing looks wrong in isolation — the camera frames it from the bounds and the model fills the view — but it will be wrong the moment it sits next to anything else in a scene, and physically-based lighting behaves differently at that scale. Set a uniform 0.001 scale on the node in your viewer, or apply it in gltf-transform once at build time.

One STL, one mesh, one draw call, no material

Because an STL has no parts, groups or objects, the glTF contains exactly one primitive. That is the cheapest possible thing to render and it means an STL-derived model never suffers the draw-call problem that a CAD export with three hundred groups creates.

It also has no material, no texture, no UV coordinates and no vertex colours, because an STL held none of them. Your viewer applies its default, which is usually a mid-grey physically-based material. Assigning something better in three.js is one line, and it is worth doing: a technical part reads far more clearly with a slightly metallic material and an environment map than with the default.

The glTF base64 buffer, and when to take the GLB instead

The .gltf written here embeds its buffer as a base64 data URI, so there is no .bin to serve alongside it and no relative path to break. Base64 costs four characters per three bytes, so that convenience is about 33 percent more bytes, on top of pretty-printed JSON.

For a file you are going to inspect, diff, or feed to gltf-transform at build time, take the glTF. For the file the visitor actually downloads, take the GLB: same geometry, same bounds, binary buffer, one request. Converting an STL to either is the same operation here, and the extension is the whole difference.

Both STL dialects convert, and how they are told apart

Binary and ASCII STL share an extension and the file does not say which it is. The common test — checking whether the file starts with the word "solid" — is unreliable, because the eighty-byte header of a binary STL can contain any text and several writers put "solid" there.

The reliable test is arithmetic: a binary STL is exactly 84 + 50n bytes for the triangle count in its header, and nothing else is. That is what this converter uses. If the length does not match, the file is decoded as text and its vertex lines are read. Either way the model reaches the same welded form before the glTF is written.

Where the STL goes while it becomes a glTF

Nowhere. The pair runs as plain JavaScript in the page — no WebAssembly engine to download, no request carrying the model, no queue. That matters more than usual for this pair, because the STLs people convert for a web preview are frequently a customer's part or an unreleased product, and a print bureau that quotes on uploaded geometry has a real reason to care where it went.

The free ceiling is 100 MB, which at fifty bytes a triangle is a two-million-triangle model. Files that large are worth decimating before conversion rather than after: the glTF will be proportionally huge, and a browser viewer on a phone will not enjoy it whatever format it arrives in.

How to convert STL to GLTF

  1. Drop your STL onto this page, or click to choose one.
  2. Triangles are welded and written as glTF in your browser.
  3. Download the .gltf and load it in your viewer.

STL against glTF: a machine format meeting a web format

STL compared with GLTF
STLGLTF
Full nameStereolithographyGL Transmission Format
File extension.stl.gltf
Media typemodel/stlmodel/gltf+json
First published19872015
Published by3D SystemsKhronos Group
SpecificationglTF 2.0
LicensingOpen standardOpen standard
Standing todayCurrentCurrent
Opens in a browserNo browserNo browser
Considered instead3MF, OBJ, PLYGLB, OBJ

Opening the result

Blender reads both STL and GLTF, so there is a way to check the result against the original without a second tool.

What each format is for

The two are aimed at different work: STL at 3D printing, GLTF at the web and handing a finished file over. That is worth weighing before converting, because the reason one exists is usually the reason the other is awkward.

GLTF comes from Khronos Group and dates from 2015, specified as glTF 2.0. Blender, three.js and Babylon.js all read it.

STL was published in 1987 and GLTF in 2015. The older one is generally the safer file to hand to somebody; the newer one usually does the job in fewer bytes.

STL to glTF: questions from people building a viewer

Are my STL files uploaded anywhere?

No. This conversion runs entirely inside your browser, so the file never leaves your device. You can confirm it yourself: open the network tab of your browser's developer tools and convert something. You will see the page load, plus the analytics and advertising the site is paid for with — and nothing carrying your file.

Is the glTF smaller than the STL it came from?

Almost always, and by a large margin. STL spends 50 bytes on every triangle with no vertex sharing at all; the glTF welds coincident vertices and stores each once as 12 bytes, with 12 bytes of indices per triangle. A closed mesh loses most of its bulk that way.

Why does the model look faceted in the viewer?

Because no normals are written, and the glTF specification tells viewers to compute flat face normals in that case. For a machined or printed part that is the honest appearance — an STL has no smooth surfaces, only the triangles the exporter chose.

My part is 60 mm and appears enormous. Why?

STL numbers are conventionally millimetres and glTF defines its linear unit as the metre, so a 60 mm part becomes 60 metres of glTF. Nothing is rescaled during conversion. Apply a 0.001 scale on the node or the model in your viewer.

Will the model be framed correctly on load?

Yes. Every position accessor is written with the min and max the specification requires, and viewers use those bounds to place the camera. Files written without them are the usual reason a model appears to be missing.

How many draw calls does the result cost?

One. An STL has no parts, so the glTF contains a single mesh with a single triangle primitive in a single node, which is the cheapest thing a viewer can be asked to render.

Should I use .gltf or .glb for the web?

GLB for delivery. The .gltf written here embeds its buffer as base64, which costs about a third more bytes than the same data stored binary. Take the glTF when you are going to process or inspect the file, the GLB when you are going to serve it.

More about these formats