1---
2title: Buckets
3description: S3-compatible object storage in a Project. Bind Railway.PutObject / Railway.GetObject.
4---
5
6A [`Railway.Bucket`](/providers/railway/bucket) is S3-compatible
7object storage in a [Project](/railway/compute/projects). Each
8environment gets its own isolated instance and credentials. Bind
9[`PutObject`](/providers/railway/putobject) /
10[`GetObject`](/providers/railway/getobject) in a
11[Service](/railway/compute/services). Alchemy injects the endpoint
12and credentials. You never read `AWS_*` yourself.
13
14## Create a Bucket
15
16Pass a Project. Alchemy generates a unique name and deploys to the
17project's primary environment in `sjc`.
18
19```typescript
20const site = yield* Railway.Project("Site");
21const data = yield* Railway.Bucket("Data", { project: site });
22```
23
24:::caution[Changing `project` replaces the Bucket]
25The Bucket is created in the new Project. The old Bucket is deleted.
26:::
27
28## A stable name
29
30Pass `name` when you need a stable display name. The S3 API name is
31this plus a short hash (`s3BucketName`). Changing `name` updates in
32place.
33
34```typescript
35const data = yield* Railway.Bucket("Data", {
36 project: site,
37 name: "uploads",
38});
39```
40
41## Put and get objects
42
43Bind `PutObject` / `GetObject` in the Service's constructor. Provide the matching
44`*Http` layers.
45
46```typescript
47import * as HttpServerResponse from "effect/http/HttpServerResponse";
48
49export default class Api extends Railway.Service<Api>()(
50 "Api",
51 { project: Site, main: import.meta.url, port: 3000 },
52 Effect.gen(function* () {
53 const putObject = yield* Railway.PutObject(Data);
54 const getObject = yield* Railway.GetObject(Data);
55
56 return {
57 fetch: Effect.gen(function* () {
58 yield* putObject({
59 Key: "hello.txt",
60 Body: "hello",
61 ContentType: "text/plain",
62 });
63 const obj = yield* getObject({ Key: "hello.txt" });
64 return HttpServerResponse.json({ ok: obj.ETag !== undefined });
65 }),
66 };
67 }).pipe(Effect.provide([Railway.PutObjectHttp, Railway.GetObjectHttp])),
68) {}
69```
70
71`HeadObject`, `DeleteObject`, and `ListObjectsV2` follow the same
72shape.
73
74## Region
75
76Omit `region` to use `sjc`. Changing it replaces the Bucket. See
77[Regions](/railway/compute/regions).
78
79```typescript
80const data = yield* Railway.Bucket("Data", {
81 project: site,
82 region: "iad",
83});
84```
85
86## Environment
87
88Defaults to the Project's primary environment. Pass a
89[Environment](/railway/compute/environments) to target another one.
90
91```typescript
92const staging = yield* Railway.Environment("Staging", { project: site });
93const data = yield* Railway.Bucket("StagingData", {
94 project: site,
95 environment: staging,
96});
97```
98
99:::caution[Changing `environment` replaces the Bucket]
100The Bucket instance is created in the new environment. The old
101instance is deleted.
102:::
103
104## Where next
105
106[Services](/railway/compute/services) is the container that binds
107`PutObject` / `GetObject`.
108The [`Bucket` reference](/providers/railway/bucket) lists every
109prop.