Advanced

File Lifecycle

Understanding the complete lifecycle of files in Nuxt Upload Kit.

Plugin Lifecycle Diagram

╔═══════════════════════════════════════════════════════════════════════╗
║                           ADDING FILES                                ║
╠═══════════════════════════════════════════════════════════════════════╣
║                                                                       ║
║   addFile()/addFiles()                                                ║
║         │                                                             ║
║         ▼                                                             ║
║   ┌──────────┐     ┌─────────────┐     ┌─────────────┐               ║
║   │ validate │────▶│ preprocess  │────▶│ file:added  │               ║
║   └──────────┘     └─────────────┘     └─────────────┘               ║
║         │                                     │                       ║
║         ▼ (fail)                              ▼                       ║
║   ┌────────────┐                      autoUpload?                     ║
║   │ file:error │                       /        \                     ║
║   └────────────┘                     yes        no                    ║
║                                       │          │                    ║
║                                       ▼          ▼                    ║
║                                   upload()   [waiting]                ║
╚═══════════════════════════════════════════════════════════════════════╝
                                       │
                                       ▼
╔═══════════════════════════════════════════════════════════════════════╗
║                          UPLOAD PROCESS                               ║
╠═══════════════════════════════════════════════════════════════════════╣
║                                                                       ║
║   ┌──────────────┐                                                    ║
║   │ upload:start │                                                    ║
║   └──────────────┘                                                    ║
║         │                                                             ║
║         ▼                                                             ║
║   ┌─────────┐     ┌────────────────┐     ┌────────────────┐          ║
║   │ process │────▶│ storage.upload │────▶│ upload:progress│          ║
║   └─────────┘     └────────────────┘     └────────────────┘          ║
║         │                │                       │                    ║
║         ▼ (fail)         ▼ (fail)                ▼                    ║
║   ┌────────────┐   ┌────────────┐         ┌──────────┐               ║
║   │ file:error │   │ file:error │         │ complete │               ║
║   └────────────┘   └────────────┘         └──────────┘               ║
║                                                  │                    ║
║                                                  ▼                    ║
║                                          ┌────────────────┐          ║
║                                          │upload:complete │          ║
║                                          └────────────────┘          ║
║                                                  │                    ║
║                                                  ▼                    ║
║                                          all files done?              ║
║                                                  │ yes                ║
║                                                  ▼                    ║
║                                          ┌────────────────┐          ║
║                                          │ files:uploaded │          ║
║                                          └────────────────┘          ║
╚═══════════════════════════════════════════════════════════════════════╝

Hook Execution Order

StageHookDescription
1validateCheck file validity (type, size, count)
2preprocessImmediate transformations (thumbnails)
3processPre-upload transformations (compression)
4uploadStorage plugin uploads file
5completePost-upload processing

File States

A file goes through these statuses:

StatusDescription
waitingFile added, ready for upload
preprocessingRunning preprocess hooks
uploadingCurrently uploading
postprocessingRunning complete hooks
completeSuccessfully uploaded
errorFailed at any stage

File Sources

Files can originate from different sources:

type FileSource = 'local' | 'storage' | 'instagram' | 'dropbox' | ...
SourceDescriptionHas dataHas remoteUrl
localSelected from deviceYes (File/Blob)After upload
storageLoaded from storageNo (null)Yes

Local vs Remote Files

Local Files

Created when user selects files:

const localFile: LocalUploadFile = {
  source: "local",
  data: File | Blob, // Has binary data
  remoteUrl: undefined, // Not uploaded yet
  status: "waiting",
}

After upload:

// data is still available
// remoteUrl is now set
// status is 'complete'

Remote Files

Loaded from existing storage:

const remoteFile: RemoteUploadFile = {
  source: "storage",
  data: null, // No local data
  remoteUrl: "https://...", // Already uploaded
  status: "complete",
}

Working with Both Types

Use the source property to handle files differently:

if (file.source === "local") {
  // TypeScript knows: file.data is File | Blob
  const blob = file.data
  const objectUrl = URL.createObjectURL(blob)
} else {
  // TypeScript knows: file.data is null, file.remoteUrl exists
  const url = file.remoteUrl
}

Or use the helper methods:

// Works for both local and remote
const url = await uploader.getFileURL(file.id)
const data = await uploader.getFileData(file.id) // Fetches remote if needed

Replacing File Data

When you edit a file (crop, rotate), call replaceFileData:

const cropped = await cropImage(originalBlob)
await uploader.replaceFileData(file.id, cropped, "cropped-image.jpg")

This:

  1. Updates file.data with new content
  2. Changes source to 'local' (even if it was remote)
  3. Resets status to 'waiting'
  4. Clears remoteUrl
  5. Re-runs preprocess hooks (regenerates thumbnail)
  6. Emits file:replaced event

Initializing Existing Files

Load files from your database:

// Replaces the file list with these remote files
await uploader.initializeExistingFiles([
  { storageKey: "path/to/file1.jpg" },
  { storageKey: "path/to/file2.png" },
])

The storage plugin's getRemoteFile hook fetches metadata:

// Storage plugin provides:
{
  size: number,
  mimeType: string,
  remoteUrl: string,
  preview?: string
}

Appending Existing Files

Use appendExistingFiles when you need to add remote files alongside files the user has already selected — for example, when a user picks items from a media library:

// User already added local files via file picker
await uploader.addFiles(localFiles)

// Later, user picks files from a media library
const added = await uploader.appendExistingFiles([
  { storageKey: "library/photo-1.jpg" },
  { storageKey: "library/photo-2.jpg" },
])

Key differences from initializeExistingFiles:

initializeExistingFilesappendExistingFiles
BehaviorReplaces all filesAdds to existing files
DeduplicationNoSkips files already present by storageKey
maxFilesNot checkedRespected (truncates to fit)
EventsNoneEmits file:added per file
ReturnsvoidUploadFile[] (files actually added)

This lets all files — local, remote, from any source — live as first-class citizens in a single files ref, eliminating the need for separate tracking arrays.

Memory Management

Nuxt Upload Kit automatically manages memory:

Object URLs

  • Created object URLs are tracked
  • Automatically revoked when file is removed
  • Cleaned up on component unmount

Large Files

For large files (>100MB), prefer streaming:

// Loads into memory (avoid for large files)
const blob = await uploader.getFileData(file.id)

// More efficient - returns URL
const url = await uploader.getFileURL(file.id)

// Most efficient - streams data
const stream = await uploader.getFileStream(file.id)

Event Timeline

Here's the complete event sequence:

addFiles([file])
    │
    ├─ (validation passes)
    │
    ├─ file:added ──────────── File visible in UI
    │
upload()
    │
    ├─ upload:start ────────── Upload begins
    │
    ├─ upload:progress ─────── Progress updates (0-100%)
    │   upload:progress
    │   upload:progress
    │   ...
    │
    ├─ upload:complete ─────── All files done
    │
    └─ (check file.uploadResult for results)

Error events can occur at any point:

addFiles([invalid])
    │
    └─ file:error ──────────── Validation failed

upload()
    │
    ├─ upload:start
    │
    └─ file:error ──────────── Upload failed

Debugging Lifecycle

Enable verbose logging:

if (import.meta.dev) {
  const events = [
    "file:added",
    "file:removed",
    "file:replaced",
    "file:error",
    "upload:start",
    "upload:progress",
    "upload:complete",
    "image-compressor:start",
    "image-compressor:complete",
  ]

  events.forEach((event) => {
    uploader.on(event, (data) => {
      console.log(`[Upload] ${event}:`, data)
    })
  })
}
Copyright © 2026