Vaultwarden Attachment Storage Limits: Configuring File Size and User Quotas

Vaultwarden provides two configurable attachment storage limits—USER_ATTACHMENT_LIMIT and ORG_ATTACHMENT_LIMIT measured in KB per user or organization—plus a hard-coded 525 MiB maximum file size enforced by Rocket's request limits.

In the dani-garcia/vaultwarden repository, administrators control attachment storage limits through environment variables and server-level request constraints. These settings determine how much data individual users and organizations can store, while the underlying Rocket framework imposes an absolute ceiling on individual upload sizes. Proper configuration prevents disk exhaustion and ensures fair resource allocation across tenants.

User and Organization Attachment Storage Limits

Vaultwarden exposes two optional quota settings defined in src/config.rs at lines 594–596:

  • user_attachment_limit (Option<i64>): Maximum total storage per user, specified in kilobytes.
  • org_attachment_limit (Option<i64>): Maximum total storage per organization, specified in kilobytes.

Validation logic at lines 1060–1069 ensures these values are non-negative integers. When set to 0, attachments are effectively disabled for that scope.

Environment Variable Configuration

Configure these limits via your .env file or environment variables:


# Maximum total attachment storage per user (KB). Set to 0 to disable.

USER_ATTACHMENT_LIMIT=524288   # 512 MiB per user

# Maximum total attachment storage per organization (KB). Set to 0 to disable.

ORG_ATTACHMENT_LIMIT=1048576   # 1 GiB per organization

Source: Variable definitions and validation in src/config.rs (lines 594–596, 1060–1069).

Tracking Current Usage

The system calculates remaining quota using helper methods in src/db/models/attachment.rs:

  • Attachment::size_by_user: Aggregates total bytes stored by a specific user.
  • Attachment::size_by_org: Aggregates total bytes stored by a specific organization.

These values are compared against the configured limits during every upload request.

Maximum Single File Upload Limit

Unlike the configurable quotas, the maximum attachment file size is hard-coded in the Rocket server configuration. In src/main.rs at lines 564–566, the application sets:

config.limits = Limits::new()
    .limit("json", 20.megabytes())
    .limit("data-form", 525.megabytes())
    .limit("file", 525.megabytes());  // Attachment-specific limit

This defines a 525 MiB ceiling for any single multipart file upload. Rocket rejects requests exceeding this threshold before they reach the business logic layer.

Modifying the Hard File-Size Cap

To change this limit, you must edit the source code in src/main.rs and adjust the .limit("file", ...) value, then recompile. There is no environment variable override for this setting.

Runtime Enforcement and Quota Calculation

When a user uploads an attachment, the API endpoint in src/api/core/ciphers.rs (lines 1196–1240) performs a multi-stage validation:

  1. Rocket Limit Check: The request is blocked if the payload exceeds 525 MiB.

  2. Quota Retrieval: The system fetches the current usage via Attachment::size_by_user or size_by_org.

  3. Remaining Space Calculation: The algorithm computes available bytes as:

    
    left = (limit_kb * 1024) - already_used + size_adjust
    

    The size_adjust variable (lines 1260–1268) provides a ±1 MiB tolerance for the v2 API to accommodate slight size discrepancies.

  4. Enforcement: If left ≤ 0, the API returns "Attachment storage limit reached". If the current file size exceeds left, it returns "Attachment storage limit exceeded with this file".

For organization-owned ciphers, the identical logic applies using CONFIG.org_attachment_limit().

Configuration Examples

Setting Storage Quotas via Environment

Create or edit your .env file:


# Disable attachments for individual users

USER_ATTACHMENT_LIMIT=0

# Allow 2 GB per organization

ORG_ATTACHMENT_LIMIT=2097152

Adjusting Server-Level File Limits

To increase the single-file maximum to 1 GiB, modify src/main.rs:

// src/main.rs - Rocket configuration
config.limits = Limits::new()
    .limit("json", 20.megabytes())
    .limit("data-form", 1024.megabytes())
    .limit("file", 1024.megabytes());  // Increased from 525 MiB

Note: This requires recompiling Vaultwarden from source.

Summary

  • Configure per-user and per-org quotas using USER_ATTACHMENT_LIMIT and ORG_ATTACHMENT_LIMIT (in KB) via environment variables defined in src/config.rs.
  • Rocket enforces a hard 525 MiB single-file limit through .limit("file", 525.megabytes()) in src/main.rs.
  • Runtime enforcement occurs in src/api/core/ciphers.rs, which calculates remaining space using Attachment::size_by_user and size_by_org.
  • Setting either quota to 0 disables attachments entirely for that user or organization.
  • The v2 API includes a ±1 MiB adjustment tolerance during quota calculations to prevent edge-case rejections.

Frequently Asked Questions

What is the default attachment storage limit in Vaultwarden?

By default, both USER_ATTACHMENT_LIMIT and ORG_ATTACHMENT_LIMIT are None, meaning no quotas are enforced. The only restriction is the 525 MiB single-file maximum hard-coded in src/main.rs.

How do I completely disable attachments for all users?

Set USER_ATTACHMENT_LIMIT=0 in your environment configuration. The API logic in src/api/core/ciphers.rs explicitly checks for Some(0) and returns an "Attachments are disabled" error before processing any upload.

Why does my upload fail even when under the KB quota?

Check the Rocket file-size limit defined in src/main.rs. Any single file exceeding 525 MiB is rejected at the server level before the quota calculation logic executes. Additionally, the v2 API applies a ±1 MiB size adjustment during quota checks that may affect borderline uploads.

Can organizations have different storage limits than individual users?

Yes. ORG_ATTACHMENT_LIMIT controls storage for organization-owned ciphers independently from USER_ATTACHMENT_LIMIT. The enforcement logic in src/api/core/ciphers.rs branches based on whether the cipher belongs to a user (cipher.user_uuid) or an organization (cipher.organization_uuid), applying the respective limit from the Config struct.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →