Skip to content

Add Vercel Blob storage backend#1556

Open
jlariza wants to merge 4 commits into
jschneier:masterfrom
jlariza:feature/vercel-blob-integration
Open

Add Vercel Blob storage backend#1556
jlariza wants to merge 4 commits into
jschneier:masterfrom
jlariza:feature/vercel-blob-integration

Conversation

@jlariza

@jlariza jlariza commented Feb 28, 2026

Copy link
Copy Markdown

Summary

Adds a new VercelBlobStorage backend for VercelBlob, using the official vercel-py SDK.

What's included

  • storages/backends/vercel_blob.py — full implementation of the DjangoStorage API:
    • _open, _save, delete, exists, listdir, size, url, get_available_name
    • VercelBlobFile wrapping SpooledTemporaryFile for lazy reads and buffered writes
    • Both "public" and "private" access modes
    • URL construction from the bearer token without a network round-trip, with a head() fallback
    • Paginated listdir using mode="folded" to surface virtual directories
    • Token resolution via Django setting → BLOB_READ_WRITE_TOKENVERCEL_BLOB_READ_WRITE_TOKEN
  • tests/test_vercel_blob.py — 59 unit tests (fully mocked, no network calls)
  • docs/backends/vercel-blob.rst — full documentation covering installation, settings, private-blob proxy pattern, URL behaviour, security notes, and known limitations
  • pyproject.toml — new vercel-blob optional dependency group (vercel>=0.5.0)

Notes

  • The vercel package requires Python 3.10+. This is documented in the installation note and in the backend's docstring; the rest of django-storages continues to support Python 3.8+.
  • Vercel Blob has no presigned/expiring URL support. The docs include a proxy-view pattern for serving private blobs from Django.
  • The sync SDK creates a fresh HTTP client per call, so the backend is thread-safe without any additional locking.
  • Claude Code was used in the coding process. However, everything was reviewed and corrected by humans when necessary.

Checklist

  • Tests pass (pytest tests/test_vercel_blob.py — 59/59)
  • No type annotations (matches existing backend style)
  • Optional dependency declared in pyproject.toml
  • Documentation added and linked from docs/index.rst
  • Tested with Vercel directly. It properly worked for both default and staticfiles using this configuration
STORAGES = {
    "default": {
        "BACKEND": "storages.backends.vercel_blob.VercelBlobStorage",
        "OPTIONS": {
            "token": "<token>",
            "location": "media",
        },
    },
    "staticfiles": {
        "BACKEND": "storages.backends.vercel_blob.VercelBlobStorage",
        "OPTIONS": {
            "token": "<token>",
        },
    },
}
Screenshot 2026-02-28 at 9 24 14 AM Screenshot 2026-02-28 at 9 24 03 AM Screenshot 2026-02-28 at 9 23 56 AM

@jlariza

jlariza commented Mar 7, 2026

Copy link
Copy Markdown
Author

@jschneier please, check. Thank you

@dnwpark

dnwpark commented Mar 23, 2026

Copy link
Copy Markdown

The only things I'd maybe add are support for random suffixes and cache max age. Not that critical.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants