Skip to content

feat(tables): raise per-plan table limits#5135

Merged
TheodoreSpeaks merged 2 commits into
stagingfrom
feat/increase-table-defaults
Jun 19, 2026
Merged

feat(tables): raise per-plan table limits#5135
TheodoreSpeaks merged 2 commits into
stagingfrom
feat/increase-table-defaults

Conversation

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator

Summary

  • Raise per-plan table caps in DEFAULT_TABLE_PLAN_LIMITS: free 5 tables / 50k rows, pro 100 / 100k, max (team) 1,000 / 500k; enterprise stays the custom backstop
  • Update env.ts override doc comments and landing pricing cards to match; enterprise card now reads "Custom tables & rows"
  • Upgrade comparison table already showed these numbers, so no change there
  • Limits are enforced live against the workspace's current plan (post-0241 assertRowCapacity), so this applies to existing tables immediately — no backfill

Type of Change

  • New feature / enhancement

Testing

Tested manually. bun run lint clean, bun run check:api-validation:strict passed.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

TheodoreSpeaks and others added 2 commits June 18, 2026 17:22
…max 1k/500k)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview, Comment Jun 19, 2026 1:37am

Request Review

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@greptile review

@cursor

cursor Bot commented Jun 19, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Higher per-plan row/table caps take effect immediately via live plan enforcement, which increases storage and export/delete load for large tables without a migration or backfill.

Overview
Raises workspace table caps for Community, Pro, and Max across enforcement defaults, env override docs, and landing pricing.

Per-plan limits move from 3 / 1k rows (free), 25 / 5k (pro), and 100 / 10k (team/max) to 5 / 50k, 100 / 100k, and 1,000 / 500k in DEFAULT_TABLE_PLAN_LIMITS and matching FREE_*, PRO_*, and TEAM_* env comments. Enterprise numeric defaults are unchanged; the Enterprise pricing card now says Custom tables & rows instead of fixed table/row numbers.

Landing pricing tier feature strings are updated to match. A comment on EXPORT_ASYNC_THRESHOLD_ROWS is clarified (async export above 10k rows); the threshold value is unchanged.

Reviewed by Cursor Bugbot for commit 3436fdc. Bugbot is set up for automated code reviews on this repo. Configure here.

@greptile-apps

greptile-apps Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR raises per-plan table limits across free, pro, and team tiers and updates the pricing UI and env-var doc comments to match. All three surfaces (constants, env docs, pricing cards) are updated consistently.

  • DEFAULT_TABLE_PLAN_LIMITS updated: free 3→5 tables / 1k→50k rows, pro 25→100 / 5k→100k, team 100→1k / 10k→500k; enterprise unchanged at 10k/1M.
  • EXPORT_ASYNC_THRESHOLD_ROWS stays at 10,000, meaning every plan tier now falls into the async-export path for moderately-sized tables (previously only enterprise); the comment was updated to reflect this intentional shift.
  • Pricing card for enterprise switches from a concrete "10,000 tables · 1M rows each" to "Custom tables & rows", while backend enterprise limits remain unchanged.

Confidence Score: 4/5

Safe to merge; changes are contained to configuration constants, doc comments, and marketing copy with no new logic paths.

All three files change in sync and the numbers match across constants, env docs, and the pricing UI. The one non-obvious side effect — async export now triggering for all plans with >10k rows — appears intentional given the comment update, but is worth confirming before the limits go live.

apps/sim/lib/table/constants.ts — both the EXPORT_ASYNC_THRESHOLD_ROWS interaction and the now-stale TABLE_LIMITS hard constants are worth a second look.

Important Files Changed

