Skip to content

Plans & limits

PandaStack has four plans: free, pro, premium, and enterprise. Each plan maps to a static limits matrix that controls resource counts, monthly allowances, and feature flags. Throughout the matrix, a value of -1 means unlimited.

PlanContainersStatic sitesDatabasesFunctionsCronjobsBuild min/moBandwidth GB/moDeploy history (d)DB backup retention (d)DB connectionsTeam membersTeamsCustom domainAnalyticsAutoscaling
Free551003001001075011nonono
Prounlimitedunlimitedunlimitedunlimitedunlimited10005003015300unlimitedunlimitedyesyesyes
Premiumunlimitedunlimitedunlimitedunlimitedunlimited25001000 (1 TB)90301000unlimitedunlimitedyesyesyes
Enterpriseunlimitedunlimitedunlimitedunlimitedunlimitedunlimitedunlimited9030unlimitedunlimitedunlimitedyesyesyes
  • Functions and cronjobs are paid-only. The free plan’s count for both is 0, and the functions / cronjobs feature flags are false on free. You must be on a paid plan to create either.
  • Databases: free is capped at 1 database; all paid plans are unlimited.
  • Bandwidth is a monthly quota enforced at the gateway. Premium’s 1000 GB is exactly 1 TB (stored as 1.00 TB in the legacy table). Enterprise is unlimited (-1).
  • Build minutes are metered monthly; overage past the allowance is billed on pro and premium. See Usage & metering.
  • Deployment history retention controls how far back deploy history is kept: 10 days (free), 30 (pro), 90 (premium/enterprise).
  • DB backup retention and DB connection limit apply to provisioned databases — see Database tiers & scaling.
  • Team members / Teams: free is a single member and a single team; all paid plans are unlimited.

Five feature flags are false on free and true on pro, premium, and enterprise:

FeatureFreePaid
customDomainnoyes
analyticsnoyes
autoscalingnoyes
functionsnoyes
cronjobsnoyes

These are the paid-only feature gates. On the free plan:

  • Custom domains are blocked — adding one returns a machine-readable 402 so the dashboard shows an Upgrade CTA. See Custom domains.
  • Analytics capture is off. The one-click deploy button explicitly creates projects with analytics disabled.
  • Autoscaling is unavailable; free containers additionally scale to zero (see below).
  • Functions and Cronjobs cannot be created.

An organization is “paid” if and only if it has an active subscription joined to a plan whose name is not free:

  • isOrgPaid(orgId) returns true iff there exists an active Subscriptions row (status active) joined to Plans where the lower-cased plan name is not free. This same check gates both the container and database create paths, so paid-tier gating is consistent everywhere.
  • getOrgPlan(orgId) resolves the plan name from the same tables:
    • No active subscription, or an active Free plan → free.
    • An exact match on pro, premium, or enterprise → that plan.
    • Any unknown active paid plan name → falls back to pro (it grants the paid feature set rather than wrongly blocking a paying customer).

Enforcement happens at create paths and returns HTTP 402 quota_exceeded:

GuardBehavior
assertWithinLimit()Throws 402 quota_exceeded when the current count is at or above the plan max. Unlimited (-1) short-circuits and always passes.
assertFeature(feature)Throws 402 for free orgs that lack the requested feature flag.
assertPaidPlan()Throws 402 for any free org — used for paid-only features not in the feature-flag union (for example, Monitors).

Examples:

  • A free org creating a 6th container or a 2nd database hits assertWithinLimit and gets 402 quota_exceeded.
  • A free org trying to add a custom domain or create a function hits the corresponding feature gate and gets 402.

To guarantee a customer is never billed against a different allowance than the dashboard shows, the limits module runs a load-time assertion when the API boots. It asserts, for every plan, that:

  • PLAN_LIMITS.buildMinutesPerMonth equals the build-minutes allowance in BILLING_RATES, and
  • PLAN_LIMITS.bandwidthGbPerMonth × 1000 (MB) equals the bandwidth allowance in BILLING_RATES.

Any drift throws, and the API fails to boot. This keeps the plan matrix and the billing rates in lockstep.

The free plan has two automatic lifecycle behaviors that paid plans do not:

  • Free containers scale to zero. A free container scales to 0 instances after it is idle (via KEDA) and cold-starts on the next request (a few seconds). Paid tiers are always-on. See Autoscaling & scale-to-zero.
  • Free databases expire. A free database is automatically deleted 30 days after creation — suspended at 30 days, permanently purged 14 days later. Upgrade to a paid tier to keep it running with backups and no expiry. See Free-tier lifecycle.

Additionally, database multi-zone / High Availability (replicaset, 3 replicas) is paid-only; free databases are single-zone standalone (1 replica) only.