Artifact Workspace
Versioned filesystem-style artifact workspace on R2 - store, list, and retrieve build or agent artifacts like a remote FS
Artifacts-style versioned filesystem workspace. Cloudflare Artifacts bindings are still evolving, so this experiment uses an R2 bucket behind a typed ArtifactStore interface until a stable Artifacts binding is available.
Features
PUT /files?path=- store text contentGET /files?path=- read file contentGET /files/list?prefix=- list pathsDELETE /files?path=- delete a file
API Reference
Path rules
- Max length 256
- Allowed characters: alphanumeric,
/,_,-,. - No
..segments
PUT /files
Store text content at a path. Body is raw text.
path string (required)
Example Request
curl -X PUT "https://your-worker.workers.dev/files?path=notes/hello.txt" \
-H "Content-Type: text/plain" \
-d "hello world"Success Response
{
"path": "notes/hello.txt",
"stored": true
}GET /files
Returns the file body as text/plain, or 404 if missing.
path string (required)
Example Request
curl "https://your-worker.workers.dev/files?path=notes/hello.txt"GET /files/list
List stored paths, optionally filtered by prefix.
prefix string (optional)
Example Request
curl "https://your-worker.workers.dev/files/list?prefix=notes/"Success Response
{
"files": [{ "path": "notes/hello.txt" }],
"prefix": "notes/"
}DELETE /files
path string (required)
Example Request
curl -X DELETE "https://your-worker.workers.dev/files?path=notes/hello.txt"Success Response
{
"path": "notes/hello.txt",
"deleted": true
}Error Codes
400- Missing or invalid path/prefix (INVALID_PATH)404- File does not exist (NOT_FOUND)
Use Cases
- Learn Artifacts-style workspace patterns on Workers
- Store generated code, reports, or build outputs at the edge
- Swap R2 for a future native Artifacts binding via
ArtifactStore - Prototype multi-tenant file APIs with path prefixes
Limitations
- Uses R2 as a stand-in; not the final Artifacts product API
- Text bodies only in this demo
- Path validation rejects
..and unusual characters - No authentication or per-user isolation beyond path conventions
Use in your project
Copy these files into an existing Worker. Prefer Deployment to try the full experiment first. Source: apps/experiments/artifact-workspace.
import { MAX_PATH_LENGTH, PATH_PATTERN } from "../constants/defaults";import type { ArtifactStore } from "../types/env";export function validatePath(input: string | undefined): string | null { if (!input || typeof input !== "string") return null; const trimmed = input.trim(); if (!trimmed || trimmed.length > MAX_PATH_LENGTH) return null; if (trimmed.includes("..")) return null; if (!PATH_PATTERN.test(trimmed)) return null; return trimmed;}/** R2-backed ArtifactStore for the Artifacts-style workspace demo. */export function createR2ArtifactStore(bucket: R2Bucket): ArtifactStore { return { async put(path: string, data: string | ArrayBuffer): Promise<void> { await bucket.put(path, data); }, async get(path: string): Promise<ReadableStream | null> { const object = await bucket.get(path); return object?.body ?? null; }, async list(prefix?: string): Promise<{ path: string }[]> { const listed = await bucket.list({ prefix: prefix || undefined }); return listed.objects.map((obj) => ({ path: obj.key })); }, async delete(path: string): Promise<void> { await bucket.delete(path); }, };}Deployment
Configure R2
Create the R2 bucket artifact-workspace (or update wrangler.json) and bind it as ARTIFACTS.
Test your deployment
curl -X PUT "https://your-worker.workers.dev/files?path=notes/hello.txt" \
-H "Content-Type: text/plain" \
-d "hello world"Local Development
cd apps/experiments/artifact-workspace
npm install
npm run devcurl -X PUT "http://localhost:8787/files?path=notes/hello.txt" \
-H "Content-Type: text/plain" \
-d "hello world"Configuration
wrangler.json declares:
- R2 bucket
ARTIFACTS→artifact-workspace
When a stable Artifacts binding lands, the intended shape is artifacts: [{ binding: "ARTIFACTS", name: "workspace" }]. The ArtifactStore interface isolates route code from the backend.