enigmare/v2-crawler
1904
1{"id":"doc-data_migration_cloudflare_r2_docs-af436ef5","source":"documentation","title":"Data migration · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/data-migration/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.076Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":46}}2{"id":"doc-get_started_cloudflare_r2_docs-48e54b26","source":"documentation","title":"Get started · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/get-started/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.076Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":46}}3{"id":"doc-overview_cloudflare_r2_docs-26afc95d","source":"documentation","title":"Overview · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.076Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":46}}4{"id":"doc-how_r2_works_cloudflare_r2_docs-07cfdf90","source":"documentation","title":"How R2 works · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/how-r2-works/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.076Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":46}}5{"id":"doc-migration_strategies_cloudflare_r2_docs-0009b85c","source":"documentation","title":"Migration Strategies · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/data-migration/migration-strategies/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.076Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":46}}6{"id":"doc-workers_api_cloudflare_r2_docs-275afedf","source":"documentation","title":"Workers API · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/get-started/workers-api/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nnpx wrangler login\n```\n\nExample:\n```text\nnpx wrangler r2 bucket create my-bucket\n```\n\nExample:\n```text\nnpx wrangler r2 bucket list\n```\n\nExample:\n```text\nnpm create cloudflare@latest -- r2-worker\n```\n\nExample:\n```text\nyarn create cloudflare r2-worker\n```\n\nExample:\n```text\npnpm create cloudflare@latest r2-worker\n```\n\nExample:\n```text\ncd r2-worker\n```\n\nExample:\n```text\n{\n \"r2_buckets\": [\n {\n \"binding\": \"MY_BUCKET\",\n \"bucket_name\": \"my-bucket\"\n }\n ]\n}\n```\n\nExample:\n```text\n[[r2_buckets]]\nbinding = \"MY_BUCKET\"\nbucket_name = \"my-bucket\"\n```\n\nExample:\n```text\nnpx wrangler types\n```\n\nExample:\n```text\nexport default {\n\tasync fetch(request, env) {\n\t\t// Get the object key from the URL path\n\t\t// For example: /images/cat.png → images/cat.png\n\t\tconst url = new URL(request.url);\n\t\tconst key = url.pathname.slice(1);\n\n\t\t// PUT: Store the request body in R2\n\t\tif (request.method === \"PUT\") {\n\t\t\tawait env.MY_BUCKET.put(key, request.body);\n\t\t\treturn new Response(`Put ${key} successfully!`);\n\t\t}\n\n\t\t// GET: Retrieve the object from R2\n\t\tconst object = await env.MY_BUCKET.get(key);\n\t\tif (object === null) {\n\t\t\treturn new Response(\"Object not found\", { status: 404 });\n\t\t}\n\t\treturn new Response(object.body);\n\t},\n};\n```\n\nExample:\n```text\nexport default {\n\tasync fetch(request, env): Promise<Response> {\n\t\t// Get the object key from the URL path\n\t\t// For example: /images/cat.png → images/cat.png\n\t\tconst url = new URL(request.url);\n\t\tconst key = url.pathname.slice(1);\n\n\t\t// PUT: Store the request body in R2\n\t\tif (request.method === \"PUT\") {\n\t\t\tawait env.MY_BUCKET.put(key, request.body);\n\t\t\treturn new Response(`Put ${key} successfully!`);\n\t\t}\n\n\t\t// GET: Retrieve the object from R2\n\t\tconst object = await env.MY_BUCKET.get(key);\n\t\tif (object === null) {\n\t\t\treturn new Response(\"Object not found\", { status: 404 });\n\t\t}\n\t\treturn new Response(object.body);\n\t},\n} satisfies ExportedHandler<Env>;\n```\n\nExample:\n```text\nnpx wrangler dev\n```\n\nExample:\n```text\n# Store an object\ncurl -X PUT http://localhost:8787/my-file.txt -d 'Hello, R2!'\n\n# Retrieve the object\ncurl http://localhost:8787/my-file.txt\n```\n\nExample:\n```text\nnpx wrangler deploy\n```\n\nExample:\n```text\n# Store an object\ncurl -X PUT https://r2-worker.<YOUR_SUBDOMAIN>.workers.dev/my-file.txt -d 'Hello, R2!'\n\n# Retrieve the object\ncurl https://r2-worker.<YOUR_SUBDOMAIN>.workers.dev/my-file.txt\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.077Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":16,"totalLines":140,"estimatedTokens":643}}7{"id":"doc-super_slurper_cloudflare_r2_docs-b6d3d6d2","source":"documentation","title":"Super Slurper · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/data-migration/super-slurper/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\n{\n\t\"Version\": \"2012-10-17\",\n\t\"Statement\": [\n\t\t{\n\t\t\t\"Effect\": \"Allow\",\n\t\t\t\"Action\": [\"s3:Get*\", \"s3:List*\"],\n\t\t\t\"Resource\": [\"arn:aws:s3:::<BUCKET_NAME>\", \"arn:aws:s3:::<BUCKET_NAME>/*\"]\n\t\t}\n\t]\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.077Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":1,"totalLines":17,"estimatedTokens":100}}8{"id":"doc-cli_cloudflare_r2_docs-ae1a12d6","source":"documentation","title":"CLI · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/get-started/cli/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nnpx wrangler login\n```\n\nExample:\n```text\nnpx wrangler r2 bucket create my-bucket\n```\n\nExample:\n```text\nnpx wrangler r2 bucket list\n```\n\nExample:\n```text\nnpm i -D wrangler\n```\n\nExample:\n```text\nyarn add -D wrangler\n```\n\nExample:\n```text\npnpm add -D wrangler\n```\n\nExample:\n```text\nbun add -d wrangler\n```\n\nExample:\n```text\nwrangler login\n```\n\nExample:\n```text\nrclone config\n```\n\nExample:\n```text\naws configure\n```\n\nExample:\n```text\necho 'Hello, R2!' > myfile.txt\n```\n\nExample:\n```text\n# Upload myfile.txt to my-bucket\nwrangler r2 object put my-bucket/myfile.txt --file ./myfile.txt\n\n# Download myfile.txt and save it as downloaded.txt\nwrangler r2 object get my-bucket/myfile.txt --file ./downloaded.txt\n```\n\nExample:\n```text\n# Upload myfile.txt to my-bucket\nrclone copy myfile.txt r2:my-bucket/\n\n# Download myfile.txt from my-bucket to the current directory\nrclone copy r2:my-bucket/myfile.txt .\n```\n\nExample:\n```text\n# Upload myfile.txt to my-bucket\naws s3 cp myfile.txt s3://my-bucket/ --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com\n\n# Download myfile.txt from my-bucket to current directory\naws s3 cp s3://my-bucket/myfile.txt ./ --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com\n\n# List all objects in my-bucket\naws s3 ls s3://my-bucket/ --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.077Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":14,"totalLines":88,"estimatedTokens":383}}9{"id":"doc-s3_cloudflare_r2_docs-5775d6af","source":"documentation","title":"S3 · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/get-started/s3/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nnpx wrangler login\n```\n\nExample:\n```text\nnpx wrangler r2 bucket create my-bucket\n```\n\nExample:\n```text\nnpx wrangler r2 bucket list\n```\n\nExample:\n```text\nhttps://<ACCOUNT_ID>.r2.cloudflarestorage.com\n```\n\nExample:\n```text\npip install boto3\n```\n\nExample:\n```text\necho 'Hello, R2!' > myfile.txt\n```\n\nExample:\n```text\nimport boto3\n\ns3 = boto3.client(\n service_name='s3',\n # Provide your R2 endpoint: https://<ACCOUNT_ID>.r2.cloudflarestorage.com\n endpoint_url='https://<ACCOUNT_ID>.r2.cloudflarestorage.com',\n # Provide your R2 Access Key ID and Secret Access Key\n aws_access_key_id='<ACCESS_KEY_ID>',\n aws_secret_access_key='<SECRET_ACCESS_KEY>',\n region_name='auto', # Required by boto3, not used by R2\n)\n\n# Upload a file\ns3.upload_file('myfile.txt', 'my-bucket', 'myfile.txt')\nprint('Uploaded myfile.txt')\n\n# Download a file\ns3.download_file('my-bucket', 'myfile.txt', 'downloaded.txt')\nprint('Downloaded to downloaded.txt')\n\n# List objects\nresponse = s3.list_objects_v2(Bucket='my-bucket')\nfor obj in response.get('Contents', []):\n print(f\"Object: {obj['Key']}\")\n```\n\nExample:\n```text\npython example.py\n```\n\nExample:\n```text\nUploaded myfile.txt\nDownloaded to downloaded.txt\nObject: myfile.txt\n```\n\nExample:\n```text\nnpm install @aws-sdk/client-s3\n```\n\nExample:\n```text\nimport {\n\tS3Client,\n\tPutObjectCommand,\n\tGetObjectCommand,\n\tListObjectsV2Command,\n} from \"@aws-sdk/client-s3\";\n\nconst s3 = new S3Client({\n\tregion: \"auto\", // Required by AWS SDK, not used by R2\n\t// Provide your R2 endpoint: https://<ACCOUNT_ID>.r2.cloudflarestorage.com\n\tendpoint: \"https://<ACCOUNT_ID>.r2.cloudflarestorage.com\",\n\tcredentials: {\n\t\t// Provide your R2 Access Key ID and Secret Access Key\n\t\taccessKeyId: \"<ACCESS_KEY_ID>\",\n\t\tsecretAccessKey: \"<SECRET_ACCESS_KEY>\",\n\t},\n});\n\n// Upload a file\nawait s3.send(\n\tnew PutObjectCommand({\n\t\tBucket: \"my-bucket\",\n\t\tKey: \"myfile.txt\",\n\t\tBody: \"Hello, R2!\",\n\t}),\n);\nconsole.log(\"Uploaded myfile.txt\");\n\n// Download a file\nconst response = await s3.send(\n\tnew GetObjectCommand({\n\t\tBucket: \"my-bucket\",\n\t\tKey: \"myfile.txt\",\n\t}),\n);\nconst content = await response.Body.transformToString();\nconsole.log(\"Downloaded:\", content);\n\n// List objects\nconst list = await s3.send(\n\tnew ListObjectsV2Command({\n\t\tBucket: \"my-bucket\",\n\t}),\n);\nconsole.log(\n\t\"Objects:\",\n\tlist.Contents.map((obj) => obj.Key),\n);\n```\n\nExample:\n```text\nnode example.mjs\n```\n\nExample:\n```text\nUploaded myfile.txt\nDownloaded: Hello, R2!\nObjects: [ 'myfile.txt' ]\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.078Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":13,"totalLines":142,"estimatedTokens":669}}10{"id":"doc-buckets_cloudflare_r2_docs-35b25237","source":"documentation","title":"Buckets · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/buckets/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.078Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":46}}11{"id":"doc-public_buckets_cloudflare_r2_docs-b7a759b2","source":"documentation","title":"Public buckets · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/buckets/public-buckets/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.078Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":46}}12{"id":"doc-sippy_cloudflare_r2_docs-4cc2d30e","source":"documentation","title":"Sippy · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/data-migration/sippy/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nnpx wrangler r2 bucket sippy enable <BUCKET_NAME>\n```\n\nExample:\n```text\nnpx wrangler r2 bucket sippy disable <BUCKET_NAME>\n```\n\nExample:\n```text\n{\n\t\"Version\": \"2012-10-17\",\n\t\"Statement\": [\n\t\t{\n\t\t\t\"Effect\": \"Allow\",\n\t\t\t\"Action\": [\"s3:ListBucket*\", \"s3:GetObject*\"],\n\t\t\t\"Resource\": [\n\t\t\t\t\"arn:aws:s3:::<BUCKET_NAME>\",\n\t\t\t\t\"arn:aws:s3:::<BUCKET_NAME>/*\"\n\t\t\t]\n\t\t}\n\t]\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.079Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":3,"totalLines":30,"estimatedTokens":143}}13{"id":"doc-create_new_buckets_cloudflare_r2_docs-d2c03224","source":"documentation","title":"Create new buckets · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/buckets/create-buckets/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nwrangler r2 bucket create your-bucket-name\n```\n\nExample:\n```text\nwrangler r2 bucket list\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.079Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":2,"totalLines":13,"estimatedTokens":74}}14{"id":"doc-bucket_locks_cloudflare_r2_docs-6a4c0c79","source":"documentation","title":"Bucket locks · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/buckets/bucket-locks/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nnpx wrangler r2 bucket lock add <BUCKET_NAME> [OPTIONS]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket lock set <BUCKET_NAME> --file <FILE_PATH>\n```\n\nExample:\n```text\ncurl -X PUT \"https://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/r2/buckets/<BUCKET_NAME>/lock\" \\\n -H \"Authorization: Bearer <API_TOKEN>\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"rules\": [\n {\n \"id\": \"lock-logs-7d\",\n \"enabled\": true,\n \"prefix\": \"logs/\",\n \"condition\": {\n \"type\": \"Age\",\n \"maxAgeSeconds\": 604800\n }\n },\n {\n \"id\": \"lock-images-indefinite\",\n \"enabled\": true,\n \"prefix\": \"images/\",\n \"condition\": {\n \"type\": \"Indefinite\"\n }\n }\n ]\n }'\n```\n\nExample:\n```text\nnpx wrangler r2 bucket lock list <BUCKET_NAME>\n```\n\nExample:\n```text\nnpx wrangler r2 bucket lock remove <BUCKET_NAME> --id <RULE_ID>\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.079Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":5,"totalLines":51,"estimatedTokens":316}}15{"id":"doc-local_uploads_cloudflare_r2_docs-d2e6fb40","source":"documentation","title":"Local uploads · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/buckets/local-uploads/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nnpx wrangler r2 bucket local-uploads enable <BUCKET_NAME>\n```\n\nExample:\n```text\nnpx wrangler r2 bucket local-uploads disable <BUCKET_NAME>\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.079Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":2,"totalLines":13,"estimatedTokens":86}}16{"id":"doc-delete_buckets_cloudflare_r2_docs-be507e31","source":"documentation","title":"Delete buckets · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/buckets/delete-buckets/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nnpx wrangler r2 bucket lifecycle add <BUCKET_NAME> --expire-days 1\n```\n\nExample:\n```text\nnpx wrangler r2 bucket lifecycle remove <BUCKET_NAME> --id <RULE_ID>\n```\n\nExample:\n```text\nnpx wrangler r2 bucket delete <BUCKET_NAME>\n```\n\nExample:\n```text\ncurl -X DELETE \"https://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/r2/buckets/<BUCKET_NAME>\" \\\n -H \"Authorization: Bearer <API_TOKEN>\"\n```\n\nExample:\n```text\ncurl -X DELETE \"https://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/r2/buckets/<BUCKET_NAME>\" \\\n -H \"Authorization: Bearer <API_TOKEN>\" \\\n -H \"cf-r2-jurisdiction: eu\"\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.080Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":5,"totalLines":31,"estimatedTokens":199}}17{"id":"doc-objects_cloudflare_r2_docs-465c6cf5","source":"documentation","title":"Objects · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/objects/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.080Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":46}}18{"id":"doc-api_cloudflare_r2_docs-24001ae3","source":"documentation","title":"API · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/api/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.080Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":46}}19{"id":"doc-configure_cors_cloudflare_r2_docs-148e84e6","source":"documentation","title":"Configure CORS · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/buckets/cors/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\n[\n {\n \"AllowedOrigins\": [\"https://example.com\"],\n \"AllowedMethods\": [\"PUT\"],\n \"AllowedHeaders\": [\"Content-Type\"],\n \"ExposeHeaders\": [\"ETag\"],\n \"MaxAgeSeconds\": 3600\n }\n]\n```\n\nExample:\n```text\n{\n \"rules\": [\n {\n \"allowed\": {\n \"origins\": [\"https://example.com\"],\n \"methods\": [\"GET\"]\n }\n }\n ]\n}\n```\n\nExample:\n```text\nnpx wrangler r2 bucket cors set <BUCKET_NAME> --file cors.json\n```\n\nExample:\n```text\nnpx wrangler r2 bucket cors list <BUCKET_NAME>\n```\n\nExample:\n```text\n[\n\t{\n\t\t\"AllowedOrigins\": [\"http://localhost:3000\"],\n\t\t\"AllowedMethods\": [\"GET\"]\n\t}\n]\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.080Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":5,"totalLines":50,"estimatedTokens":202}}20{"id":"doc-temporary_credentials_cloudflare_r2_docs-4273c722","source":"documentation","title":"Temporary credentials · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/api/s3/temporary-credentials/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\n{\n \"prefixes\": [\"uploads/user-123/\"],\n \"objects\": [\"shared/manifest.json\"]\n}\n```\n\nExample:\n```text\n{\n \"paths\": {\n \"prefixPaths\": [\"uploads/user-123/\"],\n \"objectPaths\": [\"shared/manifest.json\"]\n }\n}\n```\n\nExample:\n```text\nimport { AwsClient } from \"aws4fetch\";\n\nconst R2_URL = `https://${ACCOUNT_ID}.r2.cloudflarestorage.com`;\n\nconst client = new AwsClient({\n\taccessKeyId: ACCESS_KEY_ID,\n\tsecretAccessKey: SECRET_ACCESS_KEY,\n\tsessionToken: SESSION_TOKEN,\n\tservice: \"s3\",\n});\n\nconst response = await client.fetch(`${R2_URL}/my-bucket/image.png`);\n```\n\nExample:\n```text\nimport boto3\n\ns3 = boto3.client(\n service_name=\"s3\",\n endpoint_url=\"https://<ACCOUNT_ID>.r2.cloudflarestorage.com\",\n aws_access_key_id=\"<ACCESS_KEY_ID>\",\n aws_secret_access_key=\"<SECRET_ACCESS_KEY>\",\n aws_session_token=\"<SESSION_TOKEN>\",\n region_name=\"auto\",\n)\n```\n\nExample:\n```text\nAWS_ACCESS_KEY_ID=<ACCESS_KEY_ID>\nAWS_SECRET_ACCESS_KEY=<SECRET_ACCESS_KEY>\nAWS_SESSION_TOKEN=<SESSION_TOKEN>\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.081Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":5,"totalLines":58,"estimatedTokens":298}}21{"id":"doc-download_objects_cloudflare_r2_docs-2feab7f2","source":"documentation","title":"Download objects · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/objects/download-objects/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nexport default {\n\tasync fetch(request: Request, env: Env, ctx: ExecutionContext) {\n\t\tconst object = await env.MY_BUCKET.get(\"image.png\");\n\t\tif (object === null) {\n\t\t\treturn new Response(\"Object not found\", { status: 404 });\n\t\t}\n\t\treturn new Response(object.body);\n\t},\n} satisfies ExportedHandler<Env>;\n```\n\nExample:\n```text\nimport { S3Client, GetObjectCommand } from \"@aws-sdk/client-s3\";\n\nconst S3 = new S3Client({\n\tregion: \"auto\", // Required by SDK but not used by R2\n\t// Provide your Cloudflare account ID\n\tendpoint: `https://<ACCOUNT_ID>.r2.cloudflarestorage.com`,\n\t// Retrieve your S3 API credentials for your R2 bucket via API tokens (see: https://developers.cloudflare.com/r2/api/tokens)\n\tcredentials: {\n\t\taccessKeyId: '<ACCESS_KEY_ID>',\n\t\tsecretAccessKey: '<SECRET_ACCESS_KEY>',\n\t},\n});\n\nconst response = await S3.send(\n\tnew GetObjectCommand({\n\t\tBucket: \"my-bucket\",\n\t\tKey: \"image.png\",\n\t}),\n);\n```\n\nExample:\n```text\nimport boto3\n\ns3 = boto3.client(\n\tservice_name=\"s3\",\n\t# Provide your Cloudflare account ID\n\tendpoint_url=f\"https://{ACCOUNT_ID}.r2.cloudflarestorage.com\",\n\t# Retrieve your S3 API credentials for your R2 bucket via API tokens (see: https://developers.cloudflare.com/r2/api/tokens)\n\taws_access_key_id=ACCESS_KEY_ID,\n\taws_secret_access_key=SECRET_ACCESS_KEY,\n\tregion_name=\"auto\", # Required by SDK but not used by R2\n)\n\nresponse = s3.get_object(Bucket=\"my-bucket\", Key=\"image.png\")\nimage_data = response[\"Body\"].read()\n```\n\nExample:\n```text\nwrangler r2 object get test-bucket/image.png\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.081Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":4,"totalLines":62,"estimatedTokens":429}}22{"id":"doc-authentication_cloudflare_r2_docs-a2c9f0cb","source":"documentation","title":"Authentication · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/api/tokens/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\n\"com.cloudflare.edge.r2.bucket.<ACCOUNT_ID>_<JURISDICTION>_<BUCKET_NAME>\": \"*\"\n```\n\nExample:\n```text\n\"com.cloudflare.api.account.<ACCOUNT_ID>\": {\n \"com.cloudflare.edge.r2.bucket.*\": \"*\"\n}\n```\n\nExample:\n```text\n[\n\t{\n\t\t\"id\": \"f267e341f3dd4697bd3b9f71dd96247f\",\n\t\t\"effect\": \"allow\",\n\t\t\"resources\": {\n\t\t\t\"com.cloudflare.edge.r2.bucket.4793d734c0b8e484dfc37ec392b5fa8a_default_my-bucket\": \"*\",\n\t\t\t\"com.cloudflare.edge.r2.bucket.4793d734c0b8e484dfc37ec392b5fa8a_eu_my-eu-bucket\": \"*\"\n\t\t},\n\t\t\"permission_groups\": [\n\t\t\t{\n\t\t\t\t\"id\": \"6a018a9f2fc74eb6b293b0c548f38b39\",\n\t\t\t\t\"name\": \"Workers R2 Storage Bucket Item Read\"\n\t\t\t}\n\t\t]\n\t}\n]\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.081Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":3,"totalLines":35,"estimatedTokens":208}}23{"id":"doc-storage_classes_cloudflare_r2_docs-521914f4","source":"documentation","title":"Storage classes · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/buckets/storage-classes/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\naws s3api copy-object \\\n --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com \\\n --bucket bucket-name \\\n --key path/to/object.txt \\\n --copy-source /bucket-name/path/to/object.txt \\\n --storage-class STANDARD_IA\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.081Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":1,"totalLines":13,"estimatedTokens":107}}24{"id":"doc-delete_objects_cloudflare_r2_docs-f0a03598","source":"documentation","title":"Delete objects · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/objects/delete-objects/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nexport default {\n\tasync fetch(request: Request, env: Env, ctx: ExecutionContext) {\n\t\tawait env.MY_BUCKET.delete(\"image.png\");\n\t\treturn new Response(\"Deleted\");\n\t},\n} satisfies ExportedHandler<Env>;\n```\n\nExample:\n```text\nimport { S3Client, DeleteObjectCommand } from \"@aws-sdk/client-s3\";\n\nconst S3 = new S3Client({\n\tregion: \"auto\", // Required by SDK but not used by R2\n\t// Provide your Cloudflare account ID\n\tendpoint: `https://<ACCOUNT_ID>.r2.cloudflarestorage.com`,\n\t// Retrieve your S3 API credentials for your R2 bucket via API tokens (see: https://developers.cloudflare.com/r2/api/tokens)\n\tcredentials: {\n\t\taccessKeyId: '<ACCESS_KEY_ID>',\n\t\tsecretAccessKey: '<SECRET_ACCESS_KEY>',\n\t},\n});\n\nawait S3.send(\n\tnew DeleteObjectCommand({\n\t\tBucket: \"my-bucket\",\n\t\tKey: \"image.png\",\n\t}),\n);\n```\n\nExample:\n```text\nimport boto3\n\ns3 = boto3.client(\n\tservice_name=\"s3\",\n\t# Provide your Cloudflare account ID\n\tendpoint_url=f\"https://{ACCOUNT_ID}.r2.cloudflarestorage.com\",\n\t# Retrieve your S3 API credentials for your R2 bucket via API tokens (see: https://developers.cloudflare.com/r2/api/tokens)\n\taws_access_key_id=ACCESS_KEY_ID,\n\taws_secret_access_key=SECRET_ACCESS_KEY,\n\tregion_name=\"auto\", # Required by SDK but not used by R2\n)\n\ns3.delete_object(Bucket=\"my-bucket\", Key=\"image.png\")\n```\n\nExample:\n```text\nwrangler r2 object delete test-bucket/image.png\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.081Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":4,"totalLines":58,"estimatedTokens":390}}25{"id":"doc-extensions_cloudflare_r2_docs-176fae5d","source":"documentation","title":"Extensions · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/api/s3/extensions/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nPUT / HTTP/1.1\nHost: bucket.account.r2.cloudflarestorage.com\n<CreateBucketConfiguration xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">\n <LocationConstraint>auto</LocationConstraint>\n</CreateBucketConfiguration>\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.082Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":1,"totalLines":12,"estimatedTokens":105}}26{"id":"doc-event_notifications_cloudflare_r2_docs-ec30e9b5","source":"documentation","title":"Event notifications · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/buckets/event-notifications/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nnpx wrangler r2 bucket notification create <BUCKET_NAME> --event-type <EVENT_TYPE> --queue <QUEUE_NAME>\n```\n\nExample:\n```text\n# Filter using prefix\n$ npx wrangler r2 bucket notification create <BUCKET_NAME> --event-type <EVENT_TYPE> --queue <QUEUE_NAME> --prefix \"<PREFIX_VALUE>\"\n\n# Filter using suffix\n$ npx wrangler r2 bucket notification create <BUCKET_NAME> --event-type <EVENT_TYPE> --queue <QUEUE_NAME> --suffix \"<SUFFIX_VALUE>\"\n\n# Filter using prefix and suffix. Both the conditions will be used for filtering\n$ npx wrangler r2 bucket notification create <BUCKET_NAME> --event-type <EVENT_TYPE> --queue <QUEUE_NAME> --prefix \"<PREFIX_VALUE>\" --suffix \"<SUFFIX_VALUE>\"\n```\n\nExample:\n```text\n{\n\t\"account\": \"3f4b7e3dcab231cbfdaa90a6a28bd548\",\n\t\"action\": \"CopyObject\",\n\t\"bucket\": \"my-bucket\",\n\t\"object\": {\n\t\t\"key\": \"my-new-object\",\n\t\t\"size\": 65536,\n\t\t\"eTag\": \"c846ff7a18f28c2e262116d6e8719ef0\"\n\t},\n\t\"eventTime\": \"2024-05-24T19:36:44.379Z\",\n\t\"copySource\": {\n\t\t\"bucket\": \"my-bucket\",\n\t\t\"object\": \"my-original-object\"\n\t}\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.082Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":3,"totalLines":39,"estimatedTokens":307}}27{"id":"doc-examples_cloudflare_r2_docs-bee7f08a","source":"documentation","title":"Examples · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/examples/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.082Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":46}}28{"id":"doc-object_lifecycles_cloudflare_r2_docs-e07bc6a6","source":"documentation","title":"Object lifecycles · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/buckets/object-lifecycles/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nnpx wrangler r2 bucket lifecycle add <BUCKET_NAME> [OPTIONS]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket lifecycle set <BUCKET_NAME> --file <FILE_PATH>\n```\n\nExample:\n```text\nconst client = new S3({\n\tendpoint: \"https://<account_id>.r2.cloudflarestorage.com\",\n\tcredentials: {\n\t\taccessKeyId: \"<access_key_id>\",\n\t\tsecretAccessKey: \"<access_key_secret>\",\n\t},\n\tregion: \"auto\",\n});\n```\n\nExample:\n```text\nawait client\n\t.putBucketLifecycleConfiguration({\n\t\tBucket: \"testBucket\",\n\t\tLifecycleConfiguration: {\n\t\t\tRules: [\n\t\t\t\t// Example: deleting objects on a specific date\n\t\t\t\t// Delete 2019 documents in 2024\n\t\t\t\t{\n\t\t\t\t\tID: \"Delete 2019 Documents\",\n\t\t\t\t\tStatus: \"Enabled\",\n\t\t\t\t\tFilter: {\n\t\t\t\t\t\tPrefix: \"2019/\",\n\t\t\t\t\t},\n\t\t\t\t\tExpiration: {\n\t\t\t\t\t\tDate: new Date(\"2024-01-01\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t// Example: transitioning objects to Infrequent Access storage by age\n\t\t\t\t// Transition objects older than 30 days to Infrequent Access storage\n\t\t\t\t{\n\t\t\t\t\tID: \"Transition Objects To Infrequent Access\",\n\t\t\t\t\tStatus: \"Enabled\",\n\t\t\t\t\tTransitions: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tDays: 30,\n\t\t\t\t\t\t\tStorageClass: \"STANDARD_IA\",\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t\t// Example: deleting objects by age\n\t\t\t\t// Delete logs older than 90 days\n\t\t\t\t{\n\t\t\t\t\tID: \"Delete Old Logs\",\n\t\t\t\t\tStatus: \"Enabled\",\n\t\t\t\t\tFilter: {\n\t\t\t\t\t\tPrefix: \"logs/\",\n\t\t\t\t\t},\n\t\t\t\t\tExpiration: {\n\t\t\t\t\t\tDays: 90,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t// Example: abort all incomplete multipart uploads after a week\n\t\t\t\t{\n\t\t\t\t\tID: \"Abort Incomplete Multipart Uploads\",\n\t\t\t\t\tStatus: \"Enabled\",\n\t\t\t\t\tAbortIncompleteMultipartUpload: {\n\t\t\t\t\t\tDaysAfterInitiation: 7,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t// Example: abort user multipart uploads after a day\n\t\t\t\t{\n\t\t\t\t\tID: \"Abort User Incomplete Multipart Uploads\",\n\t\t\t\t\tStatus: \"Enabled\",\n\t\t\t\t\tFilter: {\n\t\t\t\t\t\tPrefix: \"useruploads/\",\n\t\t\t\t\t},\n\t\t\t\t\tAbortIncompleteMultipartUpload: {\n\t\t\t\t\t\t// For uploads matching the prefix, this rule will take precedence\n\t\t\t\t\t\t// over the one above due to its earlier expiration.\n\t\t\t\t\t\tDaysAfterInitiation: 1,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t})\n\t.promise();\n```\n\nExample:\n```text\nnpx wrangler r2 bucket lifecycle list <BUCKET_NAME>\n```\n\nExample:\n```text\nimport S3 from \"aws-sdk/clients/s3.js\";\n\n// Configure the S3 client to talk to R2.\nconst client = new S3({\n\tendpoint: \"https://<account_id>.r2.cloudflarestorage.com\",\n\tcredentials: {\n\t\taccessKeyId: \"<access_key_id>\",\n\t\tsecretAccessKey: \"<access_key_secret>\",\n\t},\n\tregion: \"auto\",\n});\n\n// Get lifecycle configuration for bucket\nconsole.log(\n\tawait client\n\t\t.getBucketLifecycleConfiguration({\n\t\t\tBucket: \"bucketName\",\n\t\t})\n\t\t.promise(),\n);\n```\n\nExample:\n```text\nnpx wrangler r2 bucket lifecycle remove <BUCKET_NAME> --id <RULE_ID>\n```\n\nExample:\n```text\nimport S3 from \"aws-sdk/clients/s3.js\";\n\n// Configure the S3 client to talk to R2.\nconst client = new S3({\n\tendpoint: \"https://<account_id>.r2.cloudflarestorage.com\",\n\tcredentials: {\n\t\taccessKeyId: \"<access_key_id>\",\n\t\tsecretAccessKey: \"<access_key_secret>\",\n\t},\n\tregion: \"auto\",\n});\n\n// Delete lifecycle configuration for bucket\nawait client\n\t.deleteBucketLifecycle({\n\t\tBucket: \"bucketName\",\n\t})\n\t.promise();\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.083Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":8,"totalLines":151,"estimatedTokens":819}}29{"id":"doc-use_the_r2_multipart_api_from_workers_cloudflare-341ccbb9","source":"documentation","title":"Use the R2 multipart API from Workers · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/api/workers/workers-multipart-usage/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\ninterface Env {\n MY_BUCKET: R2Bucket;\n}\n\nexport default {\n async fetch(\n request,\n env,\n ctx\n ): Promise<Response> {\n const bucket = env.MY_BUCKET;\n\n const url = new URL(request.url);\n const key = url.pathname.slice(1);\n const action = url.searchParams.get(\"action\");\n\n if (action === null) {\n return new Response(\"Missing action type\", { status: 400 });\n }\n\n // Route the request based on the HTTP method and action type\n switch (request.method) {\n case \"POST\":\n switch (action) {\n case \"mpu-create\": {\n const multipartUpload = await bucket.createMultipartUpload(key);\n return new Response(\n JSON.stringify({\n key: multipartUpload.key,\n uploadId: multipartUpload.uploadId,\n })\n );\n }\n case \"mpu-complete\": {\n const uploadId = url.searchParams.get(\"uploadId\");\n if (uploadId === null) {\n return new Response(\"Missing uploadId\", { status: 400 });\n }\n\n const multipartUpload = env.MY_BUCKET.resumeMultipartUpload(\n key,\n uploadId\n );\n\n interface completeBody {\n parts: R2UploadedPart[];\n }\n const completeBody: completeBody = await request.json();\n if (completeBody === null) {\n return new Response(\"Missing or incomplete body\", {\n status: 400,\n });\n }\n\n // Error handling in case the multipart upload does not exist anymore\n try {\n const object = await multipartUpload.complete(completeBody.parts);\n return new Response(null, {\n headers: {\n etag: object.httpEtag,\n },\n });\n } catch (error: any) {\n return new Response(error.message, { status: 400 });\n }\n }\n default:\n return new Response(`Unknown action ${action} for POST`, {\n status: 400,\n });\n }\n case \"PUT\":\n switch (action) {\n case \"mpu-uploadpart\": {\n const uploadId = url.searchParams.get(\"uploadId\");\n const partNumberString = url.searchParams.get(\"partNumber\");\n if (partNumberString === null || uploadId === null) {\n return new Response(\"Missing partNumber or uploadId\", {\n status: 400,\n });\n }\n if (request.body === null) {\n return new Response(\"Missing request body\", { status: 400 });\n }\n\n const partNumber = parseInt(partNumberString);\n const multipartUpload = env.MY_BUCKET.resumeMultipartUpload(\n key,\n uploadId\n );\n try {\n const uploadedPart: R2UploadedPart =\n await multipartUpload.uploadPart(partNumber, request.body);\n return new Response(JSON.stringify(uploadedPart));\n } catch (error: any) {\n return new Response(error.message, { status: 400 });\n }\n }\n default:\n return new Response(`Unknown action ${action} for PUT`, {\n status: 400,\n });\n }\n case \"GET\":\n if (action !== \"get\") {\n return new Response(`Unknown action ${action} for GET`, {\n status: 400,\n });\n }\n const object = await env.MY_BUCKET.get(key);\n if (object === null) {\n return new Response(\"Object Not Found\", { status: 404 });\n }\n const headers = new Headers();\n object.writeHttpMetadata(headers);\n headers.set(\"etag\", object.httpEtag);\n return new Response(object.body, { headers });\n case \"DELETE\":\n switch (action) {\n case \"mpu-abort\": {\n const uploadId = url.searchParams.get(\"uploadId\");\n if (uploadId === null) {\n return new Response(\"Missing uploadId\", { status: 400 });\n }\n const multipartUpload = env.MY_BUCKET.resumeMultipartUpload(\n key,\n uploadId\n );\n\n try {\n multipartUpload.abort();\n } catch (error: any) {\n return new Response(error.message, { status: 400 });\n }\n return new Response(null, { status: 204 });\n }\n case \"delete\": {\n await env.MY_BUCKET.delete(key);\n return new Response(null, { status: 204 });\n }\n default:\n return new Response(`Unknown action ${action} for DELETE`, {\n status: 400,\n });\n }\n default:\n return new Response(\"Method Not Allowed\", {\n status: 405,\n headers: { Allow: \"PUT, POST, GET, DELETE\" },\n });\n }\n },\n} satisfies ExportedHandler<Env>;\n```\n\nExample:\n```text\nfrom workers import WorkerEntrypoint, Response\nfrom urllib.parse import urlparse, parse_qs\nimport json\n\n\nclass Default(WorkerEntrypoint):\n async def fetch(self, request):\n bucket = self.env.MY_BUCKET\n\n url = urlparse(request.url)\n key = url.path[1:]\n params = parse_qs(url.query)\n action = params.get(\"action\", [None])[0]\n\n if action is None:\n return Response(\"Missing action type\", status=400)\n\n if request.method == \"POST\":\n if action == \"mpu-create\":\n multipart_upload = await bucket.createMultipartUpload(key)\n return Response.json({\n \"key\": multipart_upload.key,\n \"uploadId\": multipart_upload.uploadId,\n })\n elif action == \"mpu-complete\":\n upload_id = params.get(\"uploadId\", [None])[0]\n if upload_id is None:\n return Response(\"Missing uploadId\", status=400)\n\n multipart_upload = bucket.resumeMultipartUpload(key, upload_id)\n complete_body = await request.json()\n if complete_body is None:\n return Response(\"Missing or incomplete body\", status=400)\n\n try:\n obj = await multipart_upload.complete(complete_body.parts)\n return Response(None, headers={\"etag\": obj.httpEtag})\n except Exception as error:\n return Response(str(error), status=400)\n else:\n return Response(f\"Unknown action {action} for POST\", status=400)\n\n elif request.method == \"PUT\":\n if action == \"mpu-uploadpart\":\n upload_id = params.get(\"uploadId\", [None])[0]\n part_number_str = params.get(\"partNumber\", [None])[0]\n if part_number_str is None or upload_id is None:\n return Response(\"Missing partNumber or uploadId\", status=400)\n if request.body is None:\n return Response(\"Missing request body\", status=400)\n\n part_number = int(part_number_str)\n multipart_upload = bucket.resumeMultipartUpload(key, upload_id)\n try:\n uploaded_part = await multipart_upload.uploadPart(part_number, request.body)\n return Response.json(uploaded_part)\n except Exception as error:\n return Response(str(error), status=400)\n else:\n return Response(f\"Unknown action {action} for PUT\", status=400)\n\n elif request.method == \"GET\":\n if action != \"get\":\n return Response(f\"Unknown action {action} for GET\", status=400)\n obj = await bucket.get(key)\n if obj is None:\n return Response(\"Object Not Found\", status=404)\n body = await obj.text()\n headers = {\"etag\": obj.httpEtag}\n return Response(body, headers=headers)\n\n elif request.method == \"DELETE\":\n if action == \"mpu-abort\":\n upload_id = params.get(\"uploadId\", [None])[0]\n if upload_id is None:\n return Response(\"Missing uploadId\", status=400)\n multipart_upload = bucket.resumeMultipartUpload(key, upload_id)\n try:\n await multipart_upload.abort()\n except Exception as error:\n return Response(str(error), status=400)\n return Response(None, status=204)\n elif action == \"delete\":\n await bucket.delete(key)\n return Response(None, status=204)\n else:\n return Response(f\"Unknown action {action} for DELETE\", status=400)\n\n else:\n return Response(\n \"Method Not Allowed\",\n status=405,\n headers={\"Allow\": \"PUT, POST, GET, DELETE\"},\n )\n```\n\nExample:\n```text\nimport math\nimport os\nimport requests\nfrom requests.adapters import HTTPAdapter, Retry\nimport sys\nimport concurrent.futures\n\n# Take the file to upload as an argument\nfilename = sys.argv[1]\n# The endpoint for our worker, change this to wherever you deploy your worker\nworker_endpoint = \"https://myworker.myzone.workers.dev/\"\n# Configure the part size to be 10MB. 5MB is the minimum part size, except for the last part\npartsize = 10 * 1024 * 1024\n\n\ndef upload_file(worker_endpoint, filename, partsize):\n url = f\"{worker_endpoint}{filename}\"\n\n # Create the multipart upload\n uploadId = requests.post(url, params={\"action\": \"mpu-create\"}).json()[\"uploadId\"]\n\n part_count = math.ceil(os.stat(filename).st_size / partsize)\n # Create an executor for up to 25 concurrent uploads.\n executor = concurrent.futures.ThreadPoolExecutor(25)\n # Submit a task to the executor to upload each part\n futures = [\n executor.submit(upload_part, filename, partsize, url, uploadId, index)\n for index in range(part_count)\n ]\n concurrent.futures.wait(futures)\n # get the parts from the futures\n uploaded_parts = [future.result() for future in futures]\n\n # complete the multipart upload\n response = requests.post(\n url,\n params={\"action\": \"mpu-complete\", \"uploadId\": uploadId},\n json={\"parts\": uploaded_parts},\n )\n if response.status_code == 200:\n print(\"🎉 successfully completed multipart upload\")\n else:\n print(response.text)\n\n\ndef upload_part(filename, partsize, url, uploadId, index):\n # Open the file in rb mode, which treats it as raw bytes rather than attempting to parse utf-8\n with open(filename, \"rb\") as file:\n file.seek(partsize * index)\n part = file.read(partsize)\n\n # Retry policy for when uploading a part fails\n s = requests.Session()\n retries = Retry(total=3, status_forcelist=[400, 500, 502, 503, 504])\n s.mount(\"https://\", HTTPAdapter(max_retries=retries))\n\n return s.put(\n url,\n params={\n \"action\": \"mpu-uploadpart\",\n \"uploadId\": uploadId,\n \"partNumber\": str(index + 1),\n },\n data=part,\n ).json()\n\n\nupload_file(worker_endpoint, filename, partsize)\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.083Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":3,"totalLines":330,"estimatedTokens":2859}}30{"id":"doc-presigned_urls_cloudflare_r2_docs-b9453131","source":"documentation","title":"Presigned URLs · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/api/s3/presigned-urls/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nimport { S3Client, GetObjectCommand, PutObjectCommand } from \"@aws-sdk/client-s3\";\nimport { getSignedUrl } from \"@aws-sdk/s3-request-presigner\";\n\nconst S3 = new S3Client({\n\tregion: \"auto\", // Required by SDK but not used by R2\n\t// Provide your Cloudflare account ID\n\tendpoint: `https://<ACCOUNT_ID>.r2.cloudflarestorage.com`,\n\t// Retrieve your S3 API credentials for your R2 bucket via API tokens (see: https://developers.cloudflare.com/r2/api/tokens)\n\tcredentials: {\n\t\taccessKeyId: '<ACCESS_KEY_ID>',\n\t\tsecretAccessKey: '<SECRET_ACCESS_KEY>',\n\t},\n});\n\n// Generate presigned URL for reading (GET)\nconst getUrl = await getSignedUrl(\n\tS3,\n\tnew GetObjectCommand({ Bucket: \"my-bucket\", Key: \"image.png\" }),\n\t{ expiresIn: 3600 }, // Valid for 1 hour\n);\n// https://my-bucket.<ACCOUNT_ID>.r2.cloudflarestorage.com/image.png?X-Amz-Algorithm=...\n\n// Generate presigned URL for writing (PUT)\n// Specify ContentType to restrict uploads to a specific file type\nconst putUrl = await getSignedUrl(\n\tS3,\n\tnew PutObjectCommand({\n\t\tBucket: \"my-bucket\",\n\t\tKey: \"image.png\",\n\t\tContentType: \"image/png\",\n\t}),\n\t{ expiresIn: 3600 },\n);\n```\n\nExample:\n```text\nimport boto3\n\ns3 = boto3.client(\n service_name=\"s3\",\n # Provide your Cloudflare account ID\n endpoint_url='https://<ACCOUNT_ID>.r2.cloudflarestorage.com',\n # Retrieve your S3 API credentials for your R2 bucket via API tokens (see: https://developers.cloudflare.com/r2/api/tokens)\n aws_access_key_id='<ACCESS_KEY_ID>',\n aws_secret_access_key='<SECRET_ACCESS_KEY>',\n region_name=\"auto\", # Required by SDK but not used by R2\n)\n\n# Generate presigned URL for reading (GET)\nget_url = s3.generate_presigned_url(\n\t'get_object',\n\tParams={'Bucket': 'my-bucket', 'Key': 'image.png'},\n\tExpiresIn=3600 # Valid for 1 hour\n)\n# https://my-bucket.<ACCOUNT_ID>.r2.cloudflarestorage.com/image.png?X-Amz-Algorithm=...\n\n# Generate presigned URL for writing (PUT)\n# Specify ContentType to restrict uploads to a specific file type\nput_url = s3.generate_presigned_url(\n\t'put_object',\n\tParams={\n\t\t'Bucket': 'my-bucket',\n\t\t'Key': 'image.png',\n\t\t'ContentType': 'image/png'\n\t},\n\tExpiresIn=3600\n)\n```\n\nExample:\n```text\n# Generate presigned URL for reading (GET)\n# The AWS CLI presign command defaults to GET operations\naws s3 presign --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com \\\n s3://my-bucket/image.png \\\n --expires-in 3600\n\n# Output:\n# https://<ACCOUNT_ID>.r2.cloudflarestorage.com/my-bucket/image.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...\n\n# Note: The AWS CLI presign command only supports GET operations.\n# For PUT operations, use one of the SDK examples above.\n```\n\nExample:\n```text\n# Download using a GET presigned URL\ncurl \"https://my-bucket.<ACCOUNT_ID>.r2.cloudflarestorage.com/image.png?X-Amz-Algorithm=...\"\n\n# Upload using a PUT presigned URL\ncurl -X PUT \"https://my-bucket.<ACCOUNT_ID>.r2.cloudflarestorage.com/image.png?X-Amz-Algorithm=...\" \\\n --data-binary @image.png\n```\n\nExample:\n```text\nhttps://my-bucket.123456789abcdef0123456789abcdef.r2.cloudflarestorage.com/photos/cat.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=CFEXAMPLEKEY12345%2F20251201%2Fauto%2Fs3%2Faws4_request&X-Amz-Date=20251201T180512Z&X-Amz-Expires=3600&X-Amz-Signature=8c3ac40fa6c83d64b4516e0c9e5fa94c998bb79131be9ddadf90cefc5ec31033&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.084Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":5,"totalLines":105,"estimatedTokens":902}}31{"id":"doc-workers_api_reference_cloudflare_r2_docs-d9da42dd","source":"documentation","title":"Workers API reference · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/api/workers/workers-api-reference/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\n{\n\t\"r2_buckets\": [\n\t\t{\n\t\t\t\"binding\": \"MY_BUCKET\", // <~ valid JavaScript variable name\n\t\t\t\"bucket_name\": \"<YOUR_BUCKET_NAME>\"\n\t\t}\n\t]\n}\n```\n\nExample:\n```text\n[[r2_buckets]]\nbinding = \"MY_BUCKET\"\nbucket_name = \"<YOUR_BUCKET_NAME>\"\n```\n\nExample:\n```text\nexport default {\n\tasync fetch(request, env) {\n\t\tconst url = new URL(request.url);\n\t\tconst key = url.pathname.slice(1);\n\n\t\tswitch (request.method) {\n\t\t\tcase \"PUT\":\n\t\t\t\tawait env.MY_BUCKET.put(key, request.body);\n\t\t\t\treturn new Response(`Put ${key} successfully!`);\n\n\t\t\tdefault:\n\t\t\t\treturn new Response(`${request.method} is not allowed.`, {\n\t\t\t\t\tstatus: 405,\n\t\t\t\t\theaders: {\n\t\t\t\t\t\tAllow: \"PUT\",\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t}\n\t},\n};\n```\n\nExample:\n```text\nfrom workers import WorkerEntrypoint, Response\nfrom urllib.parse import urlparse\n\nclass Default(WorkerEntrypoint):\n\tasync def fetch(self, request):\n\t\turl = urlparse(request.url)\n\t\tkey = url.path[1:]\n\n\t\tif request.method == \"PUT\":\n\t\t\tawait self.env.MY_BUCKET.put(key, request.body)\n\t\t\treturn Response(f\"Put {key} successfully!\")\n\t\telse:\n\t\t\treturn Response(\n\t\t\t\tf\"{request.method} is not allowed.\",\n\t\t\t\tstatus=405,\n\t\t\t\theaders={\"Allow\": \"PUT\"}\n\t\t\t)\n```\n\nExample:\n```text\nconst options = {\n\tlimit: 500,\n\tinclude: [\"customMetadata\"],\n};\n\nconst listed = await env.MY_BUCKET.list(options);\n\nlet truncated = listed.truncated;\nlet cursor = truncated ? listed.cursor : undefined;\n\n// ❌ - if your limit can't fit into a single response or your\n// bucket has less objects than the limit, it will get stuck here.\nwhile (listed.objects.length < options.limit) {\n\t// ...\n}\n\n// ✅ - use the truncated property to check if there are more\n// objects to be returned\nwhile (truncated) {\n\tconst next = await env.MY_BUCKET.list({\n\t\t...options,\n\t\tcursor: cursor,\n\t});\n\tlisted.objects.push(...next.objects);\n\n\ttruncated = next.truncated;\n\tcursor = next.cursor;\n}\n```\n\nExample:\n```text\nlimit = 500\ninclude = [\"customMetadata\"]\n\nlisted = await self.env.MY_BUCKET.list(limit=limit, include=include)\n\ntruncated = listed.truncated\ncursor = listed.cursor if truncated else None\n\n# ❌ - if your limit can't fit into a single response or your\n# bucket has less objects than the limit, it will get stuck here.\nwhile len(listed.objects) < limit:\n ...\n\n# ✅ - use the truncated property to check if there are more\n# objects to be returned\nwhile truncated:\n next_page = await self.env.MY_BUCKET.list(limit=limit, include=include, cursor=cursor)\n listed.objects.extend(next_page.objects)\n\n truncated = next_page.truncated\n cursor = next_page.cursor\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.085Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":6,"totalLines":124,"estimatedTokens":681}}32{"id":"doc-configure_custom_headers_cloudflare_r2_docs-e42816bc","source":"documentation","title":"Configure custom headers · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/examples/aws/custom-header/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nimport boto3\n\nclient = boto3.resource('s3',\n # Provide your Cloudflare account ID\n endpoint_url = 'https://<ACCOUNT_ID>.r2.cloudflarestorage.com',\n # Retrieve your S3 API credentials for your R2 bucket via API tokens (see: https://developers.cloudflare.com/r2/api/tokens)\n aws_access_key_id = '<ACCESS_KEY_ID>',\n aws_secret_access_key = '<SECRET_ACCESS_KEY>'\n)\n\nevent_system = client.meta.events\n\n# Define function responsible for adding the header\ndef add_custom_header(params, **kwargs):\n params[\"headers\"]['cf-create-bucket-if-missing'] = 'true'\n\nevent_system.register('before-call.s3.PutObject', add_custom_header)\n\nresponse = client.put_object(Bucket=\"my-bucket\", Key=\"my_file\", Body=\"file_contents\")\nprint(response)\n```\n\nExample:\n```text\nimport { PutObjectCommand, S3Client } from \"@aws-sdk/client-s3\";\nimport { HttpRequest } from \"@smithy/core/protocols\";\n\nconst client = new S3Client({\n\tregion: \"auto\", // Required by SDK but not used by R2\n\tendpoint: `https://${ACCOUNT_ID}.r2.cloudflarestorage.com`,\n\t// Retrieve your S3 API credentials for your R2 bucket via API tokens (see: https://developers.cloudflare.com/r2/api/tokens)\n\tcredentials: {\n\t\taccessKeyId: ACCESS_KEY_ID,\n\t\tsecretAccessKey: SECRET_ACCESS_KEY,\n\t},\n});\n\nclient.middlewareStack.add(\n\t(next) => async (args) => {\n\t\tconst request = args.request;\n\n\t\tif (HttpRequest.isInstance(request)) {\n\t\t\trequest.headers[\"cf-create-bucket-if-missing\"] = \"true\";\n\t\t}\n\n\t\treturn next(args);\n\t},\n\t{ step: \"build\", name: \"customHeaders\" },\n);\n\nconst command = new PutObjectCommand({\n\tBucket: \"my-bucket\",\n\tKey: \"my_key\",\n\tBody: \"my_data\",\n});\n\nconst response = await client.send(command);\n\nconsole.log(response);\n```\n\nExample:\n```text\nimport boto3\n\nclient = boto3.resource('s3',\n # Provide your Cloudflare account ID\n endpoint_url = 'https://<ACCOUNT_ID>.r2.cloudflarestorage.com',\n # Retrieve your S3 API credentials for your R2 bucket via API tokens (see: https://developers.cloudflare.com/r2/api/tokens)\n aws_access_key_id = '<ACCESS_KEY_ID>',\n aws_secret_access_key = '<SECRET_ACCESS_KEY>'\n)\n\nevent_system = client.meta.events\n\n# Moves the custom headers from the parameters to the request context\ndef process_custom_arguments(params, context, **kwargs):\n if (custom_headers := params.pop(\"custom_headers\", None)):\n context[\"custom_headers\"] = custom_headers\n\n# Here we extract the headers from the request context and actually set them\ndef add_custom_headers(params, context, **kwargs):\n if (custom_headers := context.get(\"custom_headers\")):\n params[\"headers\"].update(custom_headers)\n\nevent_system.register('before-parameter-build.s3.PutObject', process_custom_arguments)\nevent_system.register('before-call.s3.PutObject', add_custom_headers)\n\ncustom_headers = {'If-Match' : '\"29d911f495d1ba7cb3a4d7d15e63236a\"'}\n\n# Note that boto3 will throw an exception if the precondition failed. Catch this exception if necessary\nresponse = client.put_object(Bucket=\"my-bucket\", Key=\"my_key\", Body=\"file_contents\", custom_headers=custom_headers)\nprint(response)\n```\n\nExample:\n```text\nimport { PutObjectCommand, S3Client } from \"@aws-sdk/client-s3\";\nimport { HttpRequest } from \"@smithy/core/protocols\";\n\nconst client = new S3Client({\n\tregion: \"auto\", // Required by SDK but not used by R2\n\t// Provide your Cloudflare account ID\n\tendpoint: `https://${ACCOUNT_ID}.r2.cloudflarestorage.com`,\n\t// Retrieve your S3 API credentials for your R2 bucket via API tokens (see: https://developers.cloudflare.com/r2/api/tokens)\n\tcredentials: {\n\t\taccessKeyId: ACCESS_KEY_ID,\n\t\tsecretAccessKey: SECRET_ACCESS_KEY,\n\t},\n});\n\nconst command = new PutObjectCommand({\n\tBucket: \"my-bucket\",\n\tKey: \"my_key\",\n\tBody: \"my_data\",\n});\n\nconst headers = { \"If-Match\": '\"29d911f495d1ba7cb3a4d7d15e63236a\"' };\ncommand.middlewareStack.add(\n\t(next) => (args) => {\n\t\tconst request = args.request;\n\n\t\tif (HttpRequest.isInstance(request)) {\n\t\t\tObject.assign(request.headers, headers);\n\t\t}\n\n\t\treturn next(args);\n\t},\n\t{ step: \"build\", name: \"customHeaders\" },\n);\nconst response = await client.send(command);\n\nconsole.log(response);\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.085Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":4,"totalLines":140,"estimatedTokens":1069}}33{"id":"doc-use_r2_from_workers_cloudflare_r2_docs-7e0ecd0c","source":"documentation","title":"Use R2 from Workers · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/api/workers/workers-api-usage/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nnpm create cloudflare@latest -- r2-worker\n```\n\nExample:\n```text\nyarn create cloudflare r2-worker\n```\n\nExample:\n```text\npnpm create cloudflare@latest r2-worker\n```\n\nExample:\n```text\ncd r2-worker\n```\n\nExample:\n```text\nnpx wrangler r2 bucket create <YOUR_BUCKET_NAME>\n```\n\nExample:\n```text\nnpx wrangler r2 bucket list\n```\n\nExample:\n```text\n{\n\t\"r2_buckets\": [\n\t\t{\n\t\t\t\"binding\": \"MY_BUCKET\", // <~ valid JavaScript variable name\n\t\t\t\"bucket_name\": \"<YOUR_BUCKET_NAME>\"\n\t\t}\n\t]\n}\n```\n\nExample:\n```text\n[[r2_buckets]]\nbinding = \"MY_BUCKET\"\nbucket_name = \"<YOUR_BUCKET_NAME>\"\n```\n\nExample:\n```text\nimport { WorkerEntrypoint } from \"cloudflare:workers\";\n\nexport default class extends WorkerEntrypoint<Env> {\n async fetch(request: Request) {\n const url = new URL(request.url);\n const key = url.pathname.slice(1);\n\n switch (request.method) {\n case \"PUT\": {\n await this.env.MY_BUCKET.put(key, request.body, {\n onlyIf: request.headers,\n httpMetadata: request.headers,\n });\n return new Response(`Put ${key} successfully!`);\n }\n case \"GET\": {\n const object = await this.env.MY_BUCKET.get(key, {\n onlyIf: request.headers,\n range: request.headers,\n });\n\n if (object === null) {\n return new Response(\"Object Not Found\", { status: 404 });\n }\n\n const headers = new Headers();\n object.writeHttpMetadata(headers);\n headers.set(\"etag\", object.httpEtag);\n\n // When no body is present, preconditions have failed\n return new Response(\"body\" in object ? object.body : undefined, {\n status: \"body\" in object ? 200 : 412,\n headers,\n });\n }\n case \"DELETE\": {\n await this.env.MY_BUCKET.delete(key);\n return new Response(\"Deleted!\");\n }\n default:\n return new Response(\"Method Not Allowed\", {\n status: 405,\n headers: {\n Allow: \"PUT, GET, DELETE\",\n },\n });\n }\n }\n};\n```\n\nExample:\n```text\nexport default {\n async fetch(request, env) {\n const url = new URL(request.url);\n const key = url.pathname.slice(1);\n\n switch (request.method) {\n case \"PUT\": {\n await env.MY_BUCKET.put(key, request.body, {\n onlyIf: request.headers,\n httpMetadata: request.headers,\n });\n return new Response(`Put ${key} successfully!`);\n }\n case \"GET\": {\n const object = await env.MY_BUCKET.get(key, {\n onlyIf: request.headers,\n range: request.headers,\n });\n\n if (object === null) {\n return new Response(\"Object Not Found\", { status: 404 });\n }\n\n const headers = new Headers();\n object.writeHttpMetadata(headers);\n headers.set(\"etag\", object.httpEtag);\n\n // When no body is present, preconditions have failed\n return new Response(\"body\" in object ? object.body : undefined, {\n status: \"body\" in object ? 200 : 412,\n headers,\n });\n }\n case \"DELETE\": {\n await env.MY_BUCKET.delete(key);\n return new Response(\"Deleted!\");\n }\n default:\n return new Response(\"Method Not Allowed\", {\n status: 405,\n headers: {\n Allow: \"PUT, GET, DELETE\",\n },\n });\n }\n }\n}\n```\n\nExample:\n```text\nfrom workers import WorkerEntrypoint, Response\nfrom urllib.parse import urlparse\n\n\nclass Default(WorkerEntrypoint):\n\tasync def fetch(self, request):\n\t\turl = urlparse(request.url)\n\t\tkey = url.path[1:]\n\n\t\tif request.method == \"PUT\":\n\t\t\tawait self.env.MY_BUCKET.put(\n\t\t\t\tkey,\n\t\t\t\trequest.body,\n\t\t\t\tonlyIf=request.headers,\n\t\t\t\thttpMetadata=request.headers,\n\t\t\t)\n\t\t\treturn Response(f\"Put {key} successfully!\")\n\t\telif request.method == \"GET\":\n\t\t\tobj = await self.env.MY_BUCKET.get(\n\t\t\t\tkey,\n\t\t\t\tonlyIf=request.headers,\n\t\t\t\trange=request.headers,\n\t\t\t)\n\n\t\t\tif obj is None:\n\t\t\t\treturn Response(\"Object Not Found\", status=404)\n\n\t\t\t# When no body is present, preconditions have failed\n\t\t\tbody = obj.body if hasattr(obj, \"body\") else None\n\t\t\tstatus = 200 if hasattr(obj, \"body\") else 412\n\n\t\t\theaders = {\"etag\": obj.httpEtag}\n\t\t\treturn Response(body, status=status, headers=headers)\n\t\telif request.method == \"DELETE\":\n\t\t\tawait self.env.MY_BUCKET.delete(key)\n\t\t\treturn Response(\"Deleted!\")\n\t\telse:\n\t\t\treturn Response(\n\t\t\t\t\"Method Not Allowed\",\n\t\t\t\tstatus=405,\n\t\t\t\theaders={\"Allow\": \"PUT, GET, DELETE\"},\n\t\t\t)\n```\n\nExample:\n```text\nconst ALLOW_LIST = [\"cat-pic.jpg\"];\n\n// Check requests for a pre-shared secret\nconst hasValidHeader = (request, env) => {\n\treturn request.headers.get(\"X-Custom-Auth-Key\") === env.AUTH_KEY_SECRET;\n};\n\nfunction authorizeRequest(request, env, key) {\n\tswitch (request.method) {\n\t\tcase \"PUT\":\n\t\tcase \"DELETE\":\n\t\t\treturn hasValidHeader(request, env);\n\t\tcase \"GET\":\n\t\t\treturn ALLOW_LIST.includes(key);\n\t\tdefault:\n\t\t\treturn false;\n\t}\n}\n\nexport default {\n\tasync fetch(request, env, ctx) {\n\t\tconst url = new URL(request.url);\n\t\tconst key = url.pathname.slice(1);\n\n\t\tif (!authorizeRequest(request, env, key)) {\n\t\t\treturn new Response(\"Forbidden\", { status: 403 });\n\t\t}\n\n\t\t// ...\n\t},\n};\n```\n\nExample:\n```text\nfrom workers import WorkerEntrypoint, Response\nfrom urllib.parse import urlparse\n\nALLOW_LIST = [\"cat-pic.jpg\"]\n\n# Check requests for a pre-shared secret\ndef has_valid_header(request, env):\n\treturn request.headers.get(\"X-Custom-Auth-Key\") == env.AUTH_KEY_SECRET\n\ndef authorize_request(request, env, key):\n\tif request.method in [\"PUT\", \"DELETE\"]:\n\t\treturn has_valid_header(request, env)\n\telif request.method == \"GET\":\n\t\treturn key in ALLOW_LIST\n\telse:\n\t\treturn False\n\nclass Default(WorkerEntrypoint):\n\tasync def fetch(self, request):\n\t\turl = urlparse(request.url)\n\t\tkey = url.path[1:]\n\n\t\tif not authorize_request(request, self.env, key):\n\t\t\treturn Response(\"Forbidden\", status=403)\n\n\t\t# ...\n```\n\nExample:\n```text\nnpx wrangler secret put AUTH_KEY_SECRET\n```\n\nExample:\n```text\nEnter the secret text you'd like assigned to the variable AUTH_KEY_SECRET on the script named <YOUR_WORKER_NAME>:\n*********\n🌀 Creating the secret for script name <YOUR_WORKER_NAME>\n✨ Success! Uploaded secret AUTH_KEY_SECRET.\n```\n\nExample:\n```text\nnpx wrangler deploy\n```\n\nExample:\n```text\n# Attempt to write an object without providing the \"X-Custom-Auth-Key\" header\ncurl https://your-worker.dev/cat-pic.jpg -X PUT --data-binary 'test'\n#=> Forbidden\n# Expected because header was missing\n\n# Attempt to write an object with the wrong \"X-Custom-Auth-Key\" header value\ncurl https://your-worker.dev/cat-pic.jpg -X PUT --header \"X-Custom-Auth-Key: hotdog\" --data-binary 'test'\n#=> Forbidden\n# Expected because header value did not match the AUTH_KEY_SECRET value\n\n# Attempt to write an object with the correct \"X-Custom-Auth-Key\" header value\n# Note: Assume that \"*********\" is the value of your AUTH_KEY_SECRET Wrangler secret\ncurl https://your-worker.dev/cat-pic.jpg -X PUT --header \"X-Custom-Auth-Key: *********\" --data-binary 'test'\n#=> Put cat-pic.jpg successfully!\n\n# Attempt to read object called \"foo\"\ncurl https://your-worker.dev/foo\n#=> Forbidden\n# Expected because \"foo\" is not in the ALLOW_LIST\n\n# Attempt to read an object called \"cat-pic.jpg\"\ncurl https://your-worker.dev/cat-pic.jpg\n#=> test\n# Note: This is the value that was successfully PUT above\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.086Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":17,"totalLines":313,"estimatedTokens":1874}}34{"id":"doc-error_codes_cloudflare_r2_docs-99b64ba9","source":"documentation","title":"Error codes · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/api/error-codes/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\ntry {\n await env.MY_BUCKET.put(\"my-key\", data, { customMetadata: largeMetadata });\n} catch (error) {\n console.error(error.message);\n // \"put: Your metadata headers exceed the maximum allowed metadata size. (10012)\"\n}\n```\n\nExample:\n```text\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Error>\n <Code>NoSuchKey</Code>\n <Message>The specified key does not exist.</Message>\n</Error>\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.090Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":2,"totalLines":22,"estimatedTokens":146}}35{"id":"doc-s3_api_compatibility_cloudflare_r2_docs-da76c843","source":"documentation","title":"S3 API compatibility · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/api/s3/api/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.091Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":46}}36{"id":"doc-aws_sdk_ruby_cloudflare_r2_docs-728e1f5b","source":"documentation","title":"aws-sdk-ruby · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/examples/aws/aws-sdk-ruby/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\ngem \"aws-sdk-s3\"\n```\n\nExample:\n```text\nrequire \"aws-sdk-s3\"\n\n@r2 = Aws::S3::Client.new(\n # Retrieve your S3 API credentials for your R2 bucket via API tokens (see: https://developers.cloudflare.com/r2/api/tokens)\n access_key_id: \"#{ACCESS_KEY_ID}\",\n secret_access_key: \"#{SECRET_ACCESS_KEY}\",\n # Provide your Cloudflare account ID\n endpoint: \"https://#{ACCOUNT_ID}.r2.cloudflarestorage.com\",\n region: \"auto\", # Required by SDK but not used by R2\n)\n\n# List all buckets on your account\nputs @r2.list_buckets\n\n#=> {\n#=> :buckets => [{\n#=> :name => \"your-bucket\",\n#=> :creation_date => \"…\",\n#=> }],\n#=> :owner => {\n#=> :display_name => \"…\",\n#=> :id => \"…\"\n#=> }\n#=> }\n\n# List the first 20 items in a bucket\nputs @r2.list_objects(bucket:\"your-bucket\", max_keys:20)\n\n#=> {\n#=> :is_truncated => false,\n#=> :marker => nil,\n#=> :next_marker => nil,\n#=> :name => \"your-bucket\",\n#=> :prefix => nil,\n#=> :delimiter =>nil,\n#=> :max_keys => 20,\n#=> :common_prefixes => [],\n#=> :encoding_type => nil\n#=> :contents => [\n#=> …,\n#=> …,\n#=> …,\n#=> ]\n#=> }\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.091Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":2,"totalLines":56,"estimatedTokens":327}}37{"id":"doc-upload_objects_cloudflare_r2_docs-d91ad1ed","source":"documentation","title":"Upload objects · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/objects/upload-objects/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nexport default {\n\tasync fetch(request, env) {\n\t\ttry {\n\t\t\tconst object = await env.MY_BUCKET.put(\"image.png\", request.body, {\n\t\t\t\thttpMetadata: {\n\t\t\t\t\tcontentType: \"image/png\",\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tif (object === null) {\n\t\t\t\treturn new Response(\"Precondition failed or upload returned null\", {\n\t\t\t\t\tstatus: 412,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn Response.json({\n\t\t\t\tkey: object.key,\n\t\t\t\tsize: object.size,\n\t\t\t\tetag: object.etag,\n\t\t\t});\n\t\t} catch (err) {\n\t\t\treturn new Response(`Upload failed: ${err}`, { status: 500 });\n\t\t}\n\t},\n};\n```\n\nExample:\n```text\nexport default {\n\tasync fetch(request: Request, env: Env): Promise<Response> {\n\t\ttry {\n\t\t\tconst object = await env.MY_BUCKET.put(\"image.png\", request.body, {\n\t\t\t\thttpMetadata: {\n\t\t\t\t\tcontentType: \"image/png\",\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tif (object === null) {\n\t\t\t\treturn new Response(\"Precondition failed or upload returned null\", {\n\t\t\t\t\tstatus: 412,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn Response.json({\n\t\t\t\tkey: object.key,\n\t\t\t\tsize: object.size,\n\t\t\t\tetag: object.etag,\n\t\t\t});\n\t\t} catch (err) {\n\t\t\treturn new Response(`Upload failed: ${err}`, { status: 500 });\n\t\t}\n\t},\n} satisfies ExportedHandler<Env>;\n```\n\nExample:\n```text\nexport default {\n\tasync fetch(request, env) {\n\t\tconst key = \"large-file.bin\";\n\n\t\t// Create a new multipart upload\n\t\tconst multipartUpload = await env.MY_BUCKET.createMultipartUpload(key);\n\n\t\ttry {\n\t\t\t// In a real application, these would be actual data chunks.\n\t\t\t// Each part except the last must be at least 5 MiB.\n\t\t\tconst firstChunk = new Uint8Array(5 * 1024 * 1024); // placeholder\n\t\t\tconst secondChunk = new Uint8Array(1024); // placeholder\n\n\t\t\tconst part1 = await multipartUpload.uploadPart(1, firstChunk);\n\t\t\tconst part2 = await multipartUpload.uploadPart(2, secondChunk);\n\n\t\t\t// Complete the upload with all parts\n\t\t\tconst object = await multipartUpload.complete([part1, part2]);\n\n\t\t\treturn Response.json({\n\t\t\t\tkey: object.key,\n\t\t\t\tetag: object.httpEtag,\n\t\t\t});\n\t\t} catch (err) {\n\t\t\t// Abort on failure so incomplete uploads do not count against storage\n\t\t\tawait multipartUpload.abort();\n\t\t\treturn new Response(`Multipart upload failed: ${err}`, { status: 500 });\n\t\t}\n\t},\n};\n```\n\nExample:\n```text\nexport default {\n\tasync fetch(request: Request, env: Env): Promise<Response> {\n\t\tconst key = \"large-file.bin\";\n\n\t\t// Create a new multipart upload\n\t\tconst multipartUpload = await env.MY_BUCKET.createMultipartUpload(key);\n\n\t\ttry {\n\t\t\t// In a real application, these would be actual data chunks.\n\t\t\t// Each part except the last must be at least 5 MiB.\n\t\t\tconst firstChunk = new Uint8Array(5 * 1024 * 1024); // placeholder\n\t\t\tconst secondChunk = new Uint8Array(1024); // placeholder\n\n\t\t\tconst part1 = await multipartUpload.uploadPart(1, firstChunk);\n\t\t\tconst part2 = await multipartUpload.uploadPart(2, secondChunk);\n\n\t\t\t// Complete the upload with all parts\n\t\t\tconst object = await multipartUpload.complete([part1, part2]);\n\n\t\t\treturn Response.json({\n\t\t\t\tkey: object.key,\n\t\t\t\tetag: object.httpEtag,\n\t\t\t});\n\t\t} catch (err) {\n\t\t\t// Abort on failure so incomplete uploads do not count against storage\n\t\t\tawait multipartUpload.abort();\n\t\t\treturn new Response(`Multipart upload failed: ${err}`, { status: 500 });\n\t\t}\n\t},\n} satisfies ExportedHandler<Env>;\n```\n\nExample:\n```text\nexport default {\n\tasync fetch(request, env) {\n\t\tconst url = new URL(request.url);\n\t\tconst key = url.pathname.slice(1);\n\t\tconst action = url.searchParams.get(\"action\");\n\n\t\tif (!key || !action) {\n\t\t\treturn new Response(\"Missing key or action\", { status: 400 });\n\t\t}\n\n\t\tswitch (action) {\n\t\t\t// Step 1: Client calls POST /<key>?action=mpu-create\n\t\t\tcase \"mpu-create\": {\n\t\t\t\tconst upload = await env.MY_BUCKET.createMultipartUpload(key);\n\t\t\t\treturn Response.json({ key: upload.key, uploadId: upload.uploadId });\n\t\t\t}\n\n\t\t\t// Step 2: Client calls PUT /<key>?action=mpu-uploadpart&uploadId=...&partNumber=...\n\t\t\tcase \"mpu-uploadpart\": {\n\t\t\t\tconst uploadId = url.searchParams.get(\"uploadId\");\n\t\t\t\tconst partNumber = Number(url.searchParams.get(\"partNumber\"));\n\t\t\t\tif (!uploadId || !partNumber || !request.body) {\n\t\t\t\t\treturn new Response(\"Missing uploadId, partNumber, or body\", {\n\t\t\t\t\t\tstatus: 400,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tconst upload = env.MY_BUCKET.resumeMultipartUpload(key, uploadId);\n\t\t\t\ttry {\n\t\t\t\t\tconst part = await upload.uploadPart(partNumber, request.body);\n\t\t\t\t\treturn Response.json(part);\n\t\t\t\t} catch (err) {\n\t\t\t\t\treturn new Response(String(err), { status: 400 });\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Step 3: Client calls POST /<key>?action=mpu-complete&uploadId=...\n\t\t\tcase \"mpu-complete\": {\n\t\t\t\tconst uploadId = url.searchParams.get(\"uploadId\");\n\t\t\t\tif (!uploadId) {\n\t\t\t\t\treturn new Response(\"Missing uploadId\", { status: 400 });\n\t\t\t\t}\n\t\t\t\tconst upload = env.MY_BUCKET.resumeMultipartUpload(key, uploadId);\n\t\t\t\tconst body = await request.json();\n\t\t\t\ttry {\n\t\t\t\t\tconst object = await upload.complete(body.parts);\n\t\t\t\t\treturn new Response(null, {\n\t\t\t\t\t\theaders: { etag: object.httpEtag },\n\t\t\t\t\t});\n\t\t\t\t} catch (err) {\n\t\t\t\t\treturn new Response(String(err), { status: 400 });\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Abort an in-progress upload\n\t\t\tcase \"mpu-abort\": {\n\t\t\t\tconst uploadId = url.searchParams.get(\"uploadId\");\n\t\t\t\tif (!uploadId) {\n\t\t\t\t\treturn new Response(\"Missing uploadId\", { status: 400 });\n\t\t\t\t}\n\t\t\t\tconst upload = env.MY_BUCKET.resumeMultipartUpload(key, uploadId);\n\t\t\t\ttry {\n\t\t\t\t\tawait upload.abort();\n\t\t\t\t} catch (err) {\n\t\t\t\t\treturn new Response(String(err), { status: 400 });\n\t\t\t\t}\n\t\t\t\treturn new Response(null, { status: 204 });\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\treturn new Response(`Unknown action: ${action}`, { status: 400 });\n\t\t}\n\t},\n};\n```\n\nExample:\n```text\nexport default {\n\tasync fetch(request: Request, env: Env): Promise<Response> {\n\t\tconst url = new URL(request.url);\n\t\tconst key = url.pathname.slice(1);\n\t\tconst action = url.searchParams.get(\"action\");\n\n\t\tif (!key || !action) {\n\t\t\treturn new Response(\"Missing key or action\", { status: 400 });\n\t\t}\n\n\t\tswitch (action) {\n\t\t\t// Step 1: Client calls POST /<key>?action=mpu-create\n\t\t\tcase \"mpu-create\": {\n\t\t\t\tconst upload = await env.MY_BUCKET.createMultipartUpload(key);\n\t\t\t\treturn Response.json({ key: upload.key, uploadId: upload.uploadId });\n\t\t\t}\n\n\t\t\t// Step 2: Client calls PUT /<key>?action=mpu-uploadpart&uploadId=...&partNumber=...\n\t\t\tcase \"mpu-uploadpart\": {\n\t\t\t\tconst uploadId = url.searchParams.get(\"uploadId\");\n\t\t\t\tconst partNumber = Number(url.searchParams.get(\"partNumber\"));\n\t\t\t\tif (!uploadId || !partNumber || !request.body) {\n\t\t\t\t\treturn new Response(\"Missing uploadId, partNumber, or body\", {\n\t\t\t\t\t\tstatus: 400,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tconst upload = env.MY_BUCKET.resumeMultipartUpload(key, uploadId);\n\t\t\t\ttry {\n\t\t\t\t\tconst part = await upload.uploadPart(partNumber, request.body);\n\t\t\t\t\treturn Response.json(part);\n\t\t\t\t} catch (err) {\n\t\t\t\t\treturn new Response(String(err), { status: 400 });\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Step 3: Client calls POST /<key>?action=mpu-complete&uploadId=...\n\t\t\tcase \"mpu-complete\": {\n\t\t\t\tconst uploadId = url.searchParams.get(\"uploadId\");\n\t\t\t\tif (!uploadId) {\n\t\t\t\t\treturn new Response(\"Missing uploadId\", { status: 400 });\n\t\t\t\t}\n\t\t\t\tconst upload = env.MY_BUCKET.resumeMultipartUpload(key, uploadId);\n\t\t\t\tconst body = await request.json<{ parts: R2UploadedPart[] }>();\n\t\t\t\ttry {\n\t\t\t\t\tconst object = await upload.complete(body.parts);\n\t\t\t\t\treturn new Response(null, {\n\t\t\t\t\t\theaders: { etag: object.httpEtag },\n\t\t\t\t\t});\n\t\t\t\t} catch (err) {\n\t\t\t\t\treturn new Response(String(err), { status: 400 });\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Abort an in-progress upload\n\t\t\tcase \"mpu-abort\": {\n\t\t\t\tconst uploadId = url.searchParams.get(\"uploadId\");\n\t\t\t\tif (!uploadId) {\n\t\t\t\t\treturn new Response(\"Missing uploadId\", { status: 400 });\n\t\t\t\t}\n\t\t\t\tconst upload = env.MY_BUCKET.resumeMultipartUpload(key, uploadId);\n\t\t\t\ttry {\n\t\t\t\t\tawait upload.abort();\n\t\t\t\t} catch (err) {\n\t\t\t\t\treturn new Response(String(err), { status: 400 });\n\t\t\t\t}\n\t\t\t\treturn new Response(null, { status: 204 });\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\treturn new Response(`Unknown action: ${action}`, { status: 400 });\n\t\t}\n\t},\n} satisfies ExportedHandler<Env>;\n```\n\nExample:\n```text\nimport { AwsClient } from \"aws4fetch\";\n\nexport default {\n\tasync fetch(request, env) {\n\t\tconst r2 = new AwsClient({\n\t\t\taccessKeyId: env.R2_ACCESS_KEY_ID,\n\t\t\tsecretAccessKey: env.R2_SECRET_ACCESS_KEY,\n\t\t});\n\n\t\t// Generate a presigned PUT URL valid for 1 hour\n\t\tconst url = new URL(\n\t\t\t\"https://<ACCOUNT_ID>.r2.cloudflarestorage.com/my-bucket/image.png\",\n\t\t);\n\t\turl.searchParams.set(\"X-Amz-Expires\", \"3600\");\n\n\t\tconst signed = await r2.sign(new Request(url, { method: \"PUT\" }), {\n\t\t\taws: { signQuery: true },\n\t\t});\n\n\t\t// Return the signed URL to the client — they can PUT directly to R2\n\t\treturn Response.json({ url: signed.url });\n\t},\n};\n```\n\nExample:\n```text\nimport { AwsClient } from \"aws4fetch\";\n\ninterface Env {\n\tR2_ACCESS_KEY_ID: string;\n\tR2_SECRET_ACCESS_KEY: string;\n}\n\nexport default {\n\tasync fetch(request: Request, env: Env): Promise<Response> {\n\t\tconst r2 = new AwsClient({\n\t\t\taccessKeyId: env.R2_ACCESS_KEY_ID,\n\t\t\tsecretAccessKey: env.R2_SECRET_ACCESS_KEY,\n\t\t});\n\n\t\t// Generate a presigned PUT URL valid for 1 hour\n\t\tconst url = new URL(\n\t\t\t\"https://<ACCOUNT_ID>.r2.cloudflarestorage.com/my-bucket/image.png\",\n\t\t);\n\t\turl.searchParams.set(\"X-Amz-Expires\", \"3600\");\n\n\t\tconst signed = await r2.sign(new Request(url, { method: \"PUT\" }), {\n\t\t\taws: { signQuery: true },\n\t\t});\n\n\t\t// Return the signed URL to the client — they can PUT directly to R2\n\t\treturn Response.json({ url: signed.url });\n\t},\n} satisfies ExportedHandler<Env>;\n```\n\nExample:\n```text\nimport { S3Client, PutObjectCommand } from \"@aws-sdk/client-s3\";\nimport { readFile } from \"node:fs/promises\";\n\nconst S3 = new S3Client({\n\tregion: \"auto\",\n\tendpoint: `https://<ACCOUNT_ID>.r2.cloudflarestorage.com`,\n\tcredentials: {\n\t\taccessKeyId: \"<ACCESS_KEY_ID>\",\n\t\tsecretAccessKey: \"<SECRET_ACCESS_KEY>\",\n\t},\n});\n\nconst fileContent = await readFile(\"./image.png\");\n\nconst response = await S3.send(\n\tnew PutObjectCommand({\n\t\tBucket: \"my-bucket\",\n\t\tKey: \"image.png\",\n\t\tBody: fileContent,\n\t\tContentType: \"image/png\",\n\t}),\n);\nconsole.log(`Uploaded successfully. ETag: ${response.ETag}`);\n```\n\nExample:\n```text\nimport boto3\n\ns3 = boto3.client(\n service_name=\"s3\",\n endpoint_url=\"https://<ACCOUNT_ID>.r2.cloudflarestorage.com\",\n aws_access_key_id=\"<ACCESS_KEY_ID>\",\n aws_secret_access_key=\"<SECRET_ACCESS_KEY>\",\n region_name=\"auto\",\n)\n\nwith open(\"./image.png\", \"rb\") as f:\n response = s3.put_object(\n Bucket=\"my-bucket\",\n Key=\"image.png\",\n Body=f,\n ContentType=\"image/png\",\n )\n print(f\"Uploaded successfully. ETag: {response['ETag']}\")\n```\n\nExample:\n```text\nimport { S3Client } from \"@aws-sdk/client-s3\";\nimport { Upload } from \"@aws-sdk/lib-storage\";\nimport { createReadStream } from \"node:fs\";\n\nconst S3 = new S3Client({\n\tregion: \"auto\",\n\tendpoint: `https://<ACCOUNT_ID>.r2.cloudflarestorage.com`,\n\tcredentials: {\n\t\taccessKeyId: \"<ACCESS_KEY_ID>\",\n\t\tsecretAccessKey: \"<SECRET_ACCESS_KEY>\",\n\t},\n});\n\nconst upload = new Upload({\n\tclient: S3,\n\tparams: {\n\t\tBucket: \"my-bucket\",\n\t\tKey: \"large-file.bin\",\n\t\tBody: createReadStream(\"./large-file.bin\"),\n\t},\n\t// Upload parts in parallel (default: 4)\n\tleavePartsOnError: false,\n});\n\nupload.on(\"httpUploadProgress\", (progress) => {\n\tconsole.log(`Uploaded ${progress.loaded ?? 0} bytes`);\n});\n\nconst result = await upload.done();\nconsole.log(`Upload complete. ETag: ${result.ETag}`);\n```\n\nExample:\n```text\nimport { S3Client } from \"@aws-sdk/client-s3\";\nimport { Upload } from \"@aws-sdk/lib-storage\";\nimport { createReadStream } from \"node:fs\";\n\nconst S3 = new S3Client({\n\tregion: \"auto\",\n\tendpoint: `https://<ACCOUNT_ID>.r2.cloudflarestorage.com`,\n\tcredentials: {\n\t\taccessKeyId: \"<ACCESS_KEY_ID>\",\n\t\tsecretAccessKey: \"<SECRET_ACCESS_KEY>\",\n\t},\n});\n\nconst upload = new Upload({\n\tclient: S3,\n\tparams: {\n\t\tBucket: \"my-bucket\",\n\t\tKey: \"large-file.bin\",\n\t\tBody: createReadStream(\"./large-file.bin\"),\n\t},\n\tleavePartsOnError: false,\n});\n\nupload.on(\"httpUploadProgress\", (progress) => {\n\tconsole.log(`Uploaded ${progress.loaded ?? 0} bytes`);\n});\n\nconst result = await upload.done();\nconsole.log(`Upload complete. ETag: ${result.ETag}`);\n```\n\nExample:\n```text\nimport boto3\n\ns3 = boto3.client(\n service_name=\"s3\",\n endpoint_url=\"https://<ACCOUNT_ID>.r2.cloudflarestorage.com\",\n aws_access_key_id=\"<ACCESS_KEY_ID>\",\n aws_secret_access_key=\"<SECRET_ACCESS_KEY>\",\n region_name=\"auto\",\n)\n\n# upload_file automatically uses multipart for large files.\n# For better throughput with large objects, use the manual multipart example below.\ns3.upload_file(\n Filename=\"./large-file.bin\",\n Bucket=\"my-bucket\",\n Key=\"large-file.bin\",\n)\n```\n\nExample:\n```text\nimport {\n\tS3Client,\n\tCreateMultipartUploadCommand,\n\tUploadPartCommand,\n\tCompleteMultipartUploadCommand,\n\tAbortMultipartUploadCommand,\n\ttype CompletedPart,\n} from \"@aws-sdk/client-s3\";\nimport { createReadStream, statSync } from \"node:fs\";\n\nconst S3 = new S3Client({\n\tregion: \"auto\",\n\tendpoint: `https://<ACCOUNT_ID>.r2.cloudflarestorage.com`,\n\tcredentials: {\n\t\taccessKeyId: \"<ACCESS_KEY_ID>\",\n\t\tsecretAccessKey: \"<SECRET_ACCESS_KEY>\",\n\t},\n});\n\nconst bucket = \"my-bucket\";\nconst key = \"large-file.bin\";\nconst partSize = 10 * 1024 * 1024; // 10 MiB per part\n\n// Step 1: Create the multipart upload\nconst { UploadId } = await S3.send(\n\tnew CreateMultipartUploadCommand({ Bucket: bucket, Key: key }),\n);\n\ntry {\n\tconst fileSize = statSync(\"./large-file.bin\").size;\n\tconst partCount = Math.ceil(fileSize / partSize);\n\tconst parts: CompletedPart[] = [];\n\n\t// Step 2: Upload each part\n\tfor (let i = 0; i < partCount; i++) {\n\t\tconst start = i * partSize;\n\t\tconst end = Math.min(start + partSize, fileSize);\n\t\tconst { ETag } = await S3.send(\n\t\t\tnew UploadPartCommand({\n\t\t\t\tBucket: bucket,\n\t\t\t\tKey: key,\n\t\t\t\tUploadId,\n\t\t\t\tPartNumber: i + 1,\n\t\t\t\tBody: createReadStream(\"./large-file.bin\", { start, end: end - 1 }),\n\t\t\t\tContentLength: end - start,\n\t\t\t}),\n\t\t);\n\t\tparts.push({ PartNumber: i + 1, ETag });\n\t}\n\n\t// Step 3: Complete the upload\n\tawait S3.send(\n\t\tnew CompleteMultipartUploadCommand({\n\t\t\tBucket: bucket,\n\t\t\tKey: key,\n\t\t\tUploadId,\n\t\t\tMultipartUpload: { Parts: parts },\n\t\t}),\n\t);\n\tconsole.log(\"Multipart upload complete.\");\n} catch (err) {\n\t// Abort on failure to clean up incomplete parts\n\ttry {\n\t\tawait S3.send(\n\t\t\tnew AbortMultipartUploadCommand({ Bucket: bucket, Key: key, UploadId }),\n\t\t);\n\t} catch (_abortErr) {\n\t\t// Best-effort cleanup — the original error is more important\n\t}\n\tthrow err;\n}\n```\n\nExample:\n```text\nimport {\n\tS3Client,\n\tCreateMultipartUploadCommand,\n\tUploadPartCommand,\n\tCompleteMultipartUploadCommand,\n\tAbortMultipartUploadCommand,\n} from \"@aws-sdk/client-s3\";\nimport { createReadStream, statSync } from \"node:fs\";\n\nconst S3 = new S3Client({\n\tregion: \"auto\",\n\tendpoint: `https://<ACCOUNT_ID>.r2.cloudflarestorage.com`,\n\tcredentials: {\n\t\taccessKeyId: \"<ACCESS_KEY_ID>\",\n\t\tsecretAccessKey: \"<SECRET_ACCESS_KEY>\",\n\t},\n});\n\nconst bucket = \"my-bucket\";\nconst key = \"large-file.bin\";\nconst partSize = 10 * 1024 * 1024; // 10 MiB per part\n\n// Step 1: Create the multipart upload\nconst { UploadId } = await S3.send(\n\tnew CreateMultipartUploadCommand({ Bucket: bucket, Key: key }),\n);\n\ntry {\n\tconst fileSize = statSync(\"./large-file.bin\").size;\n\tconst partCount = Math.ceil(fileSize / partSize);\n\tconst parts = [];\n\n\t// Step 2: Upload each part\n\tfor (let i = 0; i < partCount; i++) {\n\t\tconst start = i * partSize;\n\t\tconst end = Math.min(start + partSize, fileSize);\n\t\tconst { ETag } = await S3.send(\n\t\t\tnew UploadPartCommand({\n\t\t\t\tBucket: bucket,\n\t\t\t\tKey: key,\n\t\t\t\tUploadId,\n\t\t\t\tPartNumber: i + 1,\n\t\t\t\tBody: createReadStream(\"./large-file.bin\", { start, end: end - 1 }),\n\t\t\t\tContentLength: end - start,\n\t\t\t}),\n\t\t);\n\t\tparts.push({ PartNumber: i + 1, ETag });\n\t}\n\n\t// Step 3: Complete the upload\n\tawait S3.send(\n\t\tnew CompleteMultipartUploadCommand({\n\t\t\tBucket: bucket,\n\t\t\tKey: key,\n\t\t\tUploadId,\n\t\t\tMultipartUpload: { Parts: parts },\n\t\t}),\n\t);\n\tconsole.log(\"Multipart upload complete.\");\n} catch (err) {\n\t// Abort on failure to clean up incomplete parts\n\ttry {\n\t\tawait S3.send(\n\t\t\tnew AbortMultipartUploadCommand({ Bucket: bucket, Key: key, UploadId }),\n\t\t);\n\t} catch (_abortErr) {\n\t\t// Best-effort cleanup — the original error is more important\n\t}\n\tthrow err;\n}\n```\n\nExample:\n```text\nimport boto3\nimport math\nimport os\nfrom concurrent.futures import ThreadPoolExecutor\n\ns3 = boto3.client(\n service_name=\"s3\",\n endpoint_url=\"https://<ACCOUNT_ID>.r2.cloudflarestorage.com\",\n aws_access_key_id=\"<ACCESS_KEY_ID>\",\n aws_secret_access_key=\"<SECRET_ACCESS_KEY>\",\n region_name=\"auto\",\n)\n\nbucket = \"my-bucket\"\nkey = \"large-file.bin\"\nfile_path = \"./large-file.bin\"\npart_size = 16 * 1024 * 1024 # 16 MiB per part\nmax_workers = 10 # Number of parallel upload threads\n\n# Step 1: Create the multipart upload\nupload_id = None\nmpu = s3.create_multipart_upload(Bucket=bucket, Key=key)\nupload_id = mpu[\"UploadId\"]\n\ndef upload_part(part_number, data):\n response = s3.upload_part(\n Bucket=bucket,\n Key=key,\n UploadId=upload_id,\n PartNumber=part_number,\n Body=data,\n )\n return {\"PartNumber\": part_number, \"ETag\": response[\"ETag\"]}\n\ntry:\n file_size = os.path.getsize(file_path)\n part_count = math.ceil(file_size / part_size)\n\n # Step 2: Upload parts in parallel\n with ThreadPoolExecutor(max_workers=max_workers) as pool:\n futures = []\n with open(file_path, \"rb\") as f:\n for i in range(part_count):\n data = f.read(part_size)\n futures.append(pool.submit(upload_part, i + 1, data))\n\n parts = [future.result() for future in futures]\n\n # Step 3: Complete the upload\n s3.complete_multipart_upload(\n Bucket=bucket,\n Key=key,\n UploadId=upload_id,\n MultipartUpload={\"Parts\": parts},\n )\n print(\"Multipart upload complete.\")\nexcept Exception:\n # Abort on failure to clean up incomplete parts\n if upload_id:\n try:\n s3.abort_multipart_upload(Bucket=bucket, Key=key, UploadId=upload_id)\n except Exception:\n pass # Best-effort cleanup — the original error is more important\n raise\n```\n\nExample:\n```text\nimport { S3Client, PutObjectCommand } from \"@aws-sdk/client-s3\";\nimport { getSignedUrl } from \"@aws-sdk/s3-request-presigner\";\n\nconst S3 = new S3Client({\n\tregion: \"auto\",\n\tendpoint: `https://<ACCOUNT_ID>.r2.cloudflarestorage.com`,\n\tcredentials: {\n\t\taccessKeyId: \"<ACCESS_KEY_ID>\",\n\t\tsecretAccessKey: \"<SECRET_ACCESS_KEY>\",\n\t},\n});\n\nconst presignedUrl = await getSignedUrl(\n\tS3,\n\tnew PutObjectCommand({\n\t\tBucket: \"my-bucket\",\n\t\tKey: \"user-upload.png\",\n\t\tContentType: \"image/png\",\n\t}),\n\t{ expiresIn: 3600 }, // Valid for 1 hour\n);\n\nconsole.log(presignedUrl);\n// Return presignedUrl to the client\n```\n\nExample:\n```text\nimport boto3\n\ns3 = boto3.client(\n service_name=\"s3\",\n endpoint_url=\"https://<ACCOUNT_ID>.r2.cloudflarestorage.com\",\n aws_access_key_id=\"<ACCESS_KEY_ID>\",\n aws_secret_access_key=\"<SECRET_ACCESS_KEY>\",\n region_name=\"auto\",\n)\n\npresigned_url = s3.generate_presigned_url(\n \"put_object\",\n Params={\n \"Bucket\": \"my-bucket\",\n \"Key\": \"user-upload.png\",\n \"ContentType\": \"image/png\",\n },\n ExpiresIn=3600, # Valid for 1 hour\n)\n\nprint(presigned_url)\n# Return presigned_url to the client\n```\n\nExample:\n```text\n# Upload a single file\nrclone copy /path/to/local/image.png r2:bucket_name\n\n# Upload everything in a directory\nrclone copy /path/to/local/folder r2:bucket_name\n```\n\nExample:\n```text\nrclone ls r2:bucket_name\n```\n\nExample:\n```text\nwrangler r2 object put test-bucket/image.png --file=image.png\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.093Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":21,"totalLines":769,"estimatedTokens":4930}}38{"id":"doc-aws_cli_cloudflare_r2_docs-2d912036","source":"documentation","title":"aws CLI · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/examples/aws/aws-cli/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\naws configure\n```\n\nExample:\n```text\nAWS Access Key ID [None]: <ACCESS_KEY_ID>\nAWS Secret Access Key [None]: <SECRET_ACCESS_KEY>\nDefault region name [None]: auto\nDefault output format [None]: json\n```\n\nExample:\n```text\n# Provide your Cloudflare account ID\naws s3api list-buckets --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com\n# {\n# \"Buckets\": [\n# {\n# \"Name\": \"my-bucket\",\n# \"CreationDate\": \"2022-05-18T17:19:59.645000+00:00\"\n# }\n# ],\n# \"Owner\": {\n# \"DisplayName\": \"134a5a2c0ba47b38eada4b9c8ead10b6\",\n# \"ID\": \"134a5a2c0ba47b38eada4b9c8ead10b6\"\n# }\n# }\n\naws s3api list-objects-v2 --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com --bucket my-bucket\n# {\n# \"Contents\": [\n# {\n# \"Key\": \"ferriswasm.png\",\n# \"LastModified\": \"2022-05-18T17:20:21.670000+00:00\",\n# \"ETag\": \"\\\"eb2b891dc67b81755d2b726d9110af16\\\"\",\n# \"Size\": 87671,\n# \"StorageClass\": \"STANDARD\"\n# }\n# ]\n# }\n```\n\nExample:\n```text\n# You can pass the --expires-in flag to determine how long the presigned link is valid.\naws s3 presign --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com s3://my-bucket/ferriswasm.png --expires-in 3600\n# https://<ACCOUNT_ID>.r2.cloudflarestorage.com/my-bucket/ferriswasm.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=<credential>&X-Amz-Date=<timestamp>&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=<signature>\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.094Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":4,"totalLines":54,"estimatedTokens":428}}39{"id":"doc-aws_sdk_js_cloudflare_r2_docs-20e46cfc","source":"documentation","title":"aws-sdk-js · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/examples/aws/aws-sdk-js/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nimport S3 from \"aws-sdk/clients/s3.js\";\n\nconst s3 = new S3({\n\t// Provide your Cloudflare account ID\n\tendpoint: `https://${ACCOUNT_ID}.r2.cloudflarestorage.com`,\n\t// Retrieve your S3 API credentials for your R2 bucket via API tokens (see: https://developers.cloudflare.com/r2/api/tokens)\n\taccessKeyId: `${ACCESS_KEY_ID}`,\n\tsecretAccessKey: `${SECRET_ACCESS_KEY}`,\n\tsignatureVersion: \"v4\",\n});\n\nconsole.log(await s3.listBuckets().promise());\n//=> {\n//=> Buckets: [\n//=> { Name: 'user-uploads', CreationDate: 2022-04-13T21:23:47.102Z },\n//=> { Name: 'my-bucket', CreationDate: 2022-05-07T02:46:49.218Z }\n//=> ],\n//=> Owner: {\n//=> DisplayName: '...',\n//=> ID: '...'\n//=> }\n//=> }\n\nconsole.log(await s3.listObjects({ Bucket: \"my-bucket\" }).promise());\n//=> {\n//=> IsTruncated: false,\n//=> Name: 'my-bucket',\n//=> CommonPrefixes: [],\n//=> MaxKeys: 1000,\n//=> Contents: [\n//=> {\n//=> Key: 'cat.png',\n//=> LastModified: 2022-05-07T02:50:45.616Z,\n//=> ETag: '\"c4da329b38467509049e615c11b0c48a\"',\n//=> ChecksumAlgorithm: [],\n//=> Size: 751832,\n//=> Owner: [Object]\n//=> },\n//=> {\n//=> Key: 'todos.txt',\n//=> LastModified: 2022-05-07T21:37:17.150Z,\n//=> ETag: '\"29d911f495d1ba7cb3a4d7d15e63236a\"',\n//=> ChecksumAlgorithm: [],\n//=> Size: 279,\n//=> Owner: [Object]\n//=> }\n//=> ]\n//=> }\n```\n\nExample:\n```text\n// Use the expires property to determine how long the presigned link is valid.\nconsole.log(\nawait s3.getSignedUrlPromise(\"getObject\", {\n\tBucket: \"my-bucket\",\n\tKey: \"dog.png\",\n\tExpires: 3600,\n}),\n);\n// You can also create links for operations such as putObject to allow temporary write access to a specific key.\n// Specify ContentType to restrict uploads to a specific file type.\nconsole.log(\n\tawait s3.getSignedUrlPromise(\"putObject\", {\n\t\tBucket: \"my-bucket\",\n\t\tKey: \"dog.png\",\n\t\tExpires: 3600,\n\t\tContentType: \"image/png\",\n\t}),\n);\n```\n\nExample:\n```text\nhttps://my-bucket.<ACCOUNT_ID>.r2.cloudflarestorage.com/dog.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=<credential>&X-Amz-Date=<timestamp>&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=<signature>\nhttps://my-bucket.<ACCOUNT_ID>.r2.cloudflarestorage.com/dog.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=<credential>&X-Amz-Date=<timestamp>&X-Amz-Expires=3600&X-Amz-SignedHeaders=content-type%3Bhost&X-Amz-Signature=<signature>\n```\n\nExample:\n```text\ncurl -X PUT \"https://my-bucket.<ACCOUNT_ID>.r2.cloudflarestorage.com/dog.png?X-Amz-Algorithm=...\" \\\n -H \"Content-Type: image/png\" \\\n --data-binary @dog.png\n```\n\nExample:\n```text\n[\n {\n \"AllowedOrigins\": [\"https://example.com\"],\n \"AllowedMethods\": [\"PUT\"],\n \"AllowedHeaders\": [\"Content-Type\"],\n \"ExposeHeaders\": [\"ETag\"],\n \"MaxAgeSeconds\": 3600\n }\n]\n```\n\nExample:\n```text\nconst putUrl = await s3.getSignedUrlPromise(\"putObject\", {\n\tBucket: \"my-bucket\",\n\tKey: \"user-upload.png\",\n\tExpires: 3600,\n\tContentType: \"image/png\",\n});\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.094Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":6,"totalLines":113,"estimatedTokens":801}}40{"id":"doc-aws_sdk_php_cloudflare_r2_docs-636c7bbb","source":"documentation","title":"aws-sdk-php · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/examples/aws/aws-sdk-php/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\n<?php\nrequire 'vendor/aws/aws-autoloader.php';\n\n$bucket_name = \"my-bucket\";\n// Provide your Cloudflare account ID\n$account_id = \"<ACCOUNT_ID>\";\n// Retrieve your S3 API credentials for your R2 bucket via API tokens (see: https://developers.cloudflare.com/r2/api/tokens)\n$access_key_id = \"<ACCESS_KEY_ID>\";\n$access_key_secret = \"<SECRET_ACCESS_KEY>\";\n\n$credentials = new Aws\\Credentials\\Credentials($access_key_id, $access_key_secret);\n\n$options = [\n 'region' => 'auto', // Required by SDK but not used by R2\n 'endpoint' => \"https://$account_id.r2.cloudflarestorage.com\",\n 'version' => 'latest',\n 'credentials' => $credentials\n];\n\n$s3_client = new Aws\\S3\\S3Client($options);\n\n$contents = $s3_client->listObjectsV2([\n 'Bucket' => $bucket_name\n]);\n\nvar_dump($contents['Contents']);\n\n// array(1) {\n// [0]=>\n// array(5) {\n// [\"Key\"]=>\n// string(14) \"ferriswasm.png\"\n// [\"LastModified\"]=>\n// object(Aws\\Api\\DateTimeResult)#187 (3) {\n// [\"date\"]=>\n// string(26) \"2022-05-18 17:20:21.670000\"\n// [\"timezone_type\"]=>\n// int(2)\n// [\"timezone\"]=>\n// string(1) \"Z\"\n// }\n// [\"ETag\"]=>\n// string(34) \"\"eb2b891dc67b81755d2b726d9110af16\"\"\n// [\"Size\"]=>\n// string(5) \"87671\"\n// [\"StorageClass\"]=>\n// string(8) \"STANDARD\"\n// }\n// }\n\n$buckets = $s3_client->listBuckets();\n\nvar_dump($buckets['Buckets']);\n\n// array(1) {\n// [0]=>\n// array(2) {\n// [\"Name\"]=>\n// string(11) \"my-bucket\"\n// [\"CreationDate\"]=>\n// object(Aws\\Api\\DateTimeResult)#212 (3) {\n// [\"date\"]=>\n// string(26) \"2022-05-18 17:19:59.645000\"\n// [\"timezone_type\"]=>\n// int(2)\n// [\"timezone\"]=>\n// string(1) \"Z\"\n// }\n// }\n// }\n\n?>\n```\n\nExample:\n```text\n$cmd = $s3_client->getCommand('GetObject', [\n 'Bucket' => $bucket_name,\n 'Key' => 'ferriswasm.png'\n]);\n\n// The second parameter allows you to determine how long the presigned link is valid.\n$request = $s3_client->createPresignedRequest($cmd, '+1 hour');\n\nprint_r((string)$request->getUri());\n// https://my-bucket.<ACCOUNT_ID>.r2.cloudflarestorage.com/ferriswasm.png?X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=<credential>&X-Amz-Date=<timestamp>&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Signature=<signature>\n\n// You can also create links for operations such as putObject to allow temporary write access to a specific key.\n$cmd = $s3_client->getCommand('PutObject', [\n 'Bucket' => $bucket_name,\n 'Key' => 'ferriswasm.png'\n]);\n\n$request = $s3_client->createPresignedRequest($cmd, '+1 hour');\n\nprint_r((string)$request->getUri());\n```\n\nExample:\n```text\ncurl -X PUT \"https://my-bucket.<ACCOUNT_ID>.r2.cloudflarestorage.com/ferriswasm.png?X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=<credential>&X-Amz-Date=<timestamp>&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Signature=<signature>\" --data-binary @ferriswasm.png\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.094Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":3,"totalLines":108,"estimatedTokens":797}}41{"id":"doc-scalar_functions_r2_sql_docs-34768455","source":"documentation","title":"Scalar functions · R2 SQL docs","url":"https://developers.cloudflare.com/r2-sql/sql-reference/scalar-functions/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2-sql/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nSELECT arrow_cast(total_amount, 'Float32') AS amount_f32\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL\nLIMIT 1\n```\n\nExample:\n```text\nSELECT arrow_typeof(total_amount) AS amount_type,\n arrow_typeof(customer_id) AS id_type\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT coalesce(department, region, 'unknown') AS first_val\nFROM my_namespace.sales_data\nLIMIT 5\n```\n\nExample:\n```text\nSELECT get_field(named_struct('customer', customer_id, 'amount', total_amount), 'amount') AS amt\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL\nLIMIT 1\n```\n\nExample:\n```text\nSELECT greatest(total_amount, unit_price, quantity) AS max_val\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT least(total_amount, unit_price, quantity) AS min_val\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT named_struct('customer', customer_id, 'amount', total_amount) AS info\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL\nLIMIT 1\n```\n\nExample:\n```text\nSELECT nullif(department, 'Unknown') AS dept\nFROM my_namespace.sales_data\nLIMIT 5\n```\n\nExample:\n```text\nSELECT nvl(department, 'N/A') AS dept\nFROM my_namespace.sales_data\nLIMIT 5\n```\n\nExample:\n```text\nSELECT nvl2(department, 'has_dept', 'no_dept') AS dept_status\nFROM my_namespace.sales_data\nLIMIT 5\n```\n\nExample:\n```text\nSELECT customer_id,\n overlay(customer_id PLACING 'XX' FROM 1 FOR 2) AS masked\nFROM my_namespace.sales_data\nLIMIT 3\n```\n\nExample:\n```text\nSELECT struct(customer_id, total_amount, region) AS info\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL\nLIMIT 1\n```\n\nExample:\n```text\nSELECT customer_id, digest(customer_id, 'sha256') AS hash\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT customer_id, md5(customer_id) AS hash\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT sha224(customer_id) AS hash\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT customer_id, sha256(customer_id) AS hash\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT sha384(customer_id) AS hash\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT sha512(customer_id) AS hash\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT current_date() AS today_date\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT current_time() AS now_time\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT date_bin(INTERVAL '1 hour', timestamp, '2025-01-01T00:00:00Z') AS hour_bin,\n COUNT(*) AS cnt\nFROM my_namespace.sales_data\nGROUP BY date_bin(INTERVAL '1 hour', timestamp, '2025-01-01T00:00:00Z')\nORDER BY hour_bin\nLIMIT 5\n```\n\nExample:\n```text\nSELECT date_part('hour', timestamp) AS hr,\n date_part('minute', timestamp) AS mn\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT date_trunc('day', timestamp) AS day_trunc, COUNT(*) AS cnt\nFROM my_namespace.sales_data\nGROUP BY date_trunc('day', timestamp)\nORDER BY day_trunc\nLIMIT 5\n```\n\nExample:\n```text\nSELECT from_unixtime(1770000000) AS ts\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT make_date(2026, 3, 1) AS d\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT make_time(14, 30, 0) AS t\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT now() AS current_ts\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT to_char(timestamp, '%Y-%m-%d %H:%M') AS formatted\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT to_date('2026-03-01', '%Y-%m-%d') AS d\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT to_local_time(timestamp) AS local_ts\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT to_time('14:30:00', '%H:%M:%S') AS t\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT to_timestamp('2026-03-01 12:00:00', '%Y-%m-%d %H:%M:%S') AS ts\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT to_timestamp_micros(1770000000000000) AS ts\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT to_timestamp_millis(1770000000000) AS ts\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT to_timestamp_nanos(1770000000000000000) AS ts\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT to_timestamp_seconds(1770000000) AS ts\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT to_unixtime(timestamp) AS epoch\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT decode('aGVsbG8=', 'base64') AS raw\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT encode(CAST('hello' AS BYTEA), 'base64') AS b64\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT json_as_text(doc, 'description') AS description\nFROM my_namespace.sales_data\nLIMIT 5\n```\n\nExample:\n```text\nSELECT customer_id, json_contains(doc, 'email') AS has_email\nFROM my_namespace.sales_data\nLIMIT 5\n```\n\nExample:\n```text\nSELECT json_get(doc, 'name') AS name\nFROM my_namespace.sales_data\nLIMIT 5\n```\n\nExample:\n```text\nSELECT json_get_array(doc, 'tags') AS tags\nFROM my_namespace.sales_data\nLIMIT 5\n```\n\nExample:\n```text\nSELECT json_get_bool(doc, 'active') AS is_active\nFROM my_namespace.sales_data\nLIMIT 5\n```\n\nExample:\n```text\nSELECT json_get_float(doc, 'price') AS price\nFROM my_namespace.sales_data\nLIMIT 5\n```\n\nExample:\n```text\nSELECT json_get_int(doc, 'age') AS age\nFROM my_namespace.sales_data\nLIMIT 5\n```\n\nExample:\n```text\nSELECT json_get_json(doc, 'metadata') AS metadata\nFROM my_namespace.sales_data\nLIMIT 5\n```\n\nExample:\n```text\nSELECT json_get_str(doc, 'name') AS name\nFROM my_namespace.sales_data\nLIMIT 5\n```\n\nExample:\n```text\nSELECT json_length(doc, 'items') AS item_count\nFROM my_namespace.sales_data\nLIMIT 5\n```\n\nExample:\n```text\nSELECT abs(total_amount - 500) AS distance_from_500\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT cbrt(CAST(quantity AS DOUBLE)) AS cbrt_qty\nFROM my_namespace.sales_data\nWHERE quantity IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT ceil(total_amount) AS rounded_up\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT degrees(pi()) AS full_circle\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT exp(total_amount / 1000.0) AS exp_val\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT factorial(5) AS fact5\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT floor(total_amount) AS rounded_down\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT gcd(12, 8) AS gcd_val\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT sinh(1.0) AS sh, cosh(1.0) AS ch, tanh(1.0) AS th\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT isnan(0.0 / 0.0) AS is_nan\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT iszero(0.0) AS is_zero\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT lcm(4, 6) AS lcm_val\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT ln(total_amount) AS ln_val\nFROM my_namespace.sales_data\nWHERE total_amount > 0\nLIMIT 5\n```\n\nExample:\n```text\nSELECT log(10.0, total_amount) AS log10_val\nFROM my_namespace.sales_data\nWHERE total_amount > 0\nLIMIT 5\n```\n\nExample:\n```text\nSELECT log2(total_amount) AS log2_val\nFROM my_namespace.sales_data\nWHERE total_amount > 0\nLIMIT 5\n```\n\nExample:\n```text\nSELECT log10(total_amount) AS log10_val\nFROM my_namespace.sales_data\nWHERE total_amount > 0\nLIMIT 5\n```\n\nExample:\n```text\nSELECT nanvl(0.0 / 0.0, -1.0) AS safe_val\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT pi() AS pi_val\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT power(total_amount, 2.0) AS amount_squared\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT radians(180.0) AS pi_val\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT random() AS rnd\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT round(total_amount, 2) AS rounded\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT signum(total_amount - 500) AS sign_val\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT sqrt(CAST(quantity AS DOUBLE)) AS sqrt_qty\nFROM my_namespace.sales_data\nWHERE quantity IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT sin(1.0) AS s, cos(1.0) AS c, tan(1.0) AS t,\n asin(0.5) AS as_val, acos(0.5) AS ac_val, atan(1.0) AS at_val\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT trunc(total_amount, 0) AS truncated\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT department, regexp_count(department, '[aeiou]') AS vowels\nFROM my_namespace.sales_data\nWHERE department IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT department, regexp_instr(department, '[0-9]') AS digit_pos\nFROM my_namespace.sales_data\nWHERE department IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT department, regexp_like(department, '^[A-Z]{2}') AS starts_two_caps\nFROM my_namespace.sales_data\nWHERE department IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT department, regexp_match(department, '([A-Z][a-z]+)') AS first_word\nFROM my_namespace.sales_data\nWHERE department IS NOT NULL\nLIMIT 3\n```\n\nExample:\n```text\nSELECT department, regexp_replace(department, '[0-9]', '#') AS no_digits\nFROM my_namespace.sales_data\nWHERE department IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT customer_id, ascii(customer_id) AS first_code\nFROM my_namespace.sales_data\nLIMIT 3\n```\n\nExample:\n```text\nSELECT customer_id, bit_length(customer_id) AS bits\nFROM my_namespace.sales_data\nLIMIT 3\n```\n\nExample:\n```text\nSELECT btrim(' hello ') AS trimmed\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT chr(65) AS letter\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT concat(department, ' - ', region) AS label\nFROM my_namespace.sales_data\nWHERE department IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT concat_ws('/', region, department) AS path\nFROM my_namespace.sales_data\nWHERE department IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT customer_id, contains(department, 'Sales') AS is_sales\nFROM my_namespace.sales_data\nWHERE department IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT customer_id, ends_with(department, 'ing') AS ends_ing\nFROM my_namespace.sales_data\nWHERE department IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT department, levenshtein(department, 'Engineering') AS dist\nFROM my_namespace.sales_data\nWHERE department IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT lower(department) AS dept_lower\nFROM my_namespace.sales_data\nLIMIT 5\n```\n\nExample:\n```text\nSELECT ltrim(' hello') AS trimmed\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT customer_id, octet_length(customer_id) AS bytes\nFROM my_namespace.sales_data\nLIMIT 3\n```\n\nExample:\n```text\nSELECT repeat(region, 2) AS doubled\nFROM my_namespace.sales_data\nLIMIT 3\n```\n\nExample:\n```text\nSELECT department, replace(department, ' ', '_') AS underscored\nFROM my_namespace.sales_data\nWHERE department IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT rtrim('hello ') AS trimmed\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT customer_id, split_part(customer_id, '-', 1) AS first_part\nFROM my_namespace.sales_data\nWHERE customer_id IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT customer_id, starts_with(department, 'Eng') AS is_eng\nFROM my_namespace.sales_data\nWHERE department IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT to_hex(255) AS hex_ff\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT upper(region) AS region_upper\nFROM my_namespace.sales_data\nLIMIT 5\n```\n\nExample:\n```text\nSELECT uuid() AS new_id\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT department, character_length(department) AS len\nFROM my_namespace.sales_data\nWHERE department IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT find_in_set('North', 'South,North,East,West') AS pos\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT initcap('hello world') AS capped\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT department, left(department, 5) AS prefix\nFROM my_namespace.sales_data\nWHERE department IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT region, lpad(region, 15, '.') AS padded\nFROM my_namespace.sales_data\nLIMIT 5\n```\n\nExample:\n```text\nSELECT department, reverse(department) AS rev\nFROM my_namespace.sales_data\nWHERE department IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT department, right(department, 3) AS suffix\nFROM my_namespace.sales_data\nWHERE department IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT region, rpad(region, 15, '.') AS padded\nFROM my_namespace.sales_data\nLIMIT 5\n```\n\nExample:\n```text\nSELECT department, strpos(department, 'a') AS a_pos\nFROM my_namespace.sales_data\nWHERE department IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT department, substr(department, 1, 8) AS first_eight\nFROM my_namespace.sales_data\nWHERE department IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT customer_id, substr_index(customer_id, '-', 1) AS first_segment\nFROM my_namespace.sales_data\nWHERE customer_id IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT department, translate(department, 'aeiou', '12345') AS coded\nFROM my_namespace.sales_data\nWHERE department IS NOT NULL\nLIMIT 5\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.096Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":112,"totalLines":837,"estimatedTokens":3436}}42{"id":"doc-aws_sdk_kotlin_cloudflare_r2_docs-d3ac2ea1","source":"documentation","title":"aws-sdk-kotlin · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/examples/aws/aws-sdk-kotlin/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nimport aws.sdk.kotlin.runtime.auth.credentials.StaticCredentialsProvider\nimport aws.sdk.kotlin.services.s3.S3Client\nimport aws.sdk.kotlin.services.s3.listObjects\nimport aws.sdk.kotlin.services.s3.model.GetObjectRequest\nimport aws.sdk.kotlin.services.s3.model.PutObjectRequest\nimport aws.sdk.kotlin.services.s3.presigners.presignGetObject\nimport aws.sdk.kotlin.services.s3.presigners.presignPutObject\nimport aws.smithy.kotlin.runtime.auth.awscredentials.Credentials\nimport aws.smithy.kotlin.runtime.net.url.Url\nimport kotlinx.coroutines.runBlocking\nimport kotlin.time.Duration.Companion.minutes\n\nval ACCOUNT_ID = \"<ACCOUNT_ID>\"\nval ACCESS_KEY = \"<ACCESS_KEY>\"\nval SECRET_KEY = \"<SECRET_KEY>\"\n\nfun main() = runBlocking {\n val r2Client = S3Client.fromEnvironment {\n region = \"auto\" // Required by SDK, but not used by R2\n endpointUrl = Url.parse(\"https://${ACCOUNT_ID}.r2.cloudflarestorage.com\")\n credentialsProvider = StaticCredentialsProvider(\n Credentials(\n accessKeyId = ACCESS_KEY,\n secretAccessKey = SECRET_KEY\n ),\n )\n }\n\n println(\"Available buckets:\")\n r2Client.listBuckets().buckets?.forEach { bucket ->\n println(\"* ${bucket.name}\")\n }\n\n val bucketName = \"<BUCKET_NAME>\"\n println(\"\\nObjects in bucket '${bucketName}':\")\n r2Client.listObjects { bucket = bucketName }.contents?.forEach {\n println(\"* ${it.key} (size: ${it.size} bytes, modified: ${it.lastModified})\")\n }\n\n r2Client.close()\n}\n```\n\nExample:\n```text\nAvailable buckets:\n* my-bucket-1\n* my-bucket-2\n\nObjects in bucket 'my-bucket-1':\n* image1.png (size: 253167 bytes, modified: 2026-01-17T11:30:58.896Z)\n* image2.png (size: 247027 bytes, modified: 2026-01-17T11:30:57.779Z)\n```\n\nExample:\n```text\nval uploadUrl = r2Client.presignPutObject(\n input = PutObjectRequest {\n bucket = bucketName\n key = \"README.md\"\n },\n duration = 15.minutes,\n).url\nprintln(uploadUrl)\n\nval getUrl = r2Client.presignGetObject(\n input = GetObjectRequest {\n bucket = bucketName\n key = \"README.md\"\n },\n duration = 15.minutes,\n).url\nprintln(getUrl)\n```\n\nExample:\n```text\ncurl -X PUT \"https://<your-presigned-put-url>\" -H \"Content-Type: application/octet-stream\" --data-binary \"@local-file.txt\"\n```\n\nExample:\n```text\ncurl -X GET \"https://<your-presigned-get-url>\" -o downloaded-file.txt\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.096Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":5,"totalLines":90,"estimatedTokens":649}}43{"id":"doc-rclone_cloudflare_r2_docs-60a82dec","source":"documentation","title":"Rclone · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/examples/rclone/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nrclone config file\n# Configuration file is stored at:\n# ~/.config/rclone/rclone.conf\n```\n\nExample:\n```text\n[r2]\ntype = s3\nprovider = Cloudflare\naccess_key_id = abc123\nsecret_access_key = xyz456\nendpoint = https://<accountid>.r2.cloudflarestorage.com\nacl = private\n```\n\nExample:\n```text\nrclone tree r2:\n# /\n# ├── user-uploads\n# │ └── foobar.png\n# └── my-bucket-name\n# ├── cat.png\n# └── todos.txt\n\nrclone tree r2:my-bucket-name\n# /\n# ├── cat.png\n# └── todos.txt\n```\n\nExample:\n```text\n# Upload dog.txt to the user-uploads bucket\nrclone copy dog.txt r2:user-uploads/\nrclone tree r2:user-uploads\n# /\n# ├── foobar.png\n# └── dog.txt\n\n# Download dog.txt from the user-uploads bucket\nrclone copy r2:user-uploads/dog.txt .\n```\n\nExample:\n```text\nrclone copy long-video.mp4 r2:user-uploads/ --s3-upload-cutoff=100M --s3-chunk-size=100M\n```\n\nExample:\n```text\n# You can pass the --expire flag to determine how long the presigned link is valid. The --unlink flag isn't supported by R2.\nrclone link r2:my-bucket-name/cat.png --expire 3600\n# https://<accountid>.r2.cloudflarestorage.com/my-bucket-name/cat.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=<credential>&X-Amz-Date=<timestamp>&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=<signature>\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.096Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":6,"totalLines":62,"estimatedTokens":367}}44{"id":"doc-aws_sdk_go_cloudflare_r2_docs-341da831","source":"documentation","title":"aws-sdk-go · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/examples/aws/aws-sdk-go/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\npackage main\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"github.com/aws/aws-sdk-go-v2/aws\"\n\t\"github.com/aws/aws-sdk-go-v2/config\"\n\t\"github.com/aws/aws-sdk-go-v2/credentials\"\n\t\"github.com/aws/aws-sdk-go-v2/service/s3\"\n\t\"log\"\n)\n\nfunc main() {\n\tvar bucketName = \"sdk-example\"\n\t// Provide your Cloudflare account ID\n\tvar accountId = \"<ACCOUNT_ID>\"\n\t// Retrieve your S3 API credentials for your R2 bucket via API tokens\n\t// (see: https://developers.cloudflare.com/r2/api/tokens)\n\tvar accessKeyId = \"<ACCESS_KEY_ID>\"\n\tvar accessKeySecret = \"<SECRET_ACCESS_KEY>\"\n\n\tcfg, err := config.LoadDefaultConfig(context.TODO(),\n\t\tconfig.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(accessKeyId, accessKeySecret, \"\")),\n\t\tconfig.WithRegion(\"auto\"), // Required by SDK but not used by R2\n\t)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tclient := s3.NewFromConfig(cfg, func(o *s3.Options) {\n\t\t\to.BaseEndpoint = aws.String(fmt.Sprintf(\"https://%s.r2.cloudflarestorage.com\", accountId))\n\t})\n\n\tlistObjectsOutput, err := client.ListObjectsV2(context.TODO(), &s3.ListObjectsV2Input{\n\t\tBucket: &bucketName,\n\t})\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tfor _, object := range listObjectsOutput.Contents {\n\t\tobj, _ := json.MarshalIndent(object, \"\", \"\\t\")\n\t\tfmt.Println(string(obj))\n\t}\n\n\t// {\n\t// \t\"ChecksumAlgorithm\": null,\n\t// \t\"ETag\": \"\\\"eb2b891dc67b81755d2b726d9110af16\\\"\",\n\t// \t\"Key\": \"ferriswasm.png\",\n\t// \t\"LastModified\": \"2022-05-18T17:20:21.67Z\",\n\t// \t\"Owner\": null,\n\t// \t\"Size\": 87671,\n\t// \t\"StorageClass\": \"STANDARD\"\n\t// }\n\n\tlistBucketsOutput, err := client.ListBuckets(context.TODO(), &s3.ListBucketsInput{})\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tfor _, object := range listBucketsOutput.Buckets {\n\t\tobj, _ := json.MarshalIndent(object, \"\", \"\\t\")\n\t\tfmt.Println(string(obj))\n\t}\n\n\t// {\n\t// \t\t\"CreationDate\": \"2022-05-18T17:19:59.645Z\",\n\t// \t\t\"Name\": \"sdk-example\"\n\t// }\n}\n```\n\nExample:\n```text\npresignClient := s3.NewPresignClient(client)\n\n\tpresignResult, err := presignClient.PresignPutObject(context.TODO(), &s3.PutObjectInput{\n\t\tBucket: aws.String(bucketName),\n\t\tKey: aws.String(\"example.txt\"),\n\t})\n\n\tif err != nil {\n\t\tpanic(\"Couldn't get presigned URL for PutObject\")\n\t}\n\n\tfmt.Printf(\"Presigned URL For object: %s\\n\", presignResult.URL)\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.096Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":2,"totalLines":94,"estimatedTokens":614}}45{"id":"doc-aws_sdk_js_v3_cloudflare_r2_docs-06129e74","source":"documentation","title":"aws-sdk-js-v3 · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/examples/aws/aws-sdk-js-v3/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nimport {\n\tS3Client,\n\tListBucketsCommand,\n\tListObjectsV2Command,\n\tGetObjectCommand,\n\tPutObjectCommand,\n} from \"@aws-sdk/client-s3\";\n\nconst S3 = new S3Client({\n\tregion: \"auto\", // Required by SDK but not used by R2\n\t// Provide your Cloudflare account ID\n\tendpoint: `https://${ACCOUNT_ID}.r2.cloudflarestorage.com`,\n\t// Retrieve your S3 API credentials for your R2 bucket via API tokens (see: https://developers.cloudflare.com/r2/api/tokens)\n\tcredentials: {\n\t\taccessKeyId: ACCESS_KEY_ID,\n\t\tsecretAccessKey: SECRET_ACCESS_KEY,\n\t},\n});\n\nconsole.log(await S3.send(new ListBucketsCommand({})));\n// {\n// '$metadata': {\n// httpStatusCode: 200,\n// requestId: undefined,\n// extendedRequestId: undefined,\n// cfId: undefined,\n// attempts: 1,\n// totalRetryDelay: 0\n// },\n// Buckets: [\n// { Name: 'user-uploads', CreationDate: 2022-04-13T21:23:47.102Z },\n// { Name: 'my-bucket', CreationDate: 2022-05-07T02:46:49.218Z }\n// ],\n// Owner: {\n// DisplayName: '...',\n// ID: '...'\n// }\n// }\n\nconsole.log(\n\tawait S3.send(new ListObjectsV2Command({ Bucket: \"my-bucket\" })),\n);\n// {\n// '$metadata': {\n// httpStatusCode: 200,\n// requestId: undefined,\n// extendedRequestId: undefined,\n// cfId: undefined,\n// attempts: 1,\n// totalRetryDelay: 0\n// },\n// CommonPrefixes: undefined,\n// Contents: [\n// {\n// Key: 'cat.png',\n// LastModified: 2022-05-07T02:50:45.616Z,\n// ETag: '\"c4da329b38467509049e615c11b0c48a\"',\n// ChecksumAlgorithm: undefined,\n// Size: 751832,\n// StorageClass: 'STANDARD',\n// Owner: undefined\n// },\n// {\n// Key: 'todos.txt',\n// LastModified: 2022-05-07T21:37:17.150Z,\n// ETag: '\"29d911f495d1ba7cb3a4d7d15e63236a\"',\n// ChecksumAlgorithm: undefined,\n// Size: 279,\n// StorageClass: 'STANDARD',\n// Owner: undefined\n// }\n// ],\n// ContinuationToken: undefined,\n// Delimiter: undefined,\n// EncodingType: undefined,\n// IsTruncated: false,\n// KeyCount: 8,\n// MaxKeys: 1000,\n// Name: 'my-bucket',\n// NextContinuationToken: undefined,\n// Prefix: undefined,\n// StartAfter: undefined\n// }\n```\n\nExample:\n```text\nimport { getSignedUrl } from \"@aws-sdk/s3-request-presigner\";\n\n// Use the expiresIn property to determine how long the presigned link is valid.\nconsole.log(\n\tawait getSignedUrl(\n\t\tS3,\n\t\tnew GetObjectCommand({ Bucket: \"my-bucket\", Key: \"dog.png\" }),\n\t\t{ expiresIn: 3600 },\n\t),\n);\n// You can also create links for operations such as PutObject to allow temporary write access to a specific key.\n// Specify ContentType to restrict uploads to a specific file type.\nconsole.log(\n\tawait getSignedUrl(\n\t\tS3,\n\t\tnew PutObjectCommand({\n\t\t\tBucket: \"my-bucket\",\n\t\t\tKey: \"dog.png\",\n\t\t\tContentType: \"image/png\",\n\t\t}),\n\t\t{ expiresIn: 3600 },\n\t),\n);\n```\n\nExample:\n```text\nhttps://my-bucket.<ACCOUNT_ID>.r2.cloudflarestorage.com/dog.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=<credential>&X-Amz-Date=<timestamp>&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=<signature>&x-id=GetObject\nhttps://my-bucket.<ACCOUNT_ID>.r2.cloudflarestorage.com/dog.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=<credential>&X-Amz-Date=<timestamp>&X-Amz-Expires=3600&X-Amz-SignedHeaders=content-type%3Bhost&X-Amz-Signature=<signature>&x-id=PutObject\n```\n\nExample:\n```text\ncurl -X PUT \"https://my-bucket.<ACCOUNT_ID>.r2.cloudflarestorage.com/dog.png?X-Amz-Algorithm=...\" \\\n -H \"Content-Type: image/png\" \\\n --data-binary @dog.png\n```\n\nExample:\n```text\n[\n {\n \"AllowedOrigins\": [\"https://example.com\"],\n \"AllowedMethods\": [\"PUT\"],\n \"AllowedHeaders\": [\"Content-Type\"],\n \"ExposeHeaders\": [\"ETag\"],\n \"MaxAgeSeconds\": 3600\n }\n]\n```\n\nExample:\n```text\nconst putUrl = await getSignedUrl(\n\tS3,\n\tnew PutObjectCommand({\n\t\tBucket: \"my-bucket\",\n\t\tKey: \"dog.png\",\n\t\tContentType: \"image/png\",\n\t}),\n\t{ expiresIn: 3600 },\n);\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.097Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":6,"totalLines":156,"estimatedTokens":1077}}46{"id":"doc-boto3_cloudflare_r2_docs-ed6c5db5","source":"documentation","title":"boto3 · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/examples/aws/boto3/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nimport boto3\n\ns3 = boto3.client(\n service_name=\"s3\",\n endpoint_url=\"https://<ACCOUNT_ID>.r2.cloudflarestorage.com\",\n aws_access_key_id=\"<ACCESS_KEY_ID>\",\n aws_secret_access_key=\"<SECRET_ACCESS_KEY>\",\n region_name=\"auto\",\n)\n```\n\nExample:\n```text\n# Get object metadata\ns3.head_object(Bucket=\"my-bucket\", Key=\"dog.png\")\n\n# Get object\nresponse = s3.get_object(Bucket=\"my-bucket\", Key=\"dog.png\")\n\n# Upload single file\nwith open(\"./dog.png\", \"rb\") as f:\n s3.upload_fileobj(f, \"my-bucket\", \"dog.png\")\n\n# Delete object\ns3.delete_object(Bucket=\"my-bucket\", Key=\"dog.png\")\n```\n\nExample:\n```text\nimport boto3\nimport math\nimport os\nfrom concurrent.futures import ThreadPoolExecutor\n\ns3 = boto3.client(\n service_name=\"s3\",\n endpoint_url=\"https://<ACCOUNT_ID>.r2.cloudflarestorage.com\",\n aws_access_key_id=\"<ACCESS_KEY_ID>\",\n aws_secret_access_key=\"<SECRET_ACCESS_KEY>\",\n region_name=\"auto\",\n)\n\nbucket = \"my-bucket\"\nkey = \"large-file.bin\"\nfile_path = \"./large-file.bin\"\npart_size = 16 * 1024 * 1024 # 16 MiB per part\nmax_workers = 10\n\n# Step 1: Create the multipart upload\nupload_id = None\nmpu = s3.create_multipart_upload(Bucket=bucket, Key=key)\nupload_id = mpu[\"UploadId\"]\n\ndef upload_part(part_number, data):\n response = s3.upload_part(\n Bucket=bucket,\n Key=key,\n UploadId=upload_id,\n PartNumber=part_number,\n Body=data,\n )\n return {\"PartNumber\": part_number, \"ETag\": response[\"ETag\"]}\n\ntry:\n file_size = os.path.getsize(file_path)\n part_count = math.ceil(file_size / part_size)\n\n # Step 2: Upload parts in parallel\n with ThreadPoolExecutor(max_workers=max_workers) as pool:\n futures = []\n with open(file_path, \"rb\") as f:\n for i in range(part_count):\n data = f.read(part_size)\n futures.append(pool.submit(upload_part, i + 1, data))\n\n parts = [future.result() for future in futures]\n\n # Step 3: Complete the upload\n s3.complete_multipart_upload(\n Bucket=bucket,\n Key=key,\n UploadId=upload_id,\n MultipartUpload={\"Parts\": parts},\n )\n print(\"Multipart upload complete.\")\nexcept Exception:\n if upload_id:\n try:\n s3.abort_multipart_upload(Bucket=bucket, Key=key, UploadId=upload_id)\n except Exception:\n pass\n raise\n```\n\nExample:\n```text\n# Generate presigned URL for reading (GET)\nget_url = s3.generate_presigned_url(\n \"get_object\",\n Params={\"Bucket\": \"my-bucket\", \"Key\": \"dog.png\"},\n ExpiresIn=3600, # Valid for 1 hour\n)\n\n# Generate presigned URL for writing (PUT)\nput_url = s3.generate_presigned_url(\n \"put_object\",\n Params={\n \"Bucket\": \"my-bucket\",\n \"Key\": \"dog.png\",\n \"ContentType\": \"image/png\",\n },\n ExpiresIn=3600,\n)\n```\n\nExample:\n```text\nhttps://<ACCOUNT_ID>.r2.cloudflarestorage.com/my-bucket/dog.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...&X-Amz-Date=<timestamp>&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=<signature>\nhttps://<ACCOUNT_ID>.r2.cloudflarestorage.com/my-bucket/dog.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...&X-Amz-Date=<timestamp>&X-Amz-Expires=3600&X-Amz-SignedHeaders=content-type%3Bhost&X-Amz-Signature=<signature>\n```\n\nExample:\n```text\ncurl -X PUT \"https://<ACCOUNT_ID>.r2.cloudflarestorage.com/my-bucket/dog.png?X-Amz-Algorithm=...\" \\\n -H \"Content-Type: image/png\" \\\n --data-binary @dog.png\n```\n\nExample:\n```text\n[\n\t{\n\t\t\"AllowedOrigins\": [\"https://example.com\"],\n\t\t\"AllowedMethods\": [\"PUT\"],\n\t\t\"AllowedHeaders\": [\"Content-Type\"],\n\t\t\"ExposeHeaders\": [\"ETag\"],\n\t\t\"MaxAgeSeconds\": 3600\n\t}\n]\n```\n\nExample:\n```text\nput_url = s3.generate_presigned_url(\n \"put_object\",\n Params={\n \"Bucket\": \"my-bucket\",\n \"Key\": \"dog.png\",\n \"ContentType\": \"image/png\",\n },\n ExpiresIn=3600,\n)\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.097Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":8,"totalLines":159,"estimatedTokens":1010}}47{"id":"doc-aws_sdk_rust_cloudflare_r2_docs-3cf30d96","source":"documentation","title":"aws-sdk-rust · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/examples/aws/aws-sdk-rust/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nuse aws_sdk_s3 as s3;\nuse aws_smithy_types::date_time::Format::DateTime;\n\n#[tokio::main]\nasync fn main() -> Result<(), s3::Error> {\n let bucket_name = \"sdk-example\";\n // Provide your Cloudflare account ID\n let account_id = \"<ACCOUNT_ID>\";\n // Retrieve your S3 API credentials for your R2 bucket via API tokens\n // (see: https://developers.cloudflare.com/r2/api/tokens)\n let access_key_id = \"<ACCESS_KEY_ID>\";\n let access_key_secret = \"<SECRET_ACCESS_KEY>\";\n\n // Configure the client\n let config = aws_config::from_env()\n .endpoint_url(format!(\"https://{}.r2.cloudflarestorage.com\", account_id))\n .credentials_provider(aws_sdk_s3::config::Credentials::new(\n access_key_id,\n access_key_secret,\n None, // session token is not used with R2\n None,\n \"R2\",\n ))\n .region(\"auto\") // Required by SDK but not used by R2\n .load()\n .await;\n\n let client = s3::Client::new(&config);\n\n // List buckets\n let list_buckets_output = client.list_buckets().send().await?;\n\n println!(\"Buckets:\");\n for bucket in list_buckets_output.buckets() {\n println!(\" - {}: {}\",\n bucket.name().unwrap_or_default(),\n bucket.creation_date().map_or_else(\n || \"Unknown creation date\".to_string(),\n |date| date.fmt(DateTime).unwrap()\n )\n );\n }\n\n // List objects in a specific bucket\n let list_objects_output = client\n .list_objects_v2()\n .bucket(bucket_name)\n .send()\n .await?;\n\n println!(\"\\nObjects in {}:\", bucket_name);\n for object in list_objects_output.contents() {\n println!(\" - {}: {} bytes, last modified: {}\",\n object.key().unwrap_or_default(),\n object.size().unwrap_or_default(),\n object.last_modified().map_or_else(\n || \"Unknown\".to_string(),\n |date| date.fmt(DateTime).unwrap()\n )\n );\n }\n\n Ok(())\n}\n```\n\nExample:\n```text\nuse aws_sdk_s3::primitives::ByteStream;\nuse std::path::Path;\n\nasync fn upload_object(\n client: &s3::Client,\n bucket: &str,\n key: &str,\n file_path: &str,\n) -> Result<(), s3::Error> {\n let body = ByteStream::from_path(Path::new(file_path)).await.unwrap();\n\n client\n .put_object()\n .bucket(bucket)\n .key(key)\n .body(body)\n .send()\n .await?;\n\n println!(\"Uploaded {} to {}/{}\", file_path, bucket, key);\n Ok(())\n}\n```\n\nExample:\n```text\nuse std::fs;\nuse std::io::Write;\n\nasync fn download_object(\n client: &s3::Client,\n bucket: &str,\n key: &str,\n output_path: &str,\n) -> Result<(), Box<dyn std::error::Error>> {\n let resp = client\n .get_object()\n .bucket(bucket)\n .key(key)\n .send()\n .await?;\n\n let data = resp.body.collect().await?;\n let bytes = data.into_bytes();\n\n let mut file = fs::File::create(output_path)?;\n file.write_all(&bytes)?;\n\n println!(\"Downloaded {}/{} to {}\", bucket, key, output_path);\n Ok(())\n}\n```\n\nExample:\n```text\nuse aws_sdk_s3::presigning::PresigningConfig;\nuse std::time::Duration;\n\nasync fn generate_get_presigned_url(\n client: &s3::Client,\n bucket: &str,\n key: &str,\n expires_in: Duration,\n) -> Result<String, s3::Error> {\n let presigning_config = PresigningConfig::expires_in(expires_in)?;\n\n // Generate a presigned URL for GET (download)\n let presigned_get_request = client\n .get_object()\n .bucket(bucket)\n .key(key)\n .presigned(presigning_config)\n .await?;\n\n Ok(presigned_get_request.uri().to_string())\n}\n\nasync fn generate_upload_presigned_url(\n client: &s3::Client,\n bucket: &str,\n key: &str,\n expires_in: Duration,\n) -> Result<String, s3::Error> {\n let presigning_config = PresigningConfig::expires_in(expires_in)?;\n\n // Generate a presigned URL for PUT (upload)\n let presigned_put_request = client\n .put_object()\n .bucket(bucket)\n .key(key)\n .presigned(presigning_config)\n .await?;\n\n Ok(presigned_put_request.uri().to_string())\n}\n```\n\nExample:\n```text\ncurl -X PUT \"https://<your-presigned-put-url>\" -H \"Content-Type: application/octet-stream\" --data-binary \"@local-file.txt\"\n```\n\nExample:\n```text\ncurl -X GET \"https://<your-presigned-get-url>\" -o downloaded-file.txt\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.097Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":6,"totalLines":180,"estimatedTokens":1150}}48{"id":"doc-tutorials_cloudflare_r2_docs-d0e23857","source":"documentation","title":"Tutorials · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/tutorials/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.098Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":46}}49{"id":"doc-aws_sdk_java_cloudflare_r2_docs-e995957f","source":"documentation","title":"aws-sdk-java · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/examples/aws/aws-sdk-java/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nimport software.amazon.awssdk.auth.credentials.AwsBasicCredentials;\nimport software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;\nimport software.amazon.awssdk.regions.Region;\nimport software.amazon.awssdk.services.s3.S3Client;\nimport software.amazon.awssdk.services.s3.model.*;\nimport software.amazon.awssdk.services.s3.S3Configuration;\nimport software.amazon.awssdk.core.sync.RequestBody;\nimport java.net.URI;\nimport java.util.List;\n\n/**\n * Client for interacting with Cloudflare R2 Storage using AWS SDK S3 compatibility\n */\npublic class CloudflareR2Client {\n private final S3Client s3Client;\n\n /**\n * Creates a new CloudflareR2Client with the provided configuration\n */\n public CloudflareR2Client(S3Config config) {\n this.s3Client = buildS3Client(config);\n }\n\n /**\n * Configuration class for R2 credentials and endpoint\n * - accountId: Your Cloudflare account ID\n * - accessKey: Your R2 Access Key ID (see: https://developers.cloudflare.com/r2/api/tokens)\n * - secretKey: Your R2 Secret Access Key (see: https://developers.cloudflare.com/r2/api/tokens)\n */\n public static class S3Config {\n private final String accountId;\n private final String accessKey;\n private final String secretKey;\n private final String endpoint;\n\n public S3Config(String accountId, String accessKey, String secretKey) {\n this.accountId = accountId;\n this.accessKey = accessKey;\n this.secretKey = secretKey;\n this.endpoint = String.format(\"https://%s.r2.cloudflarestorage.com\", accountId);\n }\n\n public String getAccessKey() { return accessKey; }\n public String getSecretKey() { return secretKey; }\n public String getEndpoint() { return endpoint; }\n }\n\n /**\n * Builds and configures the S3 client with R2-specific settings\n */\n private static S3Client buildS3Client(S3Config config) {\n AwsBasicCredentials credentials = AwsBasicCredentials.create(\n config.getAccessKey(),\n config.getSecretKey()\n );\n\n S3Configuration serviceConfiguration = S3Configuration.builder()\n .pathStyleAccessEnabled(true)\n .chunkedEncodingEnabled(false)\n .build();\n\n return S3Client.builder()\n .endpointOverride(URI.create(config.getEndpoint()))\n .credentialsProvider(StaticCredentialsProvider.create(credentials))\n .region(Region.of(\"auto\")) // Required by SDK but not used by R2\n .serviceConfiguration(serviceConfiguration)\n .build();\n }\n\n /**\n * Lists all buckets in the R2 storage\n */\n public List<Bucket> listBuckets() {\n try {\n return s3Client.listBuckets().buckets();\n } catch (S3Exception e) {\n throw new RuntimeException(\"Failed to list buckets: \" + e.getMessage(), e);\n }\n }\n\n /**\n * Lists all objects in the specified bucket\n */\n public List<S3Object> listObjects(String bucketName) {\n try {\n ListObjectsV2Request request = ListObjectsV2Request.builder()\n .bucket(bucketName)\n .build();\n\n return s3Client.listObjectsV2(request).contents();\n } catch (S3Exception e) {\n throw new RuntimeException(\"Failed to list objects in bucket \" + bucketName + \": \" + e.getMessage(), e);\n }\n }\n\n /**\n * Uploads an object to the specified bucket\n */\n public void putObject(String bucketName, String key, String content) {\n try {\n PutObjectRequest request = PutObjectRequest.builder()\n .bucket(bucketName)\n .key(key)\n .build();\n\n s3Client.putObject(request, RequestBody.fromString(content));\n } catch (S3Exception e) {\n throw new RuntimeException(\"Failed to put object \" + key + \" in bucket \" + bucketName + \": \" + e.getMessage(), e);\n }\n }\n\n public static void main(String[] args) {\n S3Config config = new S3Config(\n \"<ACCOUNT_ID>\",\n \"<ACCESS_KEY_ID>\",\n \"<SECRET_ACCESS_KEY>\"\n );\n\n CloudflareR2Client r2Client = new CloudflareR2Client(config);\n\n // List buckets\n System.out.println(\"Available buckets:\");\n r2Client.listBuckets().forEach(bucket ->\n System.out.println(\"* \" + bucket.name())\n );\n\n // Upload an object to a bucket\n String bucketName = \"demos\";\n r2Client.putObject(bucketName, \"example.txt\", \"Hello, R2!\");\n System.out.println(\"Uploaded example.txt to bucket '\" + bucketName + \"'\");\n\n // List objects in a specific bucket\n System.out.println(\"\\nObjects in bucket '\" + bucketName + \"':\");\n r2Client.listObjects(bucketName).forEach(object ->\n System.out.printf(\"* %s (size: %d bytes, modified: %s)%n\",\n object.key(),\n object.size(),\n object.lastModified())\n );\n }\n}\n```\n\nExample:\n```text\n// import required packages for presigning\n// Rest of the packages are same as above\nimport software.amazon.awssdk.services.s3.presigner.S3Presigner;\nimport software.amazon.awssdk.services.s3.presigner.model.PutObjectPresignRequest;\nimport software.amazon.awssdk.services.s3.presigner.model.PresignedPutObjectRequest;\nimport java.time.Duration;\n\npublic class CloudflareR2Client {\n private final S3Client s3Client;\n private final S3Presigner presigner;\n\n /**\n * Creates a new CloudflareR2Client with the provided configuration\n */\n public CloudflareR2Client(S3Config config) {\n this.s3Client = buildS3Client(config);\n this.presigner = buildS3Presigner(config);\n }\n\n /**\n * Builds and configures the S3 presigner with R2-specific settings\n */\n private static S3Presigner buildS3Presigner(S3Config config) {\n AwsBasicCredentials credentials = AwsBasicCredentials.create(\n config.getAccessKey(),\n config.getSecretKey()\n );\n\n return S3Presigner.builder()\n .endpointOverride(URI.create(config.getEndpoint()))\n .credentialsProvider(StaticCredentialsProvider.create(credentials))\n .region(Region.of(\"auto\")) // Required by SDK but not used by R2\n .serviceConfiguration(S3Configuration.builder()\n .pathStyleAccessEnabled(true)\n .build())\n .build();\n }\n\n public String generatePresignedUploadUrl(String bucketName, String objectKey, Duration expiration) {\n PutObjectPresignRequest presignRequest = PutObjectPresignRequest.builder()\n .signatureDuration(expiration)\n .putObjectRequest(builder -> builder\n .bucket(bucketName)\n .key(objectKey)\n .build())\n .build();\n\n PresignedPutObjectRequest presignedRequest = presigner.presignPutObject(presignRequest);\n return presignedRequest.url().toString();\n }\n\n // Rest of the methods remains the same\n\n public static void main(String[] args) {\n // config the client as before\n\n // Generate a pre-signed upload URL valid for 15 minutes\n String uploadUrl = r2Client.generatePresignedUploadUrl(\n \"demos\",\n \"README.md\",\n Duration.ofMinutes(15)\n );\n System.out.println(\"Pre-signed Upload URL (valid for 15 minutes):\");\n System.out.println(uploadUrl);\n }\n\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.098Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":2,"totalLines":219,"estimatedTokens":1928}}50{"id":"doc-aws_sdk_net_cloudflare_r2_docs-972c71fb","source":"documentation","title":"aws-sdk-net · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/examples/aws/aws-sdk-net/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nprivate static IAmazonS3 s3Client;\n\npublic static void Main(string[] args)\n{\n\t// Retrieve your S3 API credentials for your R2 bucket via API tokens (see: https://developers.cloudflare.com/r2/api/tokens)\n\tvar accessKey = \"<ACCESS_KEY_ID>\";\n\tvar secretKey = \"<SECRET_ACCESS_KEY>\";\n\tvar credentials = new BasicAWSCredentials(accessKey, secretKey);\n\ts3Client = new AmazonS3Client(credentials, new AmazonS3Config\n\t\t{\n\t\t\t// Provide your Cloudflare account ID\n\t\t\tServiceURL = \"https://<ACCOUNT_ID>.r2.cloudflarestorage.com\",\n\t\t});\n}\n```\n\nExample:\n```text\nstatic async Task ListBuckets()\n{\n\tvar response = await s3Client.ListBucketsAsync();\n\n\tforeach (var s3Bucket in response.Buckets)\n\t{\n\t\tConsole.WriteLine(\"{0}\", s3Bucket.BucketName);\n\t}\n}\n```\n\nExample:\n```text\nsdk-example\nmy-bucket\n```\n\nExample:\n```text\nstatic async Task ListObjectsV2()\n{\n\tvar request = new ListObjectsV2Request\n\t{\n\t\tBucketName = \"my-bucket\"\n\t};\n\n\tvar response = await s3Client.ListObjectsV2Async(request);\n\n\tforeach (var s3Object in response.S3Objects)\n\t{\n\t\tConsole.WriteLine(\"{0}\", s3Object.Key);\n\t}\n}\n```\n\nExample:\n```text\ndog.png\ncat.png\n```\n\nExample:\n```text\nstatic async Task PutObject()\n{\n\tvar request = new PutObjectRequest\n\t{\n\t\tFilePath = @\"/path/file.txt\",\n\t\tBucketName = \"my-bucket\",\n\t\tDisablePayloadSigning = true,\n\t\tDisableDefaultChecksumValidation = true\n\t};\n\n\tvar response = await s3Client.PutObjectAsync(request);\n\n\tConsole.WriteLine(\"ETag: {0}\", response.ETag);\n}\n```\n\nExample:\n```text\nETag: \"186a71ee365d9686c3b98b6976e1f196\"\n```\n\nExample:\n```text\nstatic async Task GetObject()\n{\n\tvar bucket = \"my-bucket\";\n\tvar key = \"file.txt\";\n\n\tvar response = await s3Client.GetObjectAsync(bucket, key);\n\n\tConsole.WriteLine(\"ETag: {0}\", response.ETag);\n}\n```\n\nExample:\n```text\nstatic string? GeneratePresignedUrl()\n{\n\tAWSConfigsS3.UseSignatureVersion4 = true;\n\tvar presign = new GetPreSignedUrlRequest\n\t{\n\t\tBucketName = \"my-bucket\",\n\t\tKey = \"file.txt\",\n\t\tVerb = HttpVerb.GET,\n\t\tExpires = DateTime.Now.AddDays(7),\n\t};\n\n\tvar presignedUrl = s3Client.GetPreSignedURL(presign);\n\n\tConsole.WriteLine(presignedUrl);\n\n\treturn presignedUrl;\n}\n```\n\nExample:\n```text\nhttps://<ACCOUNT_ID>.r2.cloudflarestorage.com/my-bucket/file.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=<credential>&X-Amz-Date=<timestamp>&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=<signature>\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.098Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":10,"totalLines":126,"estimatedTokens":639}}51{"id":"doc-durability_cloudflare_r2_docs-6ba86430","source":"documentation","title":"Durability · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/reference/durability/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.098Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":46}}52{"id":"doc-data_security_cloudflare_r2_docs-947aa82b","source":"documentation","title":"Data security · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/reference/data-security/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.099Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":46}}53{"id":"doc-aws4fetch_cloudflare_r2_docs-99871c33","source":"documentation","title":"aws4fetch · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/examples/aws/aws4fetch/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nimport { AwsClient } from \"aws4fetch\";\n\n// Provide your Cloudflare account ID\nconst R2_URL = `https://${ACCOUNT_ID}.r2.cloudflarestorage.com`;\n\nconst client = new AwsClient({\n\t// Retrieve your S3 API credentials for your R2 bucket via API tokens (see: https://developers.cloudflare.com/r2/api/tokens)\n\taccessKeyId: ACCESS_KEY_ID,\n\tsecretAccessKey: SECRET_ACCESS_KEY,\n});\n\nconst ListBucketsResult = await client.fetch(R2_URL);\nconsole.log(await ListBucketsResult.text());\n// <ListAllMyBucketsResult>\n// <Buckets>\n// <Bucket>\n// <CreationDate>2022-04-13T21:23:47.102Z</CreationDate>\n// <Name>user-uploads</Name>\n// </Bucket>\n// <Bucket>\n// <CreationDate>2022-05-07T02:46:49.218Z</CreationDate>\n// <Name>my-bucket</Name>\n// </Bucket>\n// </Buckets>\n// <Owner>\n// <DisplayName>...</DisplayName>\n// <ID>...</ID>\n// </Owner>\n// </ListAllMyBucketsResult>\n\nconst ListObjectsV2Result = await client.fetch(\n\t`${R2_URL}/my-bucket?list-type=2`,\n);\nconsole.log(await ListObjectsV2Result.text());\n// <ListBucketResult>\n// <Name>my-bucket</Name>\n// <Contents>\n// <Key>cat.png</Key>\n// <Size>751832</Size>\n// <LastModified>2022-05-07T02:50:45.616Z</LastModified>\n// <ETag>\"c4da329b38467509049e615c11b0c48a\"</ETag>\n// <StorageClass>STANDARD</StorageClass>\n// </Contents>\n// <Contents>\n// <Key>todos.txt</Key>\n// <Size>278</Size>\n// <LastModified> 2022-05-07T21:37:17.150Z</LastModified>\n// <ETag>\"29d911f495d1ba7cb3a4d7d15e63236a\"</ETag>\n// <StorageClass>STANDARD</StorageClass>\n// </Contents>\n// <IsTruncated>false</IsTruncated>\n// <MaxKeys>1000</MaxKeys>\n// <KeyCount>2</KeyCount>\n// </ListBucketResult>\n```\n\nExample:\n```text\nimport { AwsClient } from \"aws4fetch\";\n\nconst client = new AwsClient({\n\tservice: \"s3\", // Required by SDK but not used by R2\n\tregion: \"auto\", // Required by SDK but not used by R2\n\t// Retrieve your S3 API credentials for your R2 bucket via API tokens (see: https://developers.cloudflare.com/r2/api/tokens)\n\taccessKeyId: ACCESS_KEY_ID,\n\tsecretAccessKey: SECRET_ACCESS_KEY,\n});\n\n// Provide your Cloudflare account ID\nconst R2_URL = `https://${ACCOUNT_ID}.r2.cloudflarestorage.com`;\n\n// Use the `X-Amz-Expires` query param to determine how long the presigned link is valid.\nconsole.log(\n\t(\n\t\tawait client.sign(\n\t\t\tnew Request(`${R2_URL}/my-bucket/dog.png?X-Amz-Expires=${3600}`),\n\t\t\t{\n\t\t\t\taws: { signQuery: true },\n\t\t\t},\n\t\t)\n\t).url.toString(),\n);\n// You can also create links for operations such as PutObject to allow temporary write access to a specific key.\n// Specify Content-Type header to restrict uploads to a specific file type.\nconsole.log(\n\t(\n\t\tawait client.sign(\n\t\t\tnew Request(`${R2_URL}/my-bucket/dog.png?X-Amz-Expires=${3600}`, {\n\t\t\t\tmethod: \"PUT\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"image/png\",\n\t\t\t\t},\n\t\t\t}),\n\t\t\t{\n\t\t\t\taws: { signQuery: true },\n\t\t\t},\n\t\t)\n\t).url.toString(),\n);\n```\n\nExample:\n```text\nhttps://<ACCOUNT_ID>.r2.cloudflarestorage.com/my-bucket/dog.png?X-Amz-Expires=3600&X-Amz-Date=<timestamp>&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=<credential>&X-Amz-SignedHeaders=host&X-Amz-Signature=<signature>\nhttps://<ACCOUNT_ID>.r2.cloudflarestorage.com/my-bucket/dog.png?X-Amz-Expires=3600&X-Amz-Date=<timestamp>&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=<credential>&X-Amz-SignedHeaders=content-type%3Bhost&X-Amz-Signature=<signature>\n```\n\nExample:\n```text\ncurl -X PUT \"https://<ACCOUNT_ID>.r2.cloudflarestorage.com/my-bucket/dog.png?X-Amz-Expires=3600&X-Amz-Date=<timestamp>&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=<credential>&X-Amz-SignedHeaders=content-type%3Bhost&X-Amz-Signature=<signature>\" \\\n -H \"Content-Type: image/png\" \\\n --data-binary @dog.png\n```\n\nExample:\n```text\n[\n {\n \"AllowedOrigins\": [\"https://example.com\"],\n \"AllowedMethods\": [\"PUT\"],\n \"AllowedHeaders\": [\"Content-Type\"],\n \"ExposeHeaders\": [\"ETag\"],\n \"MaxAgeSeconds\": 3600\n }\n]\n```\n\nExample:\n```text\nconst signedRequest = await client.sign(\n\tnew Request(`${R2_URL}/my-bucket/user-upload.png?X-Amz-Expires=${3600}`, {\n\t\tmethod: \"PUT\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"image/png\",\n\t\t},\n\t}),\n\t{\n\t\taws: { signQuery: true },\n\t},\n);\nconst putUrl = signedRequest.url.toString();\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.099Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":6,"totalLines":148,"estimatedTokens":1123}}54{"id":"doc-consistency_model_cloudflare_r2_docs-80d2dd5b","source":"documentation","title":"Consistency model · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/reference/consistency/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.099Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":46}}55{"id":"doc-terraform_aws_cloudflare_r2_docs-5d2b9787","source":"documentation","title":"Terraform (AWS) · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/examples/terraform-aws/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nterraform {\n required_providers {\n aws = {\n source = \"hashicorp/aws\"\n version = \"~> 5\"\n }\n }\n}\n\nprovider \"aws\" {\n region = \"us-east-1\"\n\n access_key = <R2 Access Key>\n secret_key = <R2 Secret Key>\n\n\t# Required for R2.\n\t# These options disable S3-specific validation on the client (Terraform) side.\n skip_credentials_validation = true\n skip_region_validation = true\n skip_requesting_account_id = true\n\n endpoints {\n s3 = \"https://<account id>.r2.cloudflarestorage.com\"\n }\n}\n\nresource \"aws_s3_bucket\" \"default\" {\n bucket = \"<org>-test\"\n}\n\nresource \"aws_s3_bucket_cors_configuration\" \"default\" {\n bucket = aws_s3_bucket.default.id\n\n cors_rule {\n allowed_methods = [\"GET\"]\n allowed_origins = [\"*\"]\n }\n}\n\nresource \"aws_s3_bucket_lifecycle_configuration\" \"default\" {\n bucket = aws_s3_bucket.default.id\n\n rule {\n id = \"expire-bucket\"\n status = \"Enabled\"\n expiration {\n days = 1\n }\n }\n\n rule {\n id = \"abort-multipart-upload\"\n status = \"Enabled\"\n abort_incomplete_multipart_upload {\n days_after_initiation = 1\n }\n }\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.099Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":1,"totalLines":65,"estimatedTokens":327}}56{"id":"doc-audit_logs_cloudflare_r2_docs-5e3b0654","source":"documentation","title":"Audit Logs · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/platform/audit-logs/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\n{\n \"action\": { \"info\": \"CreateBucket\", \"result\": true, \"type\": \"create\" },\n \"actor\": {\n \"email\": \"<ACTOR_EMAIL>\",\n \"id\": \"3f7b730e625b975bc1231234cfbec091\",\n \"ip\": \"fe32:43ed:12b5:526::1d2:13\",\n \"type\": \"user\"\n },\n \"id\": \"5eaeb6be-1234-406a-87ab-1971adc1234c\",\n \"interface\": \"API\",\n \"metadata\": { \"zone_name\": \"r2.cloudflarestorage.com\" },\n \"newValue\": \"\",\n \"newValueJson\": {},\n \"oldValue\": \"\",\n \"oldValueJson\": {},\n \"owner\": { \"id\": \"1234d848c0b9e484dfc37ec392b5fa8a\" },\n \"resource\": { \"id\": \"my-bucket\", \"type\": \"r2.bucket\" },\n \"when\": \"2024-07-15T16:32:52.412Z\"\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.099Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":1,"totalLines":26,"estimatedTokens":200}}57{"id":"doc-metrics_and_analytics_cloudflare_r2_docs-776f56db","source":"documentation","title":"Metrics and analytics · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/platform/metrics-analytics/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nquery R2VolumeExample(\n\t$accountTag: string!\n\t$startDate: Time\n\t$endDate: Time\n\t$bucketName: string\n) {\n\tviewer {\n\t\taccounts(filter: { accountTag: $accountTag }) {\n\t\t\tr2OperationsAdaptiveGroups(\n\t\t\t\tlimit: 10000\n\t\t\t\tfilter: {\n\t\t\t\t\tdatetime_geq: $startDate\n\t\t\t\t\tdatetime_leq: $endDate\n\t\t\t\t\tbucketName: $bucketName\n\t\t\t\t}\n\t\t\t) {\n\t\t\t\tsum {\n\t\t\t\t\trequests\n\t\t\t\t}\n\t\t\t\tdimensions {\n\t\t\t\t\tactionType\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n```\n\nExample:\n```text\nquery R2StorageExample(\n\t$accountTag: string!\n\t$startDate: Time\n\t$endDate: Time\n\t$bucketName: string\n) {\n\tviewer {\n\t\taccounts(filter: { accountTag: $accountTag }) {\n\t\t\tr2StorageAdaptiveGroups(\n\t\t\t\tlimit: 10000\n\t\t\t\tfilter: {\n\t\t\t\t\tdatetime_geq: $startDate\n\t\t\t\t\tdatetime_leq: $endDate\n\t\t\t\t\tbucketName: $bucketName\n\t\t\t\t}\n\t\t\t\torderBy: [datetime_DESC]\n\t\t\t) {\n\t\t\t\tmax {\n\t\t\t\t\tobjectCount\n\t\t\t\t\tuploadCount\n\t\t\t\t\tpayloadSize\n\t\t\t\t\tmetadataSize\n\t\t\t\t}\n\t\t\t\tdimensions {\n\t\t\t\t\tdatetime\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.100Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":2,"totalLines":67,"estimatedTokens":282}}58{"id":"doc-troubleshooting_cloudflare_r2_docs-35418f2f","source":"documentation","title":"Troubleshooting · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/platform/troubleshooting/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.100Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":46}}59{"id":"doc-limits_cloudflare_r2_docs-3a9cad2f","source":"documentation","title":"Limits · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/platform/limits/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.100Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":46}}60{"id":"doc-s3mini_cloudflare_r2_docs-440666e0","source":"documentation","title":"s3mini · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/examples/aws/s3mini/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nnpm install s3mini\n```\n\nExample:\n```text\nimport { S3mini } from \"s3mini\";\n\nconst s3 = new S3mini({\n\taccessKeyId: process.env.R2_ACCESS_KEY_ID!,\n\tsecretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,\n\t// Bucket-scoped endpoint — include your bucket name in the path\n\tendpoint: `https://${process.env.ACCOUNT_ID}.r2.cloudflarestorage.com/my-bucket`,\n\tregion: \"auto\",\n});\n\n// Upload an object\nawait s3.putObject(\"hello.txt\", \"Hello from s3mini!\");\n\n// Download an object as a string\nconst text = await s3.getObject(\"hello.txt\");\nconsole.log(text);\n\n// List objects with a prefix\nconst objects = await s3.listObjects(\"/\", \"hello\");\nconsole.log(objects);\n\n// Delete an object\nawait s3.deleteObject(\"hello.txt\");\n```\n\nExample:\n```text\nimport { S3mini } from \"s3mini\";\n\ninterface Env {\n\tR2_ACCESS_KEY_ID: string;\n\tR2_SECRET_ACCESS_KEY: string;\n\tACCOUNT_ID: string;\n}\n\nexport default {\n\tasync fetch(request: Request, env: Env): Promise<Response> {\n\t\tconst s3 = new S3mini({\n\t\t\taccessKeyId: env.R2_ACCESS_KEY_ID,\n\t\t\tsecretAccessKey: env.R2_SECRET_ACCESS_KEY,\n\t\t\tendpoint: `https://${env.ACCOUNT_ID}.r2.cloudflarestorage.com/my-bucket`,\n\t\t\tregion: \"auto\",\n\t\t});\n\n\t\tconst url = new URL(request.url);\n\t\tconst key = url.pathname.slice(1); // strip leading \"/\"\n\n\t\tif (!key) {\n\t\t\treturn new Response(\"Missing object key\", { status: 400 });\n\t\t}\n\n\t\tswitch (request.method) {\n\t\t\tcase \"PUT\": {\n\t\t\t\tconst data = await request.arrayBuffer();\n\t\t\t\tconst contentType =\n\t\t\t\t\trequest.headers.get(\"content-type\") ?? \"application/octet-stream\";\n\t\t\t\tawait s3.putObject(key, new Uint8Array(data), contentType);\n\t\t\t\treturn new Response(\"Created\", { status: 201 });\n\t\t\t}\n\n\t\t\tcase \"GET\": {\n\t\t\t\tconst response = await s3.getObjectResponse(key);\n\t\t\t\tif (!response) {\n\t\t\t\t\treturn new Response(\"Not Found\", { status: 404 });\n\t\t\t\t}\n\t\t\t\treturn new Response(response.body, {\n\t\t\t\t\theaders: {\n\t\t\t\t\t\t\"content-type\":\n\t\t\t\t\t\t\tresponse.headers.get(\"content-type\") ??\n\t\t\t\t\t\t\t\"application/octet-stream\",\n\t\t\t\t\t\tetag: response.headers.get(\"etag\") ?? \"\",\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tcase \"DELETE\": {\n\t\t\t\tawait s3.deleteObject(key);\n\t\t\t\treturn new Response(null, { status: 204 });\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\treturn new Response(\"Method Not Allowed\", { status: 405 });\n\t\t}\n\t},\n};\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.100Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":3,"totalLines":97,"estimatedTokens":606}}61{"id":"doc-use_the_cache_api_cloudflare_r2_docs-495ff310","source":"documentation","title":"Use the Cache API · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/examples/cache-api/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nexport default {\n async fetch(request, env, context) {\n try {\n const url = new URL(request.url);\n\n // Construct the cache key from the cache URL\n const cacheKey = new Request(url.toString(), request);\n const cache = caches.default;\n\n // Check whether the value is already available in the cache\n // if not, you will need to fetch it from R2, and store it in the cache\n // for future access\n let response = await cache.match(cacheKey);\n\n if (response) {\n console.log(`Cache hit for: ${request.url}.`);\n return response;\n }\n\n console.log(\n `Response for request url: ${request.url} not present in cache. Fetching and caching request.`\n );\n\n // If not in cache, get it from R2\n const objectKey = url.pathname.slice(1);\n const object = await env.MY_BUCKET.get(objectKey);\n if (object === null) {\n return new Response('Object Not Found', { status: 404 });\n }\n\n // Set the appropriate object headers\n const headers = new Headers();\n object.writeHttpMetadata(headers);\n headers.set('etag', object.httpEtag);\n\n // Cache API respects Cache-Control headers. Setting s-max-age to 10\n // will limit the response to be in cache for 10 seconds max\n // Any changes made to the response here will be reflected in the cached value\n headers.append('Cache-Control', 's-maxage=10');\n\n response = new Response(object.body, {\n headers,\n });\n\n // Store the fetched response as cacheKey\n // Use waitUntil so you can return the response without blocking on\n // writing to cache\n context.waitUntil(cache.put(cacheKey, response.clone()));\n\n return response;\n } catch (e) {\n return new Response('Error thrown ' + e.message);\n }\n },\n};\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.101Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":1,"totalLines":62,"estimatedTokens":506}}62{"id":"doc-use_sse_c_cloudflare_r2_docs-e8128ccf","source":"documentation","title":"Use SSE-C · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/examples/ssec/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\ninterface Environment {\n\tR2: R2Bucket\n\t/**\n\t * In this example, your SSE-C is stored as a hexadecimal string (preferably a secret).\n\t * The R2 API also supports providing an ArrayBuffer directly, if you want to generate/\n\t * store your keys dynamically.\n\t*/\n\tSSEC_KEY: string\n}\nexport default {\n\tasync fetch(req: Request, env: Env) {\n\t\tconst { SSEC_KEY, R2 } = env;\n\t\tconst { pathname: filename } = new URL(req.url);\n\t\tswitch(req.method) {\n\t\t\tcase \"GET\": {\n\t\t\t\tconst maybeObj = await env.BUCKET.get(filename, {\n\t\t\t\t\tonlyIf: req.headers,\n\t\t\t\t\tssecKey: SSEC_KEY,\n\t\t\t\t});\n\t\t\t\tif(!maybeObj) {\n\t\t\t\t\treturn new Response(\"Not Found\", {\n\t\t\t\t\t\tstatus: 404\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tconst headers = new Headers();\n\t\t\t\tmaybeObj.writeHttpMetadata(headers);\n\t\t\t\treturn new Response(body, {\n\t\t\t\t\theaders\n\t\t\t\t});\n\t\t\t}\n\t\t\tcase 'POST': {\n\t\t\t\tconst multipartUpload = await env.BUCKET.createMultipartUpload(filename, {\n\t\t\t\t\thttpMetadata: req.headers,\n\t\t\t\t\tssecKey: SSEC_KEY,\n\t\t\t\t});\n\t\t\t\t/**\n\t\t\t\t * This example only provides a single-part \"multipart\" upload.\n\t\t\t\t * For multiple parts, the process is the same(the key must be provided)\n\t\t\t\t * for every part.\n\t\t\t\t*/\n\t\t\t\tconst partOne = await multipartUpload.uploadPart(1, req.body, ssecKey);\n\t\t\t\tconst obj = await multipartUpload.complete([partOne]);\n\t\t\t\tconst headers = new Headers();\n\t\t\t\tobj.writeHttpMetadata(headers);\n\t\t\t\treturn new Response(null, {\n\t\t\t\t\theaders,\n\t\t\t\t\tstatus: 201\n\t\t\t\t});\n\t\t\t}\n\t\t\tcase 'PUT': {\n\t\t\t\tconst obj = await env.BUCKET.put(filename, req.body, {\n\t\t\t\t\thttpMetadata: req.headers,\n\t\t\t\t\tssecKey: SSEC_KEY,\n\t\t\t\t});\n\t\t\t\tconst headers = new Headers();\n\t\t\t\tmaybeObj.writeHttpMetadata(headers);\n\t\t\t\treturn new Response(null, {\n\t\t\t\t\theaders,\n\t\t\t\t\tstatus: 201\n\t\t\t\t});\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\treturn new Response(\"Method not allowed\", {\n\t\t\t\t\tstatus: 405\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n```\n\nExample:\n```text\n/**\n\t * In this example, your SSE-C is stored as a hexadecimal string(preferably a secret).\n\t * The R2 API also supports providing an ArrayBuffer directly, if you want to generate/\n\t * store your keys dynamically.\n*/\nexport default {\n\tasync fetch(req, env) {\n\t\tconst { SSEC_KEY, R2 } = env;\n\t\tconst { pathname: filename } = new URL(req.url);\n\t\tswitch(req.method) {\n\t\t\tcase \"GET\": {\n\t\t\t\tconst maybeObj = await env.BUCKET.get(filename, {\n\t\t\t\t\tonlyIf: req.headers,\n\t\t\t\t\tssecKey: SSEC_KEY,\n\t\t\t\t});\n\t\t\t\tif(!maybeObj) {\n\t\t\t\t\treturn new Response(\"Not Found\", {\n\t\t\t\t\t\tstatus: 404\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tconst headers = new Headers();\n\t\t\t\tmaybeObj.writeHttpMetadata(headers);\n\t\t\t\treturn new Response(body, {\n\t\t\t\t\theaders\n\t\t\t\t});\n\t\t\t}\n\t\t\tcase 'POST': {\n\t\t\t\tconst multipartUpload = await env.BUCKET.createMultipartUpload(filename, {\n\t\t\t\t\thttpMetadata: req.headers,\n\t\t\t\t\tssecKey: SSEC_KEY,\n\t\t\t\t});\n\t\t\t\t/**\n\t\t\t\t * This example only provides a single-part \"multipart\" upload.\n\t\t\t\t * For multiple parts, the process is the same(the key must be provided)\n\t\t\t\t * for every part.\n\t\t\t\t*/\n\t\t\t\tconst partOne = await multipartUpload.uploadPart(1, req.body, ssecKey);\n\t\t\t\tconst obj = await multipartUpload.complete([partOne]);\n\t\t\t\tconst headers = new Headers();\n\t\t\t\tobj.writeHttpMetadata(headers);\n\t\t\t\treturn new Response(null, {\n\t\t\t\t\theaders,\n\t\t\t\t\tstatus: 201\n\t\t\t\t});\n\t\t\t}\n\t\t\tcase 'PUT': {\n\t\t\t\tconst obj = await env.BUCKET.put(filename, req.body, {\n\t\t\t\t\thttpMetadata: req.headers,\n\t\t\t\t\tssecKey: SSEC_KEY,\n\t\t\t\t});\n\t\t\t\tconst headers = new Headers();\n\t\t\t\tmaybeObj.writeHttpMetadata(headers);\n\t\t\t\treturn new Response(null, {\n\t\t\t\t\theaders,\n\t\t\t\t\tstatus: 201\n\t\t\t\t});\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\treturn new Response(\"Method not allowed\", {\n\t\t\t\t\tstatus: 405\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n```\n\nExample:\n```text\nimport {\n\tUploadPartCommand,\n\tPutObjectCommand, S3Client,\n\tCompleteMultipartUploadCommand,\n\tCreateMultipartUploadCommand,\n\ttype UploadPartCommandOutput\n} from \"@aws-sdk/client-s3\";\n\nconst s3 = new S3Client({\n\tendpoint: process.env.R2_ENDPOINT,\n\tcredentials: {\n\t\taccessKeyId: process.env.R2_ACCESS_KEY_ID,\n\t\tsecretAccessKey: process.env.R2_SECRET_ACCESS_KEY,\n\t},\n});\n\nconst SSECustomerAlgorithm = \"AES256\";\nconst SSECustomerKey = process.env.R2_SSEC_KEY;\nconst SSECustomerKeyMD5 = process.env.R2_SSEC_KEY_MD5;\n\nawait s3.send(\n\tnew PutObjectCommand({\n\t\tBucket: \"your-bucket\",\n\t\tKey: \"single-part\",\n\t\tBody: \"BeepBoop\",\n\t\tSSECustomerAlgorithm,\n\t\tSSECustomerKey,\n\t\tSSECustomerKeyMD5,\n\t}),\n);\n\nconst multi = await s3.send(\n\tnew CreateMultipartUploadCommand({\n\t\tBucket: \"your-bucket\",\n\t\tKey: \"multi-part\",\n\t\tSSECustomerAlgorithm,\n\t\tSSECustomerKey,\n\t\tSSECustomerKeyMD5,\n\t}),\n);\nconst UploadId = multi.UploadId;\n\nconst parts: UploadPartCommandOutput[] = [];\n\nparts.push(\n\tawait s3.send(\n\t\tnew UploadPartCommand({\n\t\t\tBucket: \"your-bucket\",\n\t\t\tKey: \"multi-part\",\n\t\t\tUploadId,\n\t\t\t// \tfilledBuf()` generates some random data.\n\t\t\t// Replace with a function/body of your choice.\n\t\t\tBody: filledBuf(),\n\t\t\tPartNumber: 1,\n\t\t\tSSECustomerAlgorithm,\n\t\t\tSSECustomerKey,\n\t\t\tSSECustomerKeyMD5,\n\t\t}),\n\t),\n);\nparts.push(\n\tawait s3.send(\n\t\tnew UploadPartCommand({\n\t\t\tBucket: \"your-bucket\",\n\t\t\tKey: \"multi-part\",\n\t\t\tUploadId,\n\t\t\t// \tfilledBuf()` generates some random data.\n\t\t\t// Replace with a function/body of your choice.\n\t\t\tBody: filledBuf(),\n\t\t\tPartNumber: 2,\n\t\t\tSSECustomerAlgorithm,\n\t\t\tSSECustomerKey,\n\t\t\tSSECustomerKeyMD5,\n\t\t}),\n\t),\n);\nawait s3.send(\n\tnew CompleteMultipartUploadCommand({\n\t\tBucket: \"your-bucket\",\n\t\tKey: \"multi-part\",\n\t\tUploadId,\n\t\tMultipartUpload: {\n\t\t\tParts: parts.map(({ ETag }, PartNumber) => ({\n\t\t\t\tETag,\n\t\t\t\tPartNumber: PartNumber + 1,\n\t\t\t})),\n\t\t},\n\t\tSSECustomerAlgorithm,\n\t\tSSECustomerKey,\n\t\tSSECustomerKeyMD5,\n\t}),\n);\n\nconst HeadObjectOutput = await s3.send(\n\tnew HeadObjectCommand({\n\t\tBucket: \"your-bucket\",\n\t\tKey: \"multi-part\",\n\t\tSSECustomerAlgorithm,\n\t\tSSECustomerKey,\n\t\tSSECustomerKeyMD5,\n\t}),\n);\n\nconst GetObjectOutput = await s3.send(\n\tnew GetObjectCommand({\n\t\tBucket: \"your-bucket\",\n\t\tKey: \"single-part\",\n\t\tSSECustomerAlgorithm,\n\t\tSSECustomerKey,\n\t\tSSECustomerKeyMD5,\n\t}),\n);\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.101Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":3,"totalLines":261,"estimatedTokens":1523}}63{"id":"doc-data_location_cloudflare_r2_docs-023195ff","source":"documentation","title":"Data location · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/reference/data-location/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nawait S3.send(\n\tnew CreateBucketCommand({\n\t\tBucket: \"YOUR_BUCKET_NAME\",\n\t\tCreateBucketConfiguration: {\n\t\t\tLocationConstraint: \"WNAM\",\n\t\t},\n\t}),\n);\n```\n\nExample:\n```text\n{\n\t\"r2_buckets\": [\n\t\t{\n\t\t\t\"binding\": \"MY_BUCKET\",\n\t\t\t\"bucket_name\": \"<YOUR_BUCKET_NAME>\",\n\t\t\t\"jurisdiction\": \"<JURISDICTION>\"\n\t\t}\n\t]\n}\n```\n\nExample:\n```text\n[[r2_buckets]]\nbinding = \"MY_BUCKET\"\nbucket_name = \"<YOUR_BUCKET_NAME>\"\njurisdiction = \"<JURISDICTION>\"\n```\n\nExample:\n```text\nimport { S3Client, CreateBucketCommand } from \"@aws-sdk/client-s3\";\nconst S3 = new S3Client({\n\tendpoint: \"https://<account_id>.eu.r2.cloudflarestorage.com\",\n\tcredentials: {\n\t\taccessKeyId: \"<access_key_id\",\n\t\tsecretAccessKey: \"<access_key_secret>\",\n\t},\n\tregion: \"auto\",\n});\nawait S3.send(\n\tnew CreateBucketCommand({\n\t\tBucket: \"YOUR_BUCKET_NAME\",\n\t}),\n);\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.101Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":4,"totalLines":54,"estimatedTokens":253}}64{"id":"doc-terraform_cloudflare_r2_docs-848478ee","source":"documentation","title":"Terraform · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/examples/terraform/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nterraform {\n required_providers {\n cloudflare = {\n source = \"cloudflare/cloudflare\"\n version = \"~> 4\"\n }\n }\n}\n\nprovider \"cloudflare\" {\n api_token = \"<YOUR_API_TOKEN>\"\n}\n\nresource \"cloudflare_r2_bucket\" \"cloudflare-bucket\" {\n account_id = \"<YOUR_ACCOUNT_ID>\"\n name = \"my-tf-test-bucket\"\n location = \"WEUR\"\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.101Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":1,"totalLines":25,"estimatedTokens":136}}65{"id":"doc-event_subscriptions_cloudflare_r2_docs-f8a8148a","source":"documentation","title":"Event subscriptions · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/platform/event-subscriptions/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\n{\n \"type\": \"cf.r2.bucket.created\",\n \"source\": {\n \"type\": \"r2\"\n },\n \"payload\": {\n \"name\": \"my-bucket\",\n \"jurisdiction\": \"default\",\n \"location\": \"WNAM\",\n \"storageClass\": \"Standard\"\n },\n \"metadata\": {\n \"accountId\": \"f9f79265f388666de8122cfb508d7776\",\n \"eventSubscriptionId\": \"1830c4bb612e43c3af7f4cada31fbf3f\",\n \"eventSchemaVersion\": 1,\n \"eventTimestamp\": \"2025-05-01T02:48:57.132Z\"\n }\n}\n```\n\nExample:\n```text\n{\n \"type\": \"cf.r2.bucket.deleted\",\n \"source\": {\n \"type\": \"r2\"\n },\n \"payload\": {\n \"name\": \"my-bucket\",\n \"jurisdiction\": \"default\"\n },\n \"metadata\": {\n \"accountId\": \"f9f79265f388666de8122cfb508d7776\",\n \"eventSubscriptionId\": \"1830c4bb612e43c3af7f4cada31fbf3f\",\n \"eventSchemaVersion\": 1,\n \"eventTimestamp\": \"2025-05-01T02:48:57.132Z\"\n }\n}\n```\n\nExample:\n```text\n{\n \"type\": \"cf.superSlurper.job.started\",\n \"source\": {\n \"type\": \"superSlurper\"\n },\n \"payload\": {\n \"id\": \"job-12345678-90ab-cdef-1234-567890abcdef\",\n \"createdAt\": \"2025-05-01T02:48:57.132Z\",\n \"overwrite\": true,\n \"pathPrefix\": \"migrations/\",\n \"source\": {\n \"provider\": \"s3\",\n \"bucket\": \"source-bucket\",\n \"region\": \"us-east-1\",\n \"endpoint\": \"s3.amazonaws.com\"\n },\n \"destination\": {\n \"provider\": \"r2\",\n \"bucket\": \"destination-bucket\",\n \"jurisdiction\": \"default\"\n }\n },\n \"metadata\": {\n \"accountId\": \"f9f79265f388666de8122cfb508d7776\",\n \"eventSubscriptionId\": \"1830c4bb612e43c3af7f4cada31fbf3f\",\n \"eventSchemaVersion\": 1,\n \"eventTimestamp\": \"2025-05-01T02:48:57.132Z\"\n }\n}\n```\n\nExample:\n```text\n{\n \"type\": \"cf.superSlurper.job.paused\",\n \"source\": {\n \"type\": \"superSlurper\"\n },\n \"payload\": {\n \"id\": \"job-12345678-90ab-cdef-1234-567890abcdef\"\n },\n \"metadata\": {\n \"accountId\": \"f9f79265f388666de8122cfb508d7776\",\n \"eventSubscriptionId\": \"1830c4bb612e43c3af7f4cada31fbf3f\",\n \"eventSchemaVersion\": 1,\n \"eventTimestamp\": \"2025-05-01T02:48:57.132Z\"\n }\n}\n```\n\nExample:\n```text\n{\n \"type\": \"cf.superSlurper.job.resumed\",\n \"source\": {\n \"type\": \"superSlurper\"\n },\n \"payload\": {\n \"id\": \"job-12345678-90ab-cdef-1234-567890abcdef\"\n },\n \"metadata\": {\n \"accountId\": \"f9f79265f388666de8122cfb508d7776\",\n \"eventSubscriptionId\": \"1830c4bb612e43c3af7f4cada31fbf3f\",\n \"eventSchemaVersion\": 1,\n \"eventTimestamp\": \"2025-05-01T02:48:57.132Z\"\n }\n}\n```\n\nExample:\n```text\n{\n \"type\": \"cf.superSlurper.job.completed\",\n \"source\": {\n \"type\": \"superSlurper\"\n },\n \"payload\": {\n \"id\": \"job-12345678-90ab-cdef-1234-567890abcdef\",\n \"totalObjectsCount\": 1000,\n \"skippedObjectsCount\": 10,\n \"migratedObjectsCount\": 980,\n \"failedObjectsCount\": 10\n },\n \"metadata\": {\n \"accountId\": \"f9f79265f388666de8122cfb508d7776\",\n \"eventSubscriptionId\": \"1830c4bb612e43c3af7f4cada31fbf3f\",\n \"eventSchemaVersion\": 1,\n \"eventTimestamp\": \"2025-05-01T02:48:57.132Z\"\n }\n}\n```\n\nExample:\n```text\n{\n \"type\": \"cf.superSlurper.job.aborted\",\n \"source\": {\n \"type\": \"superSlurper\"\n },\n \"payload\": {\n \"id\": \"job-12345678-90ab-cdef-1234-567890abcdef\",\n \"totalObjectsCount\": 1000,\n \"skippedObjectsCount\": 100,\n \"migratedObjectsCount\": 500,\n \"failedObjectsCount\": 50\n },\n \"metadata\": {\n \"accountId\": \"f9f79265f388666de8122cfb508d7776\",\n \"eventSubscriptionId\": \"1830c4bb612e43c3af7f4cada31fbf3f\",\n \"eventSchemaVersion\": 1,\n \"eventTimestamp\": \"2025-05-01T02:48:57.132Z\"\n }\n}\n```\n\nExample:\n```text\n{\n \"type\": \"cf.superSlurper.job.object.migrated\",\n \"source\": {\n \"type\": \"superSlurper.job\",\n \"jobId\": \"job-12345678-90ab-cdef-1234-567890abcdef\"\n },\n \"payload\": {\n \"key\": \"migrations/file.txt\"\n },\n \"metadata\": {\n \"accountId\": \"f9f79265f388666de8122cfb508d7776\",\n \"eventSubscriptionId\": \"1830c4bb612e43c3af7f4cada31fbf3f\",\n \"eventSchemaVersion\": 1,\n \"eventTimestamp\": \"2025-05-01T02:48:57.132Z\"\n }\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.102Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":8,"totalLines":182,"estimatedTokens":1020}}66{"id":"doc-r2_data_catalog_cloudflare_r2_data_catalog_docs-26fc909a","source":"documentation","title":"R2 Data Catalog · Cloudflare R2 Data Catalog docs","url":"https://developers.cloudflare.com/r2-data-catalog/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2-data-catalog/llms.txtUse this file to discover all available pages before exploring further.\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.102Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":49}}67{"id":"doc-unicode_interoperability_cloudflare_r2_docs-b6c50bda","source":"documentation","title":"Unicode interoperability · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/reference/unicode-interoperability/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.102Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":46}}68{"id":"doc-r2_sql_r2_sql_docs-57ef55a5","source":"documentation","title":"R2 SQL · R2 SQL docs","url":"https://developers.cloudflare.com/r2-sql/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2-sql/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\n❯ npx wrangler r2 sql query \"3373912de3f5202317188ae01300bd6_data-catalog\" \\\n\"SELECT * FROM default.transactions LIMIT 10\"\n\n ⛅️ wrangler 4.38.0\n────────────────────────────────────────────────────────────────────────────\n▲ [WARNING] 🚧 `wrangler r2 sql query` is an open-beta command. Please report any issues to https://github.com/cloudflare/workers-sdk/issues/new/choose\n\n\n┌─────────────────────────────┬──────────────────────────────────────┬─────────┬──────────┬──────────────────────────────────┬───────────────┬───────────────────┬──────────┐\n│ __ingest_ts │ transaction_id │ user_id │ amount │ transaction_timestamp │ location │ merchant_category │ is_fraud │\n├─────────────────────────────┼──────────────────────────────────────┼─────────┼──────────┼──────────────────────────────────┼───────────────┼───────────────────┼──────────┤\n│ 2025-09-20T22:30:11.872554Z │ fdc1beed-157c-4d2d-90cf-630fdea58051 │ 1679 │ 13241.59 │ 2025-09-20T02:23:04.269988+00:00 │ NEW_YORK │ RESTAURANT │ false │\n├─────────────────────────────┼──────────────────────────────────────┼─────────┼──────────┼──────────────────────────────────┼───────────────┼───────────────────┼──────────┤\n│ 2025-09-20T22:30:11.724378Z │ ea7ef106-8284-4d08-9348-ad33989b6381 │ 1279 │ 17615.79 │ 2025-09-20T02:23:04.271090+00:00 │ MIAMI │ GAS_STATION │ true │\n├─────────────────────────────┼──────────────────────────────────────┼─────────┼──────────┼──────────────────────────────────┼───────────────┼───────────────────┼──────────┤\n│ 2025-09-20T22:30:11.724330Z │ afcdee4d-5c71-42be-97ec-e282b6937a8c │ 1843 │ 7311.65 │ 2025-09-20T06:23:04.267890+00:00 │ SEATTLE │ GROCERY │ true │\n├─────────────────────────────┼──────────────────────────────────────┼─────────┼──────────┼──────────────────────────────────┼───────────────┼───────────────────┼──────────┤\n│ 2025-09-20T22:30:11.657007Z │ b99d14e0-dbe0-49bc-a417-0ee57f8bed99 │ 1976 │ 15228.21 │ 2025-09-16T23:23:04.269426+00:00 │ NEW_YORK │ RETAIL │ false │\n├─────────────────────────────┼──────────────────────────────────────┼─────────┼──────────┼──────────────────────────────────┼───────────────┼───────────────────┼──────────┤\n│ 2025-09-20T22:30:11.656992Z │ 712cd094-ad4c-4d24-819a-0d3daaaceea1 │ 1184 │ 7570.89 │ 2025-09-20T00:23:04.269163+00:00 │ LOS_ANGELES │ RESTAURANT │ true │\n├─────────────────────────────┼──────────────────────────────────────┼─────────┼──────────┼──────────────────────────────────┼───────────────┼───────────────────┼──────────┤\n│ 2025-09-20T22:30:11.656912Z │ b5a1aab3-676d-4492-92b8-aabcde6db261 │ 1196 │ 46611.25 │ 2025-09-20T16:23:04.268693+00:00 │ NEW_YORK │ RETAIL │ true │\n├─────────────────────────────┼──────────────────────────────────────┼─────────┼──────────┼──────────────────────────────────┼───────────────┼───────────────────┼──────────┤\n│ 2025-09-20T22:30:11.613740Z │ 432d3976-8d89-4813-9099-ea2afa2c0e70 │ 1720 │ 21547.9 │ 2025-09-20T05:23:04.273681+00:00 │ SAN FRANCISCO │ GROCERY │ true │\n├─────────────────────────────┼──────────────────────────────────────┼─────────┼──────────┼──────────────────────────────────┼───────────────┼───────────────────┼──────────┤\n│ 2025-09-20T22:30:11.532068Z │ 25e0b851-3092-4ade-842f-e3189e07d4ee │ 1562 │ 29311.54 │ 2025-09-20T05:23:04.277405+00:00 │ NEW_YORK │ RETAIL │ false │\n├─────────────────────────────┼──────────────────────────────────────┼─────────┼──────────┼──────────────────────────────────┼───────────────┼───────────────────┼──────────┤\n│ 2025-09-20T22:30:11.526037Z │ 8001746d-05fe-42fe-a189-40caf81d7aa2 │ 1817 │ 15976.5 │ 2025-09-15T16:23:04.266632+00:00 │ SEATTLE │ RESTAURANT │ true │\n└─────────────────────────────┴──────────────────────────────────────┴─────────┴──────────┴──────────────────────────────────┴───────────────┴───────────────────┴──────────┘\nRead 11.3 kB across 4 files from R2\nOn average, 3.36 kB / s\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.103Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":1,"totalLines":38,"estimatedTokens":1075}}69{"id":"doc-demos_and_architectures_cloudflare_r2_docs-915cdacd","source":"documentation","title":"Demos and architectures · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/demos/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.103Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":46}}70{"id":"doc-s3_sdks_cloudflare_r2_docs-a40716e5","source":"documentation","title":"S3 SDKs · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/examples/aws/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.110Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":46}}71{"id":"doc-https_developers_cloudflare_com_r2_examples_aws_-f6288acc","source":"documentation","title":"https://developers.cloudflare.com/r2/examples/aws/aws4fetch/index.md","url":"https://developers.cloudflare.com/r2/examples/aws/aws4fetch/index.md","text":"// // // :47.102Z // user-uploads // // // :49.218Z // my-bucket // // // // ... // ... // //\n\n// my-bucket // // cat.png // 751832 // :45.616Z // \"c4da329b38467509049e615c11b0c48a\" // STANDARD // // // todos.txt // 278 // :17.150Z // \"29d911f495d1ba7cb3a4d7d15e63236a\" // STANDARD // // false // 1000 // 2 //\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.111Z","totalSectionsIncluded":2,"totalCodeBlocksIncluded":0,"totalLines":5,"estimatedTokens":81}}72{"id":"doc-protect_an_r2_bucket_with_cloudflare_access_clou-8d6c2681","source":"documentation","title":"Protect an R2 Bucket with Cloudflare Access · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/tutorials/cloudflare-access/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.111Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":46}}73{"id":"doc-log_and_store_upload_events_in_r2_with_event_not-836b1035","source":"documentation","title":"Log and store upload events in R2 with event notifications · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/tutorials/upload-logs-event-notifications/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nnpx wrangler r2 bucket create example-upload-bucket\nnpx wrangler r2 bucket create example-log-sink-bucket\n```\n\nExample:\n```text\nnpx wrangler queues create example-event-notification-queue\n```\n\nExample:\n```text\nnpm create cloudflare@latest -- consumer-worker\n```\n\nExample:\n```text\nyarn create cloudflare consumer-worker\n```\n\nExample:\n```text\npnpm create cloudflare@latest consumer-worker\n```\n\nExample:\n```text\ncd consumer-worker\n```\n\nExample:\n```text\n{\n\t\"$schema\": \"./node_modules/wrangler/config-schema.json\",\n\t\"name\": \"event-notification-writer\",\n\t\"main\": \"src/index.ts\",\n\t// Set this to today's date\n\t\"compatibility_date\": \"2026-08-18\",\n\t\"compatibility_flags\": [\n\t\t\"nodejs_compat\"\n\t],\n\t\"queues\": {\n\t\t\"consumers\": [\n\t\t\t{\n\t\t\t\t\"queue\": \"example-event-notification-queue\",\n\t\t\t\t\"max_batch_size\": 100,\n\t\t\t\t\"max_batch_timeout\": 5\n\t\t\t}\n\t\t]\n\t},\n\t\"r2_buckets\": [\n\t\t{\n\t\t\t\"binding\": \"LOG_SINK\",\n\t\t\t\"bucket_name\": \"example-log-sink-bucket\"\n\t\t}\n\t]\n}\n```\n\nExample:\n```text\n\"$schema\" = \"./node_modules/wrangler/config-schema.json\"\nname = \"event-notification-writer\"\nmain = \"src/index.ts\"\n# Set this to today's date\ncompatibility_date = \"2026-08-18\"\ncompatibility_flags = [ \"nodejs_compat\" ]\n\n[[queues.consumers]]\nqueue = \"example-event-notification-queue\"\nmax_batch_size = 100\nmax_batch_timeout = 5\n\n[[r2_buckets]]\nbinding = \"LOG_SINK\"\nbucket_name = \"example-log-sink-bucket\"\n```\n\nExample:\n```text\nexport interface Env {\n\tLOG_SINK: R2Bucket;\n}\n\nexport default {\n\tasync queue(batch, env): Promise<void> {\n\t\tconst batchId = new Date().toISOString().replace(/[:.]/g, \"-\");\n\t\tconst fileName = `upload-logs-${batchId}.json`;\n\n\t\t// Serialize the entire batch of messages to JSON\n\t\tconst fileContent = new TextEncoder().encode(\n\t\t\tJSON.stringify(batch.messages),\n\t\t);\n\n\t\t// Write the batch of messages to R2\n\t\tawait env.LOG_SINK.put(fileName, fileContent, {\n\t\t\thttpMetadata: {\n\t\t\t\tcontentType: \"application/json\",\n\t\t\t},\n\t\t});\n\t},\n} satisfies ExportedHandler<Env>;\n```\n\nExample:\n```text\nnpx wrangler deploy\n```\n\nExample:\n```text\nnpx wrangler r2 bucket notification create example-upload-bucket --event-type object-create --queue example-event-notification-queue\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.112Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":11,"totalLines":118,"estimatedTokens":587}}74{"id":"doc-mastodon_cloudflare_r2_docs-f51c835c","source":"documentation","title":"Mastodon · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/tutorials/mastodon/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nS3_ENABLED=true\nS3_ALIAS_HOST={{mastodon-files.example.com}} # Change to the hostname determined in step 1\nS3_BUCKET={{your-bucket-name}} # Change to the bucket name set in step 2\nS3_ENDPOINT=https://{{unique-id}}.r2.cloudflarestorage.com/ # Change the {{unique-id}} to the part of S3 API retrieved in step 2\nAWS_ACCESS_KEY_ID={{your-access-key-id}} # Change to the Access Key ID retrieved in step 2\nAWS_SECRET_ACCESS_KEY={{your-secret-access-key}} # Change to the Secret Access Key retrieved in step 2\nS3_PROTOCOL=https\nS3_PERMISSION=\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.112Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":1,"totalLines":15,"estimatedTokens":207}}75{"id":"doc-postman_cloudflare_r2_docs-5bc82213","source":"documentation","title":"Postman · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/tutorials/postman/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.112Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":46}}76{"id":"doc-wrangler_commands_cloudflare_r2_docs-150a0f5c","source":"documentation","title":"Wrangler commands · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/reference/wrangler-commands/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nnpx wrangler r2 bucket create [NAME]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket create [NAME]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket create [NAME]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket info [BUCKET]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket info [BUCKET]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket info [BUCKET]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket delete [BUCKET]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket delete [BUCKET]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket delete [BUCKET]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket list\n```\n\nExample:\n```text\nyarn wrangler r2 bucket list\n```\n\nExample:\n```text\npnpm wrangler r2 bucket list\n```\n\nExample:\n```text\nnpx wrangler r2 bucket catalog enable [BUCKET]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket catalog enable [BUCKET]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket catalog enable [BUCKET]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket catalog disable [BUCKET]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket catalog disable [BUCKET]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket catalog disable [BUCKET]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket catalog get [BUCKET]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket catalog get [BUCKET]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket catalog get [BUCKET]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket catalog compaction enable [BUCKET] [NAMESPACE] [TABLE]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket catalog compaction enable [BUCKET] [NAMESPACE] [TABLE]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket catalog compaction enable [BUCKET] [NAMESPACE] [TABLE]\n```\n\nExample:\n```text\n# Enable catalog-level compaction (requires token)\nnpx wrangler r2 bucket catalog compaction enable my-bucket --token <TOKEN>\n\n# Enable table-level compaction\nnpx wrangler r2 bucket catalog compaction enable my-bucket my-namespace my-table --target-size 256\n```\n\nExample:\n```text\nnpx wrangler r2 bucket catalog compaction disable [BUCKET] [NAMESPACE] [TABLE]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket catalog compaction disable [BUCKET] [NAMESPACE] [TABLE]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket catalog compaction disable [BUCKET] [NAMESPACE] [TABLE]\n```\n\nExample:\n```text\n# Disable catalog-level compaction\nnpx wrangler r2 bucket catalog compaction disable my-bucket\n\n# Disable table-level compaction\nnpx wrangler r2 bucket catalog compaction disable my-bucket my-namespace my-table\n```\n\nExample:\n```text\nnpx wrangler r2 bucket catalog snapshot-expiration enable [BUCKET] [NAMESPACE] [TABLE]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket catalog snapshot-expiration enable [BUCKET] [NAMESPACE] [TABLE]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket catalog snapshot-expiration enable [BUCKET] [NAMESPACE] [TABLE]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket catalog snapshot-expiration disable [BUCKET] [NAMESPACE] [TABLE]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket catalog snapshot-expiration disable [BUCKET] [NAMESPACE] [TABLE]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket catalog snapshot-expiration disable [BUCKET] [NAMESPACE] [TABLE]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket cors set [BUCKET]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket cors set [BUCKET]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket cors set [BUCKET]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket cors delete [BUCKET]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket cors delete [BUCKET]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket cors delete [BUCKET]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket cors list [BUCKET]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket cors list [BUCKET]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket cors list [BUCKET]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket dev-url enable [BUCKET]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket dev-url enable [BUCKET]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket dev-url enable [BUCKET]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket dev-url disable [BUCKET]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket dev-url disable [BUCKET]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket dev-url disable [BUCKET]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket dev-url get [BUCKET]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket dev-url get [BUCKET]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket dev-url get [BUCKET]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket domain add [BUCKET]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket domain add [BUCKET]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket domain add [BUCKET]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket domain remove [BUCKET]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket domain remove [BUCKET]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket domain remove [BUCKET]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket domain update [BUCKET]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket domain update [BUCKET]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket domain update [BUCKET]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket domain get [BUCKET]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket domain get [BUCKET]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket domain get [BUCKET]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket domain list [BUCKET]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket domain list [BUCKET]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket domain list [BUCKET]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket lifecycle add [BUCKET] [NAME] [PREFIX]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket lifecycle add [BUCKET] [NAME] [PREFIX]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket lifecycle add [BUCKET] [NAME] [PREFIX]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket lifecycle remove [BUCKET]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket lifecycle remove [BUCKET]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket lifecycle remove [BUCKET]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket lifecycle list [BUCKET]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket lifecycle list [BUCKET]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket lifecycle list [BUCKET]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket lifecycle set [BUCKET]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket lifecycle set [BUCKET]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket lifecycle set [BUCKET]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket lock add [BUCKET] [NAME] [PREFIX]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket lock add [BUCKET] [NAME] [PREFIX]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket lock add [BUCKET] [NAME] [PREFIX]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket lock remove [BUCKET]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket lock remove [BUCKET]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket lock remove [BUCKET]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket lock list [BUCKET]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket lock list [BUCKET]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket lock list [BUCKET]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket lock set [BUCKET]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket lock set [BUCKET]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket lock set [BUCKET]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket notification create [BUCKET]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket notification create [BUCKET]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket notification create [BUCKET]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket notification delete [BUCKET]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket notification delete [BUCKET]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket notification delete [BUCKET]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket notification list [BUCKET]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket notification list [BUCKET]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket notification list [BUCKET]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket sippy enable [NAME]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket sippy enable [NAME]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket sippy enable [NAME]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket sippy disable [NAME]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket sippy disable [NAME]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket sippy disable [NAME]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket sippy get [NAME]\n```\n\nExample:\n```text\nyarn wrangler r2 bucket sippy get [NAME]\n```\n\nExample:\n```text\npnpm wrangler r2 bucket sippy get [NAME]\n```\n\nExample:\n```text\nnpx wrangler r2 object get [OBJECTPATH]\n```\n\nExample:\n```text\nyarn wrangler r2 object get [OBJECTPATH]\n```\n\nExample:\n```text\npnpm wrangler r2 object get [OBJECTPATH]\n```\n\nExample:\n```text\nnpx wrangler r2 object put [OBJECTPATH]\n```\n\nExample:\n```text\nyarn wrangler r2 object put [OBJECTPATH]\n```\n\nExample:\n```text\npnpm wrangler r2 object put [OBJECTPATH]\n```\n\nExample:\n```text\nnpx wrangler r2 object delete [OBJECTPATH]\n```\n\nExample:\n```text\nyarn wrangler r2 object delete [OBJECTPATH]\n```\n\nExample:\n```text\npnpm wrangler r2 object delete [OBJECTPATH]\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.115Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":119,"totalLines":606,"estimatedTokens":2256}}77{"id":"doc-use_event_notification_to_summarize_pdf_files_on-f687853c","source":"documentation","title":"Use event notification to summarize PDF files on upload · Cloudflare R2 docs","url":"https://developers.cloudflare.com/r2/tutorials/summarize-pdf/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nnpm create cloudflare@latest -- pdf-summarizer\n```\n\nExample:\n```text\nyarn create cloudflare pdf-summarizer\n```\n\nExample:\n```text\npnpm create cloudflare@latest pdf-summarizer\n```\n\nExample:\n```text\ncd pdf-summarizer\n```\n\nExample:\n```text\n{\n\t\"assets\": {\n\t\t\"directory\": \"public\"\n\t}\n}\n```\n\nExample:\n```text\n[assets]\ndirectory = \"public\"\n```\n\nExample:\n```text\n<!doctype html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"UTF-8\" />\n\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n\t\t<title>PDF Summarizer</title>\n\t\t<style>\n\t\t\tbody {\n\t\t\t\tfont-family: Arial, sans-serif;\n\t\t\t\tdisplay: flex;\n\t\t\t\tflex-direction: column;\n\t\t\t\tmin-height: 100vh;\n\t\t\t\tmargin: 0;\n\t\t\t\tbackground-color: #fefefe;\n\t\t\t}\n\t\t\t.content {\n\t\t\t\tflex: 1;\n\t\t\t\tdisplay: flex;\n\t\t\t\tjustify-content: center;\n\t\t\t\talign-items: center;\n\t\t\t}\n\t\t\t.upload-container {\n\t\t\t\tbackground-color: #f0f0f0;\n\t\t\t\tpadding: 20px;\n\t\t\t\tborder-radius: 8px;\n\t\t\t\tbox-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n\t\t\t}\n\t\t\t.upload-button {\n\t\t\t\tbackground-color: #4caf50;\n\t\t\t\tcolor: white;\n\t\t\t\tpadding: 10px 15px;\n\t\t\t\tborder: none;\n\t\t\t\tborder-radius: 4px;\n\t\t\t\tcursor: pointer;\n\t\t\t\tfont-size: 16px;\n\t\t\t}\n\t\t\t.upload-button:hover {\n\t\t\t\tbackground-color: #45a049;\n\t\t\t}\n\t\t\tfooter {\n\t\t\t\tbackground-color: #f0f0f0;\n\t\t\t\tcolor: white;\n\t\t\t\ttext-align: center;\n\t\t\t\tpadding: 10px;\n\t\t\t\twidth: 100%;\n\t\t\t}\n\t\t\tfooter a {\n\t\t\t\tcolor: #333;\n\t\t\t\ttext-decoration: none;\n\t\t\t\tmargin: 0 10px;\n\t\t\t}\n\t\t\tfooter a:hover {\n\t\t\t\ttext-decoration: underline;\n\t\t\t}\n\t\t</style>\n\t</head>\n\t<body>\n\t\t<div class=\"content\">\n\t\t\t<div class=\"upload-container\">\n\t\t\t\t<h2>Upload PDF File</h2>\n\t\t\t\t<form id=\"uploadForm\" onsubmit=\"return handleSubmit(event)\">\n\t\t\t\t\t<input\n\t\t\t\t\t\ttype=\"file\"\n\t\t\t\t\t\tid=\"pdfFile\"\n\t\t\t\t\t\tname=\"pdfFile\"\n\t\t\t\t\t\taccept=\".pdf\"\n\t\t\t\t\t\trequired\n\t\t\t\t\t/>\n\t\t\t\t\t<button type=\"submit\" id=\"uploadButton\" class=\"upload-button\">\n\t\t\t\t\t\tUpload\n\t\t\t\t\t</button>\n\t\t\t\t</form>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<footer>\n\t\t\t<a\n\t\t\t\thref=\"https://developers.cloudflare.com/r2/buckets/event-notifications/\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\t>R2 Event Notification</a\n\t\t\t>\n\t\t\t<a\n\t\t\t\thref=\"https://developers.cloudflare.com/queues/get-started/#3-create-a-queue\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\t>Cloudflare Queues</a\n\t\t\t>\n\t\t\t<a href=\"https://developers.cloudflare.com/workers-ai/\" target=\"_blank\"\n\t\t\t\t>Workers AI</a\n\t\t\t>\n\t\t\t<a\n\t\t\t\thref=\"https://github.com/harshil1712/pdf-summarizer-r2-event-notification\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\t>GitHub Repo</a\n\t\t\t>\n\t\t</footer>\n\n\t\t<script>\n\t\t\thandleSubmit = async (event) => {\n\t\t\t\tevent.preventDefault();\n\n\t\t\t\t// Disable the upload button and show a loading message\n\t\t\t\tconst uploadButton = document.getElementById(\"uploadButton\");\n\t\t\t\tuploadButton.disabled = true;\n\t\t\t\tuploadButton.textContent = \"Uploading...\";\n\n\t\t\t\t// get form data\n\t\t\t\tconst formData = new FormData(event.target);\n\t\t\t\tconst file = formData.get(\"pdfFile\");\n\n\t\t\t\tif (file) {\n\t\t\t\t\t// call /api/upload endpoint and send the file\n\t\t\t\t\tawait fetch(\"/api/upload\", {\n\t\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\t\tbody: formData,\n\t\t\t\t\t});\n\n\t\t\t\t\tevent.target.reset();\n\t\t\t\t} else {\n\t\t\t\t\tconsole.log(\"No file selected\");\n\t\t\t\t}\n\t\t\t\tuploadButton.disabled = false;\n\t\t\t\tuploadButton.textContent = \"Upload\";\n\t\t\t};\n\t\t</script>\n\t</body>\n</html>\n```\n\nExample:\n```text\nnpm run dev\n```\n\nExample:\n```text\n⛅️ wrangler 3.80.2\n-------------------\n\n⎔ Starting local server...\n[wrangler:inf] Ready on http://localhost:8787\n╭───────────────────────────╮\n│ [b] open a browser │\n│ [d] open devtools │\n│ [l] turn off local mode │\n│ [c] clear console │\n│ [x] to exit │\n╰───────────────────────────╯\n```\n\nExample:\n```text\n{\n\t\"r2_buckets\": [\n\t\t{\n\t\t\t\"binding\": \"MY_BUCKET\",\n\t\t\t\"bucket_name\": \"<R2_BUCKET_NAME>\"\n\t\t}\n\t]\n}\n```\n\nExample:\n```text\n[[r2_buckets]]\nbinding = \"MY_BUCKET\"\nbucket_name = \"<R2_BUCKET_NAME>\"\n```\n\nExample:\n```text\nexport default {\n\tasync fetch(request, env, ctx): Promise<Response> {\n\t\t// Get the pathname from the request\n\t\tconst pathname = new URL(request.url).pathname;\n\n\t\tif (pathname === \"/api/upload\" && request.method === \"POST\") {\n\t\t\t// Get the file from the request\n\t\t\tconst formData = await request.formData();\n\t\t\tconst file = formData.get(\"pdfFile\") as File;\n\n\t\t\t// Upload the file to Cloudflare R2\n\t\t\tconst upload = await env.MY_BUCKET.put(file.name, file);\n\t\t\treturn new Response(\"File uploaded successfully\", { status: 200 });\n\t\t}\n\n\t\treturn new Response(\"incorrect route\", { status: 404 });\n\t},\n} satisfies ExportedHandler<Env>;\n```\n\nExample:\n```text\nnpm run cf-typegen\n```\n\nExample:\n```text\nnpx wrangler queues create pdf-summarizer\n```\n\nExample:\n```text\n{\n\t\"queues\": {\n\t\t\"consumers\": [\n\t\t\t{\n\t\t\t\t\"queue\": \"pdf-summarizer\"\n\t\t\t}\n\t\t]\n\t}\n}\n```\n\nExample:\n```text\n[[queues.consumers]]\nqueue = \"pdf-summarizer\"\n```\n\nExample:\n```text\nexport default {\n\tasync fetch(request, env, ctx): Promise<Response> {\n\t\t// No changes in the fetch handler\n\t},\n\tasync queue(batch, env) {\n\t\tfor (let message of batch.messages) {\n\t\t\tconsole.log(`Processing the file: ${message.body.object.key}`);\n\t\t}\n\t},\n} satisfies ExportedHandler<Env>;\n```\n\nExample:\n```text\nnpm i unpdf\n```\n\nExample:\n```text\nyarn add unpdf\n```\n\nExample:\n```text\npnpm add unpdf\n```\n\nExample:\n```text\nbun add unpdf\n```\n\nExample:\n```text\nimport { extractText, getDocumentProxy } from \"unpdf\";\n```\n\nExample:\n```text\nasync queue(batch, env) {\n for(let message of batch.messages) {\n console.log(`Processing file: ${message.body.object.key}`);\n // Get the file from the R2 bucket\n const file = await env.MY_BUCKET.get(message.body.object.key);\n if (!file) {\n\t\t\t\tconsole.error(`File not found: ${message.body.object.key}`);\n\t\t\t\tcontinue;\n\t\t\t}\n // Extract the textual content from the PDF\n const buffer = await file.arrayBuffer();\n const document = await getDocumentProxy(new Uint8Array(buffer));\n\n const {text} = await extractText(document, {mergePages: true});\n console.log(`Extracted text: ${text.substring(0, 100)}...`);\n }\n}\n```\n\nExample:\n```text\n{\n\t\"ai\": {\n\t\t\"binding\": \"AI\"\n\t}\n}\n```\n\nExample:\n```text\n[ai]\nbinding = \"AI\"\n```\n\nExample:\n```text\nasync queue(batch, env) {\n for(let message of batch.messages) {\n // Extract the textual content from the PDF\n const {text} = await extractText(document, {mergePages: true});\n console.log(`Extracted text: ${text.substring(0, 100)}...`);\n\n // Use Workers AI to summarize the content\n const result: AiSummarizationOutput = await env.AI.run(\n \"@cf/facebook/bart-large-cnn\",\n {\n input_text: text,\n }\n );\n const summary = result.summary;\n console.log(`Summary: ${summary.substring(0, 100)}...`);\n }\n}\n```\n\nExample:\n```text\nasync queue(batch, env) {\n for(let message of batch.messages) {\n // Extract the textual content from the PDF\n // ...\n // Use Workers AI to summarize the content\n // ...\n\n // Add the summary to the R2 bucket\n const upload = await env.MY_BUCKET.put(`${message.body.object.key}-summary.txt`, summary, {\n\t\t\t\t\thttpMetadata: {\n\t\t\t\t\t\tcontentType: 'text/plain',\n\t\t\t\t\t},\n\t\t});\n\t\tconsole.log(`Summary added to the R2 bucket: ${upload.key}`);\n }\n}\n```\n\nExample:\n```text\nnpx wrangler r2 bucket notification create <R2_BUCKET_NAME> --event-type object-create --queue pdf-summarizer --suffix \"pdf\"\n```\n\nExample:\n```text\nnpx wrangler deploy\n```\n\nExample:\n```text\nnpx wrangler tail\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.116Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":30,"totalLines":390,"estimatedTokens":1863}}78{"id":"doc-manage_catalogs_cloudflare_r2_data_catalog_docs-5ac87dfd","source":"documentation","title":"Manage catalogs · Cloudflare R2 Data Catalog docs","url":"https://developers.cloudflare.com/r2-data-catalog/manage-catalogs/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2-data-catalog/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nnpx wrangler r2 bucket catalog enable <BUCKET_NAME>\n```\n\nExample:\n```text\nnpx wrangler r2 bucket catalog disable <BUCKET_NAME>\n```\n\nExample:\n```text\n# Enable catalog-level compaction (all tables)\nnpx wrangler r2 bucket catalog compaction enable <BUCKET_NAME> --target-size 128 --token <API_TOKEN>\n\n# Enable compaction for a specific table\nnpx wrangler r2 bucket catalog compaction enable <BUCKET_NAME> <NAMESPACE> <TABLE> --target-size 128\n```\n\nExample:\n```text\n# Disable catalog-level compaction (all tables)\nnpx wrangler r2 bucket catalog compaction disable <BUCKET_NAME>\n\n# Disable compaction for a specific table\nnpx wrangler r2 bucket catalog compaction disable <BUCKET_NAME> <NAMESPACE> <TABLE>\n```\n\nExample:\n```text\n# Enable catalog-level snapshot expiration (all tables)\nnpx wrangler r2 bucket catalog snapshot-expiration enable <BUCKET_NAME> \\\n --token <API_TOKEN> \\\n --older-than-days 7 \\\n --retain-last 10\n\n# Enable snapshot expiration for a specific table\nnpx wrangler r2 bucket catalog snapshot-expiration enable <BUCKET_NAME> <NAMESPACE> <TABLE> \\\n --older-than-days 2 \\\n --retain-last 5\n```\n\nExample:\n```text\n# Disable catalog-level snapshot expiration (all tables)\nnpx wrangler r2 bucket catalog snapshot-expiration disable <BUCKET_NAME>\n\n# Disable snapshot expiration for a specific table\nnpx wrangler r2 bucket catalog snapshot-expiration disable <BUCKET_NAME> <NAMESPACE> <TABLE>\n```\n\nExample:\n```text\n[\n\t{\n\t\t\"id\": \"f267e341f3dd4697bd3b9f71dd96247f\",\n\t\t\"effect\": \"allow\",\n\t\t\"resources\": {\n\t\t\t\"com.cloudflare.edge.r2.bucket.4793d734c0b8e484dfc37ec392b5fa8a_default_my-bucket\": \"*\",\n\t\t\t\"com.cloudflare.edge.r2.bucket.4793d734c0b8e484dfc37ec392b5fa8a_eu_my-eu-bucket\": \"*\"\n\t\t},\n\t\t\"permission_groups\": [\n\t\t\t{\n\t\t\t\t\"id\": \"d229766a2f7f4d299f20eaa8c9b1fde9\",\n\t\t\t\t\"name\": \"Workers R2 Data Catalog Write\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"2efd5506f9c8494dacb1fa10a3e7d5b6\",\n\t\t\t\t\"name\": \"Workers R2 Storage Bucket Item Write\"\n\t\t\t}\n\t\t]\n\t}\n]\n```\n\nExample:\n```text\n[\n\t{\n\t\t\"id\": \"f267e341f3dd4697bd3b9f71dd96247f\",\n\t\t\"effect\": \"allow\",\n\t\t\"resources\": {\n\t\t\t\"com.cloudflare.edge.r2.bucket.4793d734c0b8e484dfc37ec392b5fa8a_default_my-bucket\": \"*\",\n\t\t\t\"com.cloudflare.edge.r2.bucket.4793d734c0b8e484dfc37ec392b5fa8a_eu_my-eu-bucket\": \"*\"\n\t\t},\n\t\t\"permission_groups\": [\n\t\t\t{\n\t\t\t\t\"id\": \"45db74139a62490b9b60eb7c4f34994b\",\n\t\t\t\t\"name\": \"Workers R2 Data Catalog Read\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"6a018a9f2fc74eb6b293b0c548f38b39\",\n\t\t\t\t\"name\": \"Workers R2 Storage Bucket Item Read\"\n\t\t\t}\n\t\t]\n\t}\n]\n```\n\nExample:\n```text\nnpx wrangler r2 bucket catalog local-uploads enable <R2_Data_Catalog_BUCKET_NAME>\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.117Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":9,"totalLines":107,"estimatedTokens":700}}79{"id":"doc-starrocks_cloudflare_r2_data_catalog_docs-385fa21d","source":"documentation","title":"StarRocks · Cloudflare R2 Data Catalog docs","url":"https://developers.cloudflare.com/r2-data-catalog/config-examples/starrocks/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2-data-catalog/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\n-- Create an Iceberg catalog named `r2` and set it as the current catalog\n\nCREATE EXTERNAL CATALOG r2\nPROPERTIES\n(\n \"type\" = \"iceberg\",\n \"iceberg.catalog.type\" = \"rest\",\n \"iceberg.catalog.uri\" = \"<r2_catalog_uri>\",\n \"iceberg.catalog.security\" = \"oauth2\",\n \"iceberg.catalog.oauth2.token\" = \"<r2_api_token>\",\n \"iceberg.catalog.warehouse\" = \"<r2_warehouse_name>\"\n);\n\nSET CATALOG r2;\n\n-- Create a database and display all databases in newly connected catalog\n\nCREATE DATABASE testdb;\n\nSHOW DATABASES FROM r2;\n\n+--------------------+\n| Database |\n+--------------------+\n| information_schema |\n| testdb |\n+--------------------+\n2 rows in set (0.66 sec)\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.117Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":1,"totalLines":35,"estimatedTokens":227}}80{"id":"doc-duckdb_cloudflare_r2_data_catalog_docs-dcf587e4","source":"documentation","title":"DuckDB · Cloudflare R2 Data Catalog docs","url":"https://developers.cloudflare.com/r2-data-catalog/config-examples/duckdb/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2-data-catalog/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\n-- Install the iceberg DuckDB extension (if you haven't already) and load the extension.\nINSTALL iceberg;\nLOAD iceberg;\n\n-- Install and load httpfs extension for reading/writing files over HTTP(S).\nINSTALL httpfs;\nLOAD httpfs;\n\n-- Create a DuckDB secret to store R2 Data Catalog credentials.\nCREATE SECRET r2_secret (\n TYPE ICEBERG,\n TOKEN '<token>'\n);\n\n-- Attach R2 Data Catalog with the following ATTACH statement.\nATTACH '<warehouse_name>' AS my_r2_catalog (\n TYPE ICEBERG,\n ENDPOINT '<catalog_uri>'\n);\n\n-- Create the default schema in the catalog and set it as the active schema.\nCREATE SCHEMA my_r2_catalog.default;\nUSE my_r2_catalog.default;\n\n-- Create and populate a sample Iceberg table with data.\nCREATE TABLE my_iceberg_table AS SELECT a FROM range(4) t(a);\n\n-- Show all available tables.\nSHOW ALL TABLES;\n\n-- Query the Iceberg table you just created.\nSELECT * FROM my_r2_catalog.default.my_iceberg_table;\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.117Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":1,"totalLines":39,"estimatedTokens":287}}81{"id":"doc-getting_started_cloudflare_r2_data_catalog_docs-8e0014bb","source":"documentation","title":"Getting started · Cloudflare R2 Data Catalog docs","url":"https://developers.cloudflare.com/r2-data-catalog/get-started/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2-data-catalog/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nnpx wrangler login\n```\n\nExample:\n```text\nnpx wrangler r2 bucket create r2-data-catalog-tutorial\n```\n\nExample:\n```text\nnpx wrangler r2 bucket catalog enable r2-data-catalog-tutorial\n```\n\nExample:\n```text\nmkdir r2-data-catalog-notebook\n```\n\nExample:\n```text\ncd r2-data-catalog-notebook\n```\n\nExample:\n```text\nuv init\n```\n\nExample:\n```text\nuv add marimo pyiceberg pyarrow pandas\n```\n\nExample:\n```text\nimport marimo\n\n__generated_with = \"0.11.31\"\napp = marimo.App(width=\"medium\")\n\n\n@app.cell\ndef _():\n\t\timport marimo as mo\n\t\treturn (mo,)\n\n\n@app.cell\ndef _():\n\t\timport pandas\n\t\timport pyarrow as pa\n\t\timport pyarrow.compute as pc\n\t\timport pyarrow.parquet as pq\n\n\t\tfrom pyiceberg.catalog.rest import RestCatalog\n\n\t\t# Define catalog connection details (replace variables)\n\t\tWAREHOUSE = \"<WAREHOUSE>\"\n\t\tTOKEN = \"<TOKEN>\"\n\t\tCATALOG_URI = \"<CATALOG_URI>\"\n\n\t\t# Connect to R2 Data Catalog\n\t\tcatalog = RestCatalog(\n\t\t\t\tname=\"my_catalog\",\n\t\t\t\twarehouse=WAREHOUSE,\n\t\t\t\turi=CATALOG_URI,\n\t\t\t\ttoken=TOKEN,\n\t\t)\n\t\treturn (\n\t\t\t\tCATALOG_URI,\n\t\t\t\tRestCatalog,\n\t\t\t\tTOKEN,\n\t\t\t\tWAREHOUSE,\n\t\t\t\tcatalog,\n\t\t\t\tpa,\n\t\t\t\tpandas,\n\t\t\t\tpc,\n\t\t\t\tpq,\n\t\t)\n\n\n@app.cell\ndef _(catalog):\n\t\t# Create default namespace if needed\n\t\tcatalog.create_namespace_if_not_exists(\"default\")\n\t\treturn\n\n\n@app.cell\ndef _(pa):\n\t\t# Create simple PyArrow table\n\t\tdf = pa.table({\n\t\t\t\t\"id\": [1, 2, 3],\n\t\t\t\t\"name\": [\"Alice\", \"Bob\", \"Charlie\"],\n\t\t\t\t\"score\": [80.0, 92.5, 88.0],\n\t\t})\n\t\treturn (df,)\n\n\n@app.cell\ndef _(catalog, df):\n\t\t# Create or load Iceberg table\n\t\ttest_table = (\"default\", \"people\")\n\t\tif not catalog.table_exists(test_table):\n\t\t\t\tprint(f\"Creating table: {test_table}\")\n\t\t\t\ttable = catalog.create_table(\n\t\t\t\t\t\ttest_table,\n\t\t\t\t\t\tschema=df.schema,\n\t\t\t\t)\n\t\telse:\n\t\t\t\ttable = catalog.load_table(test_table)\n\t\treturn table, test_table\n\n\n@app.cell\ndef _(df, table):\n\t\t# Append data\n\t\ttable.append(df)\n\t\treturn\n\n\n@app.cell\ndef _(table):\n\t\tprint(\"Table contents:\")\n\t\tscanned = table.scan().to_arrow()\n\t\tprint(scanned.to_pandas())\n\t\treturn (scanned,)\n\n\n@app.cell\ndef _():\n\t\t# Optional cleanup. To run uncomment and run cell\n\t\t# print(f\"Deleting table: {test_table}\")\n\t\t# catalog.drop_table(test_table)\n\t\t# print(\"Table dropped.\")\n\t\treturn\n\n\nif __name__ == \"__main__\":\n\t\tapp.run()\n```\n\nExample:\n```text\nuv run marimo edit r2-data-catalog-tutorial.py\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.117Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":9,"totalLines":152,"estimatedTokens":627}}82{"id":"doc-connect_to_iceberg_engines_cloudflare_r2_data_ca-b9eeeed2","source":"documentation","title":"Connect to Iceberg engines · Cloudflare R2 Data Catalog docs","url":"https://developers.cloudflare.com/r2-data-catalog/config-examples/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2-data-catalog/llms.txtUse this file to discover all available pages before exploring further.\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.117Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":49}}83{"id":"doc-table_maintenance_cloudflare_r2_data_catalog_doc-80cf709a","source":"documentation","title":"Table maintenance · Cloudflare R2 Data Catalog docs","url":"https://developers.cloudflare.com/r2-data-catalog/table-maintenance/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2-data-catalog/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\n# Enable catalog-level compaction (all tables)\nnpx wrangler r2 bucket catalog compaction enable my-bucket \\\n --target-size 128 \\\n --token $R2_CATALOG_TOKEN\n\n# Enable compaction for a specific table\nnpx wrangler r2 bucket catalog compaction enable my-bucket my-namespace my-table \\\n --target-size 256\n\n# Disable catalog-level compaction\nnpx wrangler r2 bucket catalog compaction disable my-bucket\n\n# Disable compaction for a specific table\nnpx wrangler r2 bucket catalog compaction disable my-bucket my-namespace my-table\n```\n\nExample:\n```text\n# Enable snapshot expiration for entire catalog\n# Keep minimum 10 snapshots, expire those older than 7 days\nnpx wrangler r2 bucket catalog snapshot-expiration enable my-bucket \\\n --token $R2_CATALOG_TOKEN \\\n --older-than-days 7 \\\n --retain-last 10\n\n# Enable for specific table\n# Keep minimum 5 snapshots, expire those older than 2 days\nnpx wrangler r2 bucket catalog snapshot-expiration enable my-bucket my-namespace my-table \\\n --token $R2_CATALOG_TOKEN \\\n --older-than-days 2 \\\n --retain-last 5\n\n# Disable snapshot expiration for a catalog\nnpx wrangler r2 bucket catalog snapshot-expiration disable my-bucket\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.118Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":2,"totalLines":41,"estimatedTokens":346}}84{"id":"doc-trino_cloudflare_r2_data_catalog_docs-c6353477","source":"documentation","title":"Trino · Cloudflare R2 Data Catalog docs","url":"https://developers.cloudflare.com/r2-data-catalog/config-examples/trino/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2-data-catalog/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nmkdir -p trino-catalog && cd trino-catalog/\n```\n\nExample:\n```text\n# r2.properties\nconnector.name=iceberg\n\n# R2 Configuration\nfs.native-s3.enabled=true\ns3.region=auto\ns3.aws-access-key=<Your R2 access key>\ns3.aws-secret-key=<Your R2 secret>\ns3.endpoint=<Your R2 endpoint>\ns3.path-style-access=true\n\n# R2 Data Catalog Configuration\niceberg.catalog.type=rest\niceberg.rest-catalog.uri=<Your R2 Data Catalog URI>\niceberg.rest-catalog.warehouse=<Your R2 Data Catalog warehouse>\niceberg.rest-catalog.security=OAUTH2\niceberg.rest-catalog.oauth2.token=<Your R2 authentication token>\n```\n\nExample:\n```text\n# Create a local directory for the catalog configuration\nmkdir -p trino-catalog\n\n# Place your r2.properties file in the catalog directory\ncp r2.properties trino-catalog/\n\n# Run Trino with the catalog configuration\ndocker run -d \\\n --name trino-r2 \\\n -p 8080:8080 \\\n -v $(pwd)/trino-catalog:/etc/trino/catalog \\\n trinodb/trino:latest\n```\n\nExample:\n```text\n# Connect to the Trino CLI\ndocker exec -it trino-r2 trino\n```\n\nExample:\n```text\n-- Show all schemas in the R2 catalog\nSHOW SCHEMAS IN r2;\n\n-- Show all schemas in the R2 catalog\nCREATE SCHEMA r2.example_schema\n\n-- Create a table with some values in it\nCREATE TABLE r2.example_schema.yearly_clicks (\n year,\n clicks\n)\nWITH (\n partitioning = ARRAY['year']\n)\nAS VALUES\n (2021, 10000),\n (2022, 20000);\n\n-- Show tables in a specific schema\nSHOW TABLES IN r2.example_schema;\n\n-- Query your Iceberg table\nSELECT * FROM r2.example_schema.yearly_clicks;\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.118Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":5,"totalLines":78,"estimatedTokens":433}}85{"id":"doc-query_data_r2_sql_docs-5a4742a4","source":"documentation","title":"Query data · R2 SQL docs","url":"https://developers.cloudflare.com/r2-sql/query-data/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2-sql/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nnpx wrangler r2 bucket catalog get <BUCKET_NAME>\n```\n\nExample:\n```text\nexport WRANGLER_R2_SQL_AUTH_TOKEN=YOUR_API_TOKEN\n```\n\nExample:\n```text\nWRANGLER_R2_SQL_AUTH_TOKEN=YOUR_API_TOKEN\n```\n\nExample:\n```text\nnpx wrangler r2 sql query <WAREHOUSE> \"SELECT * FROM namespace.table_name limit 10;\"\n```\n\nExample:\n```text\ncurl -X POST \\\n \"https://api.sql.cloudflarestorage.com/api/v1/accounts/{ACCOUNT_ID}/r2-sql/query/{BUCKET_NAME}\" \\\n -H \"Authorization: Bearer ${WRANGLER_R2_SQL_AUTH_TOKEN}\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"query\": \"SELECT * FROM namespace.table_name limit 10;\"\n }'\n```\n\nExample:\n```text\n[\n\t{\n\t\t\"id\": \"f267e341f3dd4697bd3b9f71dd96247f\",\n\t\t\"effect\": \"allow\",\n\t\t\"resources\": {\n\t\t\t\"com.cloudflare.edge.r2.bucket.4793d734c0b8e484dfc37ec392b5fa8a_default_my-bucket\": \"*\",\n\t\t\t\"com.cloudflare.edge.r2.bucket.4793d734c0b8e484dfc37ec392b5fa8a_eu_my-eu-bucket\": \"*\"\n\t\t},\n\t\t\"permission_groups\": [\n\t\t\t{\n\t\t\t\t\"id\": \"f45430d92e2b4a6cb9f94f2594c141b8\",\n\t\t\t\t\"name\": \"Workers R2 SQL Read\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"d229766a2f7f4d299f20eaa8c9b1fde9\",\n\t\t\t\t\"name\": \"Workers R2 Data Catalog Write\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"bf7481a1826f439697cb59a20b22293e\",\n\t\t\t\t\"name\": \"Workers R2 Storage Write\"\n\t\t\t}\n\t\t]\n\t}\n]\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.118Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":6,"totalLines":62,"estimatedTokens":357}}86{"id":"doc-snowflake_cloudflare_r2_data_catalog_docs-56c5d0e7","source":"documentation","title":"Snowflake · Cloudflare R2 Data Catalog docs","url":"https://developers.cloudflare.com/r2-data-catalog/config-examples/snowflake/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2-data-catalog/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\n-- Create a database (if you don't already have one) to organize your external data\nCREATE DATABASE IF NOT EXISTS r2_example_db;\n\n-- Create an external volume pointing to your R2 bucket\nCREATE OR REPLACE EXTERNAL VOLUME ext_vol_r2\n STORAGE_LOCATIONS = (\n (\n NAME = 'my_r2_storage_location'\n STORAGE_PROVIDER = 'S3COMPAT'\n STORAGE_BASE_URL = 's3compat://<bucket-name>'\n CREDENTIALS = (\n AWS_KEY_ID = '<access_key>'\n AWS_SECRET_KEY = '<secret_access_key>'\n )\n STORAGE_ENDPOINT = '<account_id>.r2.cloudflarestorage.com'\n )\n )\n ALLOW_WRITES = FALSE;\n\n-- Create a catalog integration for R2 Data Catalog (read-only)\nCREATE OR REPLACE CATALOG INTEGRATION r2_data_catalog\n CATALOG_SOURCE = ICEBERG_REST\n TABLE_FORMAT = ICEBERG\n CATALOG_NAMESPACE = 'default'\n REST_CONFIG = (\n CATALOG_URI = '<catalog_uri>'\n CATALOG_NAME = '<warehouse_name>'\n )\n REST_AUTHENTICATION = (\n TYPE = BEARER\n BEARER_TOKEN = '<token>'\n )\n ENABLED = TRUE;\n\n-- Create an Apache Iceberg table in your selected Snowflake database\nCREATE ICEBERG TABLE my_iceberg_table\n CATALOG = 'r2_data_catalog'\n EXTERNAL_VOLUME = 'ext_vol_r2'\n CATALOG_TABLE_NAME = 'my_table'; -- Name of existing table in your R2 data catalog\n\n-- Query your Iceberg table\nSELECT * FROM my_iceberg_table;\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.118Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":1,"totalLines":49,"estimatedTokens":410}}87{"id":"doc-spark_pyspark_cloudflare_r2_data_catalog_docs-c6037cdc","source":"documentation","title":"Spark (PySpark) · Cloudflare R2 Data Catalog docs","url":"https://developers.cloudflare.com/r2-data-catalog/config-examples/spark-python/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2-data-catalog/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nfrom pyspark.sql import SparkSession\n\n# Define catalog connection details (replace variables)\nWAREHOUSE = \"<WAREHOUSE>\"\nTOKEN = \"<TOKEN>\"\nCATALOG_URI = \"<CATALOG_URI>\"\n\n# Build Spark session with Iceberg configurations\nspark = SparkSession.builder \\\n .appName(\"R2DataCatalogExample\") \\\n .config('spark.jars.packages', 'org.apache.iceberg:iceberg-spark-runtime-3.5_2.12:1.6.1,org.apache.iceberg:iceberg-aws-bundle:1.6.1') \\\n .config(\"spark.sql.extensions\", \"org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions\") \\\n .config(\"spark.sql.catalog.my_catalog\", \"org.apache.iceberg.spark.SparkCatalog\") \\\n .config(\"spark.sql.catalog.my_catalog.type\", \"rest\") \\\n .config(\"spark.sql.catalog.my_catalog.uri\", CATALOG_URI) \\\n .config(\"spark.sql.catalog.my_catalog.warehouse\", WAREHOUSE) \\\n .config(\"spark.sql.catalog.my_catalog.token\", TOKEN) \\\n .config(\"spark.sql.catalog.my_catalog.header.X-Iceberg-Access-Delegation\", \"vended-credentials\") \\\n .config(\"spark.sql.catalog.my_catalog.s3.remote-signing-enabled\", \"false\") \\\n .config(\"spark.sql.defaultCatalog\", \"my_catalog\") \\\n .getOrCreate()\nspark.sql(\"USE my_catalog\")\n\n# Create namespace if it does not exist\nspark.sql(\"CREATE NAMESPACE IF NOT EXISTS default\")\n\n# Create a table in the namespace using Iceberg\nspark.sql(\"\"\"\n CREATE TABLE IF NOT EXISTS default.my_table (\n id BIGINT,\n name STRING\n )\n USING iceberg\n\"\"\")\n\n# Create a simple DataFrame\ndf = spark.createDataFrame(\n [(1, \"Alice\"), (2, \"Bob\"), (3, \"Charlie\")],\n [\"id\", \"name\"]\n)\n\n# Write the DataFrame to the Iceberg table\ndf.write \\\n .format(\"iceberg\") \\\n .mode(\"append\") \\\n .save(\"default.my_table\")\n\n# Read the data back from the Iceberg table\nresult_df = spark.read \\\n .format(\"iceberg\") \\\n .load(\"default.my_table\")\n\nresult_df.show()\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.118Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":1,"totalLines":60,"estimatedTokens":507}}88{"id":"doc-pyiceberg_cloudflare_r2_data_catalog_docs-be6ec27a","source":"documentation","title":"PyIceberg · Cloudflare R2 Data Catalog docs","url":"https://developers.cloudflare.com/r2-data-catalog/config-examples/pyiceberg/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2-data-catalog/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nimport pyarrow as pa\nfrom pyiceberg.catalog.rest import RestCatalog\nfrom pyiceberg.exceptions import NamespaceAlreadyExistsError\n\n# Define catalog connection details (replace variables)\nWAREHOUSE = \"<WAREHOUSE>\"\nTOKEN = \"<TOKEN>\"\nCATALOG_URI = \"<CATALOG_URI>\"\n\n# Connect to R2 Data Catalog\ncatalog = RestCatalog(\n name=\"my_catalog\",\n warehouse=WAREHOUSE,\n uri=CATALOG_URI,\n token=TOKEN,\n)\n\n# Create default namespace\ncatalog.create_namespace(\"default\")\n\n# Create simple PyArrow table\ndf = pa.table({\n \"id\": [1, 2, 3],\n \"name\": [\"Alice\", \"Bob\", \"Charlie\"],\n})\n\n# Create an Iceberg table\ntest_table = (\"default\", \"my_table\")\ntable = catalog.create_table(\n test_table,\n schema=df.schema,\n)\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.171Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":1,"totalLines":39,"estimatedTokens":233}}89{"id":"doc-spark_scala_cloudflare_r2_data_catalog_docs-5926608c","source":"documentation","title":"Spark (Scala) · Cloudflare R2 Data Catalog docs","url":"https://developers.cloudflare.com/r2-data-catalog/config-examples/spark-scala/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2-data-catalog/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\npackage com.example\n\nimport org.apache.spark.sql.SparkSession\n\nobject R2DataCatalogDemo {\n def main(args: Array[String]): Unit = {\n\n val uri = sys.env(\"CATALOG_URI\")\n val warehouse = sys.env(\"WAREHOUSE\")\n val token = sys.env(\"TOKEN\")\n\n val spark = SparkSession.builder()\n .appName(\"My R2 Data Catalog Demo\")\n .master(\"local[*]\")\n .config(\"spark.sql.extensions\", \"org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions\")\n .config(\"spark.sql.catalog.mydemo\", \"org.apache.iceberg.spark.SparkCatalog\")\n .config(\"spark.sql.catalog.mydemo.type\", \"rest\")\n .config(\"spark.sql.catalog.mydemo.uri\", uri)\n .config(\"spark.sql.catalog.mydemo.warehouse\", warehouse)\n .config(\"spark.sql.catalog.mydemo.token\", token)\n .getOrCreate()\n\n import spark.implicits._\n\n val data = Seq(\n (1, \"Alice\", 25),\n (2, \"Bob\", 30),\n (3, \"Charlie\", 35),\n (4, \"Diana\", 40)\n ).toDF(\"id\", \"name\", \"age\")\n\n spark.sql(\"USE mydemo\")\n\n spark.sql(\"CREATE NAMESPACE IF NOT EXISTS demoNamespace\")\n\n data.writeTo(\"demoNamespace.demotable\").createOrReplace()\n\n val readResult = spark.sql(\"SELECT * FROM demoNamespace.demotable WHERE age > 30\")\n println(\"Records with age > 30:\")\n readResult.show()\n }\n}\n```\n\nExample:\n```text\nname := \"R2DataCatalogDemo\"\n\nversion := \"1.0\"\n\nval sparkVersion = \"3.5.3\"\nval icebergVersion = \"1.8.1\"\n\n// You need to use binaries of Spark compiled with either 2.12 or 2.13; and 2.12 is more common.\n// If you download Spark 3.5.3 with sdkman, then it comes with 2.12.18\nscalaVersion := \"2.12.18\"\n\nlibraryDependencies ++= Seq(\n \"org.apache.spark\" %% \"spark-core\" % sparkVersion,\n \"org.apache.spark\" %% \"spark-sql\" % sparkVersion,\n \"org.apache.iceberg\" % \"iceberg-core\" % icebergVersion,\n \"org.apache.iceberg\" % \"iceberg-spark-runtime-3.5_2.12\" % icebergVersion,\n \"org.apache.iceberg\" % \"iceberg-aws-bundle\" % icebergVersion,\n)\n\n// build a fat JAR with all dependencies\nassembly / assemblyMergeStrategy := {\n case PathList(\"META-INF\", \"services\", xs @ _*) => MergeStrategy.concat\n case PathList(\"META-INF\", xs @ _*) => MergeStrategy.discard\n case \"reference.conf\" => MergeStrategy.concat\n case \"application.conf\" => MergeStrategy.concat\n case x if x.endsWith(\".properties\") => MergeStrategy.first\n case x => MergeStrategy.first\n}\n\n// For Java 17 Compatibility\nCompile / javacOptions ++= Seq(\"--release\", \"17\")\n```\n\nExample:\n```text\naddSbtPlugin(\"com.eed3si9n\" % \"sbt-assembly\" % \"1.2.0\")\n```\n\nExample:\n```text\nsdk install java 17.0.14-amzn\nsdk install spark 3.5.3\nsdk install sbt 1.10.11\n```\n\nExample:\n```text\nsbt clean assembly\n```\n\nExample:\n```text\n# We need to set these \"--add-opens\" so that Spark can run on Java 17 (it needs access to\n# parts of the JVM which have been modularized and made internal).\nJAVA_17_COMPATIBILITY=\"--add-opens=java.base/sun.nio.ch=ALL-UNNAMED --add-opens=java.base/java.nio=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED\"\n\nspark-submit \\\n--conf \"spark.driver.extraJavaOptions=$JAVA_17_COMPATIBILITY\" \\\n--conf \"spark.executor.extraJavaOptions=$JAVA_17_COMPATIBILITY\" \\\n--class com.example.R2DataCatalogDemo target/scala-2.12/R2DataCatalogDemo-assembly-1.0.jar\n```\n\nExample:\n```text\nchmod +x submit.sh\n```\n\nExample:\n```text\nexport CATALOG_URI=\nexport WAREHOUSE=\nexport TOKEN=\n```\n\nExample:\n```text\n./submit.sh\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.171Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":9,"totalLines":130,"estimatedTokens":958}}90{"id":"doc-getting_started_r2_sql_docs-581d406d","source":"documentation","title":"Getting started · R2 SQL docs","url":"https://developers.cloudflare.com/r2-sql/get-started/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2-sql/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nnpx wrangler login\n```\n\nExample:\n```text\nnpx wrangler r2 bucket create pipelines-tutorial\n```\n\nExample:\n```text\nnpx wrangler r2 bucket catalog enable pipelines-tutorial\n```\n\nExample:\n```text\n{\n\t\"fields\": [\n\t\t{\n\t\t\t\"name\": \"user_id\",\n\t\t\t\"type\": \"string\",\n\t\t\t\"required\": true\n\t\t},\n\t\t{\n\t\t\t\"name\": \"event_type\",\n\t\t\t\"type\": \"string\",\n\t\t\t\"required\": true\n\t\t},\n\t\t{\n\t\t\t\"name\": \"product_id\",\n\t\t\t\"type\": \"string\",\n\t\t\t\"required\": false\n\t\t},\n\t\t{\n\t\t\t\"name\": \"amount\",\n\t\t\t\"type\": \"float64\",\n\t\t\t\"required\": false\n\t\t}\n\t]\n}\n```\n\nExample:\n```text\nnpx wrangler pipelines setup\n```\n\nExample:\n```text\nINSERT INTO ecommerce_sink SELECT * FROM ecommerce_stream\n```\n\nExample:\n```text\n{\n\t\"fields\": [\n\t\t{\n\t\t\t\"name\": \"user_id\",\n\t\t\t\"type\": \"string\",\n\t\t\t\"required\": true\n\t\t},\n\t\t{\n\t\t\t\"name\": \"event_type\",\n\t\t\t\"type\": \"string\",\n\t\t\t\"required\": true\n\t\t},\n\t\t{\n\t\t\t\"name\": \"product_id\",\n\t\t\t\"type\": \"string\",\n\t\t\t\"required\": false\n\t\t},\n\t\t{\n\t\t\t\"name\": \"amount\",\n\t\t\t\"type\": \"f64\",\n\t\t\t\"required\": false\n\t\t}\n\t]\n}\n```\n\nExample:\n```text\nINSERT INTO ecommerce_sink SELECT * FROM ecommerce_stream;\n```\n\nExample:\n```text\ncurl -X POST https://{stream-id}.ingest.cloudflare.com \\\n -H \"Content-Type: application/json\" \\\n -d '[\n {\n \"user_id\": \"user_12345\",\n \"event_type\": \"purchase\",\n \"product_id\": \"widget-001\",\n \"amount\": 29.99\n },\n {\n \"user_id\": \"user_67890\",\n \"event_type\": \"view_product\",\n \"product_id\": \"widget-002\"\n },\n {\n \"user_id\": \"user_12345\",\n \"event_type\": \"add_to_cart\",\n \"product_id\": \"widget-003\",\n \"amount\": 15.50\n }\n ]'\n```\n\nExample:\n```text\nexport WRANGLER_R2_SQL_AUTH_TOKEN=YOUR_API_TOKEN\n```\n\nExample:\n```text\nWRANGLER_R2_SQL_AUTH_TOKEN=YOUR_API_TOKEN\n```\n\nExample:\n```text\nnpx wrangler r2 sql query \"YOUR_WAREHOUSE_NAME\" \"\nSELECT\n user_id,\n event_type,\n product_id,\n amount\nFROM default.ecommerce\nWHERE event_type = 'purchase'\nLIMIT 10\"\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.172Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":12,"totalLines":137,"estimatedTokens":526}}91{"id":"doc-metrics_and_analytics_cloudflare_r2_data_catalog-4ad3518b","source":"documentation","title":"Metrics and analytics · Cloudflare R2 Data Catalog docs","url":"https://developers.cloudflare.com/r2-data-catalog/observability/metrics/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2-data-catalog/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nquery CatalogDataOperations(\n\t$accountTag: String!\n\t$warehouseName: String!\n\t$datetimeStart: Time!\n\t$datetimeEnd: Time!\n) {\n\tviewer {\n\t\taccounts(filter: { accountTag: $accountTag }) {\n\t\t\tr2CatalogDataOperationsAdaptiveGroups(\n\t\t\t\tlimit: 10000\n\t\t\t\tfilter: {\n\t\t\t\t\twarehouseName: $warehouseName\n\t\t\t\t\tdatetime_geq: $datetimeStart\n\t\t\t\t\tdatetime_leq: $datetimeEnd\n\t\t\t\t}\n\t\t\t) {\n\t\t\t\tcount\n\t\t\t\tdimensions {\n\t\t\t\t\toperation\n\t\t\t\t}\n\t\t\t\tsum {\n\t\t\t\t\trequestBodyBytes\n\t\t\t\t\trequestDurationMs\n\t\t\t\t}\n\t\t\t\tavg {\n\t\t\t\t\trequestDurationMs\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n```\n\nExample:\n```text\nquery CatalogLatencyPercentiles(\n\t$accountTag: String!\n\t$warehouseName: String!\n\t$datetimeStart: Time!\n\t$datetimeEnd: Time!\n) {\n\tviewer {\n\t\taccounts(filter: { accountTag: $accountTag }) {\n\t\t\tr2CatalogDataOperationsAdaptiveGroups(\n\t\t\t\tlimit: 10000\n\t\t\t\tfilter: {\n\t\t\t\t\twarehouseName: $warehouseName\n\t\t\t\t\tdatetime_geq: $datetimeStart\n\t\t\t\t\tdatetime_leq: $datetimeEnd\n\t\t\t\t}\n\t\t\t) {\n\t\t\t\tcount\n\t\t\t\tdimensions {\n\t\t\t\t\toperation\n\t\t\t\t}\n\t\t\t\tquantiles {\n\t\t\t\t\trequestDurationMsP50\n\t\t\t\t\trequestDurationMsP90\n\t\t\t\t\trequestDurationMsP99\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n```\n\nExample:\n```text\nquery CatalogMaintenanceMetrics(\n\t$accountTag: String!\n\t$warehouseName: String!\n\t$datetimeStart: Time!\n\t$datetimeEnd: Time!\n) {\n\tviewer {\n\t\taccounts(filter: { accountTag: $accountTag }) {\n\t\t\tr2CatalogTableMaintenanceAdaptiveGroups(\n\t\t\t\tlimit: 10000\n\t\t\t\tfilter: {\n\t\t\t\t\twarehouseName: $warehouseName\n\t\t\t\t\tdatetime_geq: $datetimeStart\n\t\t\t\t\tdatetime_leq: $datetimeEnd\n\t\t\t\t}\n\t\t\t) {\n\t\t\t\tcount\n\t\t\t\tdimensions {\n\t\t\t\t\tjobType\n\t\t\t\t\ttableName\n\t\t\t\t\tsuccess\n\t\t\t\t}\n\t\t\t\tsum {\n\t\t\t\t\tfilesProcessed\n\t\t\t\t\tfilesOutput\n\t\t\t\t\tinputBytes\n\t\t\t\t\toutputBytes\n\t\t\t\t\tjobDurationMs\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n```\n\nExample:\n```text\nquery CatalogFilterByOperation(\n\t$accountTag: String!\n\t$datetimeStart: Time!\n\t$datetimeEnd: Time!\n) {\n\tviewer {\n\t\taccounts(filter: { accountTag: $accountTag }) {\n\t\t\tr2CatalogDataOperationsAdaptiveGroups(\n\t\t\t\tlimit: 10000\n\t\t\t\tfilter: {\n\t\t\t\t\twarehouseName: \"my-warehouse\"\n\t\t\t\t\toperation: \"load-table\"\n\t\t\t\t\ttableName: \"my_table\"\n\t\t\t\t\tdatetime_geq: $datetimeStart\n\t\t\t\t\tdatetime_leq: $datetimeEnd\n\t\t\t\t}\n\t\t\t) {\n\t\t\t\tcount\n\t\t\t\tsum {\n\t\t\t\t\trequestDurationMs\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n```\n\nExample:\n```text\nquery CatalogFailedMaintenanceJobs(\n\t$accountTag: String!\n\t$datetimeStart: Time!\n\t$datetimeEnd: Time!\n) {\n\tviewer {\n\t\taccounts(filter: { accountTag: $accountTag }) {\n\t\t\tr2CatalogTableMaintenanceAdaptiveGroups(\n\t\t\t\tlimit: 10000\n\t\t\t\tfilter: {\n\t\t\t\t\twarehouseName: \"my-warehouse\"\n\t\t\t\t\tsuccess: 0\n\t\t\t\t\tdatetime_geq: $datetimeStart\n\t\t\t\t\tdatetime_leq: $datetimeEnd\n\t\t\t\t}\n\t\t\t) {\n\t\t\t\tcount\n\t\t\t\tdimensions {\n\t\t\t\t\tjobType\n\t\t\t\t\ttableName\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n```\n\nExample:\n```text\nquery CatalogAllWarehouses(\n\t$accountTag: String!\n\t$datetimeStart: Time!\n\t$datetimeEnd: Time!\n) {\n\tviewer {\n\t\taccounts(filter: { accountTag: $accountTag }) {\n\t\t\tr2CatalogDataOperationsAdaptiveGroups(\n\t\t\t\tlimit: 10000\n\t\t\t\tfilter: { datetime_geq: $datetimeStart, datetime_leq: $datetimeEnd }\n\t\t\t) {\n\t\t\t\tcount\n\t\t\t\tdimensions {\n\t\t\t\t\twarehouseName\n\t\t\t\t\toperation\n\t\t\t\t}\n\t\t\t\tsum {\n\t\t\t\t\trequestDurationMs\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.172Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":6,"totalLines":193,"estimatedTokens":825}}92{"id":"doc-deleting_data_cloudflare_r2_data_catalog_docs-44a21c7e","source":"documentation","title":"Deleting data · Cloudflare R2 Data Catalog docs","url":"https://developers.cloudflare.com/r2-data-catalog/deleting-data/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2-data-catalog/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\n# Enable automatic snapshot expiration for entire catalog\nnpx wrangler r2 bucket catalog snapshot-expiration enable my-bucket \\\n\t--older-than-days 30 \\\n\t--retain-last 5\n\n# Enable automatic compaction for entire catalog\nnpx wrangler r2 bucket catalog compaction enable my-bucket \\\n\t--target-size 256\n```\n\nExample:\n```text\n# Creates new snapshots and marks old files for cleanup\nspark.sql(\"\"\"\n\tDELETE FROM r2dc.namespace.table_name\n\tWHERE column_name = 'value'\n\"\"\")\n\n# The following is effectively a TRUNCATE operation\nspark.sql(\"DELETE FROM r2dc.namespace.table_name\")\n\n# For large deletes, use partitioned tables and delete entire partitions for faster performance:\nspark.sql(\"\"\"\n DELETE FROM r2dc.namespace.table_name\n WHERE date_partition < '2024-01-01'\n\"\"\")\n```\n\nExample:\n```text\n# Removes table from catalog but keeps data files in R2 storage\nspark.sql(\"DROP TABLE r2dc.namespace.table_name\")\n\n# ⚠️ DANGER: Permanently deletes all data files from R2\n# This operation cannot be undone\nspark.sql(\"DROP TABLE r2dc.namespace.table_name PURGE\")\n\n# Use CASCADE to drop all tables within the namespace\nspark.sql(\"DROP NAMESPACE r2dc.namespace_name CASCADE\")\n\n# You will need to PURGE the tables before running CASCADE to permanently delete data files\n# This can be done with a loop over all tables in the namespace\ntables = spark.sql(\"SHOW TABLES IN r2dc.namespace_name\").collect()\nfor row in tables:\n\ttable_name = row['tableName']\n spark.sql(f\"DROP TABLE r2dc.namespace_name.{table_name} PURGE\")\nspark.sql(\"DROP NAMESPACE r2dc.namespace_name CASCADE\")\n```\n\nExample:\n```text\n# Remove old metadata and data files marked for deletion\n# The following retains the last 5 snapshots and deletes files older than Nov 28, 2024\nspark.sql(\"\"\"\n\tCALL r2dc.system.expire_snapshots(\n table => 'r2dc.namespace_name.table_name',\n older_than => TIMESTAMP '2024-11-28 00:00:00',\n retain_last => 5\n )\n\"\"\")\n\n# Removes unreferenced data files from R2 storage (orphan files)\nspark.sql(\"\"\"\n CALL r2dc.system.remove_orphan_files(\n table => 'namespace.table_name'\n )\n\"\"\")\n\n# Rewrite data files with a target file size (e.g., 512 MB)\nspark.sql(\"\"\"\n CALL r2dc.system.rewrite_data_files(\n table => 'r2dc.namespace_name.table_name',\n options => map('target-file-size-bytes', '536870912')\n )\n\"\"\")\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.173Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":4,"totalLines":82,"estimatedTokens":629}}93{"id":"doc-limitations_and_best_practices_r2_sql_docs-4a5cece4","source":"documentation","title":"Limitations and best practices · R2 SQL docs","url":"https://developers.cloudflare.com/r2-sql/reference/limitations-best-practices/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2-sql/llms.txtUse this file to discover all available pages before exploring further.\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.173Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":47}}94{"id":"doc-wrangler_commands_r2_sql_docs-5b7f9b5a","source":"documentation","title":"Wrangler commands · R2 SQL docs","url":"https://developers.cloudflare.com/r2-sql/reference/wrangler-commands/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2-sql/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nnpx wrangler r2 sql query [WAREHOUSE] [QUERY]\n```\n\nExample:\n```text\nyarn wrangler r2 sql query [WAREHOUSE] [QUERY]\n```\n\nExample:\n```text\npnpm wrangler r2 sql query [WAREHOUSE] [QUERY]\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.173Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":3,"totalLines":18,"estimatedTokens":99}}95{"id":"doc-troubleshooting_guide_r2_sql_docs-84258fcb","source":"documentation","title":"Troubleshooting guide · R2 SQL docs","url":"https://developers.cloudflare.com/r2-sql/troubleshooting/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2-sql/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\n-- Invalid - Missing FROM clause\nSELECT user_id WHERE status = 200;\n\n-- Valid\nSELECT user_id\nFROM my_namespace.http_requests\nWHERE status = 200 AND timestamp BETWEEN '2025-09-24T01:00:00Z' AND '2025-09-25T01:00:00Z';\n```\n\nExample:\n```text\n-- May timeout: cross-joining two large fact tables\nSELECT COUNT(DISTINCT h.ray_id), COUNT(DISTINCT f.event_id)\nFROM my_namespace.http_requests h\nINNER JOIN my_namespace.firewall_events f ON h.zone_id = f.zone_id\n```\n\nExample:\n```text\n-- Better: filter both sides and use approx_distinct\nSELECT z.plan,\n approx_distinct(h.ray_id) AS unique_requests\nFROM my_namespace.zones z\nINNER JOIN my_namespace.http_requests h ON z.zone_id = h.zone_id\nWHERE z.plan = 'enterprise'\n AND h.status_code >= 400\nGROUP BY z.plan\n```\n\nExample:\n```text\n-- Fails: nullable_col may contain NULLs\nSELECT zone_id\nFROM my_namespace.http_requests\nWHERE zone_id NOT IN (\n SELECT nullable_col FROM my_namespace.other_table\n)\nLIMIT 20\n```\n\nExample:\n```text\n-- Works: NOT EXISTS handles NULLs correctly\nSELECT h.zone_id\nFROM my_namespace.http_requests h\nWHERE NOT EXISTS (\n SELECT 1 FROM my_namespace.other_table o\n WHERE o.nullable_col = h.zone_id\n)\nLIMIT 20\n```\n\nExample:\n```text\n-- Slower: multiple filter conditions in correlated subquery\nSELECT z.domain\nFROM my_namespace.zones z\nWHERE EXISTS (\n SELECT 1 FROM my_namespace.firewall_events f\n WHERE f.zone_id = z.zone_id\n AND f.risk_score > 0.9\n AND f.colo = 'SJC'\n)\nLIMIT 20\n```\n\nExample:\n```text\n-- Invalid - JSON path operators not supported\nSELECT * FROM my_namespace.requests WHERE json_data->>'level' = 'error'\n\n-- Valid - Filter on the entire JSON column\nSELECT * FROM my_namespace.logs WHERE json_data IS NOT NULL LIMIT 100\n```\n\nExample:\n```text\nSELECT * FROM my_namespace.products WHERE pricing['price'] > 50 LIMIT 100\n```\n\nExample:\n```text\n-- Invalid - Out of range\nSELECT * FROM my_namespace.events LIMIT 50000\n\n-- Valid\nSELECT * FROM my_namespace.events LIMIT 10000\n```\n\nExample:\n```text\n-- Invalid - Pagination not supported\nSELECT * FROM my_namespace.events LIMIT 100 OFFSET 200\n\n-- Valid - Use cursor-based pagination with ORDER BY and WHERE\n-- Page 1\nSELECT * FROM my_namespace.events\nWHERE timestamp >= '2024-01-01'\nORDER BY timestamp\nLIMIT 100\n\n-- Page 2 - Use the last timestamp from the previous page\nSELECT * FROM my_namespace.events\nWHERE timestamp > '2024-01-01T10:30:00Z'\nORDER BY timestamp\nLIMIT 100\n```\n\nExample:\n```text\n-- Invalid - Schema changes not supported\nALTER TABLE my_namespace.events ADD COLUMN new_field STRING\nUPDATE my_namespace.events SET status = 200 WHERE user_id = '123'\nCREATE TABLE my_namespace.test (id INT)\nDROP TABLE my_namespace.events\n```\n\nExample:\n```text\n-- Good - Narrows data scan to one day\nSELECT * FROM my_namespace.events\nWHERE timestamp BETWEEN '2024-01-01' AND '2024-01-02'\nLIMIT 100\n```\n\nExample:\n```text\n-- Good - Multiple filters reduce scanned data\nSELECT * FROM my_namespace.events\nWHERE status = 200 AND region = 'US' AND timestamp > '2024-01-01'\nLIMIT 100\n```\n\nExample:\n```text\n-- Good - Only reads the columns you need\nSELECT user_id, status, timestamp\nFROM my_namespace.events\nWHERE timestamp > '2024-01-01'\nLIMIT 100\n```\n\nExample:\n```text\nEXPLAIN SELECT user_id, status\nFROM my_namespace.events\nWHERE timestamp > '2024-01-01' AND status = 200\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.173Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":15,"totalLines":154,"estimatedTokens":880}}96{"id":"doc-aggregate_functions_r2_sql_docs-9099b571","source":"documentation","title":"Aggregate functions · R2 SQL docs","url":"https://developers.cloudflare.com/r2-sql/sql-reference/aggregate-functions/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2-sql/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nSELECT COUNT(*) AS total_rows\nFROM my_namespace.sales_data\n\nSELECT department, COUNT(*) AS dept_count\nFROM my_namespace.sales_data\nGROUP BY department\nORDER BY dept_count DESC\n```\n\nExample:\n```text\nSELECT SUM(total_amount) AS grand_total\nFROM my_namespace.sales_data\n\nSELECT department, SUM(total_amount) AS dept_total\nFROM my_namespace.sales_data\nGROUP BY department\nORDER BY dept_total DESC\n```\n\nExample:\n```text\nSELECT AVG(total_amount) AS avg_amount\nFROM my_namespace.sales_data\n\nSELECT department, AVG(total_amount) AS avg_amount\nFROM my_namespace.sales_data\nGROUP BY department\nORDER BY avg_amount DESC\n```\n\nExample:\n```text\nSELECT MIN(total_amount) AS min_amount, MIN(customer_id) AS first_customer\nFROM my_namespace.sales_data\n\nSELECT department, MIN(total_amount) AS min_amount\nFROM my_namespace.sales_data\nGROUP BY department\n```\n\nExample:\n```text\nSELECT MAX(total_amount) AS max_amount, MAX(customer_id) AS last_customer\nFROM my_namespace.sales_data\n\nSELECT department, MAX(total_amount) AS max_amount\nFROM my_namespace.sales_data\nGROUP BY department\n```\n\nExample:\n```text\nSELECT MEDIAN(total_amount) AS median_amount\nFROM my_namespace.sales_data\n\nSELECT department, MEDIAN(total_amount) AS median_amount\nFROM my_namespace.sales_data\nGROUP BY department\n```\n\nExample:\n```text\nSELECT PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY total_amount) AS median,\n PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY total_amount) AS p95\nFROM my_namespace.sales_data\n```\n\nExample:\n```text\nSELECT approx_percentile_cont(total_amount, 0.5) AS median,\n approx_percentile_cont(total_amount, 0.95) AS p95\nFROM my_namespace.sales_data\n\nSELECT department,\n approx_percentile_cont(total_amount, 0.5) AS median\nFROM my_namespace.sales_data\nGROUP BY department\nORDER BY median DESC\n```\n\nExample:\n```text\nSELECT approx_percentile_cont_with_weight(unit_price, quantity, 0.5) AS weighted_median\nFROM my_namespace.sales_data\nWHERE unit_price IS NOT NULL AND quantity IS NOT NULL\n```\n\nExample:\n```text\nSELECT approx_median(total_amount) AS median_amount\nFROM my_namespace.sales_data\n\nSELECT department, approx_median(total_amount) AS median\nFROM my_namespace.sales_data\nGROUP BY department\n```\n\nExample:\n```text\nSELECT approx_distinct(customer_id) AS unique_customers\nFROM my_namespace.sales_data\n\nSELECT department, approx_distinct(customer_id) AS unique_customers\nFROM my_namespace.sales_data\nGROUP BY department\n```\n\nExample:\n```text\nSELECT approx_top_k(department, 5) AS top_departments\nFROM my_namespace.sales_data\n```\n\nExample:\n```text\nSELECT var(total_amount) AS variance\nFROM my_namespace.sales_data\n\nSELECT department, var(total_amount) AS variance\nFROM my_namespace.sales_data\nGROUP BY department\n```\n\nExample:\n```text\nSELECT var_pop(total_amount) AS pop_variance\nFROM my_namespace.sales_data\n```\n\nExample:\n```text\nSELECT stddev(total_amount) AS std_dev\nFROM my_namespace.sales_data\n\nSELECT department, stddev(total_amount) AS std_dev\nFROM my_namespace.sales_data\nGROUP BY department\n```\n\nExample:\n```text\nSELECT stddev_pop(total_amount) AS pop_std_dev\nFROM my_namespace.sales_data\n```\n\nExample:\n```text\nSELECT covar_samp(total_amount, CAST(quantity AS DOUBLE)) AS covariance\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL AND quantity IS NOT NULL\n```\n\nExample:\n```text\nSELECT covar_pop(total_amount, CAST(quantity AS DOUBLE)) AS pop_covariance\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL AND quantity IS NOT NULL\n```\n\nExample:\n```text\nSELECT corr(total_amount, CAST(quantity AS DOUBLE)) AS correlation\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL AND quantity IS NOT NULL\n```\n\nExample:\n```text\nSELECT regr_slope(total_amount, CAST(quantity AS DOUBLE)) AS slope\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL AND quantity IS NOT NULL\n```\n\nExample:\n```text\nSELECT regr_intercept(total_amount, CAST(quantity AS DOUBLE)) AS intercept\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL AND quantity IS NOT NULL\n```\n\nExample:\n```text\nSELECT regr_count(total_amount, CAST(quantity AS DOUBLE)) AS pair_count\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL AND quantity IS NOT NULL\n```\n\nExample:\n```text\nSELECT regr_r2(total_amount, CAST(quantity AS DOUBLE)) AS r_squared\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL AND quantity IS NOT NULL\n```\n\nExample:\n```text\nSELECT regr_avgx(total_amount, CAST(quantity AS DOUBLE)) AS avg_qty\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL AND quantity IS NOT NULL\n```\n\nExample:\n```text\nSELECT regr_avgy(total_amount, CAST(quantity AS DOUBLE)) AS avg_amount\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL AND quantity IS NOT NULL\n```\n\nExample:\n```text\nSELECT regr_sxx(total_amount, CAST(quantity AS DOUBLE)) AS sxx\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL AND quantity IS NOT NULL\n```\n\nExample:\n```text\nSELECT regr_syy(total_amount, CAST(quantity AS DOUBLE)) AS syy\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL AND quantity IS NOT NULL\n```\n\nExample:\n```text\nSELECT regr_sxy(total_amount, CAST(quantity AS DOUBLE)) AS sxy\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL AND quantity IS NOT NULL\n```\n\nExample:\n```text\nSELECT department, bit_and(quantity) AS and_result\nFROM my_namespace.sales_data\nWHERE quantity IS NOT NULL\nGROUP BY department\n```\n\nExample:\n```text\nSELECT department, bit_or(quantity) AS or_result\nFROM my_namespace.sales_data\nWHERE quantity IS NOT NULL\nGROUP BY department\n```\n\nExample:\n```text\nSELECT department, bit_xor(quantity) AS xor_result\nFROM my_namespace.sales_data\nWHERE quantity IS NOT NULL\nGROUP BY department\n```\n\nExample:\n```text\nSELECT department, bool_and(is_completed) AS all_completed\nFROM my_namespace.sales_data\nWHERE is_completed IS NOT NULL\nGROUP BY department\n```\n\nExample:\n```text\nSELECT department, bool_or(is_completed) AS any_completed\nFROM my_namespace.sales_data\nWHERE is_completed IS NOT NULL\nGROUP BY department\n```\n\nExample:\n```text\nSELECT department,\n first_value(customer_id ORDER BY total_amount ASC) AS lowest_spender\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL\nGROUP BY department\n```\n\nExample:\n```text\nSELECT department,\n last_value(customer_id ORDER BY total_amount ASC) AS highest_spender\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL\nGROUP BY department\n```\n\nExample:\n```text\nSELECT department, array_agg(customer_id) AS customers\nFROM my_namespace.sales_data\nGROUP BY department\n```\n\nExample:\n```text\nSELECT department, string_agg(customer_id, ', ') AS customer_list\nFROM my_namespace.sales_data\nGROUP BY department\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.179Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":37,"totalLines":307,"estimatedTokens":1707}}97{"id":"doc-complex_types_r2_sql_docs-847ac631","source":"documentation","title":"Complex types · R2 SQL docs","url":"https://developers.cloudflare.com/r2-sql/sql-reference/complex-types/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2-sql/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nSELECT pricing['price'] AS price,\n pricing['discount_percent'] AS discount\nFROM my_namespace.products\nLIMIT 5\n```\n\nExample:\n```text\nSELECT get_field(pricing, 'price') AS price,\n get_field(pricing, 'discount_percent') AS discount\nFROM my_namespace.products\nLIMIT 5\n```\n\nExample:\n```text\nSELECT customer_id, pricing['price'] AS price\nFROM my_namespace.products\nWHERE pricing['price'] > 50\nLIMIT 10\n```\n\nExample:\n```text\nSELECT customer_id, pricing['price'] AS price\nFROM my_namespace.products\nWHERE pricing['price'] IS NOT NULL\nORDER BY pricing['price'] DESC\nLIMIT 10\n```\n\nExample:\n```text\nSELECT platforms['windows'] AS windows_support,\n COUNT(*) AS product_count,\n AVG(pricing['price']) AS avg_price\nFROM my_namespace.products\nWHERE pricing['price'] IS NOT NULL\nGROUP BY platforms['windows']\n```\n\nExample:\n```text\n-- named_struct creates a struct with named fields\nSELECT named_struct('id', customer_id, 'amount', total_amount) AS info\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL\nLIMIT 1\n\n-- struct creates a struct with positional fields\nSELECT struct(customer_id, total_amount, region) AS info\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL\nLIMIT 1\n```\n\nExample:\n```text\nSELECT customer_id, tags[1] AS first_tag, tags[2] AS second_tag\nFROM my_namespace.products\nLIMIT 5\n```\n\nExample:\n```text\nSELECT make_array(1, 2, 3) AS nums\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT string_to_array(categories, ',') AS cat_array\nFROM my_namespace.products\nWHERE categories IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT range(0, 5) AS nums\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT generate_series(1, 5) AS nums\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT customer_id, array_length(tags) AS tag_count\nFROM my_namespace.products\nLIMIT 5\n```\n\nExample:\n```text\nSELECT customer_id, cardinality(tags) AS tag_count\nFROM my_namespace.products\nLIMIT 5\n```\n\nExample:\n```text\nSELECT customer_id, empty(tags) AS has_no_tags\nFROM my_namespace.products\nLIMIT 5\n```\n\nExample:\n```text\nSELECT array_ndims(make_array(1, 2, 3)) AS ndims\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT array_dims(make_array(1, 2, 3)) AS dims\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT customer_id, array_has(tags, 'premium') AS is_premium\nFROM my_namespace.products\nLIMIT 5\n```\n\nExample:\n```text\nSELECT array_has_all(make_array(1, 2, 3, 4), make_array(2, 3)) AS has_all\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT array_has_any(make_array(1, 2, 3), make_array(3, 4, 5)) AS has_any\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT array_position(make_array('a', 'b', 'c', 'b'), 'b') AS pos\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT array_positions(make_array(1, 2, 1, 3, 1), 1) AS positions\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT array_sort(make_array(3, 1, 2)) AS sorted\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT array_reverse(make_array(1, 2, 3)) AS reversed\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT array_distinct(make_array(1, 2, 2, 3, 3, 3)) AS unique_vals\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT flatten(make_array(make_array(1, 2), make_array(3, 4))) AS flat\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT array_slice(make_array(10, 20, 30, 40, 50), 2, 4) AS sliced\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT array_append(make_array(1, 2, 3), 4) AS appended\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT array_prepend(0, make_array(1, 2, 3)) AS prepended\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT array_concat(make_array(1, 2), make_array(3, 4)) AS merged\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT array_remove(make_array(1, 2, 3, 2), 2) AS result\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT array_remove_all(make_array(1, 2, 3, 2, 2), 2) AS result\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT array_remove_n(make_array(1, 2, 2, 2, 3), 2, 2) AS result\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT array_replace(make_array(1, 2, 3), 2, 99) AS result\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT array_replace_n(make_array(1, 2, 2, 2, 3), 2, 99, 2) AS result\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT array_replace_all(make_array(1, 2, 3, 2), 2, 99) AS result\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT array_pop_back(make_array(1, 2, 3)) AS result\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT array_pop_front(make_array(1, 2, 3)) AS result\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT array_repeat(region, 3) AS repeated\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT array_resize(make_array(1, 2), 5, 0) AS resized\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT array_intersect(make_array(1, 2, 3), make_array(2, 3, 4)) AS common\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT array_union(make_array(1, 2, 3), make_array(3, 4, 5)) AS merged\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT array_except(make_array(1, 2, 3, 4), make_array(2, 4)) AS diff\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT customer_id, array_max(scores) AS max_score\nFROM my_namespace.products\nLIMIT 5\n```\n\nExample:\n```text\nSELECT customer_id, array_min(scores) AS min_score\nFROM my_namespace.products\nLIMIT 5\n```\n\nExample:\n```text\nSELECT array_any_value(make_array(NULL, 42, NULL)) AS first_val\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT array_element(make_array(10, 20, 30), 2) AS second_val\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT customer_id, array_to_string(tags, ', ') AS tag_list\nFROM my_namespace.products\nLIMIT 5\n```\n\nExample:\n```text\nSELECT map_keys(metadata) AS keys\nFROM my_namespace.products\nLIMIT 5\n```\n\nExample:\n```text\nSELECT map_values(metadata) AS vals\nFROM my_namespace.products\nLIMIT 5\n```\n\nExample:\n```text\nSELECT map_extract(metadata, 'source') AS source,\n map_extract(metadata, 'store_name') AS store\nFROM my_namespace.products\nLIMIT 5\n```\n\nExample:\n```text\nSELECT map(make_array('a', 'b'), make_array(1, 2)) AS m\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.179Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":51,"totalLines":378,"estimatedTokens":1671}}98{"id":"doc-build_an_end_to_end_data_pipeline_r2_sql_docs-98f42494","source":"documentation","title":"Build an end to end data pipeline · R2 SQL docs","url":"https://developers.cloudflare.com/r2-sql/tutorials/end-to-end-pipeline/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2-sql/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nexport WRANGLER_R2_SQL_AUTH_TOKEN= #paste your token here\n```\n\nExample:\n```text\nnpx wrangler login\n```\n\nExample:\n```text\nnpx wrangler r2 bucket create fraud-pipeline\n```\n\nExample:\n```text\nnpx wrangler r2 bucket catalog enable fraud-pipeline\n```\n\nExample:\n```text\nexport WAREHOUSE= #Paste your warehouse here\n```\n\nExample:\n```text\nnpx wrangler r2 bucket catalog compaction enable fraud-pipeline --token $WRANGLER_R2_SQL_AUTH_TOKEN\n```\n\nExample:\n```text\n{\n\t\"fields\": [\n\t\t{ \"name\": \"transaction_id\", \"type\": \"string\", \"required\": true },\n\t\t{ \"name\": \"user_id\", \"type\": \"int64\", \"required\": true },\n\t\t{ \"name\": \"amount\", \"type\": \"float64\", \"required\": false },\n\t\t{ \"name\": \"transaction_timestamp\", \"type\": \"string\", \"required\": false },\n\t\t{ \"name\": \"location\", \"type\": \"string\", \"required\": false },\n\t\t{ \"name\": \"merchant_category\", \"type\": \"string\", \"required\": false },\n\t\t{ \"name\": \"is_fraud\", \"type\": \"bool\", \"required\": false }\n\t]\n}\n```\n\nExample:\n```text\nnpx wrangler pipelines streams create raw_events_stream \\\n --schema-file raw_transactions_schema.json \\\n --http-enabled true \\\n --http-auth false\n```\n\nExample:\n```text\n# The http ingest endpoint from the output (see example below)\nexport STREAM_ENDPOINT= #the http ingest endpoint from the output (see example below)\n```\n\nExample:\n```text\n🌀 Creating stream 'raw_events_stream'...\n✨ Successfully created stream 'raw_events_stream' with id 'stream_id'.\n\nCreation Summary:\nGeneral:\n Name: raw_events_stream\n\nHTTP Ingest:\n Enabled: Yes\n Authentication: Yes\n Endpoint: https://stream_id.ingest.cloudflare.com\n CORS Origins: None\n\nInput Schema:\n┌───────────────────────┬────────┬────────────┬──────────┐\n│ Field Name │ Type │ Unit/Items │ Required │\n├───────────────────────┼────────┼────────────┼──────────┤\n│ transaction_id │ string │ │ Yes │\n├───────────────────────┼────────┼────────────┼──────────┤\n│ user_id │ int64 │ │ Yes │\n├───────────────────────┼────────┼────────────┼──────────┤\n│ amount │float64 │ │ No │\n├───────────────────────┼────────┼────────────┼──────────┤\n│ transaction_timestamp │ string │ │ No │\n├───────────────────────┼────────┼────────────┼──────────┤\n│ location │ string │ │ No │\n├───────────────────────┼────────┼────────────┼──────────┤\n│ merchant_category │ string │ │ No │\n├───────────────────────┼────────┼────────────┼──────────┤\n│ is_fraud │ bool │ │ No │\n└───────────────────────┴────────┴────────────┴──────────┘\n```\n\nExample:\n```text\nnpx wrangler pipelines sinks create raw_events_sink \\\n --type \"r2-data-catalog\" \\\n --bucket \"fraud-pipeline\" \\\n --roll-interval 30 \\\n --namespace \"fraud_detection\" \\\n --table \"transactions\" \\\n --catalog-token $WRANGLER_R2_SQL_AUTH_TOKEN\n```\n\nExample:\n```text\nnpx wrangler pipelines create raw_events_pipeline \\\n --sql \"INSERT INTO raw_events_sink SELECT * FROM raw_events_stream\"\n```\n\nExample:\n```text\nINSERT INTO raw_events_sink SELECT * FROM raw_events_stream;\n```\n\nExample:\n```text\nimport requests\nimport json\nimport uuid\nimport random\nimport time\nimport os\nfrom datetime import datetime, timezone, timedelta\n\n# Configuration - exported from the prior steps\nSTREAM_ENDPOINT = os.environ[\"STREAM_ENDPOINT\"]# From the stream you created\nAPI_TOKEN = os.environ[\"WRANGLER_R2_SQL_AUTH_TOKEN\"] #the same one created earlier\nEVENTS_TO_SEND = 1000 # Feel free to adjust this\n\ndef generate_transaction():\n \"\"\"Generate some random transactions with occasional fraud\"\"\"\n\n # User IDs\n high_risk_users = [1001, 1002, 1003, 1004, 1005]\n normal_users = list(range(1006, 2000))\n\n user_id = random.choice(high_risk_users + normal_users)\n is_high_risk_user = user_id in high_risk_users\n\n # Generate amounts\n if random.random() < 0.05:\n amount = round(random.uniform(5000, 50000), 2)\n elif random.random() < 0.03:\n amount = round(random.uniform(0.01, 1.00), 2)\n else:\n amount = round(random.uniform(10, 500), 2)\n\n # Locations\n normal_locations = [\"NEW_YORK\", \"LOS_ANGELES\", \"CHICAGO\", \"MIAMI\", \"SEATTLE\", \"SAN FRANCISCO\"]\n high_risk_locations = [\"UNKNOWN_LOCATION\", \"VPN_EXIT\", \"MARS\", \"BAT_CAVE\"]\n\n if is_high_risk_user and random.random() < 0.3:\n location = random.choice(high_risk_locations)\n else:\n location = random.choice(normal_locations)\n\n # Merchant categories\n normal_merchants = [\"GROCERY\", \"GAS_STATION\", \"RESTAURANT\", \"RETAIL\"]\n high_risk_merchants = [\"GAMBLING\", \"CRYPTO\", \"MONEY_TRANSFER\", \"GIFT_CARDS\"]\n\n if random.random() < 0.1: # 10% high-risk merchants\n merchant_category = random.choice(high_risk_merchants)\n else:\n merchant_category = random.choice(normal_merchants)\n\n # Series of checks to either increase fraud score by a certain margin\n fraud_score = 0\n if amount > 2000: fraud_score += 0.4\n if amount < 1: fraud_score += 0.3\n if location in high_risk_locations: fraud_score += 0.5\n if merchant_category in high_risk_merchants: fraud_score += 0.3\n if is_high_risk_user: fraud_score += 0.2\n\n # Compare the fraud scores\n is_fraud = random.random() < min(fraud_score * 0.3, 0.8)\n\n # Generate timestamps (some fraud happens at unusual hours)\n base_time = datetime.now(timezone.utc)\n if is_fraud and random.random() < 0.4: # 40% of fraud at night\n hour = random.randint(0, 5) # Late night/early morning\n transaction_time = base_time.replace(hour=hour)\n else:\n transaction_time = base_time - timedelta(\n hours=random.randint(0, 168) # Last week\n )\n\n return {\n \"transaction_id\": str(uuid.uuid4()),\n \"user_id\": user_id,\n \"amount\": amount,\n \"transaction_timestamp\": transaction_time.isoformat(),\n \"location\": location,\n \"merchant_category\": merchant_category,\n \"is_fraud\": True if is_fraud else False\n }\n\ndef send_batch_to_stream(events, batch_size=100):\n \"\"\"Send events to Cloudflare Stream in batches\"\"\"\n\n headers = {\n \"Authorization\": f\"Bearer {API_TOKEN}\",\n \"Content-Type\": \"application/json\"\n }\n\n total_sent = 0\n fraud_count = 0\n\n for i in range(0, len(events), batch_size):\n batch = events[i:i + batch_size]\n fraud_in_batch = sum(1 for event in batch if event[\"is_fraud\"] == True)\n\n try:\n response = requests.post(STREAM_ENDPOINT, headers=headers, json=batch)\n\n if response.status_code in [200, 201]:\n total_sent += len(batch)\n fraud_count += fraud_in_batch\n print(f\"Sent batch of {len(batch)} events (Total: {total_sent})\")\n else:\n print(f\"Failed to send batch: {response.status_code} - {response.text}\")\n\n except Exception as e:\n print(f\"Error sending batch: {e}\")\n\n time.sleep(0.1)\n\n return total_sent, fraud_count\n\ndef main():\n print(\"Generating fraud detection data...\")\n\n # Generate events\n events = []\n for i in range(EVENTS_TO_SEND):\n events.append(generate_transaction())\n if (i + 1) % 100 == 0:\n print(f\"Generated {i + 1} events...\")\n\n fraud_events = sum(1 for event in events if event[\"is_fraud\"] == True)\n print(f\"📊 Generated {len(events)} total events ({fraud_events} fraud, {fraud_events/len(events)*100:.1f}%)\")\n\n # Send to stream\n print(\"Sending data to Pipeline stream...\")\n sent, fraud_sent = send_batch_to_stream(events)\n\n print(f\"\\nComplete!\")\n print(f\" Events sent: {sent:,}\")\n print(f\" Fraud events: {fraud_sent:,} ({fraud_sent/sent*100:.1f}%)\")\n print(f\" Data is now flowing through your pipeline!\")\n\nif __name__ == \"__main__\":\n main()\n```\n\nExample:\n```text\npip install requests\npython fraud_data_generator.py\n```\n\nExample:\n```text\nnpx wrangler r2 sql query \"$WAREHOUSE\" \"\nSELECT\n transaction_id,\n user_id,\n amount,\n location,\n merchant_category,\n is_fraud,\n transaction_timestamp\nFROM fraud_detection.transactions\nWHERE __ingest_ts > '2025-09-24T01:00:00Z'\nAND is_fraud = true\nLIMIT 10\"\n```\n\nExample:\n```text\nnpx wrangler pipelines sinks create fraud_filter_sink \\\n --type \"r2-data-catalog\" \\\n --bucket \"fraud-pipeline\" \\\n --roll-interval 30 \\\n --namespace \"fraud_detection\" \\\n --table \"fraud_transactions\" \\\n --catalog-token $WRANGLER_R2_SQL_AUTH_TOKEN\n```\n\nExample:\n```text\nnpx wrangler pipelines create fraud_events_pipeline \\\n --sql \"INSERT INTO fraud_filter_sink SELECT * FROM raw_events_stream WHERE is_fraud=true and amount > 1000\"\n```\n\nExample:\n```text\nnpx wrangler r2 sql query \"$WAREHOUSE\" \"\nSELECT\n transaction_id,\n user_id,\n amount,\n location,\n merchant_category,\n is_fraud,\n transaction_timestamp\nFROM fraud_detection.fraud_transactions\nLIMIT 10\"\n```\n\nExample:\n```text\nnpx wrangler r2 sql query \"$WAREHOUSE\" \"\nSELECT\n transaction_id,\n user_id,\n amount,\n location,\n merchant_category,\n is_fraud,\n transaction_timestamp\nFROM fraud_detection.fraud_transactions\nWHERE is_fraud = false\nLIMIT 10\"\n```\n\nExample:\n```text\nQuery executed successfully with no results\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.180Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":21,"totalLines":335,"estimatedTokens":2357}}99{"id":"doc-sql_reference_r2_sql_docs-e72fe1e4","source":"documentation","title":"SQL reference · R2 SQL docs","url":"https://developers.cloudflare.com/r2-sql/sql-reference/","text":"Documentation IndexFetch the complete documentation index ://developers.cloudflare.com/r2-sql/llms.txtUse this file to discover all available pages before exploring further.\n\nExample:\n```text\nSELECT [DISTINCT] column_list | expression | aggregate_function | window_function\nFROM namespace_name.table_name\n[JOIN namespace_name.table_name ON condition]\n[WHERE conditions]\n[GROUP BY column_list]\n[HAVING conditions]\n[QUALIFY window_condition]\n[ORDER BY expression [ASC | DESC]]\n[LIMIT number]\n```\n\nExample:\n```text\nSHOW DATABASES;\n```\n\nExample:\n```text\nSHOW NAMESPACES;\n```\n\nExample:\n```text\nSHOW TABLES IN namespace_name;\n```\n\nExample:\n```text\nDESCRIBE namespace_name.table_name;\n```\n\nExample:\n```text\nSELECT [DISTINCT] column_specification [, column_specification, ...]\n```\n\nExample:\n```text\nSELECT * FROM my_namespace.sales_data LIMIT 10\nSELECT customer_id, region, total_amount FROM my_namespace.sales_data LIMIT 10\nSELECT region, total_amount * 1.1 AS total_with_tax FROM my_namespace.sales_data LIMIT 10\n```\n\nExample:\n```text\n-- Unique combinations\nSELECT DISTINCT region, department FROM my_namespace.sales_data\n\n-- First row per region by amount\nSELECT DISTINCT ON (region) region, customer_id, total_amount\nFROM my_namespace.sales_data\nORDER BY region, total_amount DESC\n```\n\nExample:\n```text\nWITH cte_name AS (\n SELECT ...\n FROM namespace_name.table_name\n [WHERE ...]\n)\nSELECT ... FROM cte_name\n```\n\nExample:\n```text\nWITH filtered AS (\n SELECT customer_id, department, total_amount\n FROM my_namespace.sales_data\n WHERE total_amount > 0\n),\nsummary AS (\n SELECT department,\n COUNT(*) AS order_count,\n round(AVG(total_amount), 2) AS avg_amount\n FROM filtered\n GROUP BY department\n)\nSELECT *\nFROM summary\nWHERE order_count > 100\nORDER BY avg_amount DESC\n```\n\nExample:\n```text\nWITH enterprise_zones AS (\n SELECT zone_id, domain, plan\n FROM my_namespace.zones\n WHERE plan = 'enterprise'\n)\nSELECT ez.domain, f.action, COUNT(*) AS cnt\nFROM enterprise_zones ez\nINNER JOIN my_namespace.firewall_events f ON ez.zone_id = f.zone_id\nGROUP BY ez.domain, f.action\nORDER BY cnt DESC\nLIMIT 20\n```\n\nExample:\n```text\nWITH top_zones AS (\n SELECT zone_id, COUNT(*) AS req_count\n FROM my_namespace.http_requests\n GROUP BY zone_id\n ORDER BY req_count DESC\n LIMIT 50\n),\nzone_threats AS (\n SELECT zone_id, COUNT(*) AS threat_count\n FROM my_namespace.firewall_events\n WHERE risk_score > 0.5\n GROUP BY zone_id\n)\nSELECT tz.zone_id, tz.req_count, COALESCE(zt.threat_count, 0) AS threat_count\nFROM top_zones tz\nLEFT JOIN zone_threats zt ON tz.zone_id = zt.zone_id\nORDER BY tz.req_count DESC\nLIMIT 20\n```\n\nExample:\n```text\nSELECT * FROM namespace_name.table_name\n```\n\nExample:\n```text\n-- Explicit JOIN\nSELECT columns\nFROM namespace.table1 alias1\n[INNER | LEFT | RIGHT | FULL OUTER | CROSS] JOIN namespace.table2 alias2\n ON alias1.column = alias2.column\n[WHERE conditions]\n\n-- Implicit join\nSELECT columns\nFROM namespace.table1 alias1, namespace.table2 alias2\nWHERE alias1.column = alias2.column\n```\n\nExample:\n```text\nSELECT z.domain, h.method, f.action, COUNT(*) AS cnt\nFROM my_namespace.zones z\nINNER JOIN my_namespace.http_requests h ON z.zone_id = h.zone_id\nINNER JOIN my_namespace.firewall_events f ON z.zone_id = f.zone_id\nWHERE h.status_code >= 400\nGROUP BY z.domain, h.method, f.action\nORDER BY cnt DESC\nLIMIT 20\n```\n\nExample:\n```text\nSELECT f1.source_ip, f1.zone_id AS zone1, f2.zone_id AS zone2\nFROM my_namespace.firewall_events f1\nINNER JOIN my_namespace.firewall_events f2\n ON f1.source_ip = f2.source_ip\n AND f1.zone_id < f2.zone_id\nWHERE f1.action = 'block'\nLIMIT 20\n```\n\nExample:\n```text\n-- Not supported\nSELECT * FROM (t1 JOIN t2 ON t1.id = t2.id) JOIN t3 ON t2.id = t3.id\n\n-- Supported\nSELECT * FROM t1 JOIN t2 ON t1.id = t2.id JOIN t3 ON t2.id = t3.id\n```\n\nExample:\n```text\nSELECT sub.domain, sub.total_requests\nFROM (\n SELECT z.domain, COUNT(*) AS total_requests\n FROM my_namespace.zones z\n INNER JOIN my_namespace.http_requests h ON z.zone_id = h.zone_id\n GROUP BY z.domain\n) sub\nWHERE sub.total_requests > 1000\nORDER BY sub.total_requests DESC\nLIMIT 20\n```\n\nExample:\n```text\nSELECT req.domain, req.total_reqs, fw.total_events\nFROM (\n SELECT zone_id, domain, COUNT(*) AS total_reqs\n FROM my_namespace.zones z\n INNER JOIN my_namespace.http_requests h ON z.zone_id = h.zone_id\n GROUP BY zone_id, domain\n) req\nINNER JOIN (\n SELECT zone_id, COUNT(*) AS total_events\n FROM my_namespace.firewall_events\n GROUP BY zone_id\n) fw ON req.zone_id = fw.zone_id\nORDER BY fw.total_events DESC\nLIMIT 20\n```\n\nExample:\n```text\n-- Find requests from enterprise zones\nSELECT method, status_code, COUNT(*) AS cnt\nFROM my_namespace.http_requests\nWHERE zone_id IN (\n SELECT zone_id FROM my_namespace.zones WHERE plan = 'enterprise'\n)\nGROUP BY method, status_code\nORDER BY cnt DESC\nLIMIT 20\n```\n\nExample:\n```text\n-- NOT IN example\nSELECT zone_id, COUNT(*) AS cnt\nFROM my_namespace.http_requests\nWHERE zone_id NOT IN (\n SELECT zone_id FROM my_namespace.firewall_events WHERE action = 'block'\n)\nGROUP BY zone_id\nLIMIT 10\n```\n\nExample:\n```text\n-- Instead of NOT IN on a nullable column:\nSELECT z.domain\nFROM my_namespace.zones z\nWHERE NOT EXISTS (\n SELECT 1 FROM my_namespace.firewall_events f\n WHERE f.zone_id = z.zone_id\n)\nLIMIT 20\n```\n\nExample:\n```text\n-- Find zones with blocked firewall events (semi-join)\nSELECT z.domain, z.plan\nFROM my_namespace.zones z\nWHERE EXISTS (\n SELECT 1 FROM my_namespace.firewall_events f\n WHERE f.zone_id = z.zone_id AND f.action = 'block'\n)\nORDER BY z.domain\nLIMIT 20\n```\n\nExample:\n```text\n-- Find zones with NO firewall events (anti-join)\nSELECT z.domain, z.plan\nFROM my_namespace.zones z\nWHERE NOT EXISTS (\n SELECT 1 FROM my_namespace.firewall_events f\n WHERE f.zone_id = z.zone_id\n)\nORDER BY z.domain\nLIMIT 20\n```\n\nExample:\n```text\n-- In SELECT (constant value per row)\nSELECT z.domain, z.plan,\n (SELECT COUNT(*) FROM my_namespace.zones) AS total_zones\nFROM my_namespace.zones z\nWHERE z.plan = 'enterprise'\nLIMIT 10\n```\n\nExample:\n```text\n-- In WHERE (comparison)\nSELECT z.domain, z.plan, z.requests_30d\nFROM my_namespace.zones z\nWHERE z.requests_30d > (\n SELECT AVG(requests_30d) FROM my_namespace.zones\n)\nORDER BY z.requests_30d DESC\nLIMIT 20\n```\n\nExample:\n```text\nSELECT * FROM namespace_name.table_name WHERE condition [AND | OR condition ...]\n```\n\nExample:\n```text\nSELECT * FROM my_namespace.sales_data\nWHERE timestamp BETWEEN '2025-09-24T01:00:00Z' AND '2025-09-25T01:00:00Z'\n\nSELECT * FROM my_namespace.sales_data\nWHERE status = 200 AND response_time > 1000\n\nSELECT * FROM my_namespace.sales_data\nWHERE (region = 'North' OR region = 'South')\n AND total_amount IS NOT NULL\n\nSELECT * FROM my_namespace.sales_data\nWHERE department ILIKE '%eng%'\n```\n\nExample:\n```text\nSELECT column_list, aggregation_function(column)\nFROM namespace_name.table_name\n[WHERE conditions]\nGROUP BY column_list\n```\n\nExample:\n```text\nSELECT department, COUNT(*) AS dept_count\nFROM my_namespace.sales_data\nGROUP BY department\n\nSELECT department, category, SUM(total_amount) AS total\nFROM my_namespace.sales_data\nGROUP BY department, category\n```\n\nExample:\n```text\n-- Subtotals per department plus a grand total\nSELECT department, SUM(total_amount) AS total\nFROM my_namespace.sales_data\nGROUP BY ROLLUP(department)\n\n-- Every combination of department and category\nSELECT department, category, SUM(total_amount) AS total\nFROM my_namespace.sales_data\nGROUP BY CUBE(department, category)\n\n-- Explicit groupings\nSELECT department, category, SUM(total_amount) AS total\nFROM my_namespace.sales_data\nGROUP BY GROUPING SETS ((department, category), (department), ())\n```\n\nExample:\n```text\nSELECT column_list, aggregation_function(column) AS alias\nFROM namespace_name.table_name\nGROUP BY column_list\nHAVING aggregation_function(column) comparison_operator value\n```\n\nExample:\n```text\nSELECT department, COUNT(*) AS dept_count\nFROM my_namespace.sales_data\nGROUP BY department\nHAVING COUNT(*) > 1000\n\nSELECT region, SUM(total_amount) AS total\nFROM my_namespace.sales_data\nGROUP BY region\nHAVING SUM(total_amount) > 1000000\n```\n\nExample:\n```text\nORDER BY expression [ASC | DESC] [, expression [ASC | DESC], ...]\n```\n\nExample:\n```text\nSELECT customer_id, total_amount\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL\nORDER BY total_amount DESC\nLIMIT 50\n\nSELECT department, COUNT(*) AS dept_count\nFROM my_namespace.sales_data\nGROUP BY department\nORDER BY dept_count DESC, department ASC\n```\n\nExample:\n```text\nLIMIT number\n```\n\nExample:\n```text\nSELECT * FROM my_namespace.sales_data LIMIT 100\n```\n\nExample:\n```text\nfunction(args) OVER (\n [PARTITION BY expression [, ...]]\n [ORDER BY expression [ASC | DESC] [, ...]]\n [frame_specification]\n)\n```\n\nExample:\n```text\n-- Rank rows within each partition\nSELECT customer_id, region,\n ROW_NUMBER() OVER (PARTITION BY region ORDER BY total_amount DESC) AS rank_in_region,\n LAG(total_amount) OVER (PARTITION BY region ORDER BY total_amount DESC) AS prev_amount\nFROM my_namespace.sales_data\n\n-- Running total with an explicit frame\nSELECT customer_id, total_amount,\n SUM(total_amount) OVER (ORDER BY total_amount ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS running_total\nFROM my_namespace.sales_data\n```\n\nExample:\n```text\n-- Keep only the top 3 customers by amount in each region\nSELECT customer_id, region, total_amount\nFROM my_namespace.sales_data\nQUALIFY ROW_NUMBER() OVER (PARTITION BY region ORDER BY total_amount DESC) <= 3\n```\n\nExample:\n```text\nSELECT ... FROM table1\nUNION | UNION ALL | INTERSECT | EXCEPT\nSELECT ... FROM table2\n```\n\nExample:\n```text\n-- Find zones that had either firewall blocks OR high-risk requests\nSELECT zone_id FROM my_namespace.firewall_events WHERE action = 'block'\nUNION\nSELECT zone_id FROM my_namespace.http_requests WHERE risk_score > 0.8\n```\n\nExample:\n```text\n-- Find zones with both firewall blocks AND entries in the zones table\nSELECT zone_id FROM my_namespace.firewall_events WHERE action = 'block'\nINTERSECT\nSELECT zone_id FROM my_namespace.zones WHERE plan = 'enterprise'\n```\n\nExample:\n```text\n-- Find enterprise zones that have no firewall events\nSELECT zone_id FROM my_namespace.zones WHERE plan = 'enterprise'\nEXCEPT\nSELECT zone_id FROM my_namespace.firewall_events\n```\n\nExample:\n```text\nEXPLAIN SELECT department, COUNT(*) AS dept_count\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL\nGROUP BY department;\n```\n\nExample:\n```text\nEXPLAIN FORMAT JSON SELECT * FROM my_namespace.sales_data LIMIT 10;\n```\n\nExample:\n```text\nSELECT 42 AS int_val, 3.14 AS float_val, 'hello' AS str_val, TRUE AS bool_val, NULL AS null_val\nFROM my_namespace.sales_data LIMIT 1\n```\n\nExample:\n```text\nSELECT customer_id, total_amount * 1.1 AS total_with_tax, total_amount % 10 AS remainder\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL\nLIMIT 5\n```\n\nExample:\n```text\nSELECT customer_id || ' - ' || region AS label\nFROM my_namespace.sales_data\nLIMIT 5\n```\n\nExample:\n```text\nSELECT customer_id,\n CASE\n WHEN total_amount > 1000 THEN 'high'\n WHEN total_amount > 100 THEN 'medium'\n ELSE 'low'\n END AS tier\nFROM my_namespace.sales_data\nLIMIT 10\n```\n\nExample:\n```text\nSELECT customer_id,\n CASE region\n WHEN 'North' THEN 'N'\n WHEN 'South' THEN 'S'\n ELSE 'Other'\n END AS region_code\nFROM my_namespace.sales_data\nLIMIT 10\n```\n\nExample:\n```text\n-- CAST\nSELECT CAST(total_amount AS INT) AS amount_int FROM my_namespace.sales_data LIMIT 5\n\n-- TRY_CAST (returns NULL on failure instead of error)\nSELECT TRY_CAST(customer_id AS INT) AS id_int FROM my_namespace.sales_data LIMIT 5\n\n-- Shorthand (::)\nSELECT total_amount::INT AS amount_int FROM my_namespace.sales_data LIMIT 5\n```\n\nExample:\n```text\nSELECT EXTRACT(YEAR FROM timestamp) AS yr,\n EXTRACT(MONTH FROM timestamp) AS mo,\n EXTRACT(DAY FROM timestamp) AS dy\nFROM my_namespace.sales_data\nLIMIT 1\n```\n\nExample:\n```text\nSELECT * FROM my_namespace.sales_data WHERE (status = 404 OR status = 500) AND region = 'North'\n```\n\nExample:\n```text\nSELECT *\nFROM my_namespace.sales_data\nWHERE timestamp BETWEEN '2025-09-24T01:00:00Z' AND '2025-09-25T01:00:00Z'\nLIMIT 100\n```\n\nExample:\n```text\nSELECT customer_id, timestamp, status, total_amount\nFROM my_namespace.sales_data\nWHERE status >= 400 AND total_amount > 5000\nORDER BY total_amount DESC\nLIMIT 50\n```\n\nExample:\n```text\nSELECT region, COUNT(*) AS region_count, AVG(total_amount) AS avg_amount\nFROM my_namespace.sales_data\nWHERE status = 'completed'\nGROUP BY region\nHAVING COUNT(*) > 1000\nORDER BY avg_amount DESC\nLIMIT 20\n```\n\nExample:\n```text\nSELECT customer_id,\n CASE\n WHEN total_amount >= 1000 THEN 'Premium'\n WHEN total_amount >= 100 THEN 'Standard'\n ELSE 'Basic'\n END AS tier,\n total_amount\nFROM my_namespace.sales_data\nWHERE total_amount IS NOT NULL\nORDER BY total_amount DESC\nLIMIT 20\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:16:47.181Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":58,"totalLines":592,"estimatedTokens":3233}}100 