Building a Full-Stack Task Manager with Gleam: One Language, Every Platform

Building a Full-Stack Task Manager with Gleam: One Language, Every Platform

Apr 30, 2026 gleam full-stack development type safety web architecture backend development frontend development cross-platform apps erlang lustre tauri

Building a Full-Stack Task Manager with Gleam: One Language, Every Platform

The dream of write-once-deploy-everywhere has haunted developers for decades. We've chased it with Java applets, Electron, React Native, and Flutter. But what if the answer wasn't about frameworks—what if it was about choosing the right language from the start?

Enter Gleam: a statically-typed language that compiles to both Erlang (for backend) and JavaScript (for frontend), enabling genuinely unified full-stack development. Today, we're exploring how this works in practice by examining a real-world example: a task manager application that demonstrates the full power of this approach.

The Vision: One Codebase, Multiple Platforms

Let's be clear about what we're discussing here. When most frameworks claim "write once, run anywhere," they're usually referring to a specific flavor of deployment. Gleam goes deeper—it literally compiles the same source code to different runtime environments.

The task manager we're building here—let's call it Doable—is intentionally simple by design. It handles the bread-and-butter operations: create, read, update, and delete tasks. But its simplicity is deceptive. Behind that humble CRUD interface lies an entire architectural stack:

  • JSON HTTP API running on Erlang with PostgreSQL persistence
  • Browser-based frontend with reactive state management
  • Native desktop applications for Windows, macOS, and Linux via Tauri
  • iOS and Android mobile apps, also packaged through Tauri

All of this. Same language. Same type system. Same validation logic.

Architecture: Development vs. Production Thinking

How Developers Actually Work

During development, you need fast feedback loops. That means Docker for your database and API server, a hot-reload dev server that works across all your frontends, and the ability to test against integration tests without rebuilding everything.

The development setup achieves this elegantly:

  • PostgreSQL runs in Docker with separate databases for development and testing
  • Your Gleam API server can run either in Docker or locally for active development
  • A single Lustre dev server handles hot reload for browser, desktop, and mobile clients
  • API proxying avoids CORS headaches—everything flows through one development entry point
  • Integration tests run directly against your router with a dedicated test database

This matters because developer velocity is real. Waiting 30 seconds between changes isn't scaling—it's death by a thousand cuts.

How Production Actually Runs

Once you ship, complexity disappears. Everything containerizes inside Docker. Caddy becomes your single entry point, reverse-proxying to both your Gleam API server and a file server hosting the compiled frontend.

Here's the elegant part: your browser clients request the frontend through Caddy's file server and send API calls through the same proxy. Your Tauri-packaged desktop and mobile apps? They bundle the same compiled frontend locally but use Tauri's HTTP plugin to reach Caddy's API endpoint. Same application, optimized delivery per platform.

The Technical Stack Breakdown

Backend: Erlang's Proven Reliability

Your API server compiles to Erlang using Wisp and Mist libraries. You're not just getting a web framework—you're inheriting decades of telecom infrastructure engineering. Erlang's runtime handles concurrency, fault tolerance, and distribution in ways that most modern languages are still learning.

PostgreSQL gives you traditional relational persistence with the reliability Erlang developers have trusted since the 1990s.

Shared Code: The Real Win

Here's where Gleam's architecture reveals its genius: you maintain a shared project—a multi-target Gleam library that compiles to both Erlang and JavaScript. Type definitions, validation logic, serialization—all shared. When you update a task structure, that change propagates automatically to every platform.

No type mismatches between frontend and backend. No "it works on my machine" validation surprises. The compiler catches architectural inconsistencies before they become runtime bugs.

Frontend: Elm Architecture Patterns

Your web frontend uses Lustre, implementing the Elm Architecture—a proven pattern for managing complex UI state. If you've built Elm applications, this feels familiar. If you haven't, it's worth learning: this architectural approach has become the gold standard for predictable, testable frontend code.

Desktop and mobile versions follow the same patterns, just running on different deployment targets.

Why This Matters for Your Next Project

Full-stack type safety is increasingly relevant as applications grow more complex. Here's what actually changes:

Refactoring becomes fearless. Rename a field in your database schema, update it in the shared types, and the compiler tells you exactly which 47 places in your codebase need attention. No mysteries.

Cross-platform consistency is free. You're not translating the same validation logic between TypeScript, Swift, and Kotlin. Write it once in Gleam, compile to three targets.

Developer onboarding accelerates. New team members learning one language and one type system versus juggling three ecosystems is a massive productivity multiplier.

Operational simplicity compounds. Fewer languages means fewer dependency trees, fewer deployment strategies, fewer runtime surprises.

The Practical Reality

Is Gleam the future of all web development? Probably not. Communities and ecosystems matter. Gleam is smaller than TypeScript or Python, and that's a real consideration for hiring and library availability.

But for teams building greenfield full-stack applications where type safety and unified code matter? This approach eliminates entire categories of bugs before they become incidents.

The task manager example is deliberately simple—that's the point. It proves the architecture works at small scale. Real applications add complexity, but the core philosophy remains: compile once, validate everywhere, deploy to many.

Getting Started

If this resonates with you, the learning curve is real but manageable. Gleam's syntax borrows from languages you probably know (JavaScript, Python, Rust). The type system is powerful but doesn't demand mastery on day one.

Start with the Erlang backend. Build your API. Then layer in Lustre for the frontend and watch shared types eliminate entire classes of bugs. Once you experience what unified full-stack development feels like, going back to fragment-and-translate approaches feels... vintage.

The future of full-stack development might not be about choosing different tools for different layers. It might be about choosing the right language that can target every layer you need.


Ready to explore full-stack Gleam development? Start with the Gleam documentation and consider how your next project might benefit from type-safe compilation across all platforms.

Read in other languages:

RU BG EL CS UZ TR SV FI RO PT PL NB NL HU IT FR ES DE DA ZH-HANS