Non-public is not private
The Spaces alpha announcement presents Spaces as a way to store non-public data. It does not say private data. That choice is deliberate. The post states the limit clearly a few paragraphs later.
It's important to remember that spaces give you access control not confidentiality. The data in a space is readable by any user or application with access to that space, it's not encrypted.
We build on Spaces. We explain that sentence to people often. This post is the full version. It covers why the word matters. It covers what Spaces do well. It covers where the bytes sit. It covers what you trust when you trust a space authority. It covers what you can do if you need real confidentiality today.
The name moved away from a promise
The announcement lists its own history. The feature was first called private data. Then it was called permissioned data. Then it was briefly called buckets. Now it is called spaces. Each rename moved further from a claim the design does not make.
Private is a statement about who can read something. Permissioned is a statement about who is allowed to ask. Those sound similar until a server operator, a subpoena, or an application bug enters the picture. Access control decides whether a request is answered. Confidentiality decides whether the data is intelligible to whoever holds it. Spaces give you access control. Only encryption gives you confidentiality. Spaces do not encrypt.
The honest reading of non-public is simple. The data is not broadcast to the world. The data does not appear in the firehose. A server turns down readers who are not members. That is a real and useful property. It is not the same as nobody else can read this.
What access control is good for
The announcement lists a broad range of uses. That range is a good guide to the shape of problem that fits.
- A space with exactly one member holds settings, drafts, bookmarks, and other per-user state that an app must not publish.
- A space with paying members holds gated content, such as a subscription publication.
- A large space holds a shared social context. The post describes this as the design target for Spaces, scaled to communities of millions.
The common thread is clear. A boundary adds value. A leak does limited damage. A bookmark list that escapes is embarrassing. A forum post that reaches a non-member is a moderation problem, not a catastrophe. Access control is the right tool when you want a room with a door, not a safe.
Our own case fits the same shape. A project is a set of files owned by an organization. The files are shared with the people who work on them. We gate them because company documents are not public posts. We do not gate them because each document is a secret.
The mirror image is the set of things that do not fit. Credentials, private keys, health records, and payroll records belong somewhere else. So does anything covered by a regulation with a breach notification clause. So does anything where one unauthorized read is the entire harm. For those, the question is not whether the server checks membership. The question is what an attacker gets when they hold the disk. With a space today, the answer is everything.
Where the data is
The protocol has a short answer for this. Records live in per-space permissioned repos on the author's PDS. There is no central space server that holds the contents. If five people write into a space, those records sit in five repos. Each repo sits on the server that person uses.
The space authority is not a storage location. It decides who can read. Reading happens against the PDS hosts that hold the repos.
Spaces also skip the relay. The relay is the part of AT Protocol that rebroadcasts public data to anyone who wants it. The announcement is explicit. There is no relay for space data. Applications sync directly from PDS hosts. So the set of machines that can see the plaintext includes the PDS hosts that hold member repos. It also includes every application a member authorized to sync on their behalf. It also includes anyone with operational access to those disks or their backups.
That last group is easy to forget. Non-public means the data is not published. It does not mean fewer parties hold the data than a normal database.
For Elastic Projects specifically, here is where things sit today. A general answer is not enough when you decide what to upload.
| Piece | Where it lives |
|---|---|
| File paths, hashes, and text bodies | The application replica, which is Postgres in production and SQLite when you run it locally |
| Bytes of binary files | Object storage, content addressed by their sha256 |
| The signed repository for each project | Object storage as CAR slices, served at a did:web subdomain of this host |
| Repo signing keys | Private objects in the same store, never in the database |
None of that is encrypted at rest by us beyond what the underlying provider does with its own disks. The data server page describes the storage shape. The limits page lists what the alpha does not do. One limit is worth repeating here. Live projects are still minted with the signed-in person's DID as the space authority. They are not minted with the organization's data server. That is the gap between the model we describe and the code we run.
What you trust when you trust a space authority
The announcement describes the authority plainly. It is a DID like any other account. In some cases it is your own account. It determines which other DIDs can access the space.
Follow that to its conclusion. The authority can add members. Nothing stops it from adding a DID it also controls. There is no membership change an authority cannot make. A member cannot detect that change from inside the data model. So the security of a space against its own authority is not a technical property. Trusting a space means trusting whoever holds the authority's keys. This is the same as trusting a company Google Drive and trusting whoever holds the admin account.
That is not a criticism of the design. Every shared system has an administrator. It does mean the interesting questions are about people and operations, not the protocol. Ask three questions before you put anything into someone else's space.
The first is who holds the signing keys. Ask whether that is one person, a company, or a service. The second is who runs the server that answers for the DID. That operator can read every record it stores. The third is what happens when you want to leave. An authority that you can repoint only with the operator's help is an authority you cannot exit.
Our answer to the first two is this.
The authority must be an organization rather than a person.
Then the files survive staff changes without anyone handing over a personal account.
Our answer to the third is a rule we hold ourselves to.
A did:plc can only be repointed by a rotation key.
An organization we host keeps a rotation key we do not have.
It can move to another host without our cooperation.
That build is not done yet.
The hosting page says the same thing.
Until it is done, treat hosted organizations here as a preview rather than a custody arrangement.
Encrypting it yourself
Spaces will not encrypt for you. Nothing stops you from encrypting first. A space stores bytes. We store the bytes you give us without inspecting them. Ciphertext round-trips through a project the same as any other file.
Three approaches are worth knowing, in rough order of cost.
Keep the secret out of the space. Store a name instead of a value. Resolve that name against a secret manager at the point of use. This is the right answer for credentials and API keys. It is the only one on this list that removes the problem rather than moving it.
Encrypt whole files before you publish. Use a reviewed tool, such as age or GPG. Publish the output.
# Encrypt for one teammate
age -r age1ql3z... plan.md > plan.md.age
# Encrypt for two, so either can open it
age -r age1ql3z... -r age1lh8... plan.md > plan.md.age
# Read it back with your own key
age -d -i ~/.age/key.txt plan.md.age > plan.md
The space then holds an opaque blob. Membership becomes a second lock rather than the only one.
Encrypt values inside a record. Keep the record shape readable so applications can still sync and index it. Encrypt only the fields that carry the sensitive part. You keep the ability to build views. You give up any view that depends on the encrypted values.
Whichever you pick, be clear about what encryption does not hide.
The path names stay readable.
A name like finance/2026-layoffs.md tells a story on its own.
File sizes, timestamps, the author of each record, the member list, and change frequency all stay visible.
If your threat model includes traffic analysis, encrypting the contents is a partial answer at best.
You also give up the product. Preview, diff, search, and the editor all work on text we can read. An encrypted file in a project today shows up as a binary blob. You download it and decrypt it yourself. That cost is real. It is the honest reason we do not present encryption as a feature.
Key management is the hard part
The encryption is the easy half. The keys are where these schemes usually fail. One asymmetry is worth stating plainly.
Adding a member is cheap. You encrypt the file to one more recipient, or wrap the per-file key with one more public key, and publish again. Tools like age support several recipients directly. This is a one-line change.
Removing a member is not cheap. It is not fully possible. Taking someone out of a space stops the server from answering their requests from that moment on. It does nothing about the ciphertext they already downloaded. It does nothing about the key they still hold. So a removal must be a rotation. Generate a new key. Re-encrypt everything. Publish it. Treat every file the departing member can read as already read. Any design that skips this step pretends that access control and confidentiality are the same thing. That is the mistake this whole post is about.
Two smaller traps are worth avoiding. Do not build your own scheme. Handling nonces, key derivation, and authentication correctly is a specialist job. The tools above already do it. Do not use deterministic encryption to keep content addressing tidy. Identical plaintext then produces identical ciphertext. An observer learns which files match without decrypting anything. Random nonces are the correct choice. Losing deduplication is the price.
What we tell you today
The alpha announcement gives advice we do not soften. The code did not receive a careful security review. Do not upload sensitive information, yours or anyone else's. Encrypting first does not change that. The encryption protects the contents. The bugs live in everything around them.
So the practical rule for a space today is this. Hold work you are comfortable with a colleague reading. Keep it out of public view because it is nobody else's business. Plans, drafts, notes, specifications, and the ordinary material of a team all qualify. Anything whose disclosure is the harm itself does not belong there yet. A cipher in front of it does not change that.
Non-public is a real and useful property. The announcement is right to be careful with the word. A door is worth having. A door is not a safe. Spaces never claimed to be one.
The public demo on this deployment is Elastic Projects hosting its own product tree at the share link. It is world-readable and world-editable on purpose. It is a reasonable place to see what a space feels like. It is a very unreasonable place to test your encryption.