Skip to content

Buckets

A Railway.Bucket is S3-compatible object storage in a Project. Each environment gets its own isolated instance and credentials. Bind PutObject / GetObject in a Service. Alchemy injects the endpoint and credentials. You never read AWS_* yourself.

Pass a Project. Alchemy generates a unique name and deploys to the project’s primary environment in sjc.

const site = yield* Railway.Project("Site");
const data = yield* Railway.Bucket("Data", { project: site });

Pass name when you need a stable display name. The S3 API name is this plus a short hash (s3BucketName). Changing name updates in place.

const data = yield* Railway.Bucket("Data", {
project: site,
name: "uploads",
});

Bind PutObject / GetObject in Service init. Provide the matching *Http layers.

import * as HttpServerResponse from "effect/unstable/http/HttpServerResponse";
export default class Api extends Railway.Service<Api>()(
"Api",
{ project: Site, main: import.meta.url, port: 3000 },
Effect.gen(function* () {
const putObject = yield* Railway.PutObject(Data);
const getObject = yield* Railway.GetObject(Data);
return {
fetch: Effect.gen(function* () {
yield* putObject({
Key: "hello.txt",
Body: "hello",
ContentType: "text/plain",
});
const obj = yield* getObject({ Key: "hello.txt" });
return HttpServerResponse.json({ ok: obj.ETag !== undefined });
}),
};
}).pipe(Effect.provide([Railway.PutObjectHttp, Railway.GetObjectHttp])),
) {}

HeadObject, DeleteObject, and ListObjectsV2 follow the same shape.

Omit region to use sjc. Changing it replaces the Bucket. See Regions.

const data = yield* Railway.Bucket("Data", {
project: site,
region: "iad",
});

Defaults to the Project’s primary environment. Pass a Environment to target another one.

const staging = yield* Railway.Environment("Staging", { project: site });
const data = yield* Railway.Bucket("StagingData", {
project: site,
environment: staging,
});

Services is the container that binds PutObject / GetObject. The Bucket reference lists every prop.