Skip to content

feat!: Compile optimized fetch and route handler functions#5

Merged
aklinker1 merged 16 commits intomainfrom
compiled-handlers
Dec 27, 2025
Merged

feat!: Compile optimized fetch and route handler functions#5
aklinker1 merged 16 commits intomainfrom
compiled-handlers

Conversation

@aklinker1
Copy link
Copy Markdown
Owner

@aklinker1 aklinker1 commented Dec 27, 2025

Caution

Breaking changes:

  1. Global hooks that are async are no longer awaited before calling the next one or moving on.

    If you have an async onGlobalRequest hook that returns a value, the return value is ignored.

  2. Renamed OnGlobalErrorHooks type to OnGlobalErrorHook

This closes #4. Here's the benchmark results:

$ bun run src/__tests__/bench.ts
Static Response: 7.8x more ops/s
┌───┬────────────┬──────────────────┬──────────────────┬────────────────────────┬────────────────────────┬─────────┐
│   │ Task name  │ Latency avg (ns) │ Latency med (ns) │ Throughput avg (ops/s) │ Throughput med (ops/s) │ Samples │
├───┼────────────┼──────────────────┼──────────────────┼────────────────────────┼────────────────────────┼─────────┤
│ 0 │ vanilla    │ 251.02 ± 0.41%   │ 183.00 ± 6.00    │ 5260964 ± 0.02%        │ 5464481 ± 173476       │ 3983677 │
│ 1 │ elysia     │ 352.72 ± 0.40%   │ 271.00 ± 5.00    │ 3564918 ± 0.02%        │ 3690037 ± 66849        │ 2835086 │
│ 2 │ hono       │ 1488.7 ± 0.56%   │ 1081.0 ± 43.00   │ 830947 ± 0.06%         │ 925069 ± 37395         │ 671743  │
│ 3 │ zeta (OLD) │ 1632.4 ± 0.46%   │ 1335.0 ± 56.00   │ 706271 ± 0.04%         │ 749064 ± 32186         │ 612587  │
│ 4 │ zeta (NEW) │ 211.43 ± 0.69%   │ 171.00 ± 9.00    │ 5631414 ± 0.02%        │ 5847953 ± 323091       │ 4729688 │
└───┴────────────┴──────────────────┴──────────────────┴────────────────────────┴────────────────────────┴─────────┘
Validate and Echo JSON Body: 3.54x more ops/s
┌───┬────────────┬──────────────────┬──────────────────┬────────────────────────┬────────────────────────┬─────────┐
│   │ Task name  │ Latency avg (ns) │ Latency med (ns) │ Throughput avg (ops/s) │ Throughput med (ops/s) │ Samples │
├───┼────────────┼──────────────────┼──────────────────┼────────────────────────┼────────────────────────┼─────────┤
│ 0 │ vanilla    │ 347.56 ± 0.20%   │ 311.00 ± 10.00   │ 3154822 ± 0.01%        │ 3215434 ± 100169       │ 2877272 │
│ 1 │ elysia     │ 1587.9 ± 0.69%   │ 1303.0 ± 56.00   │ 737085 ± 0.04%         │ 767460 ± 33245         │ 629780  │
│ 2 │ hono       │ 1821.0 ± 0.81%   │ 1408.0 ± 66.00   │ 645072 ± 0.06%         │ 710227 ± 33820         │ 549136  │
│ 3 │ zeta (OLD) │ 3294.1 ± 0.80%   │ 2761.0 ± 109.00  │ 345238 ± 0.06%         │ 362188 ± 14602         │ 303569  │
│ 4 │ zeta (NEW) │ 984.75 ± 1.38%   │ 780.00 ± 33.00   │ 1238194 ± 0.03%        │ 1282051 ± 55057        │ 1015488 │
└───┴────────────┴──────────────────┴──────────────────┴────────────────────────┴────────────────────────┴─────────┘
Validate and Echo Query Params: 3.2x more ops/s
┌───┬────────────┬──────────────────┬──────────────────┬────────────────────────┬────────────────────────┬─────────┐
│   │ Task name  │ Latency avg (ns) │ Latency med (ns) │ Throughput avg (ops/s) │ Throughput med (ops/s) │ Samples │
├───┼────────────┼──────────────────┼──────────────────┼────────────────────────┼────────────────────────┼─────────┤
│ 0 │ vanilla    │ 1921.6 ± 2.47%   │ 1327.0 ± 70.00   │ 703586 ± 0.06%         │ 753580 ± 40702         │ 520410  │
│ 1 │ elysia     │ 685.22 ± 0.59%   │ 557.00 ± 31.00   │ 1699683 ± 0.03%        │ 1795332 ± 102201       │ 1459378 │
│ 2 │ hono       │ 3760.2 ± 2.66%   │ 2673.0 ± 220.00  │ 331676 ± 0.10%         │ 374111 ± 32558         │ 265944  │
│ 3 │ zeta (OLD) │ 2916.2 ± 0.45%   │ 2523.0 ± 93.00   │ 376393 ± 0.05%         │ 396354 ± 14831         │ 342907  │
│ 4 │ zeta (NEW) │ 928.82 ± 0.25%   │ 786.00 ± 24.00   │ 1206065 ± 0.03%        │ 1272265 ± 40071        │ 1076636 │
└───┴────────────┴──────────────────┴──────────────────┴────────────────────────┴────────────────────────┴─────────┘
Validate and Echo Path Params: 3.83x more ops/s
┌───┬────────────┬──────────────────┬──────────────────┬────────────────────────┬────────────────────────┬─────────┐
│   │ Task name  │ Latency avg (ns) │ Latency med (ns) │ Throughput avg (ops/s) │ Throughput med (ops/s) │ Samples │
├───┼────────────┼──────────────────┼──────────────────┼────────────────────────┼────────────────────────┼─────────┤
│ 0 │ elysia     │ 457.17 ± 0.44%   │ 358.00 ± 30.00   │ 2641961 ± 0.03%        │ 2793296 ± 246217       │ 2187391 │
│ 1 │ hono       │ 3586.2 ± 0.62%   │ 2777.0 ± 146.00  │ 330052 ± 0.08%         │ 360101 ± 19617         │ 278845  │
│ 2 │ zeta (OLD) │ 3286.9 ± 0.47%   │ 2760.0 ± 114.00  │ 344046 ± 0.06%         │ 362319 ± 15217         │ 304237  │
│ 3 │ zeta (NEW) │ 896.12 ± 0.46%   │ 721.00 ± 34.00   │ 1311020 ± 0.03%        │ 1386963 ± 66526        │ 1115926 │
└───┴────────────┴──────────────────┴──────────────────┴────────────────────────┴────────────────────────┴─────────┘
Response Validation: 8.90x more ops/s
┌───┬────────────┬──────────────────┬──────────────────┬────────────────────────┬────────────────────────┬─────────┐
│   │ Task name  │ Latency avg (ns) │ Latency med (ns) │ Throughput avg (ops/s) │ Throughput med (ops/s) │ Samples │
├───┼────────────┼──────────────────┼──────────────────┼────────────────────────┼────────────────────────┼─────────┤
│ 0 │ vanilla    │ 859.17 ± 0.43%   │ 576.00 ± 29.00   │ 1592347 ± 0.04%        │ 1736111 ± 88706        │ 1163908 │
│ 1 │ elysia     │ 364.46 ± 0.33%   │ 297.00 ± 29.00   │ 3188618 ± 0.03%        │ 3367003 ± 345855       │ 2743796 │
│ 2 │ hono       │ 2932.8 ± 0.89%   │ 2222.0 ± 131.00  │ 413088 ± 0.07%         │ 450045 ± 27510         │ 340975  │
│ 3 │ zeta (OLD) │ 2280.5 ± 1.08%   │ 1941.0 ± 113.00  │ 493737 ± 0.05%         │ 515198 ± 30937         │ 438498  │
│ 4 │ zeta (NEW) │ 261.38 ± 0.50%   │ 218.00 ± 13.00   │ 4407710 ± 0.02%        │ 4587156 ± 276811       │ 3825864 │
└───┴────────────┴──────────────────┴──────────────────┴────────────────────────┴────────────────────────┴─────────┘
Single hook: 12.83x more ops/s
┌───┬────────────┬──────────────────┬──────────────────┬────────────────────────┬────────────────────────┬─────────┐
│   │ Task name  │ Latency avg (ns) │ Latency med (ns) │ Throughput avg (ops/s) │ Throughput med (ops/s) │ Samples │
├───┼────────────┼──────────────────┼──────────────────┼────────────────────────┼────────────────────────┼─────────┤
│ 0 │ elysia     │ 237.08 ± 0.39%   │ 193.00 ± 8.00    │ 4899404 ± 0.02%        │ 5181347 ± 224058       │ 4218030 │
│ 1 │ hono       │ 3724.6 ± 1.16%   │ 2920.0 ± 253.00  │ 318619 ± 0.08%         │ 342466 ± 30947         │ 268483  │
│ 2 │ zeta (OLD) │ 2932.7 ± 0.49%   │ 2554.0 ± 138.00  │ 375514 ± 0.05%         │ 391543 ± 21680         │ 340988  │
│ 3 │ zeta (NEW) │ 245.71 ± 0.51%   │ 199.00 ± 9.00    │ 4743778 ± 0.02%        │ 5025126 ± 238033       │ 4069862 │
└───┴────────────┴──────────────────┴──────────────────┴────────────────────────┴────────────────────────┴─────────┘

To accomplish this, I had to make a few changes:

  1. Require sync global hooks - having an async fetch function made the throughput 10x slower. so these functions had to be sync.
  2. "Compile" fetch function - if there are no global hooks, don't include the hook code. Remove any async/await usage from here.
  3. "Compile" route handlers - if there are no hooks, don't include the hook code. If there are no schemas provided for validation, don't include the validation code.
  4. Context class - creating instances of classes is faster than creating a new object on every request. Additionally, getters have no overhead when used in classes, but have a lot of overhead when defined on objects every request. Combined, those two things (creating objects and adding getters to them) was the second most effective change at speeding things up.

@aklinker1 aklinker1 self-assigned this Dec 27, 2025
@aklinker1 aklinker1 changed the title feat!: Compile optimized fetch and handler functions per route feat!: Compile fetch and handler functions per route into optimized functions Dec 27, 2025
@aklinker1 aklinker1 marked this pull request as ready for review December 27, 2025 20:29
@aklinker1 aklinker1 changed the title feat!: Compile fetch and handler functions per route into optimized functions feat!: Compile optimized fetch and handler functions per route Dec 27, 2025
@aklinker1 aklinker1 changed the title feat!: Compile optimized fetch and handler functions per route feat!: Compile optimized fetch and route handler functions Dec 27, 2025
@aklinker1 aklinker1 merged commit 6f82ad9 into main Dec 27, 2025
2 checks passed
@aklinker1 aklinker1 deleted the compiled-handlers branch December 27, 2025 20:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JIT specialized code gen for route handlers

1 participant