feat: allow 500 GB uploads (#37120)

* feat: allow 500 GB uploads

* upsell

* docs + pricing page

* Update StorageSettings.tsx

* Small alignment fix

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
This commit is contained in:
Kevin GrünebergandJoshen Lim authored and GitHub committed 2025-07-23 12:43:53 -04:00
1 parent 1efa09cf54
commit eaa2f2e68b
6 files changed
+51 -22

No files matched your search

@@ -8,13 +8,13 @@ sidebar_label: 'Limits'
## Global file size
You can set the max file size across all your buckets by setting this global value in the dashboard [here](https://supabase.com/dashboard/project/_/settings/storage). For Free projects, the limit can't exceed 50 MB. On the Pro Plan and up, you can set this value to up to 50 GB. If you need more than 50 GB, [contact us](https://supabase.com/dashboard/support/new).
You can set the max file size across all your buckets by setting this global value in the dashboard [here](https://supabase.com/dashboard/project/_/settings/storage). For Free projects, the limit can't exceed 50 MB. On the Pro Plan and up, you can set this value to up to 500 GB. If you need more than 500 GB, [contact us](https://supabase.com/dashboard/support/new).
| Plan | Max File Size Limit |
| ---------- | ------------------- |
| Free | 50 MB |
| Pro | 50 GB |
| Team | 50 GB |
| Pro | 500 GB |
| Team | 500 GB |
| Enterprise | Custom |
<Admonition type="note">
@@ -17,7 +17,7 @@ The S3 protocol supports file upload using:
The `PutObject` action uploads the file in a single request. This matches the behavior of the Supabase SDK [Standard Upload](/docs/guides/storage/uploads/standard-uploads).
Use `PutObject` to upload smaller files, where retrying the entire upload won't be an issue. The maximum file size on paid plans is 50 GB.
Use `PutObject` to upload smaller files, where retrying the entire upload won't be an issue. The maximum file size on paid plans is 500 GB.
For example, using JavaScript and the `aws-sdk` client:
@@ -42,7 +42,7 @@ await s3Client.send(uploadCommand)
Multipart Uploads split the file into smaller parts and upload them in parallel, maximizing the upload speed on a fast network. When uploading large files, this allows you to retry the upload of individual parts in case of network issues.
This method is preferable over [Resumable Upload](/docs/guides/storage/uploads/resumable-uploads) for server-side uploads, when you want to maximize upload speed at the cost of resumability. The maximum file size on paid plans is 50 GB.
This method is preferable over [Resumable Upload](/docs/guides/storage/uploads/resumable-uploads) for server-side uploads, when you want to maximize upload speed at the cost of resumability. The maximum file size on paid plans is 500 GB.
### Upload a file in parts
@@ -1,4 +1,8 @@
export const STORAGE_FILE_SIZE_LIMIT_MAX_BYTES = 50 * 1024 * 1024 * 1024 // 50 GB
export const STORAGE_FILE_SIZE_LIMIT_MAX_BYTES_FREE_PLAN = 50 * 1024 * 1024 // 50 MB
/** Max bytes for capped storage (i.e. Pro with spend cap) */
export const STORAGE_FILE_SIZE_LIMIT_MAX_BYTES_CAPPED = 50 * 1024 * 1024 * 1024 // 50 GB
/** Max bytes for uncapped storage (i.e. Pro without spend cap, Team, Enterprise) */
export const STORAGE_FILE_SIZE_LIMIT_MAX_BYTES_UNCAPPED = 500 * 1024 * 1024 * 1024 // 500 GB
export enum StorageSizeUnits {
BYTES = 'bytes',
@@ -1,7 +1,6 @@
import { zodResolver } from '@hookform/resolvers/zod'
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { Clock } from 'lucide-react'
import { useEffect, useState } from 'react'
import { useEffect, useMemo, useState } from 'react'
import { SubmitHandler, useForm } from 'react-hook-form'
import { toast } from 'sonner'
import * as z from 'zod'
@@ -16,6 +15,7 @@ import { useProjectStorageConfigQuery } from 'data/config/project-storage-config
import { useProjectStorageConfigUpdateUpdateMutation } from 'data/config/project-storage-config-update-mutation'
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
import { formatBytes } from 'lib/helpers'
import {
Button,
FormControl_Shadcn_,
@@ -32,7 +32,12 @@ import {
Select_Shadcn_,
Switch,
} from 'ui'
import { STORAGE_FILE_SIZE_LIMIT_MAX_BYTES, StorageSizeUnits } from './StorageSettings.constants'
import {
STORAGE_FILE_SIZE_LIMIT_MAX_BYTES_CAPPED,
STORAGE_FILE_SIZE_LIMIT_MAX_BYTES_FREE_PLAN,
STORAGE_FILE_SIZE_LIMIT_MAX_BYTES_UNCAPPED,
StorageSizeUnits,
} from './StorageSettings.constants'
import { convertFromBytes, convertToBytes } from './StorageSettings.utils'
interface StorageSettingsState {
@@ -56,6 +61,8 @@ const StorageSettings = () => {
const organization = useSelectedOrganization()
const isFreeTier = organization?.plan.id === 'free'
const isSpendCapOn =
organization?.plan.id === 'pro' && organization?.usage_billing_enabled === false
const [initialValues, setInitialValues] = useState<StorageSettingsState>({
fileSizeLimit: 0,
@@ -84,9 +91,17 @@ const StorageSettings = () => {
}
}, [isSuccess, config])
const formattedMaxSizeBytes = `${new Intl.NumberFormat('en-US').format(
STORAGE_FILE_SIZE_LIMIT_MAX_BYTES
)} bytes`
const maxBytes = useMemo(() => {
if (organization?.plan.id === 'free') {
return STORAGE_FILE_SIZE_LIMIT_MAX_BYTES_FREE_PLAN
} else if (organization?.usage_billing_enabled) {
return STORAGE_FILE_SIZE_LIMIT_MAX_BYTES_UNCAPPED
} else {
return STORAGE_FILE_SIZE_LIMIT_MAX_BYTES_CAPPED
}
}, [organization])
const formattedMaxSizeBytes = `${new Intl.NumberFormat('en-US').format(maxBytes)} bytes`
const FormSchema = z
.object({
@@ -96,7 +111,7 @@ const StorageSettings = () => {
})
.superRefine((data, ctx) => {
const { unit, fileSizeLimit } = data
const { value: formattedMaxLimit } = convertFromBytes(STORAGE_FILE_SIZE_LIMIT_MAX_BYTES, unit)
const { value: formattedMaxLimit } = convertFromBytes(maxBytes, unit)
if (fileSizeLimit > formattedMaxLimit) {
ctx.addIssue({
@@ -156,7 +171,7 @@ const StorageSettings = () => {
</div>
<div className="relative flex flex-col col-span-12 gap-x-6 gap-y-2 lg:col-span-8">
<div className="grid grid-cols-12 col-span-12 gap-2 items-center">
<div className="grid grid-cols-12 col-span-12 gap-2 items-start">
<div className="col-span-8">
<FormField_Shadcn_
control={form.control}
@@ -222,8 +237,7 @@ const StorageSettings = () => {
limit,
storageUnit
).toLocaleString()} bytes. `}
Maximum size in bytes of a file that can be uploaded is 50 GB (
{formattedMaxSizeBytes}).
Maximum upload file size is {formatBytes(maxBytes)}.
</p>
</div>
</div>
@@ -261,9 +275,18 @@ const StorageSettings = () => {
{isFreeTier && (
<div className="px-6 pb-6">
<UpgradeToPro
icon={<Clock size={14} className="text-foreground-muted" />}
primaryText="Free Plan has a fixed upload file size limit of 50 MB."
secondaryText="Upgrade to the Pro Plan for a configurable upload file size limit of up to 50 GB."
secondaryText={`Upgrade to Pro Plan for a configurable upload file size limit of ${formatBytes(STORAGE_FILE_SIZE_LIMIT_MAX_BYTES_UNCAPPED)} and unlock image transformations.`}
source="storageSizeLimit"
/>
</div>
)}
{isSpendCapOn && (
<div className="px-6 pb-6">
<UpgradeToPro
buttonText="Disable Spend Cap"
primaryText="Reduced max upload file size limit due to Spend Cap"
secondaryText={`Disable your Spend Cap to allow file uploads of up to ${formatBytes(STORAGE_FILE_SIZE_LIMIT_MAX_BYTES_UNCAPPED)}.`}
source="storageSizeLimit"
/>
</div>
+4 -2
View File
@@ -69,7 +69,7 @@ const UpgradeToPro = ({
},
}}
>
Reset database password
{buttonText || (plan === 'free' ? 'Upgrade to Pro' : 'Enable add on')}
</ButtonTooltip>
) : (
<Button
@@ -81,7 +81,9 @@ const UpgradeToPro = ({
href={
plan === 'free'
? `/org/${organization?.slug ?? '_'}/billing?panel=subscriptionPlan&source=${source}`
: `/project/${project?.ref ?? '_'}/settings/addons?panel=${addon}&source=${source}`
: addon == null
? `/org/${organization?.slug ?? '_'}/billing?panel=costControl&source=${source}`
: `/project/${project?.ref ?? '_'}/settings/addons?panel=${addon}&source=${source}`
}
>
{buttonText || (plan === 'free' ? 'Upgrade to Pro' : 'Enable add on')}
+2 -2
View File
@@ -421,8 +421,8 @@ export const pricing: Pricing = {
title: 'Max file upload size',
plans: {
free: '50 MB',
pro: '50 GB',
team: '50 GB',
pro: '500 GB',
team: '500 GB',
enterprise: 'Custom',
},
usage_based: false,