[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-encore-encore-go-bucket":3,"mdc--9siopv-key":40,"related-org-encore-encore-go-bucket":789,"related-repo-encore-encore-go-bucket":953},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":12,"stars":27,"repoUrl":28,"updatedAt":29,"license":30,"forks":31,"topics":32,"repo":35,"sourceUrl":38,"mdContent":39},"encore-go-bucket","store files in Encore Go buckets","Store unstructured files in Encore Go using `objects.NewBucket` from `encore.dev\u002Fstorage\u002Fobjects` — uploads, images, documents, blobs.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},"encore","Encore","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fencore.png","encoredev",[13,17,20,21,24],{"name":14,"slug":15,"type":16},"Backend","backend","tag",{"name":18,"slug":19,"type":16},"File Storage","file-storage",{"name":9,"slug":8,"type":16},{"name":22,"slug":23,"type":16},"Storage","storage",{"name":25,"slug":26,"type":16},"Go","go",26,"https:\u002F\u002Fgithub.com\u002Fencoredev\u002Fskills","2026-05-16T06:00:03.633918",null,5,[33,34],"claude-code","skills",{"repoUrl":28,"stars":27,"forks":31,"topics":36,"description":37},[33,34],"Agent Skills for development with Encore.","https:\u002F\u002Fgithub.com\u002Fencoredev\u002Fskills\u002Ftree\u002FHEAD\u002Fencore\u002Fgo-bucket","---\nname: encore-go-bucket\ndescription: Store unstructured files in Encore Go using `objects.NewBucket` from `encore.dev\u002Fstorage\u002Fobjects` — uploads, images, documents, blobs.\nwhen_to_use: >-\n  User wants to upload, download, list, or delete files from an Encore Go service — profile pictures, avatars, document uploads, image storage, media assets, generated reports, blob data. Covers public vs private buckets, signed upload\u002Fdownload URLs, bucket references with permission types (Uploader, Downloader, Lister, Attrser, Remover), and operations like `Upload`, `Download`, `List`, `SignedUploadURL`. Trigger phrases: \"object storage\", \"bucket\", \"S3\", \"GCS\", \"blob\", \"user uploads\", \"profile picture\", \"image upload\", \"store a file\", \"file storage\".\n---\n\n# Encore Go Object Storage\n\n## Instructions\n\nA `Bucket` is a logical store for files. Encore provisions the underlying object storage (S3 on AWS, GCS on GCP, in-memory locally). Declare buckets as package-level variables.\n\n```go\npackage uploads\n\nimport \"encore.dev\u002Fstorage\u002Fobjects\"\n\n\u002F\u002F Private bucket (default)\nvar Uploads = objects.NewBucket(\"user-uploads\", objects.BucketConfig{})\n\n\u002F\u002F Public bucket — files accessible via public URL\nvar PublicAssets = objects.NewBucket(\"public-assets\", objects.BucketConfig{\n    Public: true,\n})\n```\n\n## Operations\n\n```go\nimport (\n    \"fmt\"\n    \"io\"\n)\n\n\u002F\u002F Upload (streaming pattern)\nwriter := Uploads.Upload(ctx, \"path\u002Fto\u002Ffile.jpg\")\n_, err := io.Copy(writer, dataReader)\nif err != nil {\n    writer.Abort()\n    return err\n}\nerr = writer.Close()\n\n\u002F\u002F Download\nreader := Uploads.Download(ctx, \"path\u002Fto\u002Ffile.jpg\")\nif err := reader.Err(); err != nil {\n    return err\n}\ndefer reader.Close()\ndata, _ := io.ReadAll(reader)\n\n\u002F\u002F Existence check\nexists, err := Uploads.Exists(ctx, \"path\u002Fto\u002Ffile.jpg\")\n\n\u002F\u002F Attributes (size, content type, ETag)\nattrs, err := Uploads.Attrs(ctx, \"path\u002Fto\u002Ffile.jpg\")\n\n\u002F\u002F List\nfor err, entry := range Uploads.List(ctx, &objects.Query{}) {\n    if err != nil {\n        return err\n    }\n    fmt.Println(entry.Key, entry.Size)\n}\n\n\u002F\u002F Delete\nerr := Uploads.Remove(ctx, \"path\u002Fto\u002Ffile.jpg\")\n\n\u002F\u002F Public URL (only for public buckets)\nurl := PublicAssets.PublicURL(\"image.jpg\")\n```\n\n## Signed URLs\n\nGenerate temporary URLs so clients can upload\u002Fdownload directly without going through your service:\n\n```go\nimport \"time\"\n\n\u002F\u002F Signed upload URL (expires in 2 hours)\nurl, err := Uploads.SignedUploadURL(ctx, \"user-uploads\u002Favatar.jpg\",\n    objects.WithTTL(time.Duration(7200)*time.Second))\n\n\u002F\u002F Signed download URL\nurl, err := Uploads.SignedDownloadURL(ctx, \"documents\u002Freport.pdf\",\n    objects.WithTTL(time.Duration(7200)*time.Second))\n```\n\n## Bucket References\n\nPass bucket access to library code with a specific permission set:\n\n```go\n\u002F\u002F Create a reference with download permission only\nref := objects.BucketRef[objects.Downloader](Uploads)\n\n\u002F\u002F Combine permissions via an interface\ntype myPerms interface {\n    objects.Downloader\n    objects.Uploader\n}\nref := objects.BucketRef[myPerms](Uploads)\n\n\u002F\u002F Permission types: Downloader, Uploader, Lister, Attrser, Remover,\n\u002F\u002F SignedDownloader, SignedUploader, ReadWriter\n```\n\n## Guidelines\n\n- Declare buckets as package-level variables.\n- Default to private buckets; opt into `Public: true` only for assets meant for unauthenticated download.\n- Use signed URLs for browser uploads\u002Fdownloads instead of streaming through your service.\n- Use bucket references when passing access to helpers — they encode the permission contract in the type system.\n",{"data":41,"body":43},{"name":4,"description":6,"when_to_use":42},"User wants to upload, download, list, or delete files from an Encore Go service — profile pictures, avatars, document uploads, image storage, media assets, generated reports, blob data. Covers public vs private buckets, signed upload\u002Fdownload URLs, bucket references with permission types (Uploader, Downloader, Lister, Attrser, Remover), and operations like `Upload`, `Download`, `List`, `SignedUploadURL`. Trigger phrases: \"object storage\", \"bucket\", \"S3\", \"GCS\", \"blob\", \"user uploads\", \"profile picture\", \"image upload\", \"store a file\", \"file storage\".",{"type":44,"children":45},"root",[46,55,62,77,186,192,546,552,557,633,639,644,744,750,783],{"type":47,"tag":48,"props":49,"children":51},"element","h1",{"id":50},"encore-go-object-storage",[52],{"type":53,"value":54},"text","Encore Go Object Storage",{"type":47,"tag":56,"props":57,"children":59},"h2",{"id":58},"instructions",[60],{"type":53,"value":61},"Instructions",{"type":47,"tag":63,"props":64,"children":65},"p",{},[66,68,75],{"type":53,"value":67},"A ",{"type":47,"tag":69,"props":70,"children":72},"code",{"className":71},[],[73],{"type":53,"value":74},"Bucket",{"type":53,"value":76}," is a logical store for files. Encore provisions the underlying object storage (S3 on AWS, GCS on GCP, in-memory locally). Declare buckets as package-level variables.",{"type":47,"tag":78,"props":79,"children":83},"pre",{"className":80,"code":81,"language":26,"meta":82,"style":82},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","package uploads\n\nimport \"encore.dev\u002Fstorage\u002Fobjects\"\n\n\u002F\u002F Private bucket (default)\nvar Uploads = objects.NewBucket(\"user-uploads\", objects.BucketConfig{})\n\n\u002F\u002F Public bucket — files accessible via public URL\nvar PublicAssets = objects.NewBucket(\"public-assets\", objects.BucketConfig{\n    Public: true,\n})\n","",[84],{"type":47,"tag":69,"props":85,"children":86},{"__ignoreMap":82},[87,98,108,117,125,133,142,150,159,168,177],{"type":47,"tag":88,"props":89,"children":92},"span",{"class":90,"line":91},"line",1,[93],{"type":47,"tag":88,"props":94,"children":95},{},[96],{"type":53,"value":97},"package uploads\n",{"type":47,"tag":88,"props":99,"children":101},{"class":90,"line":100},2,[102],{"type":47,"tag":88,"props":103,"children":105},{"emptyLinePlaceholder":104},true,[106],{"type":53,"value":107},"\n",{"type":47,"tag":88,"props":109,"children":111},{"class":90,"line":110},3,[112],{"type":47,"tag":88,"props":113,"children":114},{},[115],{"type":53,"value":116},"import \"encore.dev\u002Fstorage\u002Fobjects\"\n",{"type":47,"tag":88,"props":118,"children":120},{"class":90,"line":119},4,[121],{"type":47,"tag":88,"props":122,"children":123},{"emptyLinePlaceholder":104},[124],{"type":53,"value":107},{"type":47,"tag":88,"props":126,"children":127},{"class":90,"line":31},[128],{"type":47,"tag":88,"props":129,"children":130},{},[131],{"type":53,"value":132},"\u002F\u002F Private bucket (default)\n",{"type":47,"tag":88,"props":134,"children":136},{"class":90,"line":135},6,[137],{"type":47,"tag":88,"props":138,"children":139},{},[140],{"type":53,"value":141},"var Uploads = objects.NewBucket(\"user-uploads\", objects.BucketConfig{})\n",{"type":47,"tag":88,"props":143,"children":145},{"class":90,"line":144},7,[146],{"type":47,"tag":88,"props":147,"children":148},{"emptyLinePlaceholder":104},[149],{"type":53,"value":107},{"type":47,"tag":88,"props":151,"children":153},{"class":90,"line":152},8,[154],{"type":47,"tag":88,"props":155,"children":156},{},[157],{"type":53,"value":158},"\u002F\u002F Public bucket — files accessible via public URL\n",{"type":47,"tag":88,"props":160,"children":162},{"class":90,"line":161},9,[163],{"type":47,"tag":88,"props":164,"children":165},{},[166],{"type":53,"value":167},"var PublicAssets = objects.NewBucket(\"public-assets\", objects.BucketConfig{\n",{"type":47,"tag":88,"props":169,"children":171},{"class":90,"line":170},10,[172],{"type":47,"tag":88,"props":173,"children":174},{},[175],{"type":53,"value":176},"    Public: true,\n",{"type":47,"tag":88,"props":178,"children":180},{"class":90,"line":179},11,[181],{"type":47,"tag":88,"props":182,"children":183},{},[184],{"type":53,"value":185},"})\n",{"type":47,"tag":56,"props":187,"children":189},{"id":188},"operations",[190],{"type":53,"value":191},"Operations",{"type":47,"tag":78,"props":193,"children":195},{"className":80,"code":194,"language":26,"meta":82,"style":82},"import (\n    \"fmt\"\n    \"io\"\n)\n\n\u002F\u002F Upload (streaming pattern)\nwriter := Uploads.Upload(ctx, \"path\u002Fto\u002Ffile.jpg\")\n_, err := io.Copy(writer, dataReader)\nif err != nil {\n    writer.Abort()\n    return err\n}\nerr = writer.Close()\n\n\u002F\u002F Download\nreader := Uploads.Download(ctx, \"path\u002Fto\u002Ffile.jpg\")\nif err := reader.Err(); err != nil {\n    return err\n}\ndefer reader.Close()\ndata, _ := io.ReadAll(reader)\n\n\u002F\u002F Existence check\nexists, err := Uploads.Exists(ctx, \"path\u002Fto\u002Ffile.jpg\")\n\n\u002F\u002F Attributes (size, content type, ETag)\nattrs, err := Uploads.Attrs(ctx, \"path\u002Fto\u002Ffile.jpg\")\n\n\u002F\u002F List\nfor err, entry := range Uploads.List(ctx, &objects.Query{}) {\n    if err != nil {\n        return err\n    }\n    fmt.Println(entry.Key, entry.Size)\n}\n\n\u002F\u002F Delete\nerr := Uploads.Remove(ctx, \"path\u002Fto\u002Ffile.jpg\")\n\n\u002F\u002F Public URL (only for public buckets)\nurl := PublicAssets.PublicURL(\"image.jpg\")\n",[196],{"type":47,"tag":69,"props":197,"children":198},{"__ignoreMap":82},[199,207,215,223,231,238,246,254,262,270,278,286,295,304,312,321,330,339,347,355,364,373,381,390,399,407,415,424,432,441,450,459,468,477,486,494,502,511,520,528,537],{"type":47,"tag":88,"props":200,"children":201},{"class":90,"line":91},[202],{"type":47,"tag":88,"props":203,"children":204},{},[205],{"type":53,"value":206},"import (\n",{"type":47,"tag":88,"props":208,"children":209},{"class":90,"line":100},[210],{"type":47,"tag":88,"props":211,"children":212},{},[213],{"type":53,"value":214},"    \"fmt\"\n",{"type":47,"tag":88,"props":216,"children":217},{"class":90,"line":110},[218],{"type":47,"tag":88,"props":219,"children":220},{},[221],{"type":53,"value":222},"    \"io\"\n",{"type":47,"tag":88,"props":224,"children":225},{"class":90,"line":119},[226],{"type":47,"tag":88,"props":227,"children":228},{},[229],{"type":53,"value":230},")\n",{"type":47,"tag":88,"props":232,"children":233},{"class":90,"line":31},[234],{"type":47,"tag":88,"props":235,"children":236},{"emptyLinePlaceholder":104},[237],{"type":53,"value":107},{"type":47,"tag":88,"props":239,"children":240},{"class":90,"line":135},[241],{"type":47,"tag":88,"props":242,"children":243},{},[244],{"type":53,"value":245},"\u002F\u002F Upload (streaming pattern)\n",{"type":47,"tag":88,"props":247,"children":248},{"class":90,"line":144},[249],{"type":47,"tag":88,"props":250,"children":251},{},[252],{"type":53,"value":253},"writer := Uploads.Upload(ctx, \"path\u002Fto\u002Ffile.jpg\")\n",{"type":47,"tag":88,"props":255,"children":256},{"class":90,"line":152},[257],{"type":47,"tag":88,"props":258,"children":259},{},[260],{"type":53,"value":261},"_, err := io.Copy(writer, dataReader)\n",{"type":47,"tag":88,"props":263,"children":264},{"class":90,"line":161},[265],{"type":47,"tag":88,"props":266,"children":267},{},[268],{"type":53,"value":269},"if err != nil {\n",{"type":47,"tag":88,"props":271,"children":272},{"class":90,"line":170},[273],{"type":47,"tag":88,"props":274,"children":275},{},[276],{"type":53,"value":277},"    writer.Abort()\n",{"type":47,"tag":88,"props":279,"children":280},{"class":90,"line":179},[281],{"type":47,"tag":88,"props":282,"children":283},{},[284],{"type":53,"value":285},"    return err\n",{"type":47,"tag":88,"props":287,"children":289},{"class":90,"line":288},12,[290],{"type":47,"tag":88,"props":291,"children":292},{},[293],{"type":53,"value":294},"}\n",{"type":47,"tag":88,"props":296,"children":298},{"class":90,"line":297},13,[299],{"type":47,"tag":88,"props":300,"children":301},{},[302],{"type":53,"value":303},"err = writer.Close()\n",{"type":47,"tag":88,"props":305,"children":307},{"class":90,"line":306},14,[308],{"type":47,"tag":88,"props":309,"children":310},{"emptyLinePlaceholder":104},[311],{"type":53,"value":107},{"type":47,"tag":88,"props":313,"children":315},{"class":90,"line":314},15,[316],{"type":47,"tag":88,"props":317,"children":318},{},[319],{"type":53,"value":320},"\u002F\u002F Download\n",{"type":47,"tag":88,"props":322,"children":324},{"class":90,"line":323},16,[325],{"type":47,"tag":88,"props":326,"children":327},{},[328],{"type":53,"value":329},"reader := Uploads.Download(ctx, \"path\u002Fto\u002Ffile.jpg\")\n",{"type":47,"tag":88,"props":331,"children":333},{"class":90,"line":332},17,[334],{"type":47,"tag":88,"props":335,"children":336},{},[337],{"type":53,"value":338},"if err := reader.Err(); err != nil {\n",{"type":47,"tag":88,"props":340,"children":342},{"class":90,"line":341},18,[343],{"type":47,"tag":88,"props":344,"children":345},{},[346],{"type":53,"value":285},{"type":47,"tag":88,"props":348,"children":350},{"class":90,"line":349},19,[351],{"type":47,"tag":88,"props":352,"children":353},{},[354],{"type":53,"value":294},{"type":47,"tag":88,"props":356,"children":358},{"class":90,"line":357},20,[359],{"type":47,"tag":88,"props":360,"children":361},{},[362],{"type":53,"value":363},"defer reader.Close()\n",{"type":47,"tag":88,"props":365,"children":367},{"class":90,"line":366},21,[368],{"type":47,"tag":88,"props":369,"children":370},{},[371],{"type":53,"value":372},"data, _ := io.ReadAll(reader)\n",{"type":47,"tag":88,"props":374,"children":376},{"class":90,"line":375},22,[377],{"type":47,"tag":88,"props":378,"children":379},{"emptyLinePlaceholder":104},[380],{"type":53,"value":107},{"type":47,"tag":88,"props":382,"children":384},{"class":90,"line":383},23,[385],{"type":47,"tag":88,"props":386,"children":387},{},[388],{"type":53,"value":389},"\u002F\u002F Existence check\n",{"type":47,"tag":88,"props":391,"children":393},{"class":90,"line":392},24,[394],{"type":47,"tag":88,"props":395,"children":396},{},[397],{"type":53,"value":398},"exists, err := Uploads.Exists(ctx, \"path\u002Fto\u002Ffile.jpg\")\n",{"type":47,"tag":88,"props":400,"children":402},{"class":90,"line":401},25,[403],{"type":47,"tag":88,"props":404,"children":405},{"emptyLinePlaceholder":104},[406],{"type":53,"value":107},{"type":47,"tag":88,"props":408,"children":409},{"class":90,"line":27},[410],{"type":47,"tag":88,"props":411,"children":412},{},[413],{"type":53,"value":414},"\u002F\u002F Attributes (size, content type, ETag)\n",{"type":47,"tag":88,"props":416,"children":418},{"class":90,"line":417},27,[419],{"type":47,"tag":88,"props":420,"children":421},{},[422],{"type":53,"value":423},"attrs, err := Uploads.Attrs(ctx, \"path\u002Fto\u002Ffile.jpg\")\n",{"type":47,"tag":88,"props":425,"children":427},{"class":90,"line":426},28,[428],{"type":47,"tag":88,"props":429,"children":430},{"emptyLinePlaceholder":104},[431],{"type":53,"value":107},{"type":47,"tag":88,"props":433,"children":435},{"class":90,"line":434},29,[436],{"type":47,"tag":88,"props":437,"children":438},{},[439],{"type":53,"value":440},"\u002F\u002F List\n",{"type":47,"tag":88,"props":442,"children":444},{"class":90,"line":443},30,[445],{"type":47,"tag":88,"props":446,"children":447},{},[448],{"type":53,"value":449},"for err, entry := range Uploads.List(ctx, &objects.Query{}) {\n",{"type":47,"tag":88,"props":451,"children":453},{"class":90,"line":452},31,[454],{"type":47,"tag":88,"props":455,"children":456},{},[457],{"type":53,"value":458},"    if err != nil {\n",{"type":47,"tag":88,"props":460,"children":462},{"class":90,"line":461},32,[463],{"type":47,"tag":88,"props":464,"children":465},{},[466],{"type":53,"value":467},"        return err\n",{"type":47,"tag":88,"props":469,"children":471},{"class":90,"line":470},33,[472],{"type":47,"tag":88,"props":473,"children":474},{},[475],{"type":53,"value":476},"    }\n",{"type":47,"tag":88,"props":478,"children":480},{"class":90,"line":479},34,[481],{"type":47,"tag":88,"props":482,"children":483},{},[484],{"type":53,"value":485},"    fmt.Println(entry.Key, entry.Size)\n",{"type":47,"tag":88,"props":487,"children":489},{"class":90,"line":488},35,[490],{"type":47,"tag":88,"props":491,"children":492},{},[493],{"type":53,"value":294},{"type":47,"tag":88,"props":495,"children":497},{"class":90,"line":496},36,[498],{"type":47,"tag":88,"props":499,"children":500},{"emptyLinePlaceholder":104},[501],{"type":53,"value":107},{"type":47,"tag":88,"props":503,"children":505},{"class":90,"line":504},37,[506],{"type":47,"tag":88,"props":507,"children":508},{},[509],{"type":53,"value":510},"\u002F\u002F Delete\n",{"type":47,"tag":88,"props":512,"children":514},{"class":90,"line":513},38,[515],{"type":47,"tag":88,"props":516,"children":517},{},[518],{"type":53,"value":519},"err := Uploads.Remove(ctx, \"path\u002Fto\u002Ffile.jpg\")\n",{"type":47,"tag":88,"props":521,"children":523},{"class":90,"line":522},39,[524],{"type":47,"tag":88,"props":525,"children":526},{"emptyLinePlaceholder":104},[527],{"type":53,"value":107},{"type":47,"tag":88,"props":529,"children":531},{"class":90,"line":530},40,[532],{"type":47,"tag":88,"props":533,"children":534},{},[535],{"type":53,"value":536},"\u002F\u002F Public URL (only for public buckets)\n",{"type":47,"tag":88,"props":538,"children":540},{"class":90,"line":539},41,[541],{"type":47,"tag":88,"props":542,"children":543},{},[544],{"type":53,"value":545},"url := PublicAssets.PublicURL(\"image.jpg\")\n",{"type":47,"tag":56,"props":547,"children":549},{"id":548},"signed-urls",[550],{"type":53,"value":551},"Signed URLs",{"type":47,"tag":63,"props":553,"children":554},{},[555],{"type":53,"value":556},"Generate temporary URLs so clients can upload\u002Fdownload directly without going through your service:",{"type":47,"tag":78,"props":558,"children":560},{"className":80,"code":559,"language":26,"meta":82,"style":82},"import \"time\"\n\n\u002F\u002F Signed upload URL (expires in 2 hours)\nurl, err := Uploads.SignedUploadURL(ctx, \"user-uploads\u002Favatar.jpg\",\n    objects.WithTTL(time.Duration(7200)*time.Second))\n\n\u002F\u002F Signed download URL\nurl, err := Uploads.SignedDownloadURL(ctx, \"documents\u002Freport.pdf\",\n    objects.WithTTL(time.Duration(7200)*time.Second))\n",[561],{"type":47,"tag":69,"props":562,"children":563},{"__ignoreMap":82},[564,572,579,587,595,603,610,618,626],{"type":47,"tag":88,"props":565,"children":566},{"class":90,"line":91},[567],{"type":47,"tag":88,"props":568,"children":569},{},[570],{"type":53,"value":571},"import \"time\"\n",{"type":47,"tag":88,"props":573,"children":574},{"class":90,"line":100},[575],{"type":47,"tag":88,"props":576,"children":577},{"emptyLinePlaceholder":104},[578],{"type":53,"value":107},{"type":47,"tag":88,"props":580,"children":581},{"class":90,"line":110},[582],{"type":47,"tag":88,"props":583,"children":584},{},[585],{"type":53,"value":586},"\u002F\u002F Signed upload URL (expires in 2 hours)\n",{"type":47,"tag":88,"props":588,"children":589},{"class":90,"line":119},[590],{"type":47,"tag":88,"props":591,"children":592},{},[593],{"type":53,"value":594},"url, err := Uploads.SignedUploadURL(ctx, \"user-uploads\u002Favatar.jpg\",\n",{"type":47,"tag":88,"props":596,"children":597},{"class":90,"line":31},[598],{"type":47,"tag":88,"props":599,"children":600},{},[601],{"type":53,"value":602},"    objects.WithTTL(time.Duration(7200)*time.Second))\n",{"type":47,"tag":88,"props":604,"children":605},{"class":90,"line":135},[606],{"type":47,"tag":88,"props":607,"children":608},{"emptyLinePlaceholder":104},[609],{"type":53,"value":107},{"type":47,"tag":88,"props":611,"children":612},{"class":90,"line":144},[613],{"type":47,"tag":88,"props":614,"children":615},{},[616],{"type":53,"value":617},"\u002F\u002F Signed download URL\n",{"type":47,"tag":88,"props":619,"children":620},{"class":90,"line":152},[621],{"type":47,"tag":88,"props":622,"children":623},{},[624],{"type":53,"value":625},"url, err := Uploads.SignedDownloadURL(ctx, \"documents\u002Freport.pdf\",\n",{"type":47,"tag":88,"props":627,"children":628},{"class":90,"line":161},[629],{"type":47,"tag":88,"props":630,"children":631},{},[632],{"type":53,"value":602},{"type":47,"tag":56,"props":634,"children":636},{"id":635},"bucket-references",[637],{"type":53,"value":638},"Bucket References",{"type":47,"tag":63,"props":640,"children":641},{},[642],{"type":53,"value":643},"Pass bucket access to library code with a specific permission set:",{"type":47,"tag":78,"props":645,"children":647},{"className":80,"code":646,"language":26,"meta":82,"style":82},"\u002F\u002F Create a reference with download permission only\nref := objects.BucketRef[objects.Downloader](Uploads)\n\n\u002F\u002F Combine permissions via an interface\ntype myPerms interface {\n    objects.Downloader\n    objects.Uploader\n}\nref := objects.BucketRef[myPerms](Uploads)\n\n\u002F\u002F Permission types: Downloader, Uploader, Lister, Attrser, Remover,\n\u002F\u002F SignedDownloader, SignedUploader, ReadWriter\n",[648],{"type":47,"tag":69,"props":649,"children":650},{"__ignoreMap":82},[651,659,667,674,682,690,698,706,713,721,728,736],{"type":47,"tag":88,"props":652,"children":653},{"class":90,"line":91},[654],{"type":47,"tag":88,"props":655,"children":656},{},[657],{"type":53,"value":658},"\u002F\u002F Create a reference with download permission only\n",{"type":47,"tag":88,"props":660,"children":661},{"class":90,"line":100},[662],{"type":47,"tag":88,"props":663,"children":664},{},[665],{"type":53,"value":666},"ref := objects.BucketRef[objects.Downloader](Uploads)\n",{"type":47,"tag":88,"props":668,"children":669},{"class":90,"line":110},[670],{"type":47,"tag":88,"props":671,"children":672},{"emptyLinePlaceholder":104},[673],{"type":53,"value":107},{"type":47,"tag":88,"props":675,"children":676},{"class":90,"line":119},[677],{"type":47,"tag":88,"props":678,"children":679},{},[680],{"type":53,"value":681},"\u002F\u002F Combine permissions via an interface\n",{"type":47,"tag":88,"props":683,"children":684},{"class":90,"line":31},[685],{"type":47,"tag":88,"props":686,"children":687},{},[688],{"type":53,"value":689},"type myPerms interface {\n",{"type":47,"tag":88,"props":691,"children":692},{"class":90,"line":135},[693],{"type":47,"tag":88,"props":694,"children":695},{},[696],{"type":53,"value":697},"    objects.Downloader\n",{"type":47,"tag":88,"props":699,"children":700},{"class":90,"line":144},[701],{"type":47,"tag":88,"props":702,"children":703},{},[704],{"type":53,"value":705},"    objects.Uploader\n",{"type":47,"tag":88,"props":707,"children":708},{"class":90,"line":152},[709],{"type":47,"tag":88,"props":710,"children":711},{},[712],{"type":53,"value":294},{"type":47,"tag":88,"props":714,"children":715},{"class":90,"line":161},[716],{"type":47,"tag":88,"props":717,"children":718},{},[719],{"type":53,"value":720},"ref := objects.BucketRef[myPerms](Uploads)\n",{"type":47,"tag":88,"props":722,"children":723},{"class":90,"line":170},[724],{"type":47,"tag":88,"props":725,"children":726},{"emptyLinePlaceholder":104},[727],{"type":53,"value":107},{"type":47,"tag":88,"props":729,"children":730},{"class":90,"line":179},[731],{"type":47,"tag":88,"props":732,"children":733},{},[734],{"type":53,"value":735},"\u002F\u002F Permission types: Downloader, Uploader, Lister, Attrser, Remover,\n",{"type":47,"tag":88,"props":737,"children":738},{"class":90,"line":288},[739],{"type":47,"tag":88,"props":740,"children":741},{},[742],{"type":53,"value":743},"\u002F\u002F SignedDownloader, SignedUploader, ReadWriter\n",{"type":47,"tag":56,"props":745,"children":747},{"id":746},"guidelines",[748],{"type":53,"value":749},"Guidelines",{"type":47,"tag":751,"props":752,"children":753},"ul",{},[754,760,773,778],{"type":47,"tag":755,"props":756,"children":757},"li",{},[758],{"type":53,"value":759},"Declare buckets as package-level variables.",{"type":47,"tag":755,"props":761,"children":762},{},[763,765,771],{"type":53,"value":764},"Default to private buckets; opt into ",{"type":47,"tag":69,"props":766,"children":768},{"className":767},[],[769],{"type":53,"value":770},"Public: true",{"type":53,"value":772}," only for assets meant for unauthenticated download.",{"type":47,"tag":755,"props":774,"children":775},{},[776],{"type":53,"value":777},"Use signed URLs for browser uploads\u002Fdownloads instead of streaming through your service.",{"type":47,"tag":755,"props":779,"children":780},{},[781],{"type":53,"value":782},"Use bucket references when passing access to helpers — they encode the permission contract in the type system.",{"type":47,"tag":784,"props":785,"children":786},"style",{},[787],{"type":53,"value":788},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":790,"total":426},[791,805,817,831,847,859,875,890,907,924,934,945],{"slug":792,"name":792,"fn":793,"description":794,"org":795,"tags":796,"stars":27,"repoUrl":28,"updatedAt":804},"encore-api","build type-safe APIs with Encore","Define typed API endpoints in Encore.ts using `api(...)` from `encore.dev\u002Fapi`. Covers typed request\u002Fresponse interfaces, path\u002Fquery\u002Fheader\u002Fcookie params, request validation, and `APIError`. For raw endpoints (`api.raw()`) and inbound webhooks, use `encore-webhook` instead.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[797,800,801],{"name":798,"slug":799,"type":16},"API Development","api-development",{"name":9,"slug":8,"type":16},{"name":802,"slug":803,"type":16},"TypeScript","typescript","2026-04-06T18:09:46.044101",{"slug":806,"name":806,"fn":807,"description":808,"org":809,"tags":810,"stars":27,"repoUrl":28,"updatedAt":816},"encore-auth","implement Encore.ts authentication","Protect Encore.ts endpoints with authentication and authorize callers. Covers `authHandler`, `Gateway`, `getAuthData`, and `auth: true`.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[811,814,815],{"name":812,"slug":813,"type":16},"Auth","auth",{"name":9,"slug":8,"type":16},{"name":802,"slug":803,"type":16},"2026-04-06T18:09:47.336322",{"slug":818,"name":818,"fn":819,"description":820,"org":821,"tags":822,"stars":27,"repoUrl":28,"updatedAt":830},"encore-bucket","store files in Encore.ts buckets","Store unstructured files in Encore.ts using `Bucket` from `encore.dev\u002Fstorage\u002Fobjects` — uploads, images, documents, blobs.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[823,824,825,826,829],{"name":14,"slug":15,"type":16},{"name":9,"slug":8,"type":16},{"name":18,"slug":19,"type":16},{"name":827,"slug":828,"type":16},"File Uploads","file-uploads",{"name":802,"slug":803,"type":16},"2026-05-16T05:59:52.813772",{"slug":832,"name":832,"fn":833,"description":834,"org":835,"tags":836,"stars":27,"repoUrl":28,"updatedAt":846},"encore-cache","cache data in Redis with Encore.ts","Cache data in Redis from Encore.ts using `CacheCluster` and typed keyspaces from `encore.dev\u002Fstorage\u002Fcache`. Type-safe key\u002Fvalue access with TTLs, atomic increments, and per-keyspace data shapes.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[837,838,841,842,845],{"name":14,"slug":15,"type":16},{"name":839,"slug":840,"type":16},"Caching","caching",{"name":9,"slug":8,"type":16},{"name":843,"slug":844,"type":16},"Redis","redis",{"name":802,"slug":803,"type":16},"2026-05-16T05:59:56.808328",{"slug":848,"name":848,"fn":849,"description":850,"org":851,"tags":852,"stars":27,"repoUrl":28,"updatedAt":858},"encore-code-review","review Encore.ts code","Review existing Encore.ts code for best practices and common anti-patterns.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[853,856,857],{"name":854,"slug":855,"type":16},"Code Review","code-review",{"name":9,"slug":8,"type":16},{"name":802,"slug":803,"type":16},"2026-04-06T18:10:01.123999",{"slug":860,"name":860,"fn":861,"description":862,"org":863,"tags":864,"stars":27,"repoUrl":28,"updatedAt":874},"encore-cron","schedule recurring jobs in Encore.ts","Schedule periodic \u002F recurring work in Encore.ts using `CronJob` from `encore.dev\u002Fcron`. Covers `every: \"1h\"` interval syntax and `schedule: \"0 9 * * 1\"` cron expressions.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[865,868,869,870,873],{"name":866,"slug":867,"type":16},"Automation","automation",{"name":14,"slug":15,"type":16},{"name":9,"slug":8,"type":16},{"name":871,"slug":872,"type":16},"Scheduling","scheduling",{"name":802,"slug":803,"type":16},"2026-05-16T05:59:54.146651",{"slug":876,"name":876,"fn":877,"description":878,"org":879,"tags":880,"stars":27,"repoUrl":28,"updatedAt":889},"encore-database","build Encore databases","Work with PostgreSQL in Encore.ts using `SQLDatabase` from `encore.dev\u002Fstorage\u002Fsqldb` — schema migrations and SQL queries.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[881,884,885,888],{"name":882,"slug":883,"type":16},"Database","database",{"name":9,"slug":8,"type":16},{"name":886,"slug":887,"type":16},"ORM","orm",{"name":802,"slug":803,"type":16},"2026-04-06T18:09:54.823017",{"slug":891,"name":891,"fn":892,"description":893,"org":894,"tags":895,"stars":27,"repoUrl":28,"updatedAt":906},"encore-frontend","connect frontend to Encore backend","Connect a frontend application (React, Next.js, Vue, Svelte, etc.) to an Encore.ts backend.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[896,897,900,903],{"name":9,"slug":8,"type":16},{"name":898,"slug":899,"type":16},"Frontend","frontend",{"name":901,"slug":902,"type":16},"Next.js","next-js",{"name":904,"slug":905,"type":16},"React","react","2026-04-06T18:09:56.091006",{"slug":908,"name":908,"fn":909,"description":910,"org":911,"tags":912,"stars":27,"repoUrl":28,"updatedAt":923},"encore-getting-started","build and run applications with Encore.ts","Bootstrap a brand-new Encore.ts project from zero. Only for first-time CLI install and `encore app create` — not for architecture or feature questions.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[913,914,915,916,919,920],{"name":798,"slug":799,"type":16},{"name":14,"slug":15,"type":16},{"name":9,"slug":8,"type":16},{"name":917,"slug":918,"type":16},"Local Development","local-development",{"name":802,"slug":803,"type":16},{"name":921,"slug":922,"type":16},"Web Development","web-development","2026-04-06T18:10:04.885446",{"slug":925,"name":925,"fn":926,"description":927,"org":928,"tags":929,"stars":27,"repoUrl":28,"updatedAt":933},"encore-go-api","build APIs with Encore Go","Define typed API endpoints in Encore Go using `\u002F\u002Fencore:api` annotations. Covers typed request\u002Fresponse structs, path\u002Fquery\u002Fheader\u002Fcookie params, and error returns. For raw endpoints (`\u002F\u002Fencore:api raw`) and inbound webhooks, use `encore-go-webhook` instead.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[930,931,932],{"name":798,"slug":799,"type":16},{"name":9,"slug":8,"type":16},{"name":25,"slug":26,"type":16},"2026-04-06T18:09:48.578781",{"slug":935,"name":935,"fn":936,"description":937,"org":938,"tags":939,"stars":27,"repoUrl":28,"updatedAt":944},"encore-go-auth","implement authentication with Encore Go","Protect Encore Go endpoints with authentication and authorize callers. Covers `auth.AuthHandler`, `auth.UserID`, the `Authorization` header, and `\u002F\u002Fencore:api auth`.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[940,941,942,943],{"name":812,"slug":813,"type":16},{"name":14,"slug":15,"type":16},{"name":9,"slug":8,"type":16},{"name":25,"slug":26,"type":16},"2026-04-06T18:09:51.065102",{"slug":4,"name":4,"fn":5,"description":6,"org":946,"tags":947,"stars":27,"repoUrl":28,"updatedAt":29},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[948,949,950,951,952],{"name":14,"slug":15,"type":16},{"name":9,"slug":8,"type":16},{"name":18,"slug":19,"type":16},{"name":25,"slug":26,"type":16},{"name":22,"slug":23,"type":16},{"items":954,"total":426},[955,961,967,975,983,989,997],{"slug":792,"name":792,"fn":793,"description":794,"org":956,"tags":957,"stars":27,"repoUrl":28,"updatedAt":804},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[958,959,960],{"name":798,"slug":799,"type":16},{"name":9,"slug":8,"type":16},{"name":802,"slug":803,"type":16},{"slug":806,"name":806,"fn":807,"description":808,"org":962,"tags":963,"stars":27,"repoUrl":28,"updatedAt":816},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[964,965,966],{"name":812,"slug":813,"type":16},{"name":9,"slug":8,"type":16},{"name":802,"slug":803,"type":16},{"slug":818,"name":818,"fn":819,"description":820,"org":968,"tags":969,"stars":27,"repoUrl":28,"updatedAt":830},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[970,971,972,973,974],{"name":14,"slug":15,"type":16},{"name":9,"slug":8,"type":16},{"name":18,"slug":19,"type":16},{"name":827,"slug":828,"type":16},{"name":802,"slug":803,"type":16},{"slug":832,"name":832,"fn":833,"description":834,"org":976,"tags":977,"stars":27,"repoUrl":28,"updatedAt":846},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[978,979,980,981,982],{"name":14,"slug":15,"type":16},{"name":839,"slug":840,"type":16},{"name":9,"slug":8,"type":16},{"name":843,"slug":844,"type":16},{"name":802,"slug":803,"type":16},{"slug":848,"name":848,"fn":849,"description":850,"org":984,"tags":985,"stars":27,"repoUrl":28,"updatedAt":858},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[986,987,988],{"name":854,"slug":855,"type":16},{"name":9,"slug":8,"type":16},{"name":802,"slug":803,"type":16},{"slug":860,"name":860,"fn":861,"description":862,"org":990,"tags":991,"stars":27,"repoUrl":28,"updatedAt":874},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[992,993,994,995,996],{"name":866,"slug":867,"type":16},{"name":14,"slug":15,"type":16},{"name":9,"slug":8,"type":16},{"name":871,"slug":872,"type":16},{"name":802,"slug":803,"type":16},{"slug":876,"name":876,"fn":877,"description":878,"org":998,"tags":999,"stars":27,"repoUrl":28,"updatedAt":889},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1000,1001,1002,1003],{"name":882,"slug":883,"type":16},{"name":9,"slug":8,"type":16},{"name":886,"slug":887,"type":16},{"name":802,"slug":803,"type":16}]