Patrick Galbraith

Web developer - Adelaide, Australia

Uploading files to Salesforce using jsForce 2

There aren’t many examples of how you can upload files (aka ContentVersion entities) to Salesforce using the jsForce library. So I wanted to document what I found while working with the library.

Simplest way

The easiest way to upload a file is to base64 encode the contents and pass it to the create method. Unfortunately this method is limited to around 35MB.

const uploadContentVersion = (fileName: string, file: Buffer): Promise<jsforce.RecordResult> =>
    PathOnClient : fileName,
    VersionData : file.toString('base64')

Multipart form data

The trick here is that you need to encode the request correctly as per the example in the documentation.

Example request body

Content-Disposition: form-data; name="entity_content";
Content-Type: application/json
    "Name" : "Marketing Brochure Q1 - Sales",
    "Keywords" : "sales, marketing, first quarter"
Content-Type: application/pdf
Content-Disposition: form-data; name="Body"; filename="2011Q1MktgBrochure.pdf"
Updated document binary data goes here.

Using the nodejs request library

The popular nodejs `request` library provides a formData option which can be used like below:

import request from 'request'
import jsForce from 'jsforce'

const uploadContentVersion = (metadata: ContentVersionMetadata, file: Buffer): Promise<jsForce.RecordResult> =>
  new Promise((resolve, reject) => {
    const connection: jsForce.Connection = // ...create jsForce connection{
      url: connection.instanceUrl + '/services/data/v49.0/sobjects/ContentVersion',
      auth: {
        bearer: connection.accessToken
      formData: {
        entity_content: {
          value: JSON.stringify(metadata),
          options: {
            contentType: 'application/json'
        VersionData: {
          value: file,
          options: {
            filename: metadata.PathOnClient,
            contentType: 'application/octet-stream'
    }, (err, response) => {
      if (err)


Example using `form-data` library

You could also create the formData object manually like this.

  const formData = new FormData()

  formData.append('entity_content', JSON.stringify(metadata), { contentType: 'application/json' })
  formData.append('VersionData', file, {
    filename: metadata.PathOnClient,
    contentType: 'application/octet-stream'

  // then make request using formData object

Full example attaching to Case

export const addFileToCase = async (caseId: string, fileName: string, file: Buffer): Promise<string> => {
  // We use the helper method created previously
  const uploadResult = await uploadContentVersion(file, {
    PathOnClient: fileName,

    // For updates you can also add the following params
    // ContentDocumentId: '',
    // ReasonForChange: ''

  if (!uploadResult.success) {
    throw new Error(`Failed to upload file for case "${caseId}"`)

  const contentDocument = await connection.sobject<{
    Id: string,
    ContentDocumentId: string

  const linkResult = await connection.sobject<TRes>('ContentDocumentLink').create({
    ContentDocumentId: contentDocument.ContentDocumentId,
    LinkedEntityId: caseId,
    ShareType: 'V'

  if (!linkResult.success) {
    throw new Error(`Failed to link content document for case "${caseId}"`)



Leave a reply

  1. adrian villar said

    Hi, this is an awesome post!
    It is right what I was searching to perform smoothly a file migration I’m doing.
    I wonder whether you used LWC or nodejs or what else coding to make the coding above.

    Could you shed some light on my doubt?
    I will thanks a lot!

Leave a Reply to Patrick Cancel reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>