Workers binding
Use the Artifacts Workers binding to create, import, inspect, fork, and delete repos directly from your Worker. The Artifacts binding returns repo handles that allow repo-scoped operations such as token management and forking.
Review Namespaces first, then choose the namespace name you will bind here.
Add the Artifacts binding to your Wrangler config file:
{ "$schema": "./node_modules/wrangler/config-schema.json", "artifacts": [ { "binding": "ARTIFACTS", "namespace": "default" } ]}[[artifacts]]binding = "ARTIFACTS"namespace = "default" # replace with your Artifacts namespace# remote = true # optional: use the remote Artifacts service in local devAfter you run npx wrangler types, your Worker environment looks like this:
export interface Env { ARTIFACTS: Artifacts;}Wrangler generates the Artifacts type for consumers and binds it directly in your environment.
In named Wrangler environments, artifacts is non-inheritable. Repeat the binding in each environment where you need it.
At runtime, deployed Workers use the configured binding directly. For local Wrangler commands such as wrangler dev, wrangler deploy, or wrangler types, authenticate Wrangler first. For local OAuth authentication, refer to wrangler login. For CI or headless environments, refer to Running Wrangler in CI/CD.
Use namespace methods on env.ARTIFACTS to create, list, inspect, import, or delete repos.
nameRepoNamerequiredopts.readOnlybooleanoptionalopts.descriptionstringoptionalopts.setDefaultBranchstringoptional- Returns
Promise<ArtifactsCreateRepoResult>
async function createRepo(artifacts) { const created = await artifacts.create("starter-repo", { description: "Repository for automation experiments", readOnly: false, setDefaultBranch: "main", });
return { defaultBranch: created.defaultBranch, name: created.name, remote: created.remote, initialToken: created.token, };}async function createRepo(artifacts: Artifacts) { const created = await artifacts.create("starter-repo", { description: "Repository for automation experiments", readOnly: false, setDefaultBranch: "main", });
return { defaultBranch: created.defaultBranch, name: created.name, remote: created.remote, initialToken: created.token, };}The returned token encodes its expiry directly in the ?expires= suffix.
nameRepoNamerequired- Returns
Promise<ArtifactsRepo> - Throws if the repo does not exist or is not ready yet.
async function getRepoHandle(artifacts) { const repo = await artifacts.get("starter-repo"); return repo;}async function getRepoHandle(artifacts: Artifacts) { const repo = await artifacts.get("starter-repo"); return repo;}opts.limitnumberoptionalopts.cursorCursoroptional- Returns
Promise<ArtifactsRepoListResult>
async function listRepos(artifacts) { const page = await artifacts.list({ limit: 10 });
return { repos: page.repos.map((repo) => ({ name: repo.name, status: repo.status, })), nextCursor: page.cursor ?? null, };}async function listRepos(artifacts: Artifacts) { const page = await artifacts.list({ limit: 10 });
return { repos: page.repos.map((repo) => ({ name: repo.name, status: repo.status, })), nextCursor: page.cursor ?? null, };}Each listed repo includes a status value of ready, importing, or forking.
Import a repository from an external git remote.
params.source.urlstringrequired — HTTPS URL of the source repository.params.source.branchstringoptional — Branch to import (defaults to the remote's default branch).params.source.depthnumberoptional — Shallow clone depth.params.target.nameRepoNamerequired — Name for the imported repo.params.target.opts.descriptionstringoptionalparams.target.opts.readOnlybooleanoptional- Returns
Promise<ArtifactsCreateRepoResult>
async function importFromGitHub(artifacts) { const imported = await artifacts.import({ source: { url: "https://github.com/cloudflare/workers-sdk", branch: "main", }, target: { name: "workers-sdk", }, });
return { name: imported.name, remote: imported.remote, token: imported.token, };}async function importFromGitHub(artifacts: Artifacts) { const imported = await artifacts.import({ source: { url: "https://github.com/cloudflare/workers-sdk", branch: "main", }, target: { name: "workers-sdk", }, });
return { name: imported.name, remote: imported.remote, token: imported.token, };}Imported repos return the same create-style token format. The token encodes its expiry directly in the ?expires= suffix.
nameRepoNamerequired- Returns
Promise<boolean>
async function deleteRepo(artifacts) { return artifacts.delete("starter-repo");}async function deleteRepo(artifacts: Artifacts) { return artifacts.delete("starter-repo");}Call await artifacts.get(name) to get a repo handle. The handle extends ArtifactsRepoInfo, so repo metadata (id, name, remote, defaultBranch, etc.) is available directly as properties.
async function getRemoteUrl(artifacts) { const repo = await artifacts.get("starter-repo"); return repo.remote;}async function getRemoteUrl(artifacts: Artifacts) { const repo = await artifacts.get("starter-repo"); return repo.remote;}scope"read" | "write"optional (default: "write")ttlnumberoptional (seconds)- Returns
Promise<ArtifactsCreateTokenResult>
async function mintReadToken(artifacts) { const repo = await artifacts.get("starter-repo"); return repo.createToken("read", 3600);}async function mintReadToken(artifacts: Artifacts) { const repo = await artifacts.get("starter-repo"); return repo.createToken("read", 3600);}Unlike create() and import(), repo.createToken() returns a structured result with plaintext and expiresAt. The plaintext value is the Git token string.
- Returns
Promise<ArtifactsTokenListResult>
async function listRepoTokens(artifacts) { const repo = await artifacts.get("starter-repo"); const result = await repo.listTokens(); return { total: result.total, tokens: result.tokens, };}async function listRepoTokens(artifacts: Artifacts) { const repo = await artifacts.get("starter-repo"); const result = await repo.listTokens(); return { total: result.total, tokens: result.tokens, };}tokenOrIdstringrequired- Returns
Promise<boolean>
async function revokeToken(artifacts, tokenOrId) { const repo = await artifacts.get("starter-repo"); return repo.revokeToken(tokenOrId);}async function revokeToken(artifacts: Artifacts, tokenOrId: string) { const repo = await artifacts.get("starter-repo"); return repo.revokeToken(tokenOrId);}nameRepoNamerequiredopts.descriptionstringoptionalopts.readOnlybooleanoptionalopts.defaultBranchOnlybooleanoptional- Returns
Promise<ArtifactsCreateRepoResult>
async function forkRepo(artifacts) { const repo = await artifacts.get("starter-repo"); const forked = await repo.fork("starter-repo-copy", { description: "Fork for testing", defaultBranchOnly: true, readOnly: false, });
return forked.remote;}async function forkRepo(artifacts: Artifacts) { const repo = await artifacts.get("starter-repo"); const forked = await repo.fork("starter-repo-copy", { description: "Fork for testing", defaultBranchOnly: true, readOnly: false, });
return forked.remote;}This example combines the binding methods in one Worker route.
export default { async fetch(request, env) { const url = new URL(request.url);
if (request.method === "POST" && url.pathname === "/repos") { const created = await env.ARTIFACTS.create("starter-repo"); return Response.json({ name: created.name, remote: created.remote, }); }
if (request.method === "GET" && url.pathname === "/repos/starter-repo") { const repo = await env.ARTIFACTS.get("starter-repo"); return Response.json({ id: repo.id, name: repo.name, remote: repo.remote, defaultBranch: repo.defaultBranch, }); }
if (request.method === "POST" && url.pathname === "/tokens") { const repo = await env.ARTIFACTS.get("starter-repo"); const token = await repo.createToken("read", 3600); return Response.json(token); }
return Response.json( { message: "Use POST /repos, GET /repos/starter-repo, or POST /tokens." }, { status: 404 }, ); },};interface Env { ARTIFACTS: Artifacts;}
export default { async fetch(request: Request, env: Env): Promise<Response> { const url = new URL(request.url);
if (request.method === "POST" && url.pathname === "/repos") { const created = await env.ARTIFACTS.create("starter-repo"); return Response.json({ name: created.name, remote: created.remote, }); }
if (request.method === "GET" && url.pathname === "/repos/starter-repo") { const repo = await env.ARTIFACTS.get("starter-repo"); return Response.json({ id: repo.id, name: repo.name, remote: repo.remote, defaultBranch: repo.defaultBranch, }); }
if (request.method === "POST" && url.pathname === "/tokens") { const repo = await env.ARTIFACTS.get("starter-repo"); const token = await repo.createToken("read", 3600); return Response.json(token); }
return Response.json( { message: "Use POST /repos, GET /repos/starter-repo, or POST /tokens." }, { status: 404 }, ); },} satisfies ExportedHandler<Env>;Run npx wrangler types in your own project and treat the generated worker-configuration.d.ts file as the source of truth for the Artifacts binding types in that environment.