Welcome to Day 1 of the "12 Days of Svelte Apps" challenge! ๐
Over the next 12 days, we're exploring a collection of mini-apps built with Svelte 5 and SvelteKit. Whether you're a seasoned developer or just curious about the new Svelte 5 Runes syntax, this series will showcase practical examples of modern web development.
Today, we're tackling a problem we all face in December: Holiday Spending.
The App: Budget Tracker
The Budget Tracker is a clean, privacy-focused tool designed to help you set limits and track expenses in real-time. Itโs not just a spreadsheet; itโs a reactive application that gives you instant visual feedback on your financial health.
๐ Try the App Live
๐ป View the Code
Key Features ๐
- Visual Limits: Create budgets with specific caps (e.g., "$1000 for Gifts"). As you add expenses, the progress bar shifts color from generic green to warning yellow, and finally to "danger red" as you approach your limit.
- Multi-Currency Support: Ordering gifts from overseas? The app supports USD, EUR, GBP, JPY, and more, handling the display formatting seamlessly.
- Local-First with Backup: Your data is stored locally for instant access, but authenticated users get auto-backups to the server.
Under the Hood: Svelte 5 Runes ๐ ๏ธ
One of the coolest parts of building this app was using the new Svelte 5 reactivity model. Gone are the days of complex store subscriptions for simple local state.
1. Form State with $state
Handling form inputs is incredibly intuitive. Instead of binding to a store, we just use a comprehensive $state object or individual signals.
let budgetName = $state('');
let budgetAmount: number | undefined = $state(undefined);
let selectedCurrency = $state('USD');
function addBudget() {
// Reactivity just works!
budgetState.addBudget(budgetName, budgetAmount, selectedCurrency);
// Resetting forms is as simple as reassigning the variable
budgetName = '';
budgetAmount = undefined;
}
2. Auto-Backup with $effect
We implemented a "smart" auto-backup that watches for unsaved changes. It uses $effect to trigger a countdown whenever the state changes.
// Auto-backup effect
$effect(() => {
// Using $effect.pre to cleanup previous timers ensures no memory leaks
$effect.pre(() => {
clearTimeout(autoBackupTimer);
});
if (hasUnsavedChanges && autoBackupEnabled.current) {
// Debounce the backup trigger
autoBackupTimer = setTimeout(performAutoBackup, 3000);
}
});
This pattern ensures that every time the user types or modifies a value (hasUnsavedChanges becomes true), we reset the timer, waiting for them to stop "typing" for 3 seconds before syncing to the server.
Holiday Use Case ๐
Don't let the "New Year, New Me" resolution start with paying off credit card debt.
- Open the Budget Tracker.
- Create a "Holiday 2025" budget.
- Log every roll of wrapping paper and every Secret Santa gift.
Stay tuned for Day 2, where we'll handle the logistics of gift-giving!

Top comments (0)