Svelte 5 e Runes: A Revolucao da Reatividade no JavaScript em 2025
Ola HaWkers, o Svelte 5 chegou com uma mudanca paradigmatica que esta fazendo a comunidade JavaScript repensar como abordamos reatividade em aplicacoes web. Os Runes representam uma nova forma de pensar sobre estado e reatividade, e se voce ainda nao conhece, esta perdendo uma das inovacoes mais interessantes do ecossistema frontend.
Voce ja se perguntou por que precisamos de tantos hooks e boilerplate para gerenciar estado em React? O Svelte 5 oferece uma alternativa elegante.
O Que Sao Runes?
Runes sao uma nova primitiva de reatividade introduzida no Svelte 5. Eles substituem o sistema de reatividade anterior baseado em declaracoes reativas ($:) por um modelo mais explicito e poderoso.
Os Principais Runes
Lista de Runes disponiveis:
$state- Declara estado reativo$derived- Computa valores derivados$effect- Executa side effects reativos$props- Recebe props em componentes$bindable- Props que podem ser two-way bound$inspect- Debug de valores reativos
Comparacao: Svelte 4 vs Svelte 5
Vamos ver na pratica como a sintaxe mudou e por que e uma melhoria significativa.
Estado Simples
Svelte 4 (antigo):
<script>
let count = 0;
function increment() {
count += 1;
}
</script>
<button on:click={increment}>
Cliques: {count}
</button>Svelte 5 (Runes):
<script>
let count = $state(0);
function increment() {
count += 1;
}
</script>
<button onclick={increment}>
Cliques: {count}
</button>A diferenca parece sutil, mas o $state torna a reatividade explicita e previsivel.
Valores Derivados
Svelte 4 (antigo):
<script>
let firstName = 'John';
let lastName = 'Doe';
// Declaracao reativa - pode ser confusa
$: fullName = `${firstName} ${lastName}`;
$: greeting = `Ola, ${fullName}!`;
</script>Svelte 5 (Runes):
<script>
let firstName = $state('John');
let lastName = $state('Doe');
// Muito mais claro e previsivel
let fullName = $derived(`${firstName} ${lastName}`);
let greeting = $derived(`Ola, ${fullName}!`);
</script>
Effects (Side Effects)
Svelte 4 (antigo):
<script>
let count = 0;
// Effect implicito - dificil saber quando executa
$: {
console.log(`Count mudou para: ${count}`);
localStorage.setItem('count', count);
}
</script>Svelte 5 (Runes):
<script>
let count = $state(0);
// Effect explicito - claro quando e por que executa
$effect(() => {
console.log(`Count mudou para: ${count}`);
localStorage.setItem('count', count.toString());
});
</script>Exemplo Pratico: Todo App com Runes
Vamos construir uma aplicacao de tarefas completa usando Runes:
<script>
// Estado principal
let todos = $state([]);
let newTodo = $state('');
let filter = $state('all'); // 'all' | 'active' | 'completed'
// Valores derivados
let filteredTodos = $derived(() => {
switch (filter) {
case 'active':
return todos.filter(t => !t.completed);
case 'completed':
return todos.filter(t => t.completed);
default:
return todos;
}
});
let remainingCount = $derived(
todos.filter(t => !t.completed).length
);
let allCompleted = $derived(
todos.length > 0 && todos.every(t => t.completed)
);
// Funcoes de acao
function addTodo() {
if (newTodo.trim()) {
todos.push({
id: Date.now(),
text: newTodo.trim(),
completed: false
});
newTodo = '';
}
}
function toggleTodo(id) {
const todo = todos.find(t => t.id === id);
if (todo) {
todo.completed = !todo.completed;
}
}
function removeTodo(id) {
const index = todos.findIndex(t => t.id === id);
if (index !== -1) {
todos.splice(index, 1);
}
}
function toggleAll() {
const newState = !allCompleted;
todos.forEach(t => t.completed = newState);
}
function clearCompleted() {
todos = todos.filter(t => !t.completed);
}
// Effect para persistencia
$effect(() => {
localStorage.setItem('todos', JSON.stringify(todos));
});
// Carregar do localStorage na inicializacao
$effect(() => {
const saved = localStorage.getItem('todos');
if (saved) {
todos = JSON.parse(saved);
}
});
</script>
<div class="todo-app">
<h1>Minhas Tarefas</h1>
<form onsubmit={(e) => { e.preventDefault(); addTodo(); }}>
<input
type="text"
bind:value={newTodo}
placeholder="O que precisa ser feito?"
/>
<button type="submit">Adicionar</button>
</form>
{#if todos.length > 0}
<div class="controls">
<button onclick={toggleAll}>
{allCompleted ? 'Desmarcar' : 'Marcar'} Todas
</button>
<div class="filters">
<button
class:active={filter === 'all'}
onclick={() => filter = 'all'}
>
Todas
</button>
<button
class:active={filter === 'active'}
onclick={() => filter = 'active'}
>
Ativas
</button>
<button
class:active={filter === 'completed'}
onclick={() => filter = 'completed'}
>
Completas
</button>
</div>
</div>
<ul class="todo-list">
{#each filteredTodos as todo (todo.id)}
<li class:completed={todo.completed}>
<input
type="checkbox"
checked={todo.completed}
onchange={() => toggleTodo(todo.id)}
/>
<span>{todo.text}</span>
<button onclick={() => removeTodo(todo.id)}>X</button>
</li>
{/each}
</ul>
<footer>
<span>{remainingCount} tarefa(s) restante(s)</span>
{#if todos.some(t => t.completed)}
<button onclick={clearCompleted}>
Limpar Completas
</button>
{/if}
</footer>
{/if}
</div>
Por Que Runes Sao Melhores?
1. Reatividade Explicita
Em Svelte 4, qualquer variavel let era automaticamente reativa, o que podia causar confusao:
<!-- Svelte 4: Quando isso e reativo? -->
<script>
let data = fetch('/api').then(r => r.json()); // Reativo?
let config = { theme: 'dark' }; // Reativo?
const MAX = 100; // Nao reativo (const)
</script>Com Runes, voce declara explicitamente o que e reativo:
<!-- Svelte 5: Clareza total -->
<script>
let data = $state(null); // Reativo
let config = $state({ theme: 'dark' }); // Reativo
const MAX = 100; // Nao reativo (intencional)
</script>2. Melhor TypeScript Support
Runes funcionam perfeitamente com TypeScript:
<script lang="ts">
interface Todo {
id: number;
text: string;
completed: boolean;
}
let todos = $state<Todo[]>([]);
let newTodo = $state('');
// Tipos inferidos corretamente
let completedCount = $derived(
todos.filter(t => t.completed).length
);
</script>3. Reatividade Universal
Runes funcionam fora de componentes .svelte:
// stores/counter.svelte.ts
export function createCounter(initial = 0) {
let count = $state(initial);
return {
get value() { return count; },
increment() { count += 1; },
decrement() { count -= 1; },
reset() { count = initial; }
};
}
// Em qualquer componente
import { createCounter } from './stores/counter.svelte';
const counter = createCounter(10);
Comparacao com React
Vamos comparar a mesma funcionalidade em React e Svelte 5:
React (Hooks):
import { useState, useMemo, useEffect } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const [step, setStep] = useState(1);
// useMemo para valores derivados
const doubled = useMemo(() => count * 2, [count]);
// useEffect para side effects
useEffect(() => {
document.title = `Count: ${count}`;
}, [count]);
return (
<div>
<p>Count: {count} (doubled: {doubled})</p>
<input
type="number"
value={step}
onChange={e => setStep(Number(e.target.value))}
/>
<button onClick={() => setCount(c => c + step)}>
Increment by {step}
</button>
</div>
);
}Svelte 5 (Runes):
<script>
let count = $state(0);
let step = $state(1);
// Derivado - sem array de dependencias
let doubled = $derived(count * 2);
// Effect - sem array de dependencias
$effect(() => {
document.title = `Count: ${count}`;
});
</script>
<div>
<p>Count: {count} (doubled: {doubled})</p>
<input type="number" bind:value={step} />
<button onclick={() => count += step}>
Increment by {step}
</button>
</div>Diferencas notaveis:
- Sem arrays de dependencias (menos bugs)
- Sintaxe mais concisa
- Binding bidirecional nativo
- Menos boilerplate
Performance do Svelte 5
O Svelte 5 traz melhorias significativas de performance:
Benchmarks (js-framework-benchmark)
| Metrica | React 19 | Vue 3.5 | Svelte 5 |
|---|---|---|---|
| Create 1000 rows | 45ms | 38ms | 32ms |
| Update 1000 rows | 38ms | 32ms | 28ms |
| Select row | 3.2ms | 2.8ms | 2.1ms |
| Remove row | 35ms | 30ms | 25ms |
| Create 10000 rows | 450ms | 380ms | 320ms |
| Bundle size (gzip) | 45KB | 35KB | 3KB |
⚡ Destaque: O Svelte compila para JavaScript vanilla, resultando em bundles significativamente menores.
Migrando de Svelte 4 para Svelte 5
Estrategia de Migracao
- Atualize o Svelte:
npm install svelte@5 - Codigo existente funciona: Svelte 5 e retrocompativel
- Migre gradualmente: Converta componentes um por vez
- Use o modo legacy:
<svelte:options runes={false} />
Ferramenta de Migracao
O Svelte oferece uma ferramenta de migracao automatica:
# Migrar arquivos automaticamente
npx sv migrate svelte-5
# Verificar problemas de compatibilidade
npx svelte-checkPadroes de Migracao
Stores para Runes:
// Svelte 4: Stores
import { writable, derived } from 'svelte/store';
export const count = writable(0);
export const doubled = derived(count, $count => $count * 2);
// Svelte 5: Runes (stores ainda funcionam!)
// Mas Runes sao recomendados para novo codigo
let count = $state(0);
let doubled = $derived(count * 2);Quando Usar Svelte 5?
Use Svelte 5 quando:
- Iniciar novo projeto frontend
- Precisar de performance maxima
- Quiser menos boilerplate
- Preferir sintaxe mais proxima de JavaScript vanilla
- Precisar de bundles menores
Considere outras opcoes quando:
- Equipe muito experiente em React/Vue
- Ecossistema de bibliotecas e crucial
- Precisar de SSR complexo (SvelteKit ainda e mais jovem)
Conclusao
O Svelte 5 com Runes representa uma evolucao significativa na forma como pensamos sobre reatividade em JavaScript. A sintaxe explicita, o melhor suporte a TypeScript e a performance superior fazem dele uma escolha atraente para novos projetos.
Se voce ja trabalha com React ou Vue, os conceitos de Runes serao familiares, mas a implementacao e mais elegante e direta. Vale a pena experimentar em um projeto pessoal para sentir a diferenca.
A comunidade JavaScript continua inovando, e frameworks como Svelte mostram que ainda ha muito espaco para melhorias na forma como construimos aplicacoes web.
Se voce quer explorar mais sobre frameworks JavaScript modernos, recomendo dar uma olhada no artigo sobre React vs Vue em 2025: Qual Framework Escolher onde comparamos as principais opcoes do mercado.
Bora pra cima! 🦅
📚 Quer Aprofundar Seus Conhecimentos em JavaScript?
Este artigo cobriu o Svelte 5 e Runes, mas ha muito mais para explorar no mundo do desenvolvimento moderno.
Desenvolvedores que investem em conhecimento solido e estruturado tendem a ter mais oportunidades no mercado.
Material de Estudo Completo
Se voce quer dominar JavaScript do basico ao avancado, preparei um guia completo:
Opcoes de investimento:
- 1x de R$9,90 no cartao
- ou R$9,90 a vista
💡 Material atualizado com as melhores praticas do mercado

