<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Oskar Lebuda</title>
    <description>The latest articles on DEV Community by Oskar Lebuda (@oskarlebuda).</description>
    <link>https://dev.to/oskarlebuda</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3011331%2F8e9b8280-e527-482d-9efc-72e610937a4d.jpeg</url>
      <title>DEV Community: Oskar Lebuda</title>
      <link>https://dev.to/oskarlebuda</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/oskarlebuda"/>
    <language>en</language>
    <item>
      <title>I built Vercube because benchmarks don’t lie</title>
      <dc:creator>Oskar Lebuda</dc:creator>
      <pubDate>Mon, 19 Jan 2026 20:09:49 +0000</pubDate>
      <link>https://dev.to/oskarlebuda/i-built-vercube-because-benchmarks-dont-lie-2co7</link>
      <guid>https://dev.to/oskarlebuda/i-built-vercube-because-benchmarks-dont-lie-2co7</guid>
      <description>&lt;p&gt;Let's start with the obvious: yes, this is another Node.js framework.&lt;/p&gt;

&lt;p&gt;I know. You know. Somewhere, a counter just overflowed and a backend developer quietly closed a tab.&lt;/p&gt;

&lt;p&gt;Most of the time, that's the right reaction. You already have NestJS, Fastify, maybe a couple of internal helpers. Adding &lt;em&gt;one more&lt;/em&gt; framework usually sounds pointless.&lt;/p&gt;

&lt;p&gt;Vercube didn't start as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;We need a new framework.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It started as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Why does every framework that feels good to work with get slow - and every fast one feel like you're fighting it?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This article isn't an external review. I'm the author of &lt;a href="https://vercube.dev" rel="noopener noreferrer"&gt;Vercube&lt;/a&gt;. It's a story about why I built it, which assumptions I stopped accepting, and why the benchmark results were the moment I knew this wasn't just a side project anymore.&lt;/p&gt;




&lt;h2&gt;
  
  
  The trade-off I didn't want to accept
&lt;/h2&gt;

&lt;p&gt;For a long time, backend development felt like a forced choice.&lt;/p&gt;

&lt;p&gt;On one side, minimal frameworks: fast, predictable, efficient - but structurally thin. You end up rebuilding patterns, conventions, and discipline in every project.&lt;/p&gt;

&lt;p&gt;On the other side, full OOP frameworks like NestJS or Ts.ED: decorators, dependency injection, clear structure, code that still makes sense after a year. But you pay for it - in build time, startup cost, and runtime overhead.&lt;/p&gt;

&lt;p&gt;Vercube exists because I didn't want to keep choosing between those two worlds.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where the idea really came from
&lt;/h2&gt;

&lt;p&gt;The motivation was simple and very practical:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I wanted backend code that stays readable long after the first sprint.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;OOP still does a great job here. Clear responsibilities. Explicit dependencies. Code that reads like a system instead of a script. Decorators help express intent without adding noise.&lt;/p&gt;

&lt;p&gt;The problem isn't OOP itself - it's how most Node.js frameworks implement it.&lt;/p&gt;

&lt;p&gt;Most decorator-based frameworks rely heavily on runtime reflection.&lt;br&gt;
&lt;code&gt;reflect-metadata&lt;/code&gt; becomes a global dependency. Types are inspected at runtime. Containers infer dependencies dynamically. Metadata gets scanned and merged while the app is already running.&lt;/p&gt;

&lt;p&gt;All of that has a cost - and that cost shows up exactly where you don't want it: in build time, cold starts, latency, and throughput.&lt;/p&gt;

&lt;p&gt;In many ways, Vercube is what projects like routing-controllers were aiming to be - but rebuilt for modern TypeScript, modern runtimes, and performance as a first-class concern.&lt;/p&gt;

&lt;p&gt;So I asked a simple question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;What happens if you remove all of that?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  A different take on decorators
&lt;/h2&gt;

&lt;p&gt;In Vercube, decorators are not a runtime trick. They describe structure without inspecting types, scanning metadata, or depending on global reflection APIs. They don't make decisions at runtime.&lt;/p&gt;

&lt;p&gt;This keeps the framework predictable and avoids the usual reflection-heavy model entirely.&lt;/p&gt;

&lt;p&gt;Vercube is built on top of &lt;a href="https://srvx.h3.dev/" rel="noopener noreferrer"&gt;srvx&lt;/a&gt; and native &lt;code&gt;Request&lt;/code&gt; and &lt;code&gt;Response&lt;/code&gt; interfaces. That makes it runtime-agnostic by design - the same application model works on Node.js, Bun, and Deno without adapters or compatibility layers.&lt;/p&gt;

&lt;p&gt;The result looks familiar if you've used classic OOP frameworks - but behaves very differently under the hood. There's no magic.&lt;/p&gt;

&lt;p&gt;If a dependency exists, it's because you registered it.&lt;br&gt;
If something is resolved, it's because you explicitly allowed it.&lt;/p&gt;

&lt;p&gt;That simplicity becomes crucial once we look at performance.&lt;/p&gt;




&lt;h2&gt;
  
  
  The container as the actual core
&lt;/h2&gt;

&lt;p&gt;At the heart of Vercube is a very small IoC container - nothing more. It's not trying to be a platform or a meta-framework. It registers and resolves dependencies, and that's it.&lt;/p&gt;

&lt;p&gt;There are no hidden scopes, no proxy chains, no request-time dependency graphs. The container does its work during setup. After that, request handling is as direct as possible.&lt;/p&gt;

&lt;p&gt;It might sound boring - and that's intentional.&lt;br&gt;
The less the container tries to be clever, the easier it is to reason about both behavior and cost.&lt;/p&gt;




