The Death of Frameworks and Why I Stopped Worrying

by Igor Tosic, Software Engineer

How Svelte 5 Runes Made Me Realize the Wrong Question

When I first started considering Svelte for my enterprise canvas application, I kept asking myself the wrong question: "What if Svelte dies?"

I spent days researching market share. Stack Overflow answer counts. I compared npm downloads like they were stock charts. React has a million developers. Svelte has fifty thousand. The math was obvious, right?

Then something clicked.

The Question Nobody Asks

Here's what I realized: Nobody asks "What if React dies?" But they should.

Meta can change direction. They've done it before — remember the class components to hooks migration? Remember when everyone had to relearn everything? The React ecosystem churns constantly: Redux, then Context, then Zustand, then Jotai, then Recoil, then... what's next?

No framework is truly "safe." The difference is that React developers have normalized the chaos. We call it "ecosystem maturity."

But here's the uncomfortable truth I discovered while building my drawing application: the framework is maybe 10% of your codebase. The other 90%? That's your domain logic. Your canvas operations. Your PDF rendering. Your business rules. Usually, it's like that in a big enterprise application.

And all of that is framework-agnostic.

What Actually Matters

I've been working with React and Redux for years. Enterprise applications. Complex state. The whole ceremony.

You know the ceremony I'm talking about:

// The Redux dance: actions, reducers, selectors, dispatch
// actions.ts
export const ADD_ANNOTATION = 'ADD_ANNOTATION'
export const UNDO = 'UNDO'
export const REDO = 'REDO'

export const addAnnotation = (annotation) => ({
  type: ADD_ANNOTATION,
  payload: annotation,
})

// reducer.ts
const initialState = {
  past: [],
  present: [],
  future: [],
}

function historyReducer(state = initialState, action) {
  switch (action.type) {
    case ADD_ANNOTATION:
      return {
        past: [...state.past, state.present],
        present: [...state.present, action.payload],
        future: [],
      }
    case UNDO:
      if (state.past.length === 0) return state
    // ... another 20 lines
    // ... REDO case, another 15 lines
  }
}

// Component.tsx
import { useDispatch, useSelector } from 'react-redux'

function AnnotationPanel() {
  const dispatch = useDispatch()
  const annotations = useSelector((state) => state.history.present)
  const canUndo = useSelector((state) => state.history.past.length > 0)

  const handleAdd = () => {
    dispatch(
      addAnnotation({
        /* ... */
      }),
    )
  }

  return <button onClick={handleAdd}>Add</button>
}

That's roughly 80 lines of code. To add an item to a list. With undo capability. We've normalized this. We call it "predictable state management." We've convinced ourselves the boilerplate is a feature, not a bug.

Enter Svelte 5: When Less Becomes More

Now look at Svelte 5 with class-based stores using runes:

// stores/projects.svelte.ts
import type { Project } from "../types/projects";
import { getProjects } from "../services/projects";

export class ProjectsStore {
    projects = $state<Project[]>([]);
    selectedProject = $state<Project | null>(null);
    loading = $state<boolean>(false);
    error = $state<string | null>(null);

    get hasProjects() {
        return this.projects.length > 0;
    }

    get selectedProjectId() {
        return this.selectedProject?.id ?? null;
    }

    setProjects(projects: Project[]): void {
        this.projects = projects;
        this.error = null;
    }

    addProject(project: Project): void {
        this.projects = [...this.projects, project];
    }

    async fetchProjects(): Promise<void> {
        this.loading = true;
        this.error = null;

        try {
            const projects = await getProjects();
            this.setProjects(projects);
        } catch (err) {
            this.error = err instanceof Error ? err.message : "Failed to fetch projects";
        } finally {
            this.loading = false;
        }
    }
}

export const projectsStore = new ProjectsStore();

That's it. No actions. No reducers. No dispatch. No selectors. No connect(). No useSelector. No middleware.

Just a class. With properties. That are reactive.

In the component:

<script lang="ts">
  import { projectsStore } from "../stores/projects.svelte";
</script>

<button onclick={() => projectsStore.addProject(newProject)}>
  Add Project
</button>

