Live. This area is documented as current, user-reliable behavior.
Goal
Upload a public asset and get a CDN URL with the official SDK.
Prerequisites
- A StackShift API key
- An SDK installed in your backend app
Workflow
Create a StackShift client with apiKey.
Call the Assets upload method with a file, bucket, key, visibility, and metadata.
Store the returned asset ID in your app if you need later replacement or deletion.
Use asset.url for originals, assets.url for transforms, videoUrl helpers for playback outputs, and version helpers for pinned delivery.
TypeScript
import { StackShift } from '@stackshift-cloud/sdk'
const stackshift = new StackShift({
apiKey: process.env.STACKSHIFT_API_KEY!,
})
const asset = await stackshift.assets.upload(file, {
bucket: 'avatars',
key: 'users/user_123.png',
visibility: 'public',
metadata: { userId: 'user_123' },
})
console.log(asset.url)
NestJS
Wrap the SDK in a service and accept files through NestJS Multer interceptors. For larger browser uploads, create signed upload URLs instead of buffering through the NestJS process.
import { Injectable } from '@nestjs/common'
import { StackShift } from '@stackshift-cloud/sdk'
@Injectable()
export class AssetsService {
private readonly stackshift = new StackShift({
apiKey: process.env.STACKSHIFT_API_KEY!,
})
upload(file: Express.Multer.File) {
return this.stackshift.assets.upload(
new Blob([file.buffer], { type: file.mimetype }),
{
bucket: 'uploads',
key: file.originalname,
visibility: 'private',
metadata: { originalName: file.originalname },
},
)
}
}
import { Controller, Post, UploadedFile, UseInterceptors } from '@nestjs/common'
import { FileInterceptor } from '@nestjs/platform-express'
import { AssetsService } from './assets.service'
@Controller('assets')
export class AssetsController {
constructor(private readonly assets: AssetsService) {}
@Post('upload')
@UseInterceptors(FileInterceptor('file'))
upload(@UploadedFile() file: Express.Multer.File) {
return this.assets.upload(file)
}
}
React, Next.js, and TanStack Start
Browser apps should never receive the StackShift API key. Create a signed upload URL on a server route, then upload the browser File directly to StackShift Assets.
import { StackShift } from '@stackshift-cloud/sdk'
const stackshift = new StackShift({
apiKey: process.env.STACKSHIFT_API_KEY!,
})
export async function createAvatarUpload() {
return stackshift.assets.signedUploadUrl({
bucket: 'avatars',
key: `users/${crypto.randomUUID()}.png`,
visibility: 'public',
expiresIn: '10m',
maxBytes: 5_000_000,
})
}
async function uploadAvatar(file: File) {
const upload = await fetch('/api/assets/avatar-upload', {
method: 'POST',
}).then((response) => response.json())
await fetch(upload.url, {
method: upload.method,
body: file,
headers: { 'Content-Type': file.type },
})
}
Python
from stackshift import StackShift
stackshift = StackShift(api_key="sk_live_...")
asset = stackshift.assets.upload(
"avatar.png",
bucket="avatars",
key="users/user_123.png",
visibility="public",
metadata={"user_id": "user_123"},
)
print(asset["url"])
import (
"context"
"log"
"os"
stackshift "github.com/stackshiftCloud/assets-go"
)
client, err := stackshift.New(stackshift.Options{
APIKey: os.Getenv("STACKSHIFT_API_KEY"),
})
file, _ := os.Open("avatar.png")
defer file.Close()
asset, err := client.Assets.Upload(ctx, stackshift.AssetUpload{
File: file,
FileName: "avatar.png",
Bucket: "avatars",
Key: "users/user_123.png",
Visibility: "public",
})
log.Println(asset.URL)
Expected result
Your app uploads a file to StackShift Assets and receives provider-neutral asset metadata.
StackShift Assets overview
StackShift Assets is now a live media platform: storage, CDN delivery, image optimization, upload sessions, DAM, video, scanning, governance, AI metadata, and version history.
Direct browser uploads
Create a short-lived signed upload URL on your server, then PUT the file directly from the browser.
Image optimization
Use named presets and signed dynamic transforms for strict, cached, responsive image delivery.
AI DAM and versioning
Use OpenAI-backed asset intelligence, moderation, transcripts, smart crops, background removal, collections, saved searches, and branching versions.