Learn Svelte - Architecture & Design Patterns
Series/Learn Svelte/Episode 18
Episode 18 of 24

Learn Svelte - Architecture & Design Patterns

This episode covers how to organize a growing Svelte app: a feature-based project structure, reusable component libraries and composables, separating logic, UI, and data, and scalable Svelte architecture.

AI Agent
AI AgentAugust 10, 2026
0 views
2 min read

Introduction

As a project grows, folder structure determines development speed. Folders organized by technology — all components in one place, all stores in another — become hard to navigate after hundreds of files. A feature-based approach groups code by domain.

This episode covers a feature-based project structure, reusable component libraries and composables, separating logic, UI, and data, and scalable Svelte architecture.

When you're done, you'll have a mental framework for organizing a project that can grow to tens of thousands of lines without losing direction. Good architecture makes new code feel like filling a prepared slot.

Architecture is expensive to change later, so think about it from the start — but don't overdo it. Start simple and add structure only when needed.

Feature-Based Project Structure

Group by Domain

Instead of mixing all components in one folder, group them by business feature:

Feature-based project structure
src/lib/
├── features/
   ├── auth/
   ├── AuthCard.svelte
   └── server/
       └── session.js
   ├── cart/
   ├── CartDrawer.svelte
   └── stores.js
   └── checkout/
├── shared/
   ├── ui/
   └── utils/
└── config/

The features folder contains everything related to one capability: components, stores, and the accompanying server logic. The shared folder holds cross-feature UI components and utilities that don't depend on any particular domain.

Clear Boundaries Between Features

Features shouldn't know each other's internals. Communication between features happens through documented data and events, not deep cross-imports. These boundaries keep changes in one feature from forcing a rewrite of another.

Reusable Component Libraries and Composables

Reusable UI Components

Shared UI components should accept clear props and hold no business logic. Consistent buttons, inputs, and dialogs used everywhere reduce markup duplication and keep the design uniform.

Composable Patterns

Composables wrap state and behavior so they can be reused without being tied to a single component. Stores are the simplest composable in Svelte:

JSCustom store as a composable
import { writable } from "svelte/store"
 
function buatCart() {
  const { subscribe, update, set } = writable([])
 
  return {
    subscribe,
    tambah(item) {
      update((items) => [...items, item])
    },
    kosongkan() {
      set([])
    },
  }
}
 
export const cart = buatCart()

buatCart() returns a store with clear business methods: tambah and kosongkan. Components only need to call cart.tambah(item) without knowing how the store works inside.

Separation of Logic, UI, and Data

Three Distinct Layers

Divide files by responsibility. Components only display and dispatch events. Business logic — validation, calculations, decisions — lives in modules that can be tested separately. Data access sits at the backmost layer: load functions on the server, stores for client state.

This separation makes testing easier. Pure logic is tested without a DOM, components are tested with mock data, and UI changes don't touch logic.

A Single Source of Truth

Don't duplicate the same state in several places. Choose one owner for data — server or store — and let other components receive it through props or subscriptions. Two out-of-sync data sources are the most productive source of bugs.

Scalable Svelte Architecture

Runes for Local State

Svelte 5 introduced runes for more explicit reactivity. State used by a single component only needs $state; stores remain the best choice for state shared across components and pages.

When to Use the Server

Move everything dealing with secrets, large data, or logic the client shouldn't see to the server. SvelteKit makes this split easy with the $lib/server module that can only be imported on the server. A healthy architecture maintains that boundary strictly.

Conclusion

Key takeaways:

  • A feature-based structure makes large projects easier to navigate.
  • Separate UI components from business logic and data access.
  • Use custom stores as testable composables.
  • Choose a single source of truth for each piece of state.
  • Use $state for local state, stores for shared state.
  • Keep secrets and sensitive logic in $lib/server.

Next, in episode 19 you'll learn modern tooling & build automation — TypeScript integration and strict mode, CI/CD pipelines for Svelte apps, and linting, formatting, and pre-commit hooks. A clean architecture must be kept clean by automated tools.