Railway Buckets
Railway Buckets (private, Tigris-backed) via the S3-compatible API. Reads the AWS_* variables Railway injects; endpoint defaults to https://t3.storageapi.dev, region to auto.
Installation
@aws-sdk/client-s3, @aws-sdk/s3-presigned-post, and @aws-sdk/s3-request-presigner are optional peer dependencies of files-sdk - install alongside the SDK so the adapter’s imports resolve at runtime.
npm install files-sdk @aws-sdk/client-s3 @aws-sdk/s3-presigned-post @aws-sdk/s3-request-presignerpnpm add files-sdk @aws-sdk/client-s3 @aws-sdk/s3-presigned-post @aws-sdk/s3-request-presigneryarn add files-sdk @aws-sdk/client-s3 @aws-sdk/s3-presigned-post @aws-sdk/s3-request-presignerbun add files-sdk @aws-sdk/client-s3 @aws-sdk/s3-presigned-post @aws-sdk/s3-request-presignernub add files-sdk @aws-sdk/client-s3 @aws-sdk/s3-presigned-post @aws-sdk/s3-request-presigneraube add files-sdk @aws-sdk/client-s3 @aws-sdk/s3-presigned-post @aws-sdk/s3-request-presignerupload also needs the optional @aws-sdk/lib-storage package when it uses onProgress, multipart, or a ReadableStream body of unknown length. It’s only loaded then.
Usage
import { Files } from "files-sdk";
import { railway } from "files-sdk/railway";
const files = new Files({
adapter: railway(),
// bucket, endpoint, and credentials auto-loaded from
// AWS_S3_BUCKET_NAME / AWS_ENDPOINT_URL / AWS_ACCESS_KEY_ID /
// AWS_SECRET_ACCESS_KEY
});
Railway Buckets are private, S3-compatible object storage that runs on Tigris. The adapter is a thin wrapper around the S3 adapter: endpoint defaults to https://t3.storageapi.dev, region defaults to "auto" for signing, and errors are relabelled.
The adapter reads the same AWS_* names that railway bucket credentials prints, so railway() needs no options once a service has them:
| Variable | Option | Bucket reference | Notes |
|---|---|---|---|
AWS_S3_BUCKET_NAME |
bucket |
BUCKET |
The S3 name: your display name plus a short hash. Required. |
AWS_ACCESS_KEY_ID |
accessKeyId |
ACCESS_KEY_ID |
Required. |
AWS_SECRET_ACCESS_KEY |
secretAccessKey |
SECRET_ACCESS_KEY |
Required. |
AWS_ENDPOINT_URL |
endpoint |
ENDPOINT |
Defaults to https://t3.storageapi.dev. |
AWS_S3_URL_STYLE |
forcePathStyle |
"path" or "virtual". Buckets created before Railway moved to virtual-hosted URLs need "path"; the Credentials tab says which. |
In the dashboard, open the service’s Variables tab and auto-inject the bucket’s credentials with the AWS SDK preset. Add any variable from the table the preset didn’t create as a reference to the bucket, for example AWS_S3_BUCKET_NAME=${{my-bucket.BUCKET}}.
Pass the options explicitly to connect from outside Railway:
const files = new Files({
adapter: railway({
bucket: "uploads-jdhhd8oe18xi",
accessKeyId: process.env.RAILWAY_BUCKET_KEY_ID,
secretAccessKey: process.env.RAILWAY_BUCKET_SECRET,
}),
});
Credentials never fall back to the AWS credential chain, so a shared AWS profile or instance role can’t end up signing Railway requests. Missing keys throw at construction.
Browser uploads through signedUploadUrl() need a CORS rule on the bucket. Railway’s uploading and serving guide sets one with aws s3api put-bucket-cors.
Options
bucket?string
The bucket's S3 name: its display name plus a short hash (e.g. `my-bucket-jdhhd8oe18xi`), shown in the bucket's Credentials tab. Falls back to `AWS_S3_BUCKET_NAME`, the name `railway bucket credentials` prints it under; required if that env var isn't set.
stringendpoint?string
Override the S3 endpoint. Falls back to `AWS_ENDPOINT_URL`, then defaults to `https://t3.storageapi.dev`, the endpoint Railway's Credentials tab shows for current buckets.
stringaccessKeyId?string
Static access key ID. Falls back to `AWS_ACCESS_KEY_ID`; required if that env var isn't set.
stringsecretAccessKey?string
Static secret access key. Falls back to `AWS_SECRET_ACCESS_KEY`; required if that env var isn't set.
stringregion?string
SigV4 region used for signing. Defaults to `"auto"`, the value Railway hands out. Buckets are pinned to the region picked at creation, so this is never used for routing, but the signature requires *some* value.
stringforcePathStyle?boolean
Use path-style addressing (`/<bucket>/<key>`) rather than virtual-hosted style. Falls back to `AWS_S3_URL_STYLE` (`"path"` or `"virtual"`), which Railway hands out alongside the credentials. Current buckets use virtual-hosted style; some buckets created before Railway switched need path-style, and their Credentials tab says so.
booleanpublicBaseUrl?string
Origin used to build URLs from `url()`. Railway buckets have no public URLs of their own, so this is for a proxy service or CDN you put in front of the bucket: `url(key)` returns `${publicBaseUrl}/${key}` and skips signing. When unset, `url()` returns a presigned GetObject URL (default expiry: 1 hour).
stringdefaultUrlExpiresIn?number
Default expiry, in seconds, for the presigned URLs returned by `url()` when `publicBaseUrl` is not set. Defaults to 3600 (1 hour).
numberCompatibility
| Method | Status | Notes |
|---|---|---|
upload |
✅ | |
download |
✅ | |
delete |
✅ | |
list |
⚠️ | The S3 list API returns no per-object Content-Type, so contentType is inferred from the key’s extension (application/octet-stream when unknown). Use head() for the stored value. |
search |
✅ | |
head |
✅ | |
exists |
✅ | |
copy |
✅ | |
url |
✅ | Presigned. Railway buckets are private. |
signedUploadUrl |
✅ |