How AI is powering better personalization in e-commerce [with Vercel]. Sign up now →

Sanity image upload from Next.js API: type mismatch error

10 repliesLast updated: Nov 29, 2025

Trying to upload an image to Sanity from Next.js /api. What am I doing wrong? 😓
TypeScript doesn't complain about the type, but the error message says it's wrong type.
AI Update

This is a classic issue when uploading images from Next.js API routes to Sanity! The problem you're hitting is that the browser's File object isn't compatible with what Sanity's assets.upload() expects in a Node.js environment (like Next.js API routes).

The Root Cause

When you try to pass a browser File object to a Next.js API route, it gets serialized to an empty object {} because File objects can't be stringified with JSON.stringify(). Even if TypeScript doesn't complain, at runtime Sanity expects a Readable stream, Buffer, or Blob - not the browser's File object.

The Solution: Use Next.js API Routes

Based on this community discussion, here are two approaches:

Option 1: Client-side upload (simpler but less secure)

// Your Sanity client config
export const client = sanityClient({
  projectId: 'your-project-id',
  dataset: 'production',
  apiVersion: '2024-01-01',
  token: process.env.NEXT_PUBLIC_SANITY_WRITE_TOKEN, // Note the NEXT_PUBLIC_ prefix!
});

// In your component
const handleSubmit = async (e) => {
  e.preventDefault();
  
  // Upload the file directly from browser
  const { _id } = await client.assets.upload('image', fileInput);
  
  // Then create your document with the asset reference
  const doc = {
    _type: 'yourDocType',
    image: {
      _type: 'image',
      asset: {
        _type: 'reference',
        _ref: _id,
      },
    },
  };
  
  await client.create(doc);
};

Important: Your token will be exposed in the browser's network tab with this approach. Make sure you prefix your env variable with NEXT_PUBLIC_.

This is the better approach. You'll need to install multer for handling multipart form data:

npm install multer

Create /pages/api/upload.js:

import { client } from '../../lib/sanity';
import multer from 'multer';

async function parseFormData(req, res) {
  const storage = multer.memoryStorage();
  const multerUpload = multer({ storage });
  const multerFiles = multerUpload.any();
  
  await new Promise((resolve, reject) => {
    multerFiles(req, res, (result) => {
      if (result) return reject(result);
      return resolve(result);
    });
  });
  
  return {
    fields: req.body,
    files: req.files,
  };
}

export const config = {
  api: {
    bodyParser: false, // Important!
  },
};

export default async function handler(req, res) {
  const sanityClient = client.withConfig({
    token: process.env.SANITY_WRITE_TOKEN, // No NEXT_PUBLIC prefix needed
  });

  const data = await parseFormData(req, res);

  // Upload the buffer to Sanity
  const { _id } = await sanityClient.assets.upload(
    'image',
    data.files[0].buffer // This is the key - use the buffer!
  );
  
  const doc = {
    _type: 'yourDocType',
    ...data.fields,
    image: {
      _type: 'image',
      asset: {
        _type: 'reference',
        _ref: _id,
      },
    },
  };

  await sanityClient.create(doc);
  res.status(200).json({ success: true });
}

Your form component:

<form action='/api/upload' method='POST' encType='multipart/form-data'>
  <input name='title' type='text' />
  <input type='file' name='image' />
  <button type='submit'>Upload</button>
</form>

Key Takeaways

The error message about "wrong type" happens because Sanity's assets.upload() expects different input types depending on the environment - in the browser it can accept File, but in Node.js (API routes) it needs a Buffer, Stream, or Blob.

Show original thread
10 replies

Was this answer helpful?

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.

Related contributions