env.storage
Provides the put, get, head, delete, list, and presign APIs.
export interface Storage {
put(key: string, body: BodyInit | null, opts?: { contentType?: string }): Promise<StorageObject>;
/** Returns `null` if the key does not exist. It is not a 404 error. */
get(key: string): Promise<(StorageObject & { body: ReadableStream<Uint8Array> | null }) | null>;
head(key: string): Promise<StorageObject | null>;
/** Safe to call repeatedly. Deleting a key that does not exist still succeeds. */
delete(key: string): Promise<void>;
list(opts?: { prefix?: string; cursor?: string; limit?: number }): Promise<StorageListPage>;
/** A signed URL. Only GET and PUT are supported. ttl is in seconds (default 300, max 3600). */
presign(key: string, opts?: { method?: "GET" | "PUT"; ttl?: number }): Promise<string>;
}Object metadata has the following shape.
export interface StorageObject {
key: string;
size: number;
etag: string;
contentType: string;
/** RFC 1123 format, and may be empty. */
lastModified: string;
}A missing key returns null
get and head return null when the key does not exist. Checking whether an object exists is a common operation, so we designed the API so you don't have to wrap every call in try/catch to handle a 404.
delete is safe to call repeatedly. Deleting a key that does not exist still succeeds.
Key rules
Write keys as paths separated by /.
await env.storage.put("users/42/avatar.png", body);Empty path segments and . or .. are not allowed.
await env.storage.put("a//b", body); // TypeError
await env.storage.put("a/../b", body); // TypeErrorOnce a URL parser normalizes /o/../x to /x, the original path can no longer be inspected. That is why the worker rejects these keys before the request is sent.
A key can be at most 1024 bytes long.
Files are isolated between projects
The project identifier is added to storage keys automatically. You cannot address another project's objects by key.