How to get file URL from Sanity asset reference in Next.js?

11 replies
Last updated: Nov 29, 2025
Hello everyone, I'm trying to get a file URL to be able to download it from my Next.js Front-end, I have tried "FileURL": file.asset->url, keeps returning undefined, could anyone point me in the right direction?
AI Update

When working with file assets in Sanity, there are a couple of approaches to get the download URL in your Next.js frontend:

Option 1: Properly Resolve the Asset Reference in GROQ

The issue with file.asset->url returning undefined is that you need to fully resolve the asset reference. Try this GROQ query pattern:

*[_type == "yourDocType"] {
  ...,
  "fileUrl": file.asset->url
}

However, if that's still returning undefined, you might need to resolve it more explicitly:

*[_type == "yourDocType"] {
  ...,
  file {
    asset-> {
      url
    }
  }
}

Or spread the asset fields:

*[_type == "yourDocType"] {
  ...,
  file {
    ...,
    asset-> {
      _id,
      url,
      originalFilename,
      size
    }
  }
}

Instead of resolving the URL in GROQ, you can use the @sanity/asset-utils package to build URLs from the asset reference. This is often more efficient since you avoid extra resolving in your query:

Install the package:

npm install @sanity/asset-utils

Use a simpler GROQ query:

*[_type == "yourDocType"] {
  ...,
  file
}

Build the URL in your frontend:

import {buildFileUrl} from '@sanity/asset-utils'

// In your component
const fileUrl = buildFileUrl(file, {
  projectId: 'your-project-id',
  dataset: 'your-dataset'
})

You can also get additional file information like size and original filename:

*[_type == "yourDocType"] {
  ...,
  file {
    asset-> {
      _id,
      originalFilename,
      size
    }
  }
}

Then in your frontend:

import {buildFileUrl} from '@sanity/asset-utils'

const fileUrl = buildFileUrl(file.asset, {
  projectId: 'your-project-id',
  dataset: 'your-dataset'
})

const fileName = file.asset.originalFilename
const fileSize = file.asset.size

Enabling Downloads

To trigger a download (rather than opening in browser), append ?dl= to the URL:

<a href={`${fileUrl}?dl=`} download>
  Download File
</a>

The ?dl parameter is a Sanity CDN feature that forces the browser to download the file instead of displaying it.

Summary

The @sanity/asset-utils approach is generally preferred because:

  • It avoids unnecessary API calls to resolve references
  • It works with just the asset _ref or _id
  • It's more performant for your GROQ queries
  • You have full control over URL building in your frontend code
Show original thread
11 replies

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?