S3, without changing your code
Buckets, uploads, downloads, listings, multipart and presigned links all speak the S3 API. Point your app at a new endpoint and it keeps working.
Open-source object storage
Jay stores your files behind the same S3 API your tools already speak — on your own server, with no database and nothing else to run. Start it in a minute, keep it for years.
Free and open source (MIT) · No database to set up · Linux and macOS
$ export AWS_ENDPOINT_URL=http://localhost:9000
$ aws s3 mb s3://photos
make_bucket: photos
$ aws s3 cp cat.jpg s3://photos/
upload: ./cat.jpg to s3://photos/cat.jpg
Your existing S3 tools work unchanged. Only the endpoint is new.
import boto3
s3 = boto3.client("s3", endpoint_url="http://localhost:9000")
s3.create_bucket(Bucket="photos")
s3.upload_file("cat.jpg", "photos", "cat.jpg")
boto3 and the AWS SDKs connect like they would to Amazon S3.
// The native protocol: no HTTP, no XML, no re-hashing.
c, err := client.Dial(ctx, "localhost:4444", tokenID, secret)
if err != nil { log.Fatal(err) }
defer c.Close()
c.CreateBucket(ctx, "photos")
c.PutObject(ctx, "photos", "cat.jpg", f, size, nil)
From Go, a faster binary protocol on the same server and the same data.
// No server at all: the same engine, inside your program.
s, err := jay.Open("./data")
if err != nil { log.Fatal(err) }
defer s.Close()
s.CreateBucket(ctx, "photos")
s.Put(ctx, "photos", "cat.jpg", f, nil)
Or skip the server: import Jay as a Go package and keep it in-process.
Works with the tools you already use
How it works
No cluster to plan, no database to provision, no migrations. One container and a folder for your data.
Give it a volume and two secrets. That is the whole setup.
docker run … ghcr.io/ivangsm/jay
Mint a key for your app and choose exactly what it is allowed to do.
POST /_jay/tokens
Change the endpoint in your app or CLI. Everything else stays the same.
--endpoint-url http://localhost:9000
Features
Buckets, uploads, downloads, listings, multipart and presigned links all speak the S3 API. Point your app at a new endpoint and it keeps working.
Go services can use a lightweight binary protocol instead of HTTP. Same server, same files, a fraction of the overhead.
Import Jay into your Go program and get the whole storage engine in-process. No network, no tokens, nothing to deploy.
Every object is checksummed on the way in and re-checked in the background. A crash mid-upload never leaves a half-written file behind.
Give each app or teammate its own key, limited to certain buckets, folders and actions. Share files with links that expire.
No database, no message queue, no cluster. Everything Jay knows lives in one folder you can copy, inspect and back up.
Performance
Reads go straight from disk to the network without passing through the program. And when the caller is Go, the native protocol drops HTTP and XML altogether — the busier the server, the bigger the gap.
See every benchmark and how to reproduce it →Made for
Avatars, attachments and documents, stored next to the app instead of on a third-party bill.
Fast, local artifact and cache storage that any S3-aware tool already knows how to use.
Photos and video for a site or an image server, served with range reads straight from disk.
A real S3 endpoint on your laptop and in CI, in one container that starts in seconds.
Why Jay
Your files live on your disk, in a folder you can see. No per-request bill, no egress fees, no lock-in.
If Jay does not support something, it says so with a clear error. It never pretends a request worked and quietly drops your data.
One server, not a cluster: no replication or versioning. If you need those, Jay will tell you upfront instead of half-doing them.
One container, two secrets, a volume. Try it on your laptop today and move it to production when you are ready.