Filename Overview
apps/sim/lib/table/constants.ts Raises DEFAULT_TABLE_PLAN_LIMITS across all non-enterprise plans; updates EXPORT_ASYNC_THRESHOLD_ROWS comment to reflect that the threshold (10k) is now well below all plan row caps — tables with more than 10k rows will trigger async exports on every tier.
apps/sim/lib/core/config/env.ts Doc-comment-only update to align env var descriptions with the new default values; no logic changes.
apps/sim/app/(landing)/components/pricing/pricing.tsx Updates feature strings in PRICING_TIERS to match new limits; enterprise card changed from a hard-coded '10,000 tables · 1M rows each' to 'Custom tables & rows'.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[User Action on Table] --> B{Row Count > 10k?}
    B -- No --> C[Synchronous Stream Export]
    B -- Yes --> D[Async Background Export Job]

    subgraph "New Plan Row Caps"
        E[Free: 50,000 rows]
        F[Pro: 100,000 rows]
        G[Team: 500,000 rows]
        H[Enterprise: 1,000,000 rows]
    end

    B -. "EXPORT_ASYNC_THRESHOLD_ROWS = 10,000 (unchanged)" .- B

    style C fill:#22c55e,color:#fff
    style D fill:#f59e0b,color:#fff
    style E fill:#3b82f6,color:#fff
    style F fill:#3b82f6,color:#fff
    style G fill:#3b82f6,color:#fff
    style H fill:#3b82f6,color:#fff
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[User Action on Table] --> B{Row Count > 10k?}
    B -- No --> C[Synchronous Stream Export]
    B -- Yes --> D[Async Background Export Job]

    subgraph "New Plan Row Caps"
        E[Free: 50,000 rows]
        F[Pro: 100,000 rows]
        G[Team: 500,000 rows]
        H[Enterprise: 1,000,000 rows]
    end

    B -. "EXPORT_ASYNC_THRESHOLD_ROWS = 10,000 (unchanged)" .- B

    style C fill:#22c55e,color:#fff
    style D fill:#f59e0b,color:#fff
    style E fill:#3b82f6,color:#fff
    style F fill:#3b82f6,color:#fff
    style G fill:#3b82f6,color:#fff
    style H fill:#3b82f6,color:#fff
Loading

Comments Outside Diff (1)

  1. apps/sim/lib/table/constants.ts, line 9-10 (link)

    P2 TABLE_LIMITS hard constants now significantly understate plan limits

    MAX_TABLES_PER_WORKSPACE (100) and MAX_ROWS_PER_TABLE (10,000) in TABLE_LIMITS are now far below the team-tier limits (1,000 tables / 500,000 rows). The service.ts comment calls these values "vestigial," and enforcement flows through assertRowCapacity using the plan-based limits, so there is no active cap conflict. However, a future contributor reading TABLE_LIMITS could reasonably treat these as the authoritative system limits and introduce a regression. A brief note in the JSDoc or a rename (e.g., LEGACY_MAX_ROWS_PER_TABLE) would clarify their non-enforcement role.

Reviews (1): Last reviewed commit: "Merge remote-tracking branch 'origin/sta..." | Re-trigger Greptile

/** Row count above which an export runs as a background job instead of a synchronous stream.
* Matches the default per-table row cap, so non-enterprise tables keep instant downloads. */
* Tables at or under this stream instantly; larger ones fall back to an async export job. */
EXPORT_ASYNC_THRESHOLD_ROWS: 10000,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 EXPORT_ASYNC_THRESHOLD_ROWS now triggers async export for most tables on every plan

EXPORT_ASYNC_THRESHOLD_ROWS is kept at 10,000 while the minimum plan row cap has jumped to 50,000 (free). Any table that fills even 20% of its free-tier quota will silently switch from instant streaming to an async background job. The old comment explicitly noted this threshold was aligned with the per-plan row cap to preserve synchronous downloads for non-enterprise users — that guarantee no longer holds. This is likely intentional given the server-load implications of streaming large tables synchronously, but it's worth confirming the async export UX is ready to be the default experience for all plan tiers rather than an enterprise-only path.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@greptile-apps

greptile-apps Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR raises per-plan table caps in DEFAULT_TABLE_PLAN_LIMITS (free: 5 tables / 50k rows, pro: 100 / 100k, team: 1,000 / 500k) and updates the landing-page pricing cards and env.ts doc-comments to match. Enterprise defaults and the enforcement infrastructure (assertRowCapacity, getWorkspaceTableLimits) are unchanged.

  • constants.ts: Updates DEFAULT_TABLE_PLAN_LIMITS with new limits; updates the EXPORT_ASYNC_THRESHOLD_ROWS comment to reflect that the threshold is now decoupled from tier row caps.
  • pricing.tsx: Syncs landing-page feature bullets with the new limits; enterprise card now reads "Custom tables & rows."
  • env.ts: Updates inline doc-comment defaults on all six plan-limit env vars.

Confidence Score: 4/5

Safe to merge — the limit increases are correctly wired through the existing billing enforcement stack with no gaps in the call chain.

All six createTable call sites (API routes + copilot tool) explicitly fetch getWorkspaceTableLimits and pass maxTables, so the new limits are enforced end-to-end. The two legacy constants (TABLE_LIMITS.MAX_ROWS_PER_TABLE, MAX_TABLES_PER_WORKSPACE) stay stale but are vestigial fallbacks that current call sites bypass. The main side-effect is that EXPORT_ASYNC_THRESHOLD_ROWS (10k) is now well below even the free-tier row cap (50k), meaning more users will encounter async exports — a real UX shift that is documented in the updated comment but not mitigated in the UI.

apps/sim/lib/table/constants.ts — the top-level TABLE_LIMITS fallback constants and EXPORT_ASYNC_THRESHOLD_ROWS deserve a second look.

Important Files Changed

Filename Overview
apps/sim/lib/table/constants.ts Core limit constants updated correctly; all createTable callers verified to pass maxTables from getWorkspaceTableLimits. Legacy TABLE_LIMITS.MAX_ROWS_PER_TABLE (10k) and MAX_TABLES_PER_WORKSPACE (100) remain unchanged as vestigial fallbacks. EXPORT_ASYNC_THRESHOLD_ROWS stays at 10k while free-tier row cap is now 50k — comment updated to reflect the decoupling, but this is a meaningful UX shift.
apps/sim/app/(landing)/components/pricing/pricing.tsx Landing-page pricing strings updated to match new limits for free, pro, and team tiers; enterprise card changed from a specific number to 'Custom tables & rows'.
apps/sim/lib/core/config/env.ts Doc-comment defaults on the six plan-limit env vars updated to match the new constants; no logic changes.

Comments Outside Diff (1)

  1. apps/sim/lib/table/constants.ts, line 9-10 (link)

    P2 Legacy TABLE_LIMITS row/table constants are now significantly misleading

    MAX_ROWS_PER_TABLE: 10000 and MAX_TABLES_PER_WORKSPACE: 100 are now far below the actual plan limits (free: 50k rows, team: 1,000 tables). Per the comment in service.ts, these are vestigial fallbacks for a DB column that's no longer authoritative — actual enforcement goes through assertRowCapacitygetWorkspaceTableLimits. They pose no runtime risk today because every createTable call site fetches planLimits explicitly, but a future caller that omits maxTables would silently cap at 100 tables (breaking team-tier workspaces). A JSDoc note calling these obsolete, or aligning them with the new defaults, would prevent that footgun.

Reviews (2): Last reviewed commit: "Merge remote-tracking branch 'origin/sta..." | Re-trigger Greptile

/** Row count above which an export runs as a background job instead of a synchronous stream.
* Matches the default per-table row cap, so non-enterprise tables keep instant downloads. */
* Tables at or under this stream instantly; larger ones fall back to an async export job. */
EXPORT_ASYNC_THRESHOLD_ROWS: 10000,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Async-export threshold now triggers for nearly all real tables

EXPORT_ASYNC_THRESHOLD_ROWS stays at 10,000 while the smallest plan (free) now caps at 50,000 rows. Any free user who fills their table past 10k rows — and most pro users who would have been safely under 5k rows before — will now land on the async-export path instead of an instant download. The updated comment correctly documents the new reality, but since this is the first time regular (non-enterprise) users will routinely hit the async path, it may be worth a brief mention in release notes or in the UI (e.g., surfacing an "export started" notification proactively). No code change is strictly required, but wanted to flag the UX shift.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@TheodoreSpeaks TheodoreSpeaks merged commit c419a34 into staging Jun 19, 2026
16 checks passed
@TheodoreSpeaks TheodoreSpeaks deleted the feat/increase-table-defaults branch June 19, 2026 02:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant