Skip to main content
For production deployments, Teable is strongly recommended to use S3-compatible object storage (S3 / MinIO / OSS S3 endpoint / other S3-compatible services) with public/private dual buckets.

Why two buckets?

Teable stores different types of files in different buckets:
  • Public bucket: avatars, form cover images, and other assets that must be publicly accessible.
  • Private bucket: attachments and other content that should be protected and accessed via signed URLs.

Required environment variables

At minimum, configure:
  • Provider
    • BACKEND_STORAGE_PROVIDER: s3 or minio
  • Buckets
    • BACKEND_STORAGE_PUBLIC_BUCKET
    • BACKEND_STORAGE_PRIVATE_BUCKET
  • Public access base URL
    • STORAGE_PREFIX: should be the public bucket access base URL (or CDN in front of it)

S3 provider

BACKEND_STORAGE_PROVIDER=s3
BACKEND_STORAGE_S3_REGION=us-west-2
BACKEND_STORAGE_S3_ENDPOINT=https://s3.us-west-2.amazonaws.com
BACKEND_STORAGE_S3_ACCESS_KEY=***REDACTED***
BACKEND_STORAGE_S3_SECRET_KEY=***REDACTED***

BACKEND_STORAGE_PUBLIC_BUCKET=your-public-bucket
BACKEND_STORAGE_PRIVATE_BUCKET=your-private-bucket

# Public bucket base URL (or CDN)
STORAGE_PREFIX=https://your-public-bucket.s3.us-west-2.amazonaws.com

MinIO provider

BACKEND_STORAGE_PROVIDER=minio
BACKEND_STORAGE_MINIO_ENDPOINT=minio.example.com
BACKEND_STORAGE_MINIO_PORT=443
BACKEND_STORAGE_MINIO_USE_SSL=true
BACKEND_STORAGE_MINIO_ACCESS_KEY=***REDACTED***
BACKEND_STORAGE_MINIO_SECRET_KEY=***REDACTED***

BACKEND_STORAGE_PUBLIC_BUCKET=public
BACKEND_STORAGE_PRIVATE_BUCKET=private
STORAGE_PREFIX=https://minio.example.com

Public bucket requirements (must-do)

1) Public read access

The public bucket must allow public read for objects. If you use AWS S3, you can set a bucket policy like:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadGetObject",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::your-public-bucket/*"
    }
  ]
}
AWS S3 may require you to adjust Block Public Access settings for the public bucket. Please follow your organization’s security policy.

2) CORS (allow any origin)

For browser access, configure CORS on the public bucket to allow cross-origin requests. AWS S3 example:
[
  {
    "AllowedHeaders": ["*"],
    "AllowedMethods": ["GET", "HEAD"],
    "AllowedOrigins": ["*"],
    "ExposeHeaders": ["ETag", "x-amz-request-id", "x-amz-id-2"],
    "MaxAgeSeconds": 3000
  }
]
If you use direct browser uploads (presigned PUT), you may also need PUT in AllowedMethods.

Private bucket guidance

  • Keep the private bucket non-public.
  • Teable accesses private objects via signed URLs.
  • If your provider supports “bucket endpoint” for private access, you can configure:
    • BACKEND_STORAGE_PRIVATE_BUCKET_ENDPOINT (optional)

Azure / GCP note

Teable uses S3 APIs for object storage. Azure Blob Storage and Google Cloud Storage are not S3-native.
  • If you are on Azure or GCP, you can still use BACKEND_STORAGE_PROVIDER=s3 as long as you point to an S3 endpoint (for example, AWS S3) and your Teable runtime can reach it.
  • Or use an S3-compatible storage:
    • MinIO (self-managed) as the S3 endpoint
    • Another managed S3-compatible service (your choice)