import ProductIcon from 'components/ProductIcon' import { Fragment, ReactNode } from 'react' import { IconPricingIncludedCheck, IconPricingMinus } from './PricingIcons' import { InfoTooltip } from 'ui-patterns/info-tooltip' import { FeatureKey } from 'shared-data/pricing' import Link from 'next/link' type PricingTooltips = { [key in FeatureKey]?: { main?: ReactNode pro?: ReactNode team?: ReactNode enterprise?: ReactNode } } export const pricingTooltips: PricingTooltips = { 'database.dedicatedPostgresDatabase': { main: 'A Postgres database with no restrictions? You get it. No pseudo limited users, you are the postgres root user. No caveats.', }, 'database.size': { main: 'Billing is based on the provisioned disk size. Paid plan projects get provisioned with 8 GB of disk by default and autoscale to 1.5x the size once you get close to the limit. The first 8 GB of disk per project comes with no additional fees.\nFree plan customers are limited to 500 MB database size per project.', }, 'database.advancedDiskConfig': { main: 'Supabase databases are backed by high performance SSD disks. The disk can be scaled up to 60 TB, 80,000 IOPS and 4,000 MB/s throughput.', }, 'database.automaticBackups': { main: 'Backups are entire copies of your database that can be restored in the future.', pro: '7 days of backup (if > 1 TB, contact for Enterprise pricing)', team: '14 days of backup (if > 1 TB, contact for Enterprise pricing)', }, 'database.pitr': { main: 'PITR cannot be applied retroactively, projects can only be rolled back to the point from which PITR has been applied.', }, 'database.pausing': { main: 'Projects that have no activity or API requests will be paused. They can be reactivated via the dashboard.', }, 'database.egress': { main: 'Billing is based on the total sum of all outgoing traffic (includes Database, Storage, Realtime, Auth, API, Edge Functions, Supavisor, Log Drains) in GB throughout your billing period. Excludes cache hits.', }, 'database.cachedEgress': { main: 'Billing is based on the total sum of any outgoing traffic (includes Database, Storage, API, Edge Functions) in GB throughout your billing period that is served from our CDN cache.', }, 'auth.totalUsers': { main: 'The maximum number of users your project can have', }, 'auth.maus': { main: 'Users who log in or refresh their token count towards MAU.\nBilling is based on the sum of distinct users requesting your API throughout the billing period. Resets every billing cycle.', }, 'auth.userDataOwnership': { main: 'Full ownership and access to the underlying user data including encrypted passwords.', }, 'auth.anonSignIns': { main: 'Anonymous user requests count towards MAU, just like a permanent user.', }, 'auth.basicMFA': { main: 'Multi-factor authentication (MFA), sometimes called two-factor authentication (2FA), using Time-based One Time Passwords (TOTP) via an Authenticator App.', }, 'auth.advancedMFAPhone': { main: 'Multi-factor authentication (MFA), sometimes called two-factor authentication (2FA), using SMS or WhatsApp messages.\nAdditional fees apply based on your provider.', }, 'auth.thirdPartyMAUs': { main: 'Users who use the Supabase platform through a third-party authentication provider (Firebase Auth, Auth0 or Cognito).\nBilling is based on the sum of distinct third-party users requesting your API through the billing period. Resets every billing cycle.', }, 'storage.size': { main: "The sum of all objects' size in your storage buckets.\nBilling is prorated down to the hour and will be displayed as GB-Hrs on your invoice.", }, 'storage.maxFileSize': { main: 'You can change the upload size in the dashboard', }, 'storage.cdn': { main: 'Assets in Storage are automatically cached on a CDN. With Smart CDN caching enabled, the CDN cache is automatically re-validated when the underlying asset changes. CDN caching is enabled across all plans and assets in the paid plans are cached via the Smart CDN.', }, 'storage.transformations': { main: 'We count all images that were transformed in the billing period, ignoring any transformations.\nUsage example: You transform one image with four different size transformations and another image with just a single transformation. It counts as two, as only two images were transformed.\nBilling is based on the count of (origin) images that used transformations throughout the billing period. Resets every billing cycle.', }, 'functions.invocations': { main: 'Billing is based on the sum of all invocations, independent of response status, throughout your billing period.', }, 'realtime.concurrentConnections': { main: 'Total number of successful connections. Connections attempts are not counted towards usage.\nBilling is based on the maximum amount of concurrent peak connections throughout your billing period.', }, 'realtime.messagesPerMonth': { main: "Count of messages going through Realtime. Includes database changes, broadcast and presence. \nUsage example: If you do a database change and 5 clients listen to that change via Realtime, that's 5 messages. If you broadcast a message and 4 clients listen to that, that's 5 messages (1 message sent, 4 received).\nBilling is based on the total amount of messages throughout your billing period.", }, 'security.logDrain': { main: 'Only events processed and sent to destinations are counted. Egress required to export logs count towards usage.\nEgress through Log Drains is rolled up into the unified egress and benefits from the unified egress quota.', }, 'security.hipaa': { main: 'Available as a paid add-on on Team Plan and above.', }, 'security.privateLink': { main: ( AWS PrivateLink enables private connectivity between your AWS VPC and Supabase, keeping traffic within the AWS network. Read more in our{' '} docs . ), }, 'security.accessRoles': { main: ( Supabase provides granular access controls to manage permissions across your organizations and projects. Read more in our{' '} docs . ), }, 'security.customDomains': { enterprise: 'Volume discounts available.', }, 'auth.auditLogs': { main: ( Auth Audit Logs provide comprehensive tracking of authentication events. Audit logs are automatically captured for all authentication events and help you monitor user authentication activities, detect suspicious behavior, and maintain compliance with security requirements. Read more in our{' '} docs . ), }, 'security.platformAuditLogs': { main: ( Any Platform API/Dashboard actions performed by organization members are logged automatically for auditing and security purposes. Includes actions such as creating a new project, inviting members or changing project settings. Read more in our{' '} docs . ), }, } export const PricingTableRowDesktop = (props: any) => { const category = props.category return ( <>
{props.icon && }

{category.title}

{category.features.map((feat: any, i: number) => { const tooltips = pricingTooltips[feat.key as FeatureKey] return ( {feat.title} {tooltips?.main && ( {tooltips.main} )} {Object.entries(feat.plans).map((entry: any, i) => { const planName = entry[0] as 'pro' | 'team' | 'enterprise' const planValue = entry[1] return ( {typeof planValue === 'boolean' && planValue === true ? ( ) : typeof planValue === 'boolean' && planValue === false ? (
) : (
{tooltips?.[planName] && ( {tooltips[planName]} )} {typeof planValue === 'string' ? planValue : planValue[0]} {Array.isArray(planValue) && planValue.slice(1).map((val, idx) => ( {val} ))}
)} ) })} {i === category.features.length - 1 && ( )}
) })} ) } export const PricingTableRowMobile = (props: any) => { const category = props.category const plan = props.plan return ( {category.features.map((feat: any, i: number) => { return ( ) })}
{category.icon ? : null} {category.title}
Feature Included

{feat.title}

{typeof feat.plans[plan] === 'boolean' && feat.plans[plan] === true ? ( ) : typeof feat.plans[plan] === 'boolean' && feat.plans[plan] === false ? ( ) : ( {typeof feat.plans[plan] === 'string' ? feat.plans[plan] : feat.plans[plan][0]} {Array.isArray(feat.plans[plan]) && feat.plans[plan].slice(1).map((val, idx) => ( {val} ))} )}
) }