Skip to content

Commit eaa2f2e

Browse files
kevcodezjoshenlim
andauthored
feat: allow 500 GB uploads (supabase#37120)
* feat: allow 500 GB uploads * upsell * docs + pricing page * Update StorageSettings.tsx * Small alignment fix --------- Co-authored-by: Joshen Lim <[email protected]>
1 parent 1efa09c commit eaa2f2e

File tree

6 files changed

+51
-22
lines changed

6 files changed

+51
-22
lines changed

apps/docs/content/guides/storage/uploads/file-limits.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ sidebar_label: 'Limits'
88

99
## Global file size
1010

11-
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).
11+
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).
1212

1313
| Plan | Max File Size Limit |
1414
| ---------- | ------------------- |
1515
| Free | 50 MB |
16-
| Pro | 50 GB |
17-
| Team | 50 GB |
16+
| Pro | 500 GB |
17+
| Team | 500 GB |
1818
| Enterprise | Custom |
1919

2020
<Admonition type="note">

apps/docs/content/guides/storage/uploads/s3-uploads.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ The S3 protocol supports file upload using:
1717

1818
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).
1919

20-
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.
20+
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.
2121

2222
For example, using JavaScript and the `aws-sdk` client:
2323

@@ -42,7 +42,7 @@ await s3Client.send(uploadCommand)
4242

4343
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.
4444

45-
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.
45+
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.
4646

4747
### Upload a file in parts
4848

apps/studio/components/interfaces/Storage/StorageSettings/StorageSettings.constants.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
export const STORAGE_FILE_SIZE_LIMIT_MAX_BYTES = 50 * 1024 * 1024 * 1024 // 50 GB
1+
export const STORAGE_FILE_SIZE_LIMIT_MAX_BYTES_FREE_PLAN = 50 * 1024 * 1024 // 50 MB
2+
/** Max bytes for capped storage (i.e. Pro with spend cap) */
3+
export const STORAGE_FILE_SIZE_LIMIT_MAX_BYTES_CAPPED = 50 * 1024 * 1024 * 1024 // 50 GB
4+
/** Max bytes for uncapped storage (i.e. Pro without spend cap, Team, Enterprise) */
5+
export const STORAGE_FILE_SIZE_LIMIT_MAX_BYTES_UNCAPPED = 500 * 1024 * 1024 * 1024 // 500 GB
26

37
export enum StorageSizeUnits {
48
BYTES = 'bytes',

apps/studio/components/interfaces/Storage/StorageSettings/StorageSettings.tsx

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { zodResolver } from '@hookform/resolvers/zod'
22
import { PermissionAction } from '@supabase/shared-types/out/constants'
3-
import { Clock } from 'lucide-react'
4-
import { useEffect, useState } from 'react'
3+
import { useEffect, useMemo, useState } from 'react'
54
import { SubmitHandler, useForm } from 'react-hook-form'
65
import { toast } from 'sonner'
76
import * as z from 'zod'
@@ -16,6 +15,7 @@ import { useProjectStorageConfigQuery } from 'data/config/project-storage-config
1615
import { useProjectStorageConfigUpdateUpdateMutation } from 'data/config/project-storage-config-update-mutation'
1716
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
1817
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
18+
import { formatBytes } from 'lib/helpers'
1919
import {
2020
Button,
2121
FormControl_Shadcn_,
@@ -32,7 +32,12 @@ import {
3232
Select_Shadcn_,
3333
Switch,
3434
} from 'ui'
35-
import { STORAGE_FILE_SIZE_LIMIT_MAX_BYTES, StorageSizeUnits } from './StorageSettings.constants'
35+
import {
36+
STORAGE_FILE_SIZE_LIMIT_MAX_BYTES_CAPPED,
37+
STORAGE_FILE_SIZE_LIMIT_MAX_BYTES_FREE_PLAN,
38+
STORAGE_FILE_SIZE_LIMIT_MAX_BYTES_UNCAPPED,
39+
StorageSizeUnits,
40+
} from './StorageSettings.constants'
3641
import { convertFromBytes, convertToBytes } from './StorageSettings.utils'
3742

3843
interface StorageSettingsState {
@@ -56,6 +61,8 @@ const StorageSettings = () => {
5661

5762
const organization = useSelectedOrganization()
5863
const isFreeTier = organization?.plan.id === 'free'
64+
const isSpendCapOn =
65+
organization?.plan.id === 'pro' && organization?.usage_billing_enabled === false
5966

6067
const [initialValues, setInitialValues] = useState<StorageSettingsState>({
6168
fileSizeLimit: 0,
@@ -84,9 +91,17 @@ const StorageSettings = () => {
8491
}
8592
}, [isSuccess, config])
8693

87-
const formattedMaxSizeBytes = `${new Intl.NumberFormat('en-US').format(
88-
STORAGE_FILE_SIZE_LIMIT_MAX_BYTES
89-
)} bytes`
94+
const maxBytes = useMemo(() => {
95+
if (organization?.plan.id === 'free') {
96+
return STORAGE_FILE_SIZE_LIMIT_MAX_BYTES_FREE_PLAN
97+
} else if (organization?.usage_billing_enabled) {
98+
return STORAGE_FILE_SIZE_LIMIT_MAX_BYTES_UNCAPPED
99+
} else {
100+
return STORAGE_FILE_SIZE_LIMIT_MAX_BYTES_CAPPED
101+
}
102+
}, [organization])
103+
104+
const formattedMaxSizeBytes = `${new Intl.NumberFormat('en-US').format(maxBytes)} bytes`
90105

91106
const FormSchema = z
92107
.object({
@@ -96,7 +111,7 @@ const StorageSettings = () => {
96111
})
97112
.superRefine((data, ctx) => {
98113
const { unit, fileSizeLimit } = data
99-
const { value: formattedMaxLimit } = convertFromBytes(STORAGE_FILE_SIZE_LIMIT_MAX_BYTES, unit)
114+
const { value: formattedMaxLimit } = convertFromBytes(maxBytes, unit)
100115

101116
if (fileSizeLimit > formattedMaxLimit) {
102117
ctx.addIssue({
@@ -156,7 +171,7 @@ const StorageSettings = () => {
156171
</div>
157172

158173
<div className="relative flex flex-col col-span-12 gap-x-6 gap-y-2 lg:col-span-8">
159-
<div className="grid grid-cols-12 col-span-12 gap-2 items-center">
174+
<div className="grid grid-cols-12 col-span-12 gap-2 items-start">
160175
<div className="col-span-8">
161176
<FormField_Shadcn_
162177
control={form.control}
@@ -222,8 +237,7 @@ const StorageSettings = () => {
222237
limit,
223238
storageUnit
224239
).toLocaleString()} bytes. `}
225-
Maximum size in bytes of a file that can be uploaded is 50 GB (
226-
{formattedMaxSizeBytes}).
240+
Maximum upload file size is {formatBytes(maxBytes)}.
227241
</p>
228242
</div>
229243
</div>
@@ -261,9 +275,18 @@ const StorageSettings = () => {
261275
{isFreeTier && (
262276
<div className="px-6 pb-6">
263277
<UpgradeToPro
264-
icon={<Clock size={14} className="text-foreground-muted" />}
265278
primaryText="Free Plan has a fixed upload file size limit of 50 MB."
266-
secondaryText="Upgrade to the Pro Plan for a configurable upload file size limit of up to 50 GB."
279+
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.`}
280+
source="storageSizeLimit"
281+
/>
282+
</div>
283+
)}
284+
{isSpendCapOn && (
285+
<div className="px-6 pb-6">
286+
<UpgradeToPro
287+
buttonText="Disable Spend Cap"
288+
primaryText="Reduced max upload file size limit due to Spend Cap"
289+
secondaryText={`Disable your Spend Cap to allow file uploads of up to ${formatBytes(STORAGE_FILE_SIZE_LIMIT_MAX_BYTES_UNCAPPED)}.`}
267290
source="storageSizeLimit"
268291
/>
269292
</div>

apps/studio/components/ui/UpgradeToPro.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ const UpgradeToPro = ({
6969
},
7070
}}
7171
>
72-
Reset database password
72+
{buttonText || (plan === 'free' ? 'Upgrade to Pro' : 'Enable add on')}
7373
</ButtonTooltip>
7474
) : (
7575
<Button
@@ -81,7 +81,9 @@ const UpgradeToPro = ({
8181
href={
8282
plan === 'free'
8383
? `/org/${organization?.slug ?? '_'}/billing?panel=subscriptionPlan&source=${source}`
84-
: `/project/${project?.ref ?? '_'}/settings/addons?panel=${addon}&source=${source}`
84+
: addon == null
85+
? `/org/${organization?.slug ?? '_'}/billing?panel=costControl&source=${source}`
86+
: `/project/${project?.ref ?? '_'}/settings/addons?panel=${addon}&source=${source}`
8587
}
8688
>
8789
{buttonText || (plan === 'free' ? 'Upgrade to Pro' : 'Enable add on')}

packages/shared-data/pricing.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -421,8 +421,8 @@ export const pricing: Pricing = {
421421
title: 'Max file upload size',
422422
plans: {
423423
free: '50 MB',
424-
pro: '50 GB',
425-
team: '50 GB',
424+
pro: '500 GB',
425+
team: '500 GB',
426426
enterprise: 'Custom',
427427
},
428428
usage_based: false,

0 commit comments

Comments
 (0)