Get Lifetime Access And Unlock All Stylised Packs Today!Claim Deal - Just $69!
Asset packs

Using packs in Next.js

Serve downloaded GLBs from your Next.js app, render R3F on the client, and self-host decoders required by the selected files.

AP
Aron Prins
Founder · Updated Aug 11, 2026 · 3 min read
On this page (6)

Next.js can serve downloaded GLBs from public/ without a custom file loader. Render React Three Fiber in a Client Component, and configure only the decoders required by the selected files. Components are pack-specific and optional; you can always load a GLB directly with useGLTF.

Place the files#

A file under public/models/ is available from /models/ in the browser:

project layout
public/
  models/
    asset.glb
  draco/                 optional; required by Draco files
app/
  scene/
    Scene.tsx            Client Component
    SceneClient.tsx      client-only dynamic wrapper
    page.tsx             Server Component

If you use an included component, preserve the URL it references or edit its useGLTF and preload paths to match your layout.

Render on the client#

app/scene/Scene.tsx
'use client'

import { Canvas } from '@react-three/fiber'
import { Clone, OrbitControls, useGLTF } from '@react-three/drei'

function Model() {
  const { scene } = useGLTF('/models/asset.glb')
  return <Clone object={scene} />
}

export function Scene() {
  return (
    <Canvas camera={{ position: [4, 3, 6] }}>
      <ambientLight intensity={0.6} />
      <directionalLight position={[5, 8, 3]} />
      <Model />
      <OrbitControls />
    </Canvas>
  )
}

useGLTF.preload('/models/asset.glb')

Current low-poly individual bundle files commonly need no decoder. For a compressed catalog or prebuild, self-host compatible Draco files under public/draco/ and pass '/draco/' as the second useGLTF argument in both the load and preload calls.

Fix a TS2503 from an included component#

On React 19, an older included component can fail to compile with TS2503: Cannot find namespace 'JSX'. React 19's @types/react removed the global JSX namespace that those components' prop type referenced.

Change the component's prop type to the version-agnostic form, which compiles on React 18 with R3F v8 and on React 19 with R3F v9:

components/Asset01.tsx
export function Asset01(props: Omit<React.ComponentProps<typeof Clone>, 'object'>) {

Nothing else in the component changes. Newer bundles already ship this form. See using a pack in React Three Fiber for the full comparison.

Keep WebGL out of server rendering#

Use a Client Component wrapper for a dynamic import with ssr: false:

app/scene/SceneClient.tsx
'use client'

import dynamic from 'next/dynamic'

const Scene = dynamic(() => import('./Scene').then((module) => module.Scene), {
  ssr: false,
  loading: () => <p>Loading scene…</p>,
})

export function SceneClient() {
  return <Scene />
}

Your Server Component can render <SceneClient /> without evaluating WebGL in the server environment.

Checklist#

  • Add 'use client' to files that render R3F or use browser APIs.
  • Serve GLBs by root-relative URL from public/; do not import them as JavaScript modules.
  • Keep the component's load and preload URLs identical.
  • Self-host Draco only for files that use Draco.
  • Add KTX2 support only when the selected GLB contains KTX2 textures.
  • Verify asset caching headers in your own hosting setup when you replace a file at the same URL.

threejsassets supplies downloadable files, not a hosted asset, decoder, or npm delivery service.

Still stuck?

Ask us directly — we answer support mail ourselves.

Contact support
Share
Using packs in Next.js — threejsassets.com