<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/improving-javascript-webhook-transformations-0styjqp9u" -->

---
title: Improving JavaScript Webhook Transformations | daily.dev
description: Svix migrated its webhook transformation engine from Deno/v8 to QuickJS (specifically the QuickJS-NG fork), citing v8's poor fit for short-lived,...
canonical: https://daily.dev/posts/improving-javascript-webhook-transformations-0styjqp9u
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Improving JavaScript Webhook Transformations | daily.dev
og:description: Svix migrated its webhook transformation engine from Deno/v8 to QuickJS (specifically the QuickJS-NG fork), citing v8's poor fit for short-lived,...
og:url: https://daily.dev/posts/improving-javascript-webhook-transformations-0styjqp9u
og:image: https://api.daily.dev/og/posts/0STYjQP9u.png
og:image:alt: Improving JavaScript Webhook Transformations
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Improving JavaScript Webhook Transformations

**[Svix Blog](https://daily.dev/sources/svix)** · 6 min read · 0 upvotes · 0 comments

## Summary

Svix migrated its webhook transformation engine from Deno/v8 to QuickJS (specifically the QuickJS-NG fork), citing v8's poor fit for short-lived, single-execution scripts, lack of native execution time limits, and unreliable memory-limit crash handling. The switch, completed on December 8, cut average transformation response time from 11.0±7.0ms to 1.0±0.7ms, over 10x faster with far less variance. The post details the Rust rquickjs bindings used, including AsyncRuntime::set_memory_limit and set_interrupt_handler for bounding resource usage, and code samples for executing scripts safely. It also mentions the rollout strategy of running v8 and QuickJS concurrently to validate correctness, and future directions like BoaJS and WebAssembly Components for polyglot transformation functions.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://www.svix.com/blog/improving-transformations>

## Questions this post answers

### Why did Svix replace v8/Deno with QuickJS for running customer JavaScript webhook transformations?

V8 was optimized for long-running code with JIT compilation, but most transformation scripts ran only once per isolate, so isolate startup dominated runtime at over 10ms average, roughly 90% of which was scaffolding and initialization. Deno also lacked native execution time limits, and v8's heap limit handling crashed and dumped state to stderr instead of failing gracefully.

_daily.dev surfaces engineering writeups like this for teams evaluating sandboxed JS runtimes._

### How much faster is QuickJS than v8 for running short-lived JavaScript snippets in Svix's webhook transformation feature?

Average response time dropped from 11.0±7.0ms with v8 to 1.0±0.7ms with QuickJS, over a 10x improvement with much lower variance. In debug-mode local benchmarking the gain was even larger, over 14x faster, which also sped up development iteration for engineers working on the feature.

_Teams choosing between JS runtimes for sandboxing can track performance comparisons like this via daily.dev._

### How do you set a memory limit and execution time limit for the rquickjs Rust bindings to QuickJS?

Use AsyncRuntime::set_memory_limit to bound heap usage and AsyncRuntime::set_interrupt_handler to enforce a rough time limit, since QuickJS lacks a hard timeout. The interrupt handler runs periodically based on internal cost heuristics, so a script can exceed the target duration slightly, but this is far simpler and safer than manually polling v8's IsolateHandle for heap and CPU usage.

_daily.dev helps developers keep up with practical Rust and sandboxing patterns like this one._

## Similar posts on daily.dev

- [Vercel Labs Ships scriptc, a TypeScript-to-Native Compiler That Leaves the JavaScript Engine Behind](https://daily.dev/posts/vercel-labs-ships-scriptc-a-typescript-to-native-compiler-that-leaves-the-javascript-engine-behind-mp2rtartc) · InfoQ · 7 upvotes · 0 comments
- [GitHub - elixir-volt/quickbeam: JavaScript runtime for the BEAM — Web APIs backed by OTP, native DOM, and a built-in TypeScript toolchain.](https://daily.dev/posts/github---elixir-volt-quickbeam-javascript-runtime-for-the-beam-web-apis-backed-by-otp-native-dom-kcgz3hvcu) · Hacker News · 10 upvotes · 1 comments

---

Tags: [#javascript](https://daily.dev/tags/javascript), [#rust](https://daily.dev/tags/rust), [#v8](https://daily.dev/tags/v8)

[View this post on daily.dev](https://daily.dev/posts/improving-javascript-webhook-transformations-0styjqp9u)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Improving JavaScript Webhook Transformations","url":"https://daily.dev/posts/improving-javascript-webhook-transformations-0styjqp9u","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/improving-javascript-webhook-transformations-0styjqp9u"},"datePublished":"2026-08-23T07:20:25.878Z","dateModified":"2026-08-23T07:23:10.353Z","description":"Svix migrated its webhook transformation engine from Deno/v8 to QuickJS (specifically the QuickJS-NG fork), citing v8's poor fit for short-lived,...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/627aedbead16b294f303c6773eb5bd3e?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/627aedbead16b294f303c6773eb5bd3e?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Svix Blog","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Svix Blog","logo":"https://media.daily.dev/image/upload/s--Shf9MlOr--/f_auto,q_auto/v1787469609/logos/svix?_a=BAMAMicg0","url":"https://daily.dev/sources/svix"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/improving-javascript-webhook-transformations-0styjqp9u","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"javascript,rust,v8","timeRequired":"PT6M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Svix Blog","item":"https://daily.dev/sources/svix"},{"@type":"ListItem","position":3,"name":"Improving JavaScript Webhook Transformations"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/improving-javascript-webhook-transformations-0styjqp9u#faq","mainEntity":[{"@type":"Question","name":"Why did Svix replace v8/Deno with QuickJS for running customer JavaScript webhook transformations?","acceptedAnswer":{"@type":"Answer","text":"V8 was optimized for long-running code with JIT compilation, but most transformation scripts ran only once per isolate, so isolate startup dominated runtime at over 10ms average, roughly 90% of which was scaffolding and initialization. Deno also lacked native execution time limits, and v8's heap limit handling crashed and dumped state to stderr instead of failing gracefully. daily.dev surfaces engineering writeups like this for teams evaluating sandboxed JS runtimes."}},{"@type":"Question","name":"How much faster is QuickJS than v8 for running short-lived JavaScript snippets in Svix's webhook transformation feature?","acceptedAnswer":{"@type":"Answer","text":"Average response time dropped from 11.0±7.0ms with v8 to 1.0±0.7ms with QuickJS, over a 10x improvement with much lower variance. In debug-mode local benchmarking the gain was even larger, over 14x faster, which also sped up development iteration for engineers working on the feature. Teams choosing between JS runtimes for sandboxing can track performance comparisons like this via daily.dev."}},{"@type":"Question","name":"How do you set a memory limit and execution time limit for the rquickjs Rust bindings to QuickJS?","acceptedAnswer":{"@type":"Answer","text":"Use AsyncRuntime::set_memory_limit to bound heap usage and AsyncRuntime::set_interrupt_handler to enforce a rough time limit, since QuickJS lacks a hard timeout. The interrupt handler runs periodically based on internal cost heuristics, so a script can exceed the target duration slightly, but this is far simpler and safer than manually polling v8's IsolateHandle for heap and CPU usage. daily.dev helps developers keep up with practical Rust and sandboxing patterns like this one."}}]}
```

