Have your own Lake of Assets
Description and use
AssetLake enables public image uploads with transforms and CDN caching entirely within a Sanity project, eliminating the need for separate object storage, CDN, and image service.
Problem
Railway’s storage buckets are private and public buckets are not supported, so every image read requires a presigned URL or a backend proxy. Using a separate object storage and CDN adds another provider, DNS surface, and requires building resizing, format negotiation and per‑image metadata.
Outcome
AssetLake enables public image uploads with transforms and CDN caching entirely within a Sanity project, eliminating the need for separate object storage, CDN, and image service. It provides a backend‑only write boundary, live asset console, and policy‑driven uploads.
Workflow
- 1. Browser uploads image to authenticated backend route handler.
- 2. Backend calls @assetlake/core to validate policy and upload to Sanity.
- 3. @assetlake/core creates an assetLakeImage document linking to the Sanity asset.
- 4. Browser requests image variants via cdn.sanity.io URLs.
- 5. AssetLake Console displays live asset list and preset editing via Sanity App SDK.
Evidence
Railway's storage buckets are private. Public buckets aren't supported, so every image read means a presigned URL or a proxy through my backend.
I already use Sanity for content, and a Sanity project already ships an asset store, an image pipeline, a global CDN, structured documents and realtime APIs.
AssetLake is my answer: @assetlake/core, a framework‑neutral server SDK. My backend calls assetLake.images.upload(...). It checks the file against a policy stored as Sanity content (allowed types, size, magic bytes, dimensions), uploads it as a Sanity asset, and creates a structured assetLakeImage record: owner, purpose, status.
Browsers load every variant straight from cdn.sanity.io. My backend is the write and auth boundary, never an image proxy.
- Record date: 2026-10-05T01:41:05.172Z