{#if projectsStore.loading}
  <p>Loading...</p>
{:else}
  <ul>
    {#each projectsStore.projects as project}
      <li>{project.name}</li>
    {/each}
  </ul>
{/if}

No ceremony. No dance. You just... use it.

The Philosophy Behind Runes

Svelte 5's runes ($state, $derived, $effect) represent a philosophical shift. They're not just syntax sugar — they're a statement about what reactivity should feel like.

In React, reactivity is opt-in through hooks, wrapped in rules you must memorize. Don't call hooks conditionally. Always include dependencies in useEffect. Memoize everything or watch your app crawl.

In Svelte 5, you say what you mean:

let count = $state(0) // This is state
let doubled = $derived(count * 2) // This derives from state

$effect(() => {
  console.log('Count changed:', count)
})

The $ prefix is a rune — a compiler instruction. Not a runtime hook. Not a function that runs on every render. A compile-time transformation that generates exactly the reactive code you need.

The class-based approach takes this further. Instead of scattered stores and derived values, you encapsulate your domain:

export class AuthStore {
    user = $state<User | null>(null);
    loading = $state<boolean>(false);
    error = $state<string | null>(null);

    get isAuthenticated() {
        return this.user !== null;
    }

    clearAuth(): void {
        this.user = null;
        this.error = null;
        this.loading = false;
    }
}

export const authStore = new AuthStore();

This feels like writing JavaScript. Not React-flavored JavaScript. Not Redux-flavored JavaScript. Just... JavaScript with superpowers.

The Data Flow Difference

Let me show you what data flow looks like in practice.

React/Redux mental model:

JavaScriptComponent → dispatch(action) → middleware → reducer → new state → selector → component re-render

Every step is explicit. Every step is traceable. Every step is boilerplate.

Svelte 5 mental model:

Component → store.property = value → component re-renders

That's not an oversimplification. That's the actual model.

When you write projectsStore.projects = newProjects, Svelte knows. The compiler saw your $state declaration. It generated the reactive bindings. Your components using projectsStore.projects will update.

No action to dispatch. No reducer to write. No selector to optimize. No React.memo to consider.

The Performance Argument (And Why It Doesn't Matter)

I'll be honest: when I looked at raw performance numbers, the difference was... not what I expected.

For most operations in my canvas application, the differences were barely noticeable. Tool switching? Imperceptible in both frameworks. Drawing strokes? Konva is the bottleneck, not the framework — both hit 60fps without breaking a sweat.

The real performance bottlenecks? PDF rendering with pdf.js. Canvas operations with Konva. Network latency. None of these care about your framework choice.

So why switch?

Developer Experience: The Real Win

Here's the uncomfortable truth about framework choices: performance gains are marginal, but developer experience compounds. When I write Redux, I spend mental energy on:

  • Action naming conventions
  • Reducer organization
  • Selector memoization
  • Middleware configuration
  • DevTools setup
  • Type definitions that mirror structure three times over

When I write Svelte 5 stores, I think about:

  • My domain

That's it. I think about projects and annotations and tools. Not about the ceremony of making them reactive.

For a solo developer building a complex application, this compounds. Every feature is 30-40% faster to implement. Every bug is easier to trace (no action logs to decode). Every refactor is simpler (no reducer restructuring).

Over months, this adds up to weeks of saved time.

The Hiring Question

"But what about hiring? React developers are everywhere!"

Let me share what I've seen in enterprise applications: finding a developer who truly understands React deeply, knows Redux architecture properly, can work with Canvas APIs, understands PDF manipulation — or any complex domain logic, whether that's financial systems, healthcare workflows, real-time collaboration, or other specialized business domains — AND writes clean maintainable code — is already hard.

A good developer will pick up Svelte 5 in few weeks. The runes syntax is simpler than hooks. The class-based stores are just... classes. There's less to learn, not more.

When I eventually hire, I'll look for:

  • Strong JavaScript fundamentals
  • Experience in the relevant domain
  • Learning ability

Framework-specific experience? Nice to have. But I'd rather hire someone who can learn than someone who only knows one tool.

What I Actually Built

I didn't switch to Svelte for performance metrics. I switched because I wanted to write less code that does more.

My canvas application now has:

  • Class-based stores for each domain (projects, annotations, canvas, auth)
  • Derived properties that just work (no useMemo, no selectors)
  • Async operations that feel natural (no thunks, no sagas)
  • TypeScript that helps instead of fighting me

The migration could take about two to three weeks for a medium-sized application. Most of that time goes to UI components, not state management. The state management is actually faster to implement in Svelte than it is to maintain in Redux.

The Philosophical Conclusion

Every few years, the web development world declares a new winner. jQuery. Backbone. Angular. React. And someday, something else.

The developers who thrive aren't the ones who bet on the winning horse. They're the ones who understand that the horse doesn't matter as much as knowing how to ride.

Your domain logic — the actual business value you create — is framework-agnostic. Your understanding of state management patterns transcends any specific implementation. Your ability to learn new tools is more valuable than mastery of current ones.

I chose Svelte 5 not because I think it will "win." I chose it because it lets me focus on what I'm actually building — the product, the features, the problems I'm solving for users.

🎨 The framework is just the canvas. What you paint on it is what matters. 🖌️

More articles

The Svelte Shift: From React/Redux to SvelteKit5

The Data Flow Revolution: Built-in State Management

Read more

Redux Toolkit: The Evolution of State Management in Modern React Applications

Exploring architectural patterns for state management in NextJS applications

Read more

Ready to Transform Your Business?