Skip to main content
The Upload module provides methods for uploading files to VK. It handles the complete upload flow: getting upload server, uploading files, and saving them.

Initialization

import { API, Upload } from 'vk-io';

const api = new API({
  token: process.env.VK_TOKEN
});

const upload = new Upload({ api });

Configuration Options

api
API
required
API instance for making requests
uploadTimeout
number
default:20000
Upload timeout in milliseconds (20 seconds)
agent
Agent
HTTPS agent for upload requests
const upload = new Upload({
  api,
  uploadTimeout: 60000  // 60 seconds for large files
});

Upload Sources

VK-IO supports multiple input types:
const photo = await upload.messagePhoto({
  source: {
    value: './photos/cat.jpg'
  }
});

Photo Upload

Message Photo

Upload photo for messages:
const photo = await upload.messagePhoto({
  source: {
    value: './cat.jpg'
  }
});

await api.messages.send({
  peer_id: 123456,
  message: 'Check out this cat!',
  attachment: photo,
  random_id: 0
});

Wall Photo

Upload photo for wall posts:
const photo = await upload.wallPhoto({
  source: {
    value: './announcement.jpg'
  },
  group_id: 123456  // Optional: for group walls
});

await api.wall.post({
  owner_id: -123456,
  message: 'Important announcement',
  attachments: photo
});

Album Photo

Upload to photo album (up to 5 photos):
const photos = await upload.photoAlbum({
  album_id: 123456,
  source: {
    values: [
      { value: './photo1.jpg' },
      { value: './photo2.jpg' },
      { value: './photo3.jpg' }
    ]
  },
  caption: 'Vacation 2024'
});

console.log(`Uploaded ${photos.length} photos`);

Owner Photo

Upload profile or group photo:
const result = await upload.ownerPhoto({
  source: {
    value: './avatar.jpg'
  },
  owner_id: -123456  // Group ID (negative)
});

console.log('New photo URL:', result.photo_src);

Cover Photo

Upload community cover:
const cover = await upload.ownerCoverPhoto({
  source: {
    value: './cover.jpg'
  },
  group_id: 123456,
  crop_x: 0,
  crop_y: 0,
  crop_x2: 1590,
  crop_y2: 400
});

Document Upload

Message Document

const doc = await upload.messageDocument({
  source: {
    value: './report.pdf',
    filename: 'Monthly_Report.pdf'
  },
  title: 'Monthly Report',
  tags: 'work,report'
});

await api.messages.send({
  peer_id: 123456,
  attachment: doc,
  random_id: 0
});

Wall Document

const doc = await upload.wallDocument({
  source: {
    value: './presentation.pptx'
  },
  group_id: 123456,
  title: 'Q4 Presentation'
});

Document Types

// Regular document
const doc = await upload.messageDocument({
  source: { value: './file.pdf' },
  type: 'doc'
});

// Voice message
const voice = await upload.messageDocument({
  source: { value: './voice.ogg' },
  type: 'audio_message'
});

// Graffiti
const graffiti = await upload.messageDocument({
  source: { value: './drawing.png' },
  type: 'graffiti'
});

Video Upload

const video = await upload.video({
  source: {
    value: './video.mp4'
  },
  name: 'Tutorial Video',
  description: 'How to use our app',
  is_private: true,
  wallpost: false,
  group_id: 123456  // Optional: upload to group
});

console.log('Video ID:', video.id);
Video processing may take time. The video might not be immediately available after upload.

Audio Upload

const audio = await upload.audio({
  source: {
    value: './song.mp3'
  },
  artist: 'Artist Name',
  title: 'Song Title'
});

Story Upload

const story = await upload.story({
  source: {
    value: './story.jpg'
  },
  upload_type: 'story',
  add_to_news: true
});

Market Photo Upload

Main Photo

const photo = await upload.marketPhoto({
  source: {
    value: './product.jpg'
  },
  group_id: 123456,
  main_photo: true
});

Album Photo

const photo = await upload.marketAlbumPhoto({
  source: {
    value: './collection.jpg'
  },
  group_id: 123456
});

Poll Photo Upload

const photo = await upload.pollPhoto({
  source: {
    value: './poll-bg.jpg'
  },
  owner_id: -123456
});

Advanced Options

Custom Upload Server

Specify upload server manually:
const photo = await upload.messagePhoto({
  source: {
    value: './photo.jpg',
    uploadUrl: 'https://pu.vk.com/c1234/upload.php?...'
  }
});

Multiple Files

Some methods support multiple files:
const photos = await upload.photoAlbum({
  album_id: 123456,
  source: {
    values: [
      { value: './photo1.jpg' },
      { value: './photo2.jpg' },
      { value: 'https://example.com/photo3.jpg' },
      { value: Buffer.from('...'), filename: 'photo4.jpg' }
    ]
  }
});

Complete Options

const photo = await upload.messagePhoto({
  source: {
    values: [{
      value: './photo.jpg',
      filename: 'custom-name.jpg',
      contentType: 'image/jpeg',
      contentLength: 241000  // Required for streams
    }],
    timeout: 60000,  // Override default timeout
    uploadUrl: 'https://...'  // Custom upload server
  }
});

Return Types

Most upload methods return attachment instances:
// Returns PhotoAttachment
const photo = await upload.messagePhoto({ /* ... */ });
console.log(photo.toString()); // 'photo123456_789012'

// Use directly in API calls
await api.messages.send({
  peer_id: 123456,
  attachment: photo,  // Automatically converts to string
  random_id: 0
});

// Access attachment data
console.log(photo.id);      // 789012
console.log(photo.ownerId); // 123456
console.log(photo.sizes);   // Array of photo sizes

Error Handling

import { UploadError } from 'vk-io';

try {
  const photo = await upload.messagePhoto({
    source: { value: './photo.jpg' }
  });
} catch (error) {
  if (error instanceof UploadError) {
    console.error('Upload failed:', error.code);
    console.error('Message:', error.message);
  }
}
Common error codes:
  • MISSING_PARAMETERS - Required parameters missing
  • NO_FILES_TO_UPLOAD - No files specified
  • EXCEEDED_MAX_FILES - Too many files
  • UNSUPPORTED_SOURCE_TYPE - Invalid source type

Timeout Configuration

If you see The user aborted a request error, increase the timeout:
// Global timeout
const upload = new Upload({
  api,
  uploadTimeout: 120000  // 2 minutes
});

// Per-request timeout
const video = await upload.video({
  source: {
    value: './large-video.mp4',
    timeout: 300000  // 5 minutes for this upload
  }
});

Best Practices

File Size: Check file sizes before upload to avoid timeouts:
import { statSync } from 'fs';

const stats = statSync('./video.mp4');
const sizeMB = stats.size / (1024 * 1024);

if (sizeMB > 100) {
  console.warn('Large file, increasing timeout');
  await upload.video({
    source: {
      value: './video.mp4',
      timeout: 600000  // 10 minutes
    }
  });
}
Streams: Always use async fs.stat() instead of statSync() in production:
import { createReadStream } from 'fs';
import { stat } from 'fs/promises';

const stats = await stat('./file.mp4');
const stream = createReadStream('./file.mp4');

const video = await upload.video({
  source: {
    value: stream,
    contentLength: stats.size
  }
});

Build docs developers (and LLMs) love