You’ll build private document storage: each person uploads files into their own folder, only they can list, read, replace or delete them, a table keeps a record of each file with its title, and they can share one file with someone else through a link that expires. You’ll use: Storage, rules on storage, a table and the TypeScript client. Before you start: have sign-in working, as in An app with signed-in users.

How it works

File keys are paths. Put the owner’s id first: <user id>/<file id>.pdf. Then one rule on the bucket, “the first part of the key is the caller’s id”, protects every action. A documents table records each upload, with its own owner rule, so you can list, search and title files like any other data.

1. Create the bucket

Storage → New bucket:

2. Protect it with an owner-folder rule

Create a named rule in Policies → New policy, own_folder:
  • All of these rules pass:
    • Check a value: $auth.user_id is set
    • Compare values: $object.segments.0 equals $auth.user_id
In the bucket’s Access section, use own_folder for Who may read, Who may upload new objects, Who may list objects, Who may replace objects and Who may delete objects. $object.segments.0 is the first part of the key, before the first /. A person whose id is u_123 can reach u_123/… and nothing else.

3. Create the table

Data → Tables → Create table documents: Access: every operation Record owner (owner_id), and Add records: Signed-in users. This is exactly the setup from the signed-in app guide.

4. Upload and record the file

src/documents.ts
  • The key uses a random id, not the file’s name: names collide, leak information and can contain characters you don’t want in a path.
  • Upload first, then create the record. If the record fails, the file is orphaned but harmless; a scheduled clean-up can remove files with no record (Scheduled jobs).

Large files: upload straight from the browser

For big files, ask for a signed upload link and send the file straight to storage, so it never passes through your own server:
Creating the link checks the same upload rule, so a person can only get a link for their own folder. See Upload.

5. List, show and download

The download checks Who may read for the caller, so even if someone guessed another person’s key, they’d get 404. A signed link lets anyone who holds it read one file for a short time, with no sign-in:
Creating it checks that the caller may read the file, so people can only make links to their own documents. For longer-lived links with a label, a view or download choice and a way to revoke them, use share links.

7. Delete

Delete the file and the record together:

8. Test the boundary

test/files.test.ts

Variations

Troubleshooting

Storage

Everything buckets can do.

Rules on storage

More file rules.