How can I delete folder on s3 with node.js?

Here is an implementation in ES7 with an async function and using listObjectsV2 (the revised List Objects API):

async function emptyS3Directory(bucket, dir) {
    const listParams = {
        Bucket: bucket,
        Prefix: dir
    };

    const listedObjects = await s3.listObjectsV2(listParams).promise();

    if (listedObjects.Contents.length === 0) return;

    const deleteParams = {
        Bucket: bucket,
        Delete: { Objects: [] }
    };

    listedObjects.Contents.forEach(({ Key }) => {
        deleteParams.Delete.Objects.push({ Key });
    });

    await s3.deleteObjects(deleteParams).promise();

    if (listedObjects.IsTruncated) await emptyS3Directory(bucket, dir);
}

To call it:

await emptyS3Directory(process.env.S3_BUCKET, 'images/')

You can use aws-sdk module for deleting folder. Because you can only delete a folder when it is empty, you should first delete the files in it. I'm doing it like this :

function emptyBucket(bucketName,callback){
  var params = {
    Bucket: bucketName,
    Prefix: 'folder/'
  };

  s3.listObjects(params, function(err, data) {
    if (err) return callback(err);

    if (data.Contents.length == 0) callback();

    params = {Bucket: bucketName};
    params.Delete = {Objects:[]};
    
    data.Contents.forEach(function(content) {
      params.Delete.Objects.push({Key: content.Key});
    });

    s3.deleteObjects(params, function(err, data) {
      if (err) return callback(err);
      if (data.IsTruncated) {
        emptyBucket(bucketName, callback);
      } else {
        callback();
      }
    });
  });
}

According to accepted answer I created promise returned function, so you can chain it.

function emptyBucket(bucketName){
    let currentData;
    let params = {
        Bucket: bucketName,
        Prefix: 'folder/'
    };

    return S3.listObjects(params).promise().then(data => {
        if (data.Contents.length === 0) {
            throw new Error('List of objects empty.');
        }

        currentData = data;

        params = {Bucket: bucketName};
        params.Delete = {Objects:[]};

        currentData.Contents.forEach(content => {
            params.Delete.Objects.push({Key: content.Key});
        });

        return S3.deleteObjects(params).promise();
    }).then(() => {
        if (currentData.Contents.length === 1000) {
            emptyBucket(bucketName, callback);
        } else {
            return true;
        }
    });
}

A much simpler way is to fetch all objects (keys) at that path & delete them. In each call fetch 1000 keys & s3 deleteObjects can delete 1000 keys in each request too. Do that recursively to achieve the goal

Written in typescript

/**
     * delete a folder recursively
     * @param bucket
     * @param path - without end /
     */
    deleteFolder(bucket: string, path: string) {
        return new Promise((resolve, reject) => {
            // get all keys and delete objects
            const getAndDelete = (ct: string = null) => {
                this.s3
                    .listObjectsV2({
                        Bucket: bucket,
                        MaxKeys: 1000,
                        ContinuationToken: ct,
                        Prefix: path + "/",
                        Delimiter: "",
                    })
                    .promise()
                    .then(async (data) => {
                        // params for delete operation
                        let params = {
                            Bucket: bucket,
                            Delete: { Objects: [] },
                        };
                        // add keys to Delete Object
                        data.Contents.forEach((content) => {
                            params.Delete.Objects.push({ Key: content.Key });
                        });
                        // delete all keys
                        await this.s3.deleteObjects(params).promise();
                        // check if ct is present
                        if (data.NextContinuationToken) getAndDelete(data.NextContinuationToken);
                        else resolve(true);
                    })
                    .catch((err) => reject(err));
            };

            // init call
            getAndDelete();
        });
    }