Inspiration

Learning a new language as an adult can feel overwhelming — textbooks are dry, apps feel like mindless repetition, and finding a speaking partner is nearly impossible. We built DutchLearn because we believe language learning should feel like play, not homework. We wanted to create something that adapts to different learning styles — whether you're a visual learner who loves flashcards, a gamer who thrives on challenges, or someone preparing for a real conversation at a Dutch café. The goal was simple: make Dutch accessible, engaging, and actually stick in your memory.

What it does

DutchLearn is a comprehensive Dutch language learning platform packed into a single progressive web app. It covers every pillar of language acquisition:

  • Vocabulary & SRS Flashcards — Learn Dutch words with spaced repetition flashcards that adapt to your memory strength, ensuring you review words exactly when you're about to forget them.
  • Grammar Mastery — Interactive exercises covering articles (de/het), verb conjugations, and word-order rules with instant feedback.
  • Conversation Practice — Real-world dialogue scenarios with role-playing so you can practice responding in context.
  • Scenario-Based Learning — Navigate everyday situations like ordering at a restaurant, asking for directions, or shopping at a market.
  • News Reader — Read curated Dutch news articles with difficulty-appropriate vocabulary to bridge the gap from learner to real-world reader.
  • Listening Exercises — Train your ear with audio-based comprehension challenges.
  • Games — A competitive flashcard game that turns review sessions into quick-fire challenges.
  • Daily Quests — Gamified daily goals (complete exercises, learn new words, play games) with a points leaderboard to keep motivation high.
  • Friends & Challenges — Add friends by username, send friend requests with approval, and challenge each other to grammar duels.
  • Progress Tracking — Detailed SRS stats showing your retention rate, streaks, words mastered, and learning velocity.
  • Adaptive Themes — Three age-based color themes (Classic, Playful, Energetic) so the app feels right whether you're 8 or 80.

How we built it

We built DutchLearn as a modern React application using Vite for fast development and TypeScript for type safety across the entire codebase. The UI is powered by Tailwind CSS and shadcn/ui, giving us a polished, accessible component library with built-in dark mode support.

On the backend, we use Supabase — a Firebase alternative built on Postgres. This handles:

  • User authentication (email/password with username support)
  • Real-time database for friends, challenges, and daily quests
  • Row-Level Security (RLS) policies to ensure users only access their own data
  • Database triggers that auto-create user profiles and backfill usernames

The SRS (Spaced Repetition System) algorithm runs client-side using a custom Leitner-box-inspired implementation with localStorage persistence, so your review schedule survives refreshes and even offline use. We also implemented a 12-step interactive Demo Guide that helps new users navigate every section of the app on first visit.

Challenges we ran into

One of our biggest hurdles was the service worker we initially added for offline support. In development, a stale service worker started intercepting network requests and returning fake 408 errors, which broke login, blocked Supabase calls, and made pages appear stuck on loading. We solved this by making the service worker self-uninstalling and adding force-unregistration logic that runs before the app even mounts.

Another challenge was friend request visibility. Our initial implementation used email-based search, which was privacy-sensitive and clunky. We migrated to a username system with backfilled usernames, added RLS-safe ilike search queries, and split pending requests into incoming vs. outgoing so users could see the full state of their social graph.

We also wrestled with auth persistence — on page reload, the app would sometimes log users out because onAuthStateChange wasn't properly tracking the initial session. We rewrote the auth context with explicit event handling (SIGNED_IN, TOKEN_REFRESHED, SIGNED_OUT) and a hard timeout fallback so the app never hangs on a loading spinner.

Accomplishments that we're proud of

  • Complete learning ecosystem — Most language apps do one thing well (flashcards OR grammar OR listening). DutchLearn integrates all of them with a unified progress system.
  • SRS that actually works — Our spaced repetition algorithm isn't just a timer; it tracks per-word difficulty, adjusts intervals based on performance, and surfaces due cards intelligently.
  • Social learning — The friends, challenges, and daily quest leaderboard turn a solitary activity into a community experience. Seeing a friend's name on the leaderboard is surprisingly motivating.
  • Accessibility by design — Dark mode, age-based themes, and responsive layouts mean the app works comfortably on a phone at night or a tablet during the day.
  • Resilient auth — After fighting through service worker and auth edge cases, our login system now has timeouts, error boundaries, and graceful fallbacks. It doesn't break.

What we learned

  • Service workers are powerful but dangerous — One misconfigured caching strategy can break your entire app. We learned to be extremely careful with fetch interception and to always provide an escape hatch (force-unregistration).
  • Supabase RLS is a double-edged sword — It's great for security, but policy misconfigurations silently block legitimate queries. We learned to test every query as both authenticated and anonymous users.
  • Username search beats email search — Privacy matters. Users don't want their email exposed, and searching by username feels more like a social platform than a contact list.
  • Gamification works — Adding daily quests and a leaderboard didn't just feel fun; it measurably increased our own engagement during testing. The psychology of streaks and points is real.

What's next for Dutch Language Learning App

  • AI-powered conversation partner — Integrate a large language model so users can have open-ended Dutch conversations with real-time corrections and pronunciation feedback.
  • Speech recognition & scoring — Expand the existing pronunciation scoring to cover full sentences, not just individual words.
  • Achievement badges & certificates — Unlockable milestones (e.g., "100 Words Mastered," "7-Day Streak," "Grammar Ninja") with shareable certificates.
  • Cultural content — Add Dutch cultural notes, idioms, and regional dialect exposure so learners understand the language in context, not just in isolation.
  • Mobile app — Package the PWA as a native iOS/Android app with push notifications for daily quest reminders and SRS review alerts.
  • Community-created content — Let advanced users contribute vocabulary decks, grammar exercises, and conversation scenarios.

Built With

  • autoprefixer
  • biome
  • date-fns
  • embla-carousel
  • localstorage
  • lucide-react
  • motion-(framer-motion)
  • postcss
  • postgresql
  • radix-ui
  • react
  • react-hook-form
  • react-router-dom
  • recharts
  • row-level-security-(rls)
  • service-worker
  • sessionstorage
  • shadcn/ui
  • sonner
  • supabase
  • supabase-auth
  • tailwind-css
  • typescript
  • vite
  • zod
Share this project:

Updates