Choosing where to store
Which of the three storage surfaces fits which kind of data.
PortModels gives an app three places to put data. They are not interchangeable.
| Key/value | Files | Public assets | |
|---|---|---|---|
| Belongs to | A user, in your app | A user, in your app | Your app |
| Readable by | Your app, with kv.read | Your app, with files.read | Anyone |
| Written by | Your app, with kv.write | Your app, with files.write | You, as the developer |
| Size limit | 64KB per value | 10MB direct, more via presign | Large, via presign |
| Count limit | 1000 keys per user | Storage quota | — |
| Good for | Settings, state, small caches | Documents, exports, media | Icons, screenshots, samples |
Quick decisions#
Settings, preferences, session state. Key/value. Small, structured, read on every session.
Something the user produced and wants back. Files. A generated report, an export, a transcript.
Something big. Files, via a presigned upload. Don't try to base64 a 30MB file into a 64KB key/value entry.
Your app's own icon. Public assets. It's the same for every user and it's not private.
A cache of an expensive result. Key/value if it's small and per-user; files if it's large. Either way you're saving the user credits.
A password or an API key of your own. None of these. Keep your own secrets in your own infrastructure — per-user storage is readable by your app, which means anything you put there is only as safe as your app.
What not to assume#
- Storage is not a database. There are no queries, no indexes, and no transactions across keys. Structure your keys so you can find things by name.
- Data outlives access. Revoking your app stops your token, but does not delete what you stored. Give users a way to clear their data from inside your app.
- The user may decline. Scopes are optional at the consent screen. Design
for the case where you got
models.runand nothing else.