Skip to content

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.
storage:
  drives:
    - name: media
      size_gb: 10
  buckets:
    - name: exports

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.

storage:
  drives:
    - name: media
      size_gb: 10
    - name: exports
      size_gb: 5
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_gb above 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:

storage:
  buckets:
    - name: media
    - name: exports
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