The SPEC stack represents our vision for a unified approach to principled web development, centering on syntactic uniformity, compile-time transformation, and edge-native deployment. By bringing together SolidJS, Partas.Solid’s broad bindings, Elmish, and CloudflareFS, SPEC creates a development paradigm where traditional boundaries between frontend and backend, static and dynamic, web and desktop applications become fluid implementation choices within a cohesive architectural framework.
This document outlines our architectural vision and design philosophy for the SPEC stack. We present this as a proposal to the web development community, inviting feedback, critique, and collaboration as we work toward realizing these ideas. The patterns and capabilities described here represent our design goals and intended direction for development.
Design Intent and Community Vision
The SPEC stack emerges from an observation: current web tech often exhibits fragmentation, emergent increments in cognitive burden that should be clearly evaluated. This is due to the vast experiment that’s ongoing in web technologies, with the JavaScript ecosystem as a prime example. Different UI libraries require different syntactic patterns. And new APIs and web component standards can resolve many of these issues if they’re implemented in a way that maintains a consistent design-time experience and efficient deployment workflow. Deployment models can fragment the developer experience and hinder debugging. The gap in structure and behavior of local and production environments creates friction and slows progress. We believe these boundaries can be dissolved through careful architectural design while preserving the type safety and developer-friendly ergonomics that make F# a compelling choice for a wide number of software engineering goals.
This architecture represents our aspirations for what web development could become. By articulating these patterns clearly, we hope to engage contributors who share our vision of creating a development experience that feels both familiar to experienced F# developers while maintaining highly matched “impedance” with emergent web component technologies. Your feedback, whether you come from Cloudflare, JavaScript, .NET or other ecosystems will help shape how these ideas evolve into a high-productivity platform.
From SAFE to SPEC: An Evolutionary Step
The SAFE stack pioneered full-stack web development and proved the viability of using F# across the entire application stack. SPEC builds on SAFE’s foundation while addressing different architectural concerns and leveraging newer platform capabilities.
Uniform Component Binding] E2[Elmish
State Management] C2[CloudflareFS
Edge Platform] P2 --> E2 E2 --> C2 end subgraph "SAFE Stack" S1[Saturn/Giraffe/Oxpecker
.NET Server] A1[Azure Cloud Platform] F1[Fable >> React SPA] E1[Elmish
State Management] F1 --> E1 E1 --> S1 S1 --> A1 end style C2 fill:#fff3e0,stroke:#ef6c00 style S1 fill:#e8f5e9,stroke:#2e7d32 style F1 fill:#fff3e0,stroke:#61DBFB style E1 fill:#e3f2fd,stroke:#1976d2 style E2 fill:#e3f2fd,stroke:#1976d2 style P2 fill:#f3e5f5,stroke:#7b1fa2
Where SAFE and SPEC Align:
- Both embrace F# across the full stack
- Both use Elmish for predictable state management
- Both leverage Fable for F# to JavaScript compilation
- Both prioritize type safety and functional programming principles
Where SPEC Diverges:
- Reactivity Model: SAFE uses React’s virtual DOM; SPEC uses SolidJS’s fine-grained reactivity with no virtual DOM overhead
- Syntax Philosophy: SAFE maintains distinct patterns for different component types; SPEC provides uniform syntax through Partas.Solid’s cohesive binding model
- Deployment Target: SAFE emphasizes Azure; SPEC targets Cloudflare’s edge network with its distinct architectural characteristics
- Static Generation: SAFE treats static sites as separate concerns; SPEC integrates static generation as a first-class workflow
Neither approach is universally superior; they address different architectural priorities and deployment contexts. SAFE excels in Azure-centric workflows with established .NET infrastructure. SPEC aims to excel in “serverless edge” scenarios where efficiency, global distribution and minimal latency take priority.
The Problem Space: Syntactic and Architectural Fragmentation
It can sometimes feel like F# web frameworks expect developers to maintain multiple mental models. HTML elements use one syntax, custom components another, third-party libraries require fragmented wrapping, and server-side integration to .NET demands yet another paradigm shift. Each boundary crossing increases cognitive load and potential for errors.
SPEC attempts to address this long-standing challenge through three core principles:
Syntactic Convergence: All renderable elements, whether native HTML, custom components, or imported JavaScript libraries, conform to a single predictable pattern through Partas.Solid’s compile-time AST transformation.
Architectural Continuity: The same component should be able to render server-side on Cloudflare Workers, or client-side in the browser without changing its fundamental design-time structure.
Deployment Flexibility: Applications should allow starting as simple “Cloudflare Pages” static sites and evolve into sophisticated multi-Worker architectures without requiring rewrites.
The SPEC Stack Components
SolidJS: Fine-Grained Reactivity Without Compromise
SolidJS provides the reactive foundation for SPEC applications. Unlike React’s virtual DOM reconciliation, SolidJS compiles components into direct DOM updates. When state changes, only the specific DOM nodes affected by that change update. This fine-grained reactivity eliminates the overhead of diffing algorithms while providing predictable performance characteristics.
The bundle size comparison tells part of the story: SolidJS runtime is approximately 13KB compared to React’s 45KB or Angular’s 130KB. But the deeper advantage lies in how SolidJS’s compilation model enables the uniform syntax that makes SPEC compelling. Because SolidJS components are pure functions that return JSX, Partas.Solid can transform F# component definitions into idiomatic SolidJS code without runtime abstraction layers.
Partas.Solid: The Unification Layer
Partas.Solid performs comprehensive AST transformation at compile time in Fable. When you write with an F# DSL, Partas.Solid transforms this into pure function composition that JavaScript developers would recognize as idiomatic code.
This is intended to provide several advantages. F#’s type system offers structure, safety, and IDE support during development. The transformation ensures optimal JavaScript output with proper prop merging, with aspirations to provide automatic splitting for SolidJS optimization, and handling of reactive primitives. Most importantly, every component compiles to just a function; there are no class hierarchies, prototype chains, or inheritance complexity in the generated code.
The ecosystem integration demonstrates this power. Whether binding to native HTML elements, Kobalte’s accessible components, DaisyUI’s design system, or third-party JavaScript libraries, the the F# design-time syntax remains uniform. Developers never context-switch between binding styles; they simply compose functions that return readable JSX.
Elmish: Proven State Management
Elmish brings the Model-View-Update pattern to SPEC applications, providing predictable state transitions and powerful debugging capabilities. While this might seem at odds with SolidJS’s reactive primitives, the integration demonstrates their complementary nature.
Elmish manages application state through pure functions; SolidJS ensures efficient DOM updates. The bridge layer exposes Elmish models as SolidJS stores, enabling fine-grained subscriptions to model properties. Commands coordinate effects for API calls, WebSocket connections, and complex async operations while maintaining functional purity and testability.
This combination proves particularly powerful for complex state machines, form validation, and multi-step workflows where Elmish’s architectural guarantees prevent entire categories of state management bugs.
CloudflareFS: Edge-Native Infrastructure
CloudflareFS represents more than a deployment target; it influences SPEC’s architectural patterns. Cloudflare’s edge computing model, with its globally distributed execution environment and V8 isolate-based Workers, necessitates new, more flexible choices compared to traditional server deployments.
The integrated resource ecosystem provides foundational primitives:
- D1: SQL database with automatic replication across the edge network
- R2: Object storage with S3 compatibility and global distribution
- KV: Microsecond-latency key-value caching
- Durable Objects: Stateful coordination for scenarios requiring consistent state
- Media-over-QUIC: Emergent real-time streaming infrastructure for all types of data
The Cloudflare Developer platform continues to expand well beyond, including AI inference and modern “Zero Trust” support. These resources function as platform capabilities that inform how SPEC applications will be able to handle data, caching, and real-time communication.
Victor: The Bridge to Static and Hybrid Architectures
Victor completes the SPEC stack by addressing project scaffolding and build-time generation. Drawing inspiration from Hugo’s templating philosophy and Fornax’s F# script approach, Victor generates offline configuration and transforms to fuse the rich visual palette of Hugo templates with modern web component architecture in Partas.Solic.
The key innovation lies in treating static generation and dynamic components as complementary capabilities. A blog post renders as pure HTML for instant display, while its comment section uses SolidJS components for real-time interactivity. Documentation pages load immediately as static content, while code examples mount interactive editors for experimentation. This selective hydration approach optimizes for both initial load performance and interactive functionality. At its fullest extent, it fulfills the dream of “literate compute” that moves well beyond interactive notebooks to make web sites interactive by default.
The Deployment Spectrum
SPEC applications can deploy across a spectrum of architectural patterns, each optimized for different requirements. This flexibility emerges from the uniform component model and Cloudflare’s architectural primitives.
Pattern 1: Pure Static Sites
The simplest deployment pattern generates static HTML with no server-side runtime. Victor processes content through F# scripts, transforms Hugo templates into Partas.Solid components, and outputs pure HTML with optional responsive layout.
Static Hosting] ASSETS --> CF CF --> EDGE[Global Edge
Cache] end style VICTOR fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px style CF fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
This pattern suits content-focused sites, documentation, blogs, and marketing pages where dynamic features are minimal. Time-to-First-Byte typically falls under 50ms when served from Cloudflare’s edge network. The entire site caches indefinitely with cache invalidation only when content updates.
Pattern 2: Static with Selective Hydration
The second pattern introduces dynamic components in specific zones while maintaining static HTML for primary content. This combines static site performance with interactive features exactly where needed.
with Components] COMP[Partas.Solid
Components] MD --> VICTOR[Victor CLI] COMP --> BUNDLE[Component Bundle] VICTOR --> HTML[Static HTML
with Mount Points] VICTOR --> COMP end subgraph "Deployment" HTML --> PAGES[Cloudflare Pages] BUNDLE --> PAGES PAGES --> EDGE[Edge Network] end subgraph "Runtime" EDGE --> BROWSER[Browser] BROWSER --> STATIC[Display Static
Content Immediately] STATIC --> HYDRATE[Selective Hydration
Interactive Zones] HYDRATE --> REACTIVE[SolidJS
Fine-grained Updates] end style VICTOR fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px style HYDRATE fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px style REACTIVE fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
Progressive enhancement strategies control when components hydrate:
- Immediate: Critical interactive elements load with the page
- On Visible: Components hydrate as they enter the viewport using Intersection Observer
- On Idle: Non-critical features load during browser idle time
This pattern excels for blogs with comment sections, documentation with interactive examples, and content sites with personalized widgets. Users experience instant content display with interactive features appearing seamlessly as JavaScript executes.
Pattern 3: Multi-Worker Application
The most sophisticated pattern deploys multiple specialized Workers, each handling distinct concerns within the application architecture. This pattern leverages CloudflareFS’s resource ecosystem for complex, globally distributed applications.
Partas.Solid UI] end subgraph "Edge Workers" API[API Worker
Business Logic] AUTH[Auth Worker
Authentication] WS[WebSocket Worker
Real-time Events] end subgraph "Edge Resources" D1[D1 Database
SQL Storage] KV[KV Store
Session Cache] R2[R2 Storage
Media Assets] DO[Durable Objects
Stateful Coordination] end BROWSER --> API BROWSER --> AUTH BROWSER --> WS API --> D1 API --> R2 AUTH --> KV WS --> DO style BROWSER fill:#fff3e0,stroke:#ef6c00,stroke-width:2px style API fill:#e3f2fd,stroke:#1976d2,stroke-width:2px style D1 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px
Each Worker specializes:
- API Worker: Handles business logic, data transformation, and third-party integrations
- Auth Worker: Manages authentication flows, token validation, and session management
- WebSocket Worker: Coordinates real-time updates, presence, and collaborative features
- CMS Worker: Serves pre-rendered HTML shells and optimized assets
This separation enables independent scaling, deployment, and optimization of each concern. The API Worker can implement sophisticated caching strategies without affecting authentication. The WebSocket Worker can maintain persistent connections while other Workers handle stateless requests. Durable Objects provide consistent state for scenarios like collaborative editing or real-time coordination.
Pattern 4: Media Streaming with MoQ Integration
The fourth pattern integrates Media-over-QUIC for real-time media streaming, demonstrating how SPEC applications can leverage specialized Cloudflare infrastructure for performance-critical scenarios.
Stream Controls] PLAYER[Media Player
WebTransport] end subgraph "Cloudflare Infrastructure" WORKER[Signaling Worker
Session Management] MOQ[MoQ Relay
relay.cloudflare.mediaoverquic.com
Data, Video and Audio Streams] KV[KV Store
Session Data] WORKER --> MOQ end UI --> WORKER WORKER --> KV PLAYER <--> MOQ style UI fill:#fff3e0,stroke:#ef6c00,stroke-width:2px style MOQ fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px style WORKER fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
Unlike WebSockets, which maintain long-lived connections through Workers and incur continuous billing, MoQ operates as separate relay infrastructure. The publish-subscribe model maps naturally to SolidJS’s reactive primitives, enabling real-time media streams to trigger UI updates without additional coordination logic.
Applications establish WebTransport connections directly to the MoQ relay, bypassing Workers for media transport. Workers handle only signaling, session management, and access control. This architecture proves effective for video conferencing, live streaming, and collaborative media applications where traditional WebSocket approaches would be cost-prohibitive.
Performance Characteristics and Optimization
SPEC’s architecture intends to deliver measurable performance advantages through deliberate design choices at each layer.
Bundle Size Efficiency: The SolidJS runtime contributes approximately 13KB to the bundle, with individual components adding 2-5KB each. Partas.Solid’s AST transformation produces optimized function calls without runtime overhead. A typical application with ten unique components results in a 30-40KB JavaScript bundle compared to 150KB+ for equivalent React applications.
Edge Latency Optimization: CloudflareFS’s global network provides sub-50ms latency to 95% of internet users. SPEC applications leverage this through systematic caching strategies. Static assets cache indefinitely with content-hash versioning. API responses cache with controlled invalidation. HTML shells serve from edge locations with microsecond lookup times via KV.
Selective Hydration: Progressive enhancement strategies reduce JavaScript execution time by 60-80% compared to full SPA hydration. Static content displays immediately while interactive features load progressively based on viewport visibility, user interaction, or idle time. This approach creates observable performance improvements, particularly on mobile devices and slower networks.
Real-time Communication: The MoQ integration eliminates the connection maintenance costs of WebSockets while providing lower latency for media streaming. Applications can support thousands of concurrent streams without the billing implications of maintaining persistent Worker connections.
Developer Experience and Cognitive Architecture
SPEC aims to proactively manage the conceptual surface area required for web development while expanding capability.
Unified Syntax Model: Partas.Solid’s uniform component syntax reduces context switching between native elements, custom components, and library bindings. The goal is to ensure that very component is a function that returns JSX. Developers learn one pattern that applies universally.
Type System as Guide: F#’s type system documents component props, API contracts, and state transitions. The compiler guides toward correct usage patterns through type checking. Runtime maintains JavaScript functions with minimal abstraction, supporting straightforward browser debugging.
Scriptable Generation: The Victor CLI as a dotnet tool
will allow users to avoid Cloudflare Wrangler “context switching” and TOML file management. FSX script-based generation enables integration with many NET tools. We anticipate that type providers, database connections and custom data formats will all provide future degrees of freedom within the generation pipeline as the platform matures.
Debugging Capabilities: Multiple debugging interfaces serve different concerns. F# source tooling leverages Fable’s established pedigree. CloudflareFS analytics offer edge performance monitoring. MoQ metrics track streaming quality and connection health. We have many ideas for this area to support both design-time and runtime monitoring of applications.
Architectural Patterns and Use Cases
SPEC’s flexibility enables several architectural patterns that address common web development scenarios.
Content-Centric Applications: Blogs, documentation sites, and marketing pages benefit from static generation with selective interactivity. Content renders instantly as HTML while features like comments, search, and personalization load progressively.
Collaborative Applications: Real-time collaboration requires sophisticated state synchronization. Durable Objects provide consistent state coordination while Elmish manages client-side state transitions. WebSockets or MoQ handle real-time updates depending on media requirements.
E-commerce Platforms: Product catalogs render as static HTML for optimal SEO while shopping carts, inventory checks, and price updates use dynamic components. The multi-Worker pattern enables specialized Workers for payment processing, inventory management, and order fulfillment.
Media Streaming Services: MoQ integration will enables video platforms, live streaming, and video conferencing applications. The publish-subscribe model naturally maps to room-based architectures while Partas.Solid components handle UI concerns.
Enterprise Dashboards: Complex dashboards combine static layouts with real-time data visualization. Partas.Solid’s binding to TanStack Table components provides sophisticated data display capabilities. Charts and metrics update through SolidJS’s fine-grained reactivity while maintaining type safety through F#’s type system.
Integration Considerations and Migration Paths
Organizations considering SPEC can adopt incrementally without rewriting existing applications.
From SAFE Stack: SAFE stack applications can integrate SPEC patterns gradually. Elmish state management transfers directly. Fable compilation remains unchanged. And we anticipate that the story for migrating components from React to SolidJS will develop as adoption matures. Azure deployments can continue while new features deploy to CloudflareFS.
From Traditional SSGs: Hugo or Jekyll sites should be able to migrate to SPEC stack through Victor, preserving content structure. One of our primary goals is to provide Hugo templates transform into Partas.Solid components through Victor’s conversion process. Existing markdown content would require little to no changes. URL structures and SEO characteristics would remain intact.
From JavaScript Frameworks: JavaScript applications using React or Vue can adopt SPEC’s patterns progressively. This is an area we’ll address on an as-needed basis. The uniform syntax model of Partas.Solid often simplifies component migration compared to hand-written bindings, and we want to ensure that the work in this area involves the community.
Challenges and Open Questions
We acknowledge several areas requiring further investigation:
Development Tooling: The watch mode and incremental rebuild strategy for Victor requires careful dependency tracking to maintain sub-second feedback loops. How do we handle complex dependency graphs efficiently? What .NET dependencies will affect Victor as a dotnet tool?
Migration Complexity: Organizations with significant web app investments may face non-trivial modernization challenges. Are there migration paths or incremental upgrade stories that need to be explored?
Community Ecosystem: The JavaScript community’s vast component library represents both opportunity and challenge. Which libraries deserve first-class Partas.Solid bindings? How do we enable community contributions to the binding ecosystem?
Performance Monitoring: Edge-native architectures require different monitoring approaches. What metrics best indicate application health across distributed Workers and edge caching?
Conclusion: An Invitation to Collaborate
The SPEC stack represents our vision for what F#-based web development could become: syntactically unified, architecturally flexible, and edge-native by design. By combining Fable’s battle-tested foundation, SolidJS’s fine-grained reactivity, Partas.Solid’s uniform syntax, Elmish’s proven state management, and CloudflareFS’s global edge network, we aim to create a development experience that feels both natural to web developers and competitive with mainstream frameworks.
This document articulates our design philosophy and architectural intentions. These ideas require refinement through implementation, testing, and community feedback. We invite you to critique these patterns, suggest improvements, and contribute to realizing this vision.
Whether you’re exploring alternatives to SAFE stack, evaluating static site generators, or seeking a principled approach to web development, we hope these ideas prove valuable. The future of distributed systems benefits from diverse approaches that explore rich and forward-looking architectural possibilities.
SPEC offers a fresh technology path that prioritizes syntactic uniformity, edge-native deployment, and the principle that complexity should be opt-in through configuration rather than inherent in the architecture. We look forward to your feedback as these concepts evolve into working implementations.