Skip to content

the best scalable stack for modern web developers in 2025


<- return to blog

Vue, Bun & Elixir

A scalable, fast, killer modern tech stack for 2025


If you're building a modern web app in 2025 you need a stack that’s fast, scalable, and easy to work with. The days of bloated monolithic frameworks are behind us. Instead this stack uses specialized tools that get the job done efficiently.

Vue, Bun, and Elixir is a powerful trifecta that combines a lightweight frontend, a fast and scalable backend for APIs and a highly concurrent WebSocket server. This stack gives you speed, flexibility, and most importantly developer joy.

Why not a monolith or server-side-components?

It's simple - speed and scalability. A monolith or server-side-components will never be able to match the speed of a statically served Vue bundle from NGINX or Caddy. It's more efficient for our backend to only serve a JSON REST API or WebSocket that our statically served client can consume.

Vue.js & TypeScript for the front-end


We are going to build our front-end using Vue.js and TypeScript, and we are going to make it a single-page-application that takes advantage of lazy-loading and code-splitting. This ensures we can statically serve our entire app while keeping initial bundle size low.

Vue is a simple front-end framework - it has a wonderful DX and is lightweight and fast. It has a simple learning curve that allows you to build more with less time.

Quasar, a component library for Vue makes it simple to create amazing apps.

Vue Component Example (Composition API)

<script setup>
  import { ref } from 'vue'
  const count = ref(0)
</script>

<template>
  <button @click="count++">Count is: {{ count }}</button>
</template>

<style scoped>
  button {
    font-weight: bold;
  }
</style>

Why not React?

Vue.js was chosen because it simply provides us less headaches and lets us focus on the fun part - building the app. I consider Vue the standard and most reliable framework for web development in 2025.

JSX goes against web standards and it is highly unacceptable (and in my opinion hilariously idiotic) to do something like put Markup in a JavaScript function. If there was a wrong way do things in web development, it would be using JSX. One of the core principles of good software engineering is separation of concerns. Your markup and logic should be as separate as possible and the mustache-style templating for your markup that Vue uses is a good middle ground.

I don't know what kind of jeffreys they were smoking at Facebook when they came up with React/JSX, but it must have been some good stuff and they should get in touch with me and sell me half a bag.

In Vue, larger components or pages can highly benefit from being separated into separate CSS/SCSS, TS/JS and Vue files. Smaller and more simple components can benefit as single-file-components.

State management in Vue is simple with Pinia.

Vue embraces web standards like HTML, CSS, and the DOM, while React replaces them with abstractions.

Isn't Vue for smaller apps? What about large, enterprise apps?

Contrary to the belief, Vue actually scales much better for larger apps because of separation of concern and it's simplicity. Performance remains consistent even with large, busy applications. Onboarding new developers is a breeze.

React can get much messier the larger an app grows - complex components can become hard or impossible to read or understand, especially for developers new to your project.

I have personally built a number of larger apps and have not come across any problems.

React’s Problem: React’s Virtual DOM re-renders entire components unnecessarily unless you manually optimize it (useMemo, useCallback). Hooks in React introduce unintuitive rules, require useEffect for side effects, and lead to "stale closure" bugs. CSS in JS adds runtime overhead.

Vue reactively updates only what's needed. There is also no need for useState or useEffect.

Bun, Elysia & Drizzle for REST APIs


Bun, Elysia & Drizzle makes for a powerful and minimalistic stack for building REST APIs that are fast, typed, and efficient.

Bun is an all-in-one TypeScript runtime that’s fast, modern, and built from scratch in Zig.

Bun uses the event loop model of JavaScript, which is very good at handling I/O-bound tasks - perfect for APIs.

Elysia is a framework built on top of Bun, providing a fast, flexible, and end-to-end type-safe environment for building APIs.

Elysia Minimal Example

import { Elysia } from 'elysia'

new Elysia()
    .get('/', 'Hello World')
    .listen(3000)

Drizzle is a modern, type-safe ORM for TypeScript that lets you interact with your database using an ORM instead of raw SQL.

Bun is great at doing image manipulation using sharp for endpoints where users need to upload avatars or other images to an S3 bucket.

Bun also includes a websocket server that is useful for small projects on it's own. However, you won't get cool Elixir features like code hot-swapping, high concurrency or fault-tolerance that are useful at scale.

Why not Elixir for our REST JSON API?

Despite the popularity of Pheonix and it's rails-esque way of doing things, Elixir is simply the wrong tool for the job due to the nature of the language. Elixir’s power lies in real-time systems and fault tolerance. Elixir has characteristics that can make it challenging to write the complex business logic that REST APIs can demand.

  • Lack of Object-Oriented structures
  • No return-early pattern
  • Hard to avoid deep nesting of if, case, with statements
  • Pattern matching can get messy
  • Harder to find Elixir developers

Elixir was designed for concurrency, fault-tolerance and long-lived connections - not necessarily high-throughput, ultra-low-latency HTTP servers with short-lived connections.

Elixir for real-time features


So your front-end app happens to require real-time updates. Perhaps you have a dashboard that demands real-time data, or you want a live chat between your users.

We are going to use Elixir, Cowboy, Octo and Redis to build our real-time features.

Why Elixir?

Concurrency and fault-tolerance. Cowboy (Erlang’s HTTP server) efficiently handles WebSocket and SSE connections.

Elixir runs on BEAM, which supports millions of lightweight processes (not OS threads). Each WebSocket/SSE connection runs in its own process, isolated and crash-safe. Elixir can handle thousands to millions of concurrent long-lived connections.

Elixir also supports hot code swapping, meaning you can update code without restarting WebSocket/SSE connections for zero downtime deploys.

Erlang/Elixir is battle-tested when it comes to realtime features and is deployed in production by companies like Heroku, Discord and WhatsApp.

Building at Scale


If you're looking to build a web application or API that can handle high traffic, scale effectively, and offer a modern developer experience - the combination of Vue, Bun, and Elixir is an excellent choice.

This stack provides the speed, scalability, and flexibility required to support millions of users and can meet the demands of modern applications.

<- return to blog