Object storage thatshows its work.
Lockwell is a private, encrypted object store with an S3-compatible API, a native JSON API, and first-party Go, Node, and Java SDKs: one binary, no second store, no glue. The claims on this page are measurements, and the repository carries the harnesses to re-run them.
- crash takeover, acked writes intact
- 16 s
- disk used for the same bytes, vs MinIO
- 0.54x
- multipart PUT, 64 MiB at 64 clients
- 2.2x MinIO
- S3 production suite, 24 SDK clients
- 0 failures
- public buckets, anonymous reads
- refused
measured 2026-06-11 · one host, Docker Compose · methodology · reproduce: make bench · make prod-authority-test
Every request meets the gate
This is the whole security model in one scene. A request that presents a tenant key passes and its object is sealed, encrypted, at rest. A request without one is refused with a 401. There is no anonymous path to refuse carefully or configure away.
carries a tenant key: passes, sealed at rest no key: refused at the gate, 401
Sharing still works the safe way: mint an expiring signed link (a 7-day client download, a one-hour browser upload) and hand it out. The link carries the permission, nobody gets a key, and it dies on schedule.
The case for replacing a working MinIO
Benchmarks do not move a production system; lower bills, fewer moving parts, and a safe exit do. This is what changes the day you switch, and the honest way to find out without risking anything.
The same bytes, about half the disk
Measured 0.54x MinIO's disk for an identical write set, before deduplication gets to work on real data. Storage is the line item that grows forever; this halves its slope.
Tenancy you do not have to build
Per-customer isolation, scoped keys, quotas, and an audit trail are the server's job here, not an auth layer your team writes around a bucket and maintains for years.
Compliance in the box
Always-on encryption at rest, Object Lock retention and legal hold, audit logging, scrub and repair, and rehearsed backup-restore drills. The evidence your auditor asks for is the product's normal output.
One binary to operate
No external database, no broker, no cache to feed. Upgrades replace one binary; recovery is a drill that runs in CI, not a wiki page nobody has tested.
Exits are standard
It speaks S3, so leaving is an aws s3 sync away. A storage system you can leave easily is the only kind worth moving into.
Keep MinIO running. Audit the move first.
The migration planner reads your existing MinIO or S3-compatible store and refuses blocked features instead of silently dropping them. Run Lockwell beside production, copy with verification and checkpoints, and switch only when its own ledger has convinced you.
What teams actually run on it
Three concrete shapes, not personas. Each one is a tenant, a few scoped keys, and the parts of the server that already exist.
Client deliverables with expiring links
An agency keeps each client in its own tenant. Deliverables are shared as signed links that die after seven days: no client accounts, no public bucket, and the audit log shows every download.
Signed URLs →User files in a multi-tenant SaaS
Each customer is a tenant. Browsers upload straight to storage with signed PUT URLs, webhooks fire the thumbnail pipeline, and a leaked key can only ever see one tenant's world.
The app kit →The archive an auditor will visit
Invoices and records land under Object Lock retention with always-on encryption. Lifecycle expires what may expire, legal hold freezes what may not, and the restore drill proves the backups are real.
Object Lock →Watch it work, then check the math
The terminal replays the real lifecycle against the real CLI surface. The bars come from the committed benchmark evidence, and the harness ships in the repository, so every number can be re-run on your own hardware.
Everything an app's storage layer needs
Provisioning, signed uploads, encryption, edge support, and webhooks, all built into one server and one SDK. You do not stitch together a bucket, a queue, a signer, and a secrets store.
Multi-tenant provisioning
Ensure a tenant exists and mint a fresh, scoped access key in one call: read/write/delete, an optional bucket scope, the secret shown once. Every tenant is isolated by default.
Native + S3 + admin APIs
A native JSON data plane, S3 SigV4 compatibility, and a JSON admin API. Three surfaces over one server, reached from one SDK. Talk to storage the way your stack prefers.
Browser signed URLs
Sign a direct upload or download URL server-side and hand it straight to the browser. The native API signs write URLs, not only GET, so object bytes never round-trip your app.
Edge-ready
The native and kit clients import nothing from node:*, so they run on Cloudflare Workers, Vercel Edge, Bun, and Deno through a dedicated /edge entry with zero node:crypto.
Always-on encryption
Authenticated at-rest encryption is on by default: AES-256-GCM or XChaCha20-Poly1305 over object data, with per-tenant data keys. There is no flag to remember to set.
Webhooks you can verify
Bucket event notifications POST to your endpoint with a constant-time HMAC-SHA256 signature. verifyWebhook checks the signature in one call, and runs on the edge.
Three APIs over the same encrypted store
Lockwell exposes the same multi-tenant, encrypted object store through three interfaces. Pick the one that fits, or mix them freely.
Drop in where S3 already is
SigV4 auth, path-style and virtual-host addressing, versioning, multipart, conditional writes, presigned URLs, Object Lock, tagging and lifecycle. The parity ledger documents every operation, and anything outside it fails closed instead of pretending.
Talk to storage natively
A JSON data plane on the public listener, with no SigV4 signing and no XML. Bearer tokens are minted from access keys and refreshed for you. Native signed URLs cover GET and PUT.
Provision and manage
A bearer-authenticated JSON admin API on a private listener: tenants, scoped keys, RBAC, audit, and an OpenAPI document. Provisioning lives outside the data plane, by design.
No custom storage layer to maintain
The usual object-storage stack is a bucket, a second store for metadata, a signer service, a webhook verifier, and the glue holding them together. Lockwell collapses that into one server and one SDK: provision a tenant, get a scoped client, sign a browser upload, and verify the webhook, end to end, in the same library, on the same encrypted store.
import { LockwellKit } from '@kelphect/sdk';
const kit = new LockwellKit({
admin: { endpoint: 'https://admin.example.com', token } },
native: { endpoint: 'https://objects.example.com' },
});
// 1. provision a tenant + mint a fresh scoped key
const { key } = await kit.provisionTenant('acme', {
defaultBucket: 'inbox',
});
// 2. sign a browser upload, then hand the URL to the client
const client = kit.clientForTenant('acme', key);
const up = await kit.signedUploadUrl(client, 'inbox', 'photo.jpg', {
ttl: 300, contentType: 'image/jpeg',
});
What is not here yet, and what to do meanwhile
A feature ships when it passes the same release gates everything else passed: drills, suites, documented behavior. Until then the server says no, and this page says so out loud.
Multi-node replication
Lockwell is deliberately single-node today; the replicated profile stays suspended until it can pass the same takeover and durability drills. Meanwhile teams run a warm standby: a second instance fed by scheduled S3-level sync, with restore drills proving the seam.
Event buses (SNS, SQS, Lambda)
Bucket notifications deliver to signed webhooks you can verify in one call. A queue between Lockwell and your pipeline is one consumer away, on infrastructure you already trust.
Storage tiering
Lifecycle rules already expire and clean up; cold archival is a scheduled job copying via the S3 API to whatever cold store your bills prefer.