improvement(tables): make max row size env-configurable and raise default to 400KB (#5338)

This commit is contained in:
Theodore Li
2026-07-01 19:10:25 -04:00
committed by GitHub
parent eb367def31
commit 44215126f4
3 changed files with 18 additions and 4 deletions
+1
View File
@@ -94,6 +94,7 @@ export const env = createEnv({
TEAM_TABLE_ROWS_LIMIT: z.number().optional(), // Max rows per table on team tier (default: 500000)
ENTERPRISE_TABLES_LIMIT: z.number().optional(), // Max user tables per workspace on enterprise tier (default: 10000)
ENTERPRISE_TABLE_ROWS_LIMIT: z.number().optional(), // Max rows per table on enterprise tier (default: 1000000)
TABLE_MAX_ROW_SIZE_BYTES: z.number().optional(), // Max serialized size in bytes of a single user-table row (default: 409600)
// Credit-tier Stripe prices (monthly)
STRIPE_PRICE_TIER_25_MO: z.string().min(1).optional(), // Pro: $25/mo (6,000 credits)
+13 -1
View File
@@ -8,7 +8,7 @@ import { env, envNumber } from '@/lib/core/config/env'
export const TABLE_LIMITS = {
MAX_TABLES_PER_WORKSPACE: 100,
MAX_ROWS_PER_TABLE: 10000,
MAX_ROW_SIZE_BYTES: 100 * 1024, // 100KB
MAX_ROW_SIZE_BYTES: 400 * 1024, // 400KB
MAX_COLUMNS_PER_TABLE: 50,
MAX_TABLE_NAME_LENGTH: 128,
MAX_COLUMN_NAME_LENGTH: 50,
@@ -61,6 +61,18 @@ export const DEFAULT_TABLE_PLAN_LIMITS = {
},
} as const
/**
* Maximum serialized size in bytes of a single row. Defaults to
* `TABLE_LIMITS.MAX_ROW_SIZE_BYTES`; overridable via the
* `TABLE_MAX_ROW_SIZE_BYTES` env var (server-only, read at call time).
*/
export function getMaxRowSizeBytes(): number {
return envNumber(env.TABLE_MAX_ROW_SIZE_BYTES, TABLE_LIMITS.MAX_ROW_SIZE_BYTES, {
min: 1,
integer: true,
})
}
export type PlanName = keyof typeof DEFAULT_TABLE_PLAN_LIMITS
export interface TablePlanLimits {
+4 -3
View File
@@ -7,7 +7,7 @@ import { userTableRows } from '@sim/db/schema'
import { and, eq, or, type SQL, sql } from 'drizzle-orm'
import { NextResponse } from 'next/server'
import { getColumnId } from '@/lib/table/column-keys'
import { COLUMN_TYPES, NAME_PATTERN, TABLE_LIMITS } from '@/lib/table/constants'
import { COLUMN_TYPES, getMaxRowSizeBytes, NAME_PATTERN, TABLE_LIMITS } from '@/lib/table/constants'
import { withSeqscanOff } from '@/lib/table/planner'
import type {
ColumnDefinition,
@@ -356,11 +356,12 @@ export function coerceRowToSchema(data: RowData, schema: TableSchema): Validatio
/** Validates row data size is within limits. */
export function validateRowSize(data: RowData): ValidationResult {
const maxRowSizeBytes = getMaxRowSizeBytes()
const size = JSON.stringify(data).length
if (size > TABLE_LIMITS.MAX_ROW_SIZE_BYTES) {
if (size > maxRowSizeBytes) {
return {
valid: false,
errors: [`Row size exceeds limit (${size} bytes > ${TABLE_LIMITS.MAX_ROW_SIZE_BYTES} bytes)`],
errors: [`Row size exceeds limit (${size} bytes > ${maxRowSizeBytes} bytes)`],
}
}
return { valid: true, errors: [] }