RestoreToNewProject() — supabase Function Reference
Architecture documentation for the RestoreToNewProject() function in RestoreToNewProject.tsx from the supabase codebase.
Entity Profile
Relationship Graph
Source Code
apps/studio/components/interfaces/Database/RestoreToNewProject/RestoreToNewProject.tsx lines 35–318
export const RestoreToNewProject = () => {
const { data: project } = useSelectedProjectQuery()
const { data: organization } = useSelectedOrganizationQuery()
const isFreePlan = organization?.plan?.id === 'free'
const isOrioleDb = useIsOrioleDb()
const isAwsK8s = useIsAwsK8sCloudProvider()
const [refetchInterval, setRefetchInterval] = useState<number | false>(false)
const [selectedBackupId, setSelectedBackupId] = useState<number | null>(null)
const [showConfirmationDialog, setShowConfirmationDialog] = useState(false)
const [showNewProjectDialog, setShowNewProjectDialog] = useState(false)
const [recoveryTimeTarget, setRecoveryTimeTarget] = useState<number | null>(null)
const {
data: cloneBackups,
error,
isPending: cloneBackupsLoading,
isError,
} = useCloneBackupsQuery({ projectRef: project?.ref }, { enabled: !isFreePlan })
const isActiveHealthy = project?.status === PROJECT_STATUS.ACTIVE_HEALTHY
const { can: canReadPhysicalBackups, isSuccess: isPermissionsLoaded } = useAsyncCheckPermissions(
PermissionAction.READ,
'physical_backups'
)
const { can: canTriggerPhysicalBackups } = useAsyncCheckPermissions(
PermissionAction.INFRA_EXECUTE,
'queue_job.restore.prepare'
)
const PITR_ENABLED = cloneBackups?.pitr_enabled
const PHYSICAL_BACKUPS_ENABLED = project?.is_physical_backups_enabled
const dbVersion = getDatabaseMajorVersion(project?.dbVersion ?? '')
const IS_PG15_OR_ABOVE = dbVersion >= 15
const targetVolumeSizeGb = cloneBackups?.target_volume_size_gb
const targetComputeSize = cloneBackups?.target_compute_size
const planId = organization?.plan?.id ?? 'free'
const { data } = useDiskAttributesQuery({ projectRef: project?.ref })
const storageType = data?.attributes?.type ?? 'gp3'
const {
data: cloneStatus,
refetch: refetchCloneStatus,
isPending: cloneStatusLoading,
isSuccess: isCloneStatusSuccess,
} = useCloneStatusQuery(
{
projectRef: project?.ref,
},
{
refetchInterval,
refetchOnWindowFocus: false,
enabled: PHYSICAL_BACKUPS_ENABLED || PITR_ENABLED,
}
)
const IS_CLONED_PROJECT = cloneStatus?.cloned_from?.source_project?.ref ? true : false
const isLoading = !isPermissionsLoaded || cloneBackupsLoading || cloneStatusLoading
useEffect(() => {
if (!isCloneStatusSuccess) return
const hasTransientState = cloneStatus.clones.some((c) => c.status === 'IN_PROGRESS')
if (!hasTransientState) {
setRefetchInterval(false)
}
}, [cloneStatus?.clones, isCloneStatusSuccess])
const previousClones = cloneStatus?.clones
const isRestoring = previousClones?.some((c) => c.status === 'IN_PROGRESS')
const restoringClone = previousClones?.find((c) => c.status === 'IN_PROGRESS')
if (isFreePlan) {
return (
<UpgradeToPro
buttonText="Upgrade"
source="backupsRestoreToNewProject"
featureProposition="enable restoring to new project"
primaryText="Restore to a new project requires Pro Plan and above"
secondaryText="To restore to a new project, you need to upgrade to a Pro Plan and have physical backups enabled."
/>
)
}
if (isOrioleDb) {
return (
<Admonition
type="default"
title="Restoring to new projects are not available for OrioleDB"
description="OrioleDB is currently in public alpha and projects created are strictly ephemeral with no database backups"
/>
)
}
if (isAwsK8s) {
return (
<Admonition
type="default"
title="Restoring to new projects is temporarily not available for AWS (Revamped) projects"
/>
)
}
if (!canReadPhysicalBackups) {
return <NoPermission resourceText="view backups" />
}
if (!canTriggerPhysicalBackups) {
return <NoPermission resourceText="restore backups" />
}
if (!IS_PG15_OR_ABOVE) {
return (
<Admonition
type="default"
title="Restore to new project is not available for this database version"
>
<Markdown
className="max-w-full"
content={`Restore to new project is only available for Postgres 15 and above.
Go to [infrastructure settings](/project/${project?.ref}/settings/infrastructure)
to upgrade your database version.
`}
/>
</Admonition>
)
}
if (!PHYSICAL_BACKUPS_ENABLED) {
return (
<Admonition
type="default"
title="Physical backups are required"
description={
<>
Physical backups must be enabled to restore your database to a new project.{' '}
<InlineLink href={`${DOCS_URL}/guides/platform/backups`}>Learn more</InlineLink>
</>
}
/>
)
}
if (isLoading) {
return <GenericSkeletonLoader />
}
if (IS_CLONED_PROJECT) {
return (
<Admonition type="default" title="This project cannot be restored to a new project">
<Markdown
className="max-w-full [&>p]:!leading-normal"
content={`This is a temporary limitation whereby projects that were originally restored from another project cannot be restored to yet another project.`}
/>
<Button asChild type="default">
<Link href={`/project/${cloneStatus?.cloned_from?.source_project?.ref || ''}`}>
Go to original project
</Link>
</Button>
</Admonition>
)
}
if (isError) {
return <AlertError error={error} subject="Failed to retrieve backups" />
}
if (!isActiveHealthy) {
return (
<Admonition
type="default"
title="Restore to new project is not available while project is offline"
description="Your project needs to be online to restore your database to a new project"
/>
)
}
if (
!isLoading &&
PITR_ENABLED &&
!cloneBackups?.physicalBackupData.earliestPhysicalBackupDateUnix
) {
return (
<Admonition
type="default"
title="No backups found"
description="PITR is enabled, but no backups were found. Check again in a few minutes."
/>
)
}
if (!isLoading && !PITR_ENABLED && cloneBackups?.backups.length === 0) {
return (
<>
<Admonition
type="default"
title="No backups found"
description="Backups are enabled, but no backups were found. Check again tomorrow."
/>
</>
)
}
const additionalMonthlySpend = projectSpecToMonthlyPrice({
targetVolumeSizeGb: targetVolumeSizeGb ?? 0,
targetComputeSize: targetComputeSize ?? 'nano',
planId: planId ?? 'free',
storageType: storageType as DiskType,
})
return (
<div className="flex flex-col gap-4">
<ConfirmRestoreDialog
open={showConfirmationDialog}
onOpenChange={setShowConfirmationDialog}
onSelectContinue={() => {
setShowConfirmationDialog(false)
setShowNewProjectDialog(true)
}}
additionalMonthlySpend={additionalMonthlySpend}
/>
<CreateNewProjectDialog
open={showNewProjectDialog}
selectedBackupId={selectedBackupId}
recoveryTimeTarget={recoveryTimeTarget}
additionalMonthlySpend={additionalMonthlySpend}
onOpenChange={setShowNewProjectDialog}
onCloneSuccess={() => {
refetchCloneStatus()
setRefetchInterval(5000)
setShowNewProjectDialog(false)
}}
/>
{isRestoring ? (
<Alert_Shadcn_ className="[&>svg]:bg-none! [&>svg]:text-foreground-light mb-6">
<Loader2 className="animate-spin" />
<AlertTitle_Shadcn_>Restoration in progress</AlertTitle_Shadcn_>
<AlertDescription_Shadcn_>
<p>
The new project {(restoringClone?.target_project as any)?.name || ''} is currently
being created. You'll be able to restore again once the project is ready.
</p>
<Button asChild type="default" className="mt-2">
<Link href={`/project/${restoringClone?.target_project?.ref ?? '_'}`}>
Go to new project
</Link>
</Button>
</AlertDescription_Shadcn_>
</Alert_Shadcn_>
) : null}
{previousClones?.length ? (
<div className="flex flex-col gap-2">
<h3 className="text-sm font-medium">Previous restorations</h3>
<Panel className="flex flex-col divide-y divide-border">
{previousClones?.map((c) => <PreviousRestoreItem key={c.inserted_at} clone={c} />)}
</Panel>
</div>
) : null}
{PITR_ENABLED ? (
<>
<PITRForm
disabled={isRestoring}
onSubmit={(v) => {
setShowConfirmationDialog(true)
setRecoveryTimeTarget(v.recoveryTimeTargetUnix)
}}
earliestAvailableBackupUnix={
cloneBackups?.physicalBackupData.earliestPhysicalBackupDateUnix || 0
}
latestAvailableBackupUnix={
cloneBackups?.physicalBackupData.latestPhysicalBackupDateUnix || 0
}
/>
</>
) : (
<BackupsList
disabled={isRestoring}
onSelectRestore={(id) => {
setSelectedBackupId(id)
setShowConfirmationDialog(true)
}}
/>
)}
</div>
)
}
Domain
Subdomains
Source
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free