vercel/platforms

A full-stack Next.js app with multi-tenancy.

6,665 stars TypeScript 8 components

14 hidden assumptions · 6-stage pipeline · 8 components

Like any codebase, this fullstack makes assumptions it never checks — most are routine. The ones worth your attention are below.

Routes subdomain requests to tenant-specific pages with Redis storage

Requests enter through middleware which extracts subdomain from hostname, determines routing destination, and either serves the main site with creation form, redirects to tenant-specific pages after Redis lookup, or provides admin interface for tenant management. Form submissions trigger server actions that validate input, store data in Redis, and redirect to newly created subdomains.

Under the hood, the system uses 2 feedback loops, 1 data pool, 4 control points to manage its runtime behavior.

A 8-component fullstack. 22 files analyzed. Data flows through 6 distinct pipeline stages.

Hidden Assumptions

Most of what this code assumes is routine. These 3 are the ones most likely to cause trouble here. The rest are minor; they're under "Show everything".

Worth your attention first

Redis constructor will silently accept undefined values, causing cryptic connection errors or authentication failures only when first Redis operation is attempted

Worth your attention first

If Vercel changes their preview URL format or uses different delimiters, subdomain extraction fails and requests get routed to main site instead of tenant pages

Worth your attention first

User sees success message and gets redirected to new subdomain URL, but tenant data was never stored, resulting in 404 page when they visit their supposedly created subdomain

Show everything (11 more)
Temporal

Redis get operation to check for existing subdomain and subsequent set operation are atomic - no race condition handling

If this fails: Two users submitting the same subdomain simultaneously could both pass the duplicate check and overwrite each other's data, with the second user's emoji replacing the first user's

app/actions.ts:createSubdomainAction
Shape

Redis returns SubdomainData with exactly the expected shape {emoji: string, createdAt: number} - no validation of retrieved data structure

If this fails: If Redis contains corrupted data or data from a different schema version, the app will crash when trying to access .emoji or .createdAt properties on the returned object

lib/subdomains.ts:getSubdomainData
Scale

Redis SCAN operation will complete within reasonable time/memory limits even with large numbers of subdomain keys

If this fails: Admin dashboard becomes unusable when there are thousands of subdomains - page load times out or consumes excessive memory scanning all keys matching 'subdomain:*' pattern

lib/subdomains.ts:getAllSubdomains
Domain

Unicode property escapes (\p{Emoji}) are supported in the JavaScript runtime environment

If this fails: In older browsers or Node.js versions, the regex throws an error, falls back to length-only validation, and allows non-emoji text as icons, breaking the visual design

lib/subdomains.ts:isValidIcon
Environment

The 'host' header is always present and trustworthy in the NextRequest - no validation for missing or malformed host headers

If this fails: Malicious requests with missing or crafted host headers could cause substring operations to fail, middleware to crash, or subdomain extraction to return unexpected values

middleware.ts:extractSubdomain
Contract

The params object from Next.js always contains a 'subdomain' key and getSubdomainData never throws exceptions

If this fails: If Next.js routing changes or Redis operations throw errors, metadata generation fails silently and pages render with generic titles instead of subdomain-specific ones

app/s/[subdomain]/page.tsx:generateMetadata
Temporal

revalidatePath('/admin') successfully invalidates the cache and Redis DEL operation completes before the admin page re-renders

If this fails: Admin dashboard shows stale data with deleted tenants still visible if cache invalidation fails or Redis deletion is slow, confusing administrators

app/actions.ts:deleteSubdomainAction
Scale

Sanitized subdomain string replacement using regex /[^a-z0-9-]/g is safe for all Unicode input and doesn't create unexpected empty strings

If this fails: Unicode characters, spaces, or special characters in subdomain input could result in empty sanitized strings or collisions where different inputs produce identical sanitized names

app/actions.ts:createSubdomainAction
Environment

NEXT_PUBLIC_ROOT_DOMAIN environment variable is always set and contains a valid domain format

If this fails: If environment variable is missing, rootDomain becomes undefined, breaking URL generation, subdomain detection, and middleware routing throughout the application

lib/utils.ts:rootDomain
Domain

Production domains always follow the pattern where valid subdomains are single-level (no nested subdomains like api.tenant.domain.com)

If this fails: Multi-level subdomains get incorrectly parsed - 'api.tenant.domain.com' would extract 'api.tenant' as the subdomain instead of recognizing this as an invalid pattern

middleware.ts:extractSubdomain
Resource

All tenant operations (especially deletion) complete quickly enough that the isPending state provides adequate user feedback

If this fails: If Redis operations are slow or network is poor, users might click delete buttons multiple times during long pending states, potentially triggering multiple deletion attempts

app/admin/dashboard.tsx:TenantGrid

Open the standalone hidden-assumptions report for platforms →

How Data Flows Through the System

Requests enter through middleware which extracts subdomain from hostname, determines routing destination, and either serves the main site with creation form, redirects to tenant-specific pages after Redis lookup, or provides admin interface for tenant management. Form submissions trigger server actions that validate input, store data in Redis, and redirect to newly created subdomains.

  1. Extract subdomain from request — Middleware extracts subdomain from hostname using extractSubdomain function, handling different environments: localhost with pattern matching, production with domain suffix checking, and Vercel preview URLs with triple-dash parsing
  2. Route request based on subdomain — Middleware determines destination: if no subdomain detected, serves main site; if subdomain found, rewrites URL to /s/[subdomain] route; admin requests go to /admin unchanged
  3. Load tenant page data — The /s/[subdomain] page calls getSubdomainData which sanitizes the subdomain parameter and queries Redis using key `subdomain:{sanitizedSubdomain}` to retrieve tenant configuration
  4. Create new subdomain — createSubdomainAction validates form input (subdomain format must be lowercase alphanumeric with hyphens, emoji must pass isValidIcon check), stores SubdomainData in Redis, and redirects to new subdomain URL [CreateState → SubdomainData]
  5. List all tenants — getAllSubdomains scans Redis for keys matching pattern `subdomain:*`, retrieves all tenant data, and formats as Tenant array with subdomain names extracted from keys for admin dashboard display
  6. Delete tenant — deleteSubdomainAction removes the Redis key `subdomain:{subdomain}`, revalidates the admin page path to refresh the tenant list, and returns success/error feedback

Data Models

The data structures that flow between stages — the contracts that hold the system together.

SubdomainData lib/subdomains.ts
type with emoji: string (the tenant's chosen emoji icon) and createdAt: number (Unix timestamp)
Created when user submits subdomain form, stored in Redis with key `subdomain:{name}`, retrieved when subdomain is accessed or admin views dashboard
Tenant app/admin/dashboard.tsx
type with subdomain: string, emoji: string, and createdAt: number (flattened SubdomainData with subdomain key)
Constructed from Redis data by combining the key name with stored SubdomainData for admin dashboard display
CreateState app/subdomain-form.tsx
type with optional error: string, success: boolean, subdomain: string, and icon: string for form validation feedback
Returned by createSubdomainAction to communicate validation errors or success back to the form component
DeleteState app/admin/dashboard.tsx
type with optional error: string and success: string for deletion feedback
Returned by deleteSubdomainAction to show confirmation or error messages in admin interface

System Behavior

How the system operates at runtime — where data accumulates, what loops, what waits, and what controls what.

Data Pools

Redis tenant store (database)
Key-value store using pattern `subdomain:{name}` where each key holds SubdomainData with emoji and creation timestamp

Feedback Loops

Delays

Control Points

Technology Stack

Next.js 15 (framework)
Full-stack React framework providing App Router, server actions, middleware, and deployment optimization
React 19 (framework)
UI library with hooks for state management and form handling in subdomain creation and admin interfaces
Upstash Redis (database)
Serverless Redis for tenant data persistence using key-value storage with async operations
Tailwind CSS (framework)
Utility-first CSS framework for component styling with custom design tokens and responsive design
Radix UI (library)
Unstyled, accessible UI primitives for dialogs, popovers, labels providing keyboard navigation and ARIA support
TypeScript (runtime)
Type system ensuring data model contracts between client and server components
Frimousse (library)
Emoji picker component library for tenant icon selection with search and categorization

Key Components

Explore the interactive analysis

See the full architecture map, data flow, and code patterns visualization.

Analyze on CodeSea

Related Fullstack Repositories

Frequently Asked Questions

What is platforms used for?

Routes subdomain requests to tenant-specific pages with Redis storage vercel/platforms is a 8-component fullstack written in TypeScript. Data flows through 6 distinct pipeline stages. The codebase contains 22 files.

How is platforms architected?

platforms is organized into 4 architecture layers: Request Routing, Tenant Management, Data Layer, UI Components. Data flows through 6 distinct pipeline stages. This layered structure keeps concerns separated and modules independent.

How does data flow through platforms?

Data moves through 6 stages: Extract subdomain from request → Route request based on subdomain → Load tenant page data → Create new subdomain → List all tenants → .... Requests enter through middleware which extracts subdomain from hostname, determines routing destination, and either serves the main site with creation form, redirects to tenant-specific pages after Redis lookup, or provides admin interface for tenant management. Form submissions trigger server actions that validate input, store data in Redis, and redirect to newly created subdomains. This pipeline design reflects a complex multi-stage processing system.

What technologies does platforms use?

The core stack includes Next.js 15 (Full-stack React framework providing App Router, server actions, middleware, and deployment optimization), React 19 (UI library with hooks for state management and form handling in subdomain creation and admin interfaces), Upstash Redis (Serverless Redis for tenant data persistence using key-value storage with async operations), Tailwind CSS (Utility-first CSS framework for component styling with custom design tokens and responsive design), Radix UI (Unstyled, accessible UI primitives for dialogs, popovers, labels providing keyboard navigation and ARIA support), TypeScript (Type system ensuring data model contracts between client and server components), and 1 more. A focused set of dependencies that keeps the build manageable.

What system dynamics does platforms have?

platforms exhibits 1 data pool (Redis tenant store), 2 feedback loops, 4 control points, 3 delays. The feedback loops handle self-correction and cache-invalidation. These runtime behaviors shape how the system responds to load, failures, and configuration changes.

What design patterns does platforms use?

4 design patterns detected: Server Actions, Middleware Routing, Component Composition, Environment-Specific Logic.

Analyzed on April 20, 2026 by CodeSea. Written by .