Skip to main content
Telebot represents every file — whether stored on Telegram’s servers, on disk, at a URL, or in memory — with the File struct.

The File struct

type File struct {
    FileID   string    // Telegram's unique file ID (set after upload)
    UniqueID string    // Unique across bots; use for deduplication
    FileSize int64
    FilePath string    // Server-side path (from getFile)
    FileLocal string   // Local filesystem path
    FileURL  string    // Remote URL
    FileReader io.Reader // In-memory reader
}
File is designed to be embedded into media types (Photo, Audio, Video, etc.), so you set it as a one-liner.

Creating file references

FromDisk — upload a local file

photo := &tele.Photo{File: tele.FromDisk("banner.jpg")}
_, err := b.Send(recipient, photo)
tele.FromDisk sets FileLocal; Telebot reads the file and uploads it as a multipart form field.

FromURL — send by remote URL

photo := &tele.Photo{File: tele.FromURL("https://example.com/cat.jpg")}
_, err := b.Send(recipient, photo)
Telegram fetches the resource directly. The file is never downloaded by your bot.

FromReader — upload from io.Reader

f, _ := os.Open("report.pdf")
defer f.Close()

doc := &tele.Document{File: tele.FromReader(f)}
_, err := b.Send(recipient, doc)
Useful for in-memory buffers (bytes.Buffer, bytes.Reader, generated files, etc.).

Checking file state

Two helper methods tell you where the file lives:
file.InCloud() bool  // true when FileID != ""
file.OnDisk()  bool  // true when FileLocal exists on the local filesystem

Sending media

Every media type embeds File and implements Sendable:
// Photo
b.Send(chat, &tele.Photo{
    File:    tele.FromDisk("photo.jpg"),
    Caption: "Look at this!",
})

// Audio
b.Send(chat, &tele.Audio{
    File:      tele.FromDisk("song.mp3"),
    Title:     "My Song",
    Performer: "Artist",
    Duration:  213,
})

// Document
b.Send(chat, &tele.Document{
    File:    tele.FromDisk("report.pdf"),
    Caption: "Q3 Report",
})

// Video
b.Send(chat, &tele.Video{
    File:      tele.FromURL("https://example.com/video.mp4"),
    Caption:   "Watch this!",
    Streaming: true,
})

// Voice note
b.Send(chat, &tele.Voice{
    File:     tele.FromDisk("voice.ogg"),
    Duration: 5,
})

// Animation (GIF / MP4 without sound)
b.Send(chat, &tele.Animation{
    File:     tele.FromDisk("anim.mp4"),
    FileName: "anim.mp4", // required; omitting may send as document
})

File caching with FileID

After a successful upload Telebot automatically writes the returned FileID back into the media struct. On subsequent sends you can pass the same struct and Telebot will reuse the cloud ID instead of re-uploading:
photo := &tele.Photo{File: tele.FromDisk("logo.png")}

// First send — Telegram uploads the file and assigns a FileID
b.Send(alice, photo)
// photo.FileID is now populated

// Second send — Telebot sends by FileID; no upload happens
b.Send(bob, photo)
You can also construct a File directly from a known ID:
photo := &tele.Photo{File: tele.File{FileID: "AgACAgIAAxk..."}}
b.Send(chat, photo)
Store FileID values in your database after the first upload to avoid re-uploading the same asset on every bot restart.

Albums

b.SendAlbum() groups up to 10 media items into a single message. All items must implement Inputtable (Photo, Video, Audio, Document):
album := tele.Album{
    &tele.Photo{File: tele.FromDisk("photo1.jpg"), Caption: "First photo"},
    &tele.Photo{File: tele.FromDisk("photo2.jpg")},
    &tele.Video{File: tele.FromDisk("clip.mp4")},
}

msgs, err := b.SendAlbum(chat, album)
Only the first item in an album may carry a caption. SendAlbum supports only the tele.Silent option.

Downloading files

Use b.Download() to save a Telegram-hosted file to your local disk. It calls getFile internally to resolve the download URL:
b.Handle(tele.OnDocument, func(c tele.Context) error {
    doc := c.Message().Document
    if err := b.Download(&doc.File, "/tmp/"+doc.FileName); err != nil {
        return err
    }
    return c.Reply("Saved!")
})
For streaming access without saving to disk, use b.File():
reader, err := b.File(&doc.File)
if err != nil {
    return err
}
defer reader.Close()
io.Copy(myWriter, reader)
Telegram limits bot-side downloads to 20 MB. Larger files must be handled via the MTProto client API.

Build docs developers (and LLMs) love