Storage¶
AppMecca gives your app two kinds of persistent storage, both declared in
appmecca.yaml under a top-level storage: block:
- Drives — shared filesystem volumes your services mount as directories. Good for user uploads, generated files, and anything your code reads and writes as ordinary files.
- Buckets — private object storage with an injected, app-scoped credential. Good for bulk storage, and roughly 13× cheaper per GB than a drive.
Both are opt-in: an app with no storage: block has neither.
Storage is per-branch
Drives and buckets are scoped to the app and branch. A feature/payments
deployment gets its own empty drive and its own bucket — data never crosses
between branches, and nothing you upload on one branch appears on another.
Drives¶
A drive is a named shared-filesystem volume. Each drive gets its own isolated root directory — one app can never see another app's drives.
| Field | Description |
|---|---|
name |
Drive name — lowercase, kebab-case, starts with a letter. Referenced by deploy[].drives[].name. |
size_gb |
Declared size limit in GB. Default 5, minimum 1, maximum 100. |
Mounting a drive into a service¶
Declaring a drive doesn't mount it — a service mounts it under deploy[].drives. Every
mount must name a drive declared in storage.drives, so the two halves belong together:
storage:
drives:
- name: media
size_gb: 10
- name: exports
size_gb: 5
deploy:
- name: web
container: web
port: 8000
drives:
- name: media
path: /app/media
- name: exports
path: /app/exports
readonly: true
Mounting an undeclared drive fails the deploy
A deploy[].drives[].name that does not appear in storage.drives is rejected at
config validation — not silently ignored. Two services may mount the same drive,
and one service may mount several, but each mount path within a service must be
unique.
| Field | Description |
|---|---|
name |
A drive declared in storage.drives. |
path |
Absolute path inside the container where the drive is mounted (e.g. /app/media). |
readonly |
Mount read-only (default false). |
One service can mount several drives; one drive can be mounted by several
services (a shared volume across your fleet). Manage a drive's contents with the
mecca drive commands — see Drive File Management.
Storage limits and grants¶
Drive storage is expensive per gigabyte, so it is deliberately bounded:
- Every drive is capped at 100 GB.
size_gbabove 100 is rejected at config-load time. - The first 5 GB per app is free. If your app's declared drive total is 5 GB or less, there's nothing to arrange.
- Above 5 GB, your team needs a storage grant. An app whose declared drive total exceeds the free allowance can only deploy if the owning group holds an operator-set storage grant, and the group-wide declared total fits inside the grant.
If you declare more than the free allowance without a grant, the deploy is refused up front with a message pointing at the grant. Ask your platform operator to raise a grant for your group; once it's in place, redeploy.
Prefer a bucket for bulk storage
If you're storing many gigabytes of objects — media, exports, archives — a bucket is far cheaper than a drive and needs no grant. Use a drive when your code genuinely needs a POSIX filesystem (random-access writes, tools that expect real files); use a bucket for object blobs.
Buckets¶
A bucket is private object storage that AppMecca provisions for your app on deploy, along with a scoped credential injected into your containers. Declare buckets by name, exactly like drives:
| Field | Description |
|---|---|
name |
Bucket name — lowercase, kebab-case, starts with a letter. Determines the injected env var name. |
On the next deploy, each name becomes a distinct private, encrypted, TLS-only bucket, and your app is given one credential that can read and write all of the app's buckets.
The name you declare is a label, not the real bucket name
The physical bucket name is generated by the platform and is not the name you
wrote. Never hard-code it — always read it from the injected
APPMECCA_BUCKET_{NAME}_NAME variable described below.
Buckets are self-service — no storage grant is required. On a brand-new environment the operator has to complete a one-time setup step before the first bucket can be created; if bucket provisioning fails on a fresh environment, ask your operator.
Injected environment variables¶
Every container of the app receives:
| Variable | Value |
|---|---|
APPMECCA_BUCKET_{NAME}_NAME |
The real bucket name, one per declared bucket. media → APPMECCA_BUCKET_MEDIA_NAME; user-uploads → APPMECCA_BUCKET_USER_UPLOADS_NAME. |
APPMECCA_BUCKET_REGION |
The region your buckets live in. |
APPMECCA_BUCKET_ACCESS_KEY_ID |
The app-scoped access key id. |
APPMECCA_BUCKET_SECRET_ACCESS_KEY |
The app-scoped secret access key. |
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION |
Convenience copies under the names storage client libraries look for by default. |
Buckets speak the S3 API, so any S3-compatible client library works unchanged — and because the credential is already in the environment under the names those libraries expect, most of them need no configuration at all.
The AWS_* variables are only set if you haven't set them yourself — your own
values always win.
# Example: your code reads the injected values
import os, boto3
s3 = boto3.client("s3") # credentials are already in the environment
s3.put_object(
Bucket=os.environ["APPMECCA_BUCKET_MEDIA_NAME"],
Key="uploads/photo.jpg",
Body=data,
)
The credential is yours, and it's scoped
The injected key can only touch this app's own buckets — it can't reach any
other app's storage, and AppMecca's own platform credentials never enter your
container. Manage and rotate the credential with the mecca bucket
commands — see Buckets.
Buckets have a file surface too
mecca bucket ls / stat / upload / download / mkdir / rm / purge / archive
browse and move objects from the CLI, and the dashboard's Buckets tab
does the same in a browser — so you no longer have to reveal the credential
and install the AWS CLI just to see what is in your own bucket.
Two differences from a drive, both because S3 is not a filesystem: there is
no mv/cp (S3 has no server-side rename), and there is no quota —
a drive's size_gb has no bucket equivalent. Your application code can of
course still read and write directly with the injected credential, which is
the right choice for anything in the request path.
Next Steps¶
- Drive File Management — browse and manage drive files with
mecca drive - Buckets — browse, transfer, archive, and manage the bucket credential
- Environment Variables — how injected variables layer with your own