&lt;h2&gt;
  
  
  Benchmarks: where ideas meet numbers
&lt;/h2&gt;

&lt;p&gt;At some point, design ideas stop being interesting on their own. Numbers take over.&lt;/p&gt;

&lt;p&gt;These benchmarks are not about "winning" against every framework. They're about showing the real cost of different architectural choices.&lt;/p&gt;

&lt;p&gt;All tests use identical endpoints, identical load, and the same environment. Raw data and methodology are public - you can find them on GitHub: &lt;a href="https://github.com/vercube/benchmarks" rel="noopener noreferrer"&gt;vercube/benchmarks&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;All benchmarks were run on the same machine, using identical configuration and endpoints.&lt;/em&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Build time
&lt;/h3&gt;

&lt;p&gt;Build time directly affects developer experience and CI pipelines - yet it's rarely discussed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbqyluk7slljn5di5i8hz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbqyluk7slljn5di5i8hz.png" alt="Vercube build time benchmark" width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That means Vercube builds &lt;strong&gt;~4.6× faster than NestJS&lt;/strong&gt; in the same setup.&lt;br&gt;
Even compared to other decorator-based frameworks, Vercube consistently stays ahead.&lt;/p&gt;

&lt;p&gt;This difference comes from removing reflection, metadata scanning, and complex bootstrap logic. Vercube uses &lt;a href="https://rolldown.rs/" rel="noopener noreferrer"&gt;Rolldown&lt;/a&gt; - a blazing-fast bundler that complements this simplified architecture perfectly.&lt;/p&gt;




&lt;h3&gt;
  
  
  Cold start time
&lt;/h3&gt;

&lt;p&gt;Cold start matters in serverless environments, autoscaling setups, and frequent restarts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv6jr7mieqwp3rudvogap.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv6jr7mieqwp3rudvogap.png" alt="Vercube cold start time benchmark" width="800" height="489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vercube cold starts &lt;strong&gt;~35% faster than NestJS&lt;/strong&gt; and over &lt;strong&gt;3× faster than Ts.ED&lt;/strong&gt;.&lt;br&gt;
That gap is the cost of runtime introspection and heavy initialization.&lt;/p&gt;




&lt;h3&gt;
  
  
  Throughput (requests per second)
&lt;/h3&gt;

&lt;p&gt;Throughput is the metric everyone expects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyj3e5h20fxr7zomf4m79.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyj3e5h20fxr7zomf4m79.png" alt="Vercube RPS benchmark" width="800" height="489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's roughly &lt;strong&gt;~16% higher throughput than NestJS&lt;/strong&gt;, while still using decorators and dependency injection.&lt;/p&gt;

&lt;p&gt;The goal here isn't to dominate throughput charts - it's to stay competitive without giving up structure.&lt;/p&gt;




&lt;h3&gt;
  
  
  Latency distribution (p95)
&lt;/h3&gt;

&lt;p&gt;Average latency hides problems. p95 shows real behavior under load.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdm5xkj1ydktjqe2bj2e6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdm5xkj1ydktjqe2bj2e6.png" alt="Vercube latency benchmark" width="800" height="489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vercube stays stable under load and avoids long-tail latency spikes common in heavier frameworks.&lt;/p&gt;




&lt;h2&gt;
  
  
  It's not just about runtime
&lt;/h2&gt;

&lt;p&gt;Most frameworks talk about runtime performance.&lt;/p&gt;

&lt;p&gt;Vercube cares just as much about everything that happens &lt;em&gt;before&lt;/em&gt; the first request: build time, cold start, startup memory.&lt;/p&gt;

&lt;p&gt;In modern systems - CI-heavy workflows, serverless deployments, short-lived instances - these costs add up quickly. The benchmarks show that Vercube performs well across the entire lifecycle, not just during request handling.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why the numbers look like this
&lt;/h2&gt;

&lt;p&gt;There's no single trick behind the results.&lt;/p&gt;

&lt;p&gt;Performance comes from removing entire classes of overhead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no runtime reflection&lt;/li&gt;
&lt;li&gt;no metadata scanning&lt;/li&gt;
&lt;li&gt;no request-time dependency resolution&lt;/li&gt;
&lt;li&gt;no abstraction layers sitting on every call&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything expensive happens once. What runs per request is plain JavaScript.&lt;/p&gt;

&lt;p&gt;That also means fewer surprises. When something behaves a certain way, it's usually obvious why.&lt;/p&gt;




&lt;h2&gt;
  
  
  OOP doesn't have to mean legacy
&lt;/h2&gt;

&lt;p&gt;Many developers associate decorators with slow, over-engineered systems.&lt;/p&gt;

&lt;p&gt;That's a tooling problem - not a paradigm problem.&lt;/p&gt;

&lt;p&gt;Vercube shows that you can keep OOP, keep decorators, keep clean structure - and still hit numbers usually reserved for much more minimal frameworks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Closing thoughts
&lt;/h2&gt;

&lt;p&gt;I didn't build &lt;a href="https://vercube.dev" rel="noopener noreferrer"&gt;Vercube&lt;/a&gt; to prove a point about frameworks.&lt;/p&gt;

&lt;p&gt;I built it because I wanted to enjoy writing backend code again - without paying for that comfort in build time, startup time, or runtime performance.&lt;/p&gt;

&lt;p&gt;The benchmarks matter because they remove opinions from the discussion. You don't have to like the design or agree with the philosophy.&lt;/p&gt;

&lt;p&gt;You can just look at the numbers.&lt;/p&gt;

&lt;p&gt;And those numbers show that OOP - when done carefully - still has a place in modern backend development.&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>programming</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
