Form.io does not store your files. This is intentional. When a user uploads a file through a Form.io form, that file travels directly from the browser to your configured storage provider. Form.io acts as the authentication and authorization broker, generating temporary signed URLs that allow uploads without exposing your storage credentials to the client. The submission record stores only metadata: the file URL, name, and size.
This architecture exists because file storage requirements vary dramatically across enterprise use cases. A healthcare application collecting medical images has different compliance needs than a construction company gathering site photos. A government agency may require FedRAMP-authorized storage while a startup might use consumer Dropbox. Form.io provides the form infrastructure and lets you bring your own storage.
How the File Upload Flow Actually Works
The file component upload process involves three parties: the browser, the Form.io server, and your storage provider. Understanding this flow is essential for debugging upload failures and configuring appropriate security.
When a user selects a file, the Form.io renderer immediately initiates an upload sequence. The browser makes a POST request to /{project_alias}/form/{form_alias}/storage/{storage_provider} with file metadata. The Form.io server verifies that the user has submission permissions for that form. If authorized, the server generates a temporary URL with an embedded token that grants upload permission to your storage provider. This URL is returned to the browser, which then makes a PUT request directly to the storage provider with the file contents.
This means files upload before form submission. If a user selects a file but never submits the form, that file still exists in your storage. Form.io does not automatically clean up orphaned uploads. You will need to implement your own cleanup strategy, either through storage provider lifecycle policies or by comparing stored files against submission records periodically. This is documented in GitHub issue #2406 and remains a consideration for storage cost management.
The submission record that eventually gets saved to MongoDB contains only file metadata in JSON format:
{
"url": "https://your-bucket.s3.amazonaws.com/uploads/guid-filename.pdf",
"name": "original-filename.pdf",
"size": 245000,
"storage": "s3",
"type": "application/pdf"
}
Your actual file bytes never touch MongoDB. They go directly from browser to blob storage.
Supported Storage Providers
Form.io supports several storage backends out of the box. Each requires configuration in your project settings under Integrations > File Storage. The storage provider you select in project settings -> integrations becomes available as an option when configuring individual file components on your forms.
Amazon S3 is the most common choice for enterprise deployments. Form.io works with any S3-compatible service, meaning you can use AWS S3 directly or alternatives like MinIO for on-premise deployments or SeaweedFS (which is included in Form.io’s docker-compose deployment). S3 configuration requires IAM credentials, bucket name, region, and CORS settings. The File Storage documentation provides step-by-step IAM policy configuration. Form.io supports S3 Multipart Upload for files up to 5TB, configured per-component by enabling the checkbox and specifying a chunk size.
Azure Blob Storage provides equivalent functionality for Microsoft cloud environments. Configuration requires the storage account name, container name, and access key. Form.io’s Azure integration became native in version 4.0.0. Earlier versions required a MinIO gateway compatibility layer. If you are running a pre-4.0.0 deployment, you would need to upgrade or use the legacy MinIO image (minio/minio:RELEASE.2022-04-29T01-27-09Z). The Azure setup guide on the Form.io blog walks through every Azure portal configuration step.
Google Drive allows file uploads to go directly into a user’s Drive account. This requires OAuth configuration through the Google Developer Console integration. Files can be routed to specific folders by adding the folder ID (visible in the Drive URL) to the file component configuration. This option works well when end users need to access uploaded files outside the application.
Dropbox provides a simpler consumer-grade integration. After connecting your Dropbox account in project settings, files upload directly to your Dropbox folder. Files are limited to 150MB with this provider.
Custom URL provider offers maximum flexibility when you need to route uploads to a proprietary system. You specify the upload endpoint URL in the component configuration rather than project settings. Your endpoint receives file contents and must return a JSON object containing at least url, name, and size. The formio-upload repository on GitHub provides a reference implementation that can proxy uploads to local filesystems, Alfresco, or other document management systems.
Base64 stores file contents directly in the submission JSON. This is only appropriate for testing. Base64-encoded files bloat submission size and should not be used in production.
IndexedDB stores files in the browser’s local database. This is used in conjunction with Offline Mode to cache uploads when network connectivity is unavailable, syncing to the actual storage provider when reconnected.
File Permissions and Security
File upload and download permissions are governed by the same Roles and Permissions [/features/teams-and-permissions] system that controls submission access. This is a crucial detail that trips up developers configuring file components for the first time.
When Form.io verifies upload permission, it checks whether the requesting user has Create permissions on the associated form. For downloads, it checks Read permissions on the submission containing the file reference. If your form allows Anonymous submissions (common for public intake forms), anonymous users can upload files. If your submission permissions require authentication to read, file downloads will also require authentication.
The Private Download option on the file component adds an extra security layer. When enabled, file downloads route through a POST request with the JWT token in the header, allowing your custom endpoint to verify authorization before serving the file. The formio-upload server implements this pattern.
A common misconfiguration occurs when developers set submission Read permissions to Authenticated but expect files to be publicly viewable. If you want public file access (profile pictures, for example), you need to configure your storage provider’s access control list (ACL) to public and set the appropriate container-level permissions. The Azure guide covers this under “Allow Blob Anonymous access.”
For S3, you control file-level permissions through the Access Control List setting in project configuration. Options include private (default, requires signed URL for access) and public-read (anyone with the URL can download). Choose based on your data classification requirements.
When File Uploads Break
File upload failures typically stem from one of four causes: CORS misconfiguration, credential problems, permission issues, or network constraints.
CORS errors appear when your storage provider rejects the browser’s cross-origin request. Every storage provider requires explicit CORS configuration allowing requests from the domains where your forms are hosted. This includes both your production domain and the Form.io portal (portal.form.io) if you’re testing from the builder interface. For S3, expose the ETag header in your CORS policy if you’re using Multipart Upload.
Credential errors mean your access keys are wrong, expired, or lack the necessary IAM permissions. For S3, the IAM user needs s3:GetObject, s3:PutObject, and s3:PutObjectAcl on your bucket. Double-check that credentials in Form.io project settings match what you generated in your cloud provider console.
Permission errors occur when the user attempting to upload lacks Create submission permissions on the form. Check your form’s Access tab in the Form.io portal.
Network and size constraints cause failures when uploads exceed configured limits. Form.io project settings include Maximum File Size. S3 standard uploads are limited to 5GB; use Multipart Upload for larger files. Corporate firewalls may block direct browser-to-storage-provider connections.
What Form.io Does Not Do with Files
Form.io does not process, transform, or scan uploaded files. If you need virus scanning, image resizing, or content validation, you must implement these as separate services triggered by webhooks or by intercepting uploads through a Custom URL provider. Nevertheless, it’s common for storage providers to offer these capabilities.
Form.io does not automatically delete files when submissions are deleted. File references in MongoDB are just URLs. Deleting a submission removes the reference but leaves the file in storage. Implement retention policies in your storage provider or build cleanup automation.
Form.io does not provide a centralized file browser. Files are associated with individual submissions. To find all files uploaded across submissions, query your storage provider directly or use Form.io’s Data Reporting capabilities to aggregate file metadata from submissions.
Form.io does not provide version control for uploaded files. Each upload creates a new file with a new GUID. If users need to update attached files, they upload replacements. Previous versions remain in storage unless you implement cleanup.
Connecting to Other Form.io Features
File uploads interact with several other Form.io capabilities. PDF Forms can include file attachments in generated documents, pulling the uploaded file URL into the output. Form Revisions track changes to form definitions including file component configurations, but do not version the files themselves.
Offline Mode queues file uploads in IndexedDB when network connectivity is unavailable. When the device reconnects, queued uploads sync to the configured storage provider. This is essential for field data collection applications.
The Security Compliance features relate to file handling through the broader submission permission system. Form.io supports S3 server-side encryption (AES-256 or KMS) for files at rest. Combined with HTTPS for transit, this satisfies many compliance requirements for data protection.
For Multi-Tenancy deployments, each tenant project can configure its own storage provider. This enables data isolation where tenant files are stored in separate buckets or containers.
Configuration Checklist
Before deploying forms with file uploads:
- Create storage provider account and bucket/container
- Configure CORS to allow requests from all domains where forms will render
- Generate access credentials with appropriate permissions
- Add credentials to Form.io project settings under File Storage
- Configure form submission permissions to match your access requirements
- Set file component storage to your configured provider
- Test upload and download from the actual deployment domain, not just the portal
- Implement a strategy for cleaning orphaned files
- Consider file size limits and Multipart Upload for large files
- Verify encryption settings meet compliance requirements
The file storage integration documentation at help.form.io provides provider-specific setup instructions. The apidocs.form.io reference covers programmatic file operations through the API. For custom upload server implementations, reference the formio-upload repository.
Related Resources:
