Skip to content

Migrating from 1.x

filestore 2.0 is a redesign and is not backward compatible with 1.x. The upload pipeline is still exposed as a FastAPI dependency, but engines are now configured instances, callbacks receive a context object, configuration is validated by Pydantic, and upload results explicitly represent partial success.

Upgrade deliberately

Pin the 2.0 version, update imports and object construction, then run upload integration tests against every backend you use. Do not deploy the upgrade as an unreviewed dependency update.

1. Replace Storage Classes with Engines

Storage classes were replaced by reusable engine instances.

from filestore import LocalStorage

storage = LocalStorage("avatar")
from filestore import FileStore, LocalEngine

local = LocalEngine(base_dir="uploads", base_url="/media")
storage = FileStore("avatar", engine=local)

Use these replacements:

1.x 2.0
LocalStorage FileStore(engine=LocalEngine(...))
MemoryStorage FileStore(engine=MemoryEngine())
S3Storage FileStore(engine=S3Engine(...))
GCSStorage FileStore(engine=GCSEngine(...))
AzureStorage FileStore(engine=AzureBlobEngine(...))

Create engines once at application startup and reuse them. Cloud clients are created lazily and cached by the engine.

2. Move Backend Settings to the Engine

Buckets, containers, credentials, regions, and custom endpoints no longer belong in upload configuration.

storage = S3Storage(
    "document",
    config={"bucket_name": "documents", "region_name": "us-east-1"},
)
from filestore import FileStore, S3Engine

s3 = S3Engine(bucket="documents", region="us-east-1")
storage = FileStore("document", engine=s3)

The standard environment fallbacks remain available. See Storage Engines for each constructor and credential chain.

3. Update Callbacks

Every callback now receives one UploadContext instead of four positional arguments.

def destination(request, form, field_name, file):
    return f"users/{request.state.user_id}"
from filestore import UploadContext

def destination(ctx: UploadContext) -> str:
    return f"users/{ctx.request.state.user_id}"

The context exposes request, form, field_name, and file. Sync and async callbacks are both supported for destinations, filenames, filters, and metadata.

4. Use Validated Configuration

StoreConfig is a Pydantic model. Plain dictionaries are still accepted, and Config remains an alias, but invalid values now fail during application startup.

from filestore import FileStore, StoreConfig

storage = FileStore(
    "image",
    config=StoreConfig(
        allowed_extensions={".jpg", ".png"},
        max_file_size=5 * 1024 * 1024,
    ),
)

For multiple fields, field configuration overrides explicitly set store values; filters are concatenated and run store-first. Backend settings belong on the engine, not StoreConfig.

5. Update Result Handling

Store, FileData, and FileField are Pydantic models. Replace to_dict() with model_dump() and treat status as a four-state value.

from filestore import UploadStatus

if store.status is UploadStatus.PARTIAL:
    successful = store.successful_files
    failed = store.failed_files

payload = store.model_dump(mode="json")
Change 2.0 behavior
Store.status "completed", "partial", "failed", or "empty"
bool(store) True only for a completed upload
FileData.message Removed; use FileData.error or Store.message
Store.messages Removed; use Store.message and Store.errors
FileData.key New backend-neutral key for delete and download operations
FileData.file Memory-engine bytes; excluded from serialized output

If partial uploads are acceptable in your application, do not rely on if store: alone—inspect store.status and handle store.successful_files.

6. Update Module Imports

Most applications should import from filestore, which is the stable public API. If you used internal module paths, update them:

1.x module 2.0 module
filestore.storage_engines filestore.engines
filestore.main filestore.store
filestore.datastructures filestore.models

7. Review Changed Failure Behavior

  • Missing fields, duplicate field names, and engine classes passed instead of instances now fail when FileStore is constructed.
  • Validation and persistence failures remain per-file results in Store.
  • Direct calls to delete(), presign_upload(), and presign_download() raise StorageError or NotSupportedError and should be handled at the route boundary.
  • An unfilled browser file input is treated as missing, not as a zero-byte upload.

Upgrade Checklist

  • Pin the intended 2.0 release in the dependency file and lock file.
  • Replace storage classes with FileStore plus engine instances.
  • Move cloud settings to engine constructors.
  • Convert callbacks to UploadContext.
  • Replace to_dict() and boolean status comparisons.
  • Decide how the API should respond to partial uploads.
  • Test empty, oversized, invalid-type, and multi-file requests.
  • Test upload, download, and delete against each configured cloud backend.
  • Review the Production Checklist before deployment.

See the changelog for the complete list of additions and fixes.