Skip to main content
On this page

Framework-agnostic architectural patterns for modern full-stack applications. These principles apply regardless of which framework implements them.


Core Patterns

Server/Client Separation

Enforce a hard boundary between server and client code.

Server Client
Database connections UI components
API keys, secrets User interactions
Business logic Presentation logic
Auth verification Auth state display

Why: Prevents accidental exposure of secrets, reduces client bundle size, clarifies security boundaries.

Implementation: Use directory conventions or file suffixes that your framework enforces at build time.


Route-Based Organization

Organize code by URL routes, not by technical layers.

routes/
├── dashboard/          # /dashboard
│   ├── page            # UI
│   └── server          # Data loading, mutations
├── items/              # /items
│   ├── page
│   ├── server
│   └── [id]/           # /items/:id
│       ├── page
│       └── server
└── api/                # /api/*
    └── items/
        └── server      # JSON endpoints

Why:

  • Reduces cognitive overhead (one place to look)
  • Natural code splitting by route
  • Framework can generate types automatically
  • Scales linearly with app size

Alternative patterns:

  • MVC-style: Separate models, views, controllers. Use when strong data layer separation required.
  • Feature-based: Group by domain (auth, billing, users). Use for large teams with feature ownership.
  • tRPC/RPC: Centralized API layer. Use when multiple clients consume same API.

Colocation

Keep related code together. Route-specific code lives with the route.

Colocate Centralize
Route-specific components Shared UI components
Route-specific types Shared types
Route-specific utils Database client, auth config

Why: Reduces indirection, makes dependencies explicit, simplifies deletion.


Rendering Strategies

Choose rendering strategy per route based on content characteristics.

Strategy Characteristics Use Case
SSR Dynamic, personalized, SEO-needed Product pages, dashboards
SSG Static, cacheable, infrequent updates Blog posts, docs, marketing
SPA Interactive, no SEO needed Admin panels, authenticated apps
No-JS Maximum performance, progressive Landing pages, forms

Hybrid approach: Most apps combine strategies. Use SSG for marketing, SSR for dynamic pages, SPA for admin.


State Layers

Organize state by scope and persistence.

Layer Scope Persistence Examples
Local Component None Form inputs, UI toggles
Shared Multiple components Session Shopping cart, filters
Server Application Database User data, content
URL Shareable Bookmark/link Search params, pagination

Flow: Server → Shared → Local. Data flows down, events flow up.


Middleware Pattern

Intercept requests/responses for cross-cutting concerns.

Concern Middleware handles
Auth Verify session, attach user to request
Logging Request timing, error capture
Rate limiting Throttle by IP/user
Headers Security headers, CORS
Redirects Auth redirects, locale detection

Order matters: Auth before rate limiting, logging wraps everything.


Scaling Guidance

Do

  • Start simple — Add abstraction when pain emerges, not before
  • Enforce boundaries — Server/client separation is non-negotiable
  • Colocate by default — Extract to shared only when reused
  • Let types flow — Minimize manual type definitions
  • Use path aliases — Clean imports, easy refactoring

Don't

  • Over-abstract with unnecessary services/repositories
  • Put route-specific code in shared directories
  • Mix server and client code in same files
  • Create deep folder hierarchies prematurely
  • Duplicate framework conventions with custom ones

Implementation

See stack/core/sveltekit.md for how these patterns are implemented in SvelteKit.

← Back to Foundation