By using this site, you agree to the Privacy Policy and Terms of Use.
Accept
World of SoftwareWorld of SoftwareWorld of Software
  • News
  • Software
  • Mobile
  • Computing
  • Gaming
  • Videos
  • More
    • Gadget
    • Web Stories
    • Trending
    • Press Release
Search
  • Privacy
  • Terms
  • Advertise
  • Contact
Copyright © All Rights Reserved. World of Software.
Reading: Running Modern ES2023 JavaScript Inside Go Using QJS and WebAssembly
Share
Sign In
Notification Show More
Font ResizerAa
World of SoftwareWorld of Software
Font ResizerAa
  • Software
  • Mobile
  • Computing
  • Gadget
  • Gaming
  • Videos
Search
  • News
  • Software
  • Mobile
  • Computing
  • Gaming
  • Videos
  • More
    • Gadget
    • Web Stories
    • Trending
    • Press Release
Have an existing account? Sign In
Follow US
  • Privacy
  • Terms
  • Advertise
  • Contact
Copyright © All Rights Reserved. World of Software.
World of Software > News > Running Modern ES2023 JavaScript Inside Go Using QJS and WebAssembly
News

Running Modern ES2023 JavaScript Inside Go Using QJS and WebAssembly

News Room
Last updated: 2025/12/28 at 2:19 AM
News Room Published 28 December 2025
Share
Running Modern ES2023 JavaScript Inside Go Using QJS and WebAssembly
SHARE

QJS is a CGO-free, modern JavaScript runtime for Go that embeds the QuickJS engine in a WebAssembly module and runs it with Wazero, providing Go applications with a sandboxed ES2023 environment with async/await and tight Go–JS interoperability.

QJS targets Go developers who want to run modern JavaScript inside Go processes without linking to native C libraries. Instead of binding QuickJS directly via CGO, it compiles QuickJS-NG to WebAssembly and executes it under Wazero, providing:

  • Full ES2023 support (modules, async/await, BigInt, etc.).
  • A fully sandboxed, memory-safe execution model.
  • No CGO toolchain or C runtime dependency.

The runtime is compatible with Go 1.22+ and is distributed as a regular Go module:


go get github.com/fastschema/qjs

and then:


import "github.com/fastschema/qjs"

QJS exposes a Runtime and Context API that lets Go code evaluate JavaScript, bind functions, and exchange data structures. A minimal example creates a runtime, evaluates a script, and reads structured results back into Go:


rt, err := qjs.New()
if err != nil {
	log.Fatal(err)
}
defer rt.Close()

ctx := rt.Context()

result, err := ctx.Eval("test.js", qjs.Code(`
	const person = {
		name: "Alice",
		age: 30,
		city: "New York"
	};

	const info = Object.keys(person).map(key =>
		key + ": " + person[key]
	).join(", ");

	({ person: person, info: info });
`))
if err != nil {
	log.Fatal("Eval error:", err)
}
defer result.Free()

log.Println(result.GetPropertyStr("info").String())
log.Println(result.GetPropertyStr("person").GetPropertyStr("name").String())
log.Println(result.GetPropertyStr("person").GetPropertyStr("age").Int32())

Go functions can be exposed to JavaScript, and JS functions can be converted back to typed Go callables. For example, binding a Go function:


ctx.SetFunc("goFunction", func(this *qjs.This) (*qjs.Value, error) {
    return this.Context().NewString("Hello from Go!"), nil
})

result, err := ctx.Eval("test.js", qjs.Code(`
	const message = goFunction();
	message;
`))
if err != nil {
	log.Fatal("Eval error:", err)
}
defer result.Free()

log.Println(result.String()) // Hello from Go!

QJS also supports converting richer Go structs to JS values and back, including methods that can be invoked from JavaScript and then deserialised to typed Go values.

To avoid repeated serialisation of large or opaque Go objects, QJS introduces Proxy, a lightweight JavaScript wrapper that holds only a reference to a Go value. This is useful for contexts, DB handles, or large structs that JS should pass through without inspecting:


ctx.SetFunc("$context", func(this *qjs.This) (*qjs.Value, error) {
	passContext := context.WithValue(context.Background(), "key", "value123")
	val := ctx.NewProxyValue(passContext)
	return val, nil
})

goFuncWithContext := func(c context.Context, num int) int {
	log.Println("Context value:", c.Value("key"))
	return num * 2
}

JavaScript receives the proxy and passes it back into Go, where JsValueToGo recovers the underlying value and type.QJS supports async/await by allowing Go to resolve JS promises asynchronously. A Go async function can schedule work and resolve a promise:


ctx.SetAsyncFunc("asyncFunction", func(this *qjs.This) {
	go func() {
		time.Sleep(100 * time.Millisecond)
		result := this.Context().NewString("Async result from Go!")
		this.Promise().Resolve(result)
	}()
})

JS then awaits it:


async function main() {
	const result = await asyncFunction();
	return result;
}
({ main: main() });

The runtime can be used to implement HTTP handlers in JavaScript while keeping the server in Go. For example, routes like /about and /contact Are defined in JS, precompiled to bytecode, and executed from a pool of runtimes:


byteCode := must(ctx.Compile("script.js", qjs.Code(script), qjs.TypeModule()))
pool := qjs.NewPool(3, &qjs.Option{}, func(r *qjs.Runtime) error {
	results := must(r.Context().Eval("script.js", qjs.Bytecode(byteCode), qjs.TypeModule()))
	r.Context().Global().SetPropertyStr("handlers", results)
	return nil
})

http.HandleFunc("/about", func(w http.ResponseWriter, r *http.Request) {
	runtime := must(pool.Get())
	defer pool.Put(runtime)

	handlers := runtime.Context().Global().GetPropertyStr("handlers")
	result := must(handlers.InvokeJS("about"))
	fmt.Fprint(w, result.String())
	result.Free()
})

The Pool type manages multiple runtimes for concurrent workloads, and examples show worker goroutines borrowing a runtime, executing JS, and returning it to the pool.

Because QuickJS runs inside Wazero, QJS offers filesystem and network isolation by default, with explicit configuration required to expose additional capabilities. The Option struct lets users set working directory, memory limits, stack size, execution timeouts, and GC thresholds:


type Option struct {
    CWD             string
    MaxStackSize    int
    MemoryLimit     int
    MaxExecutionTime int
    GCThreshold     int
}

According to benchmarks in the repository, point QJS is very competitive with Goja and ModerncQuickJS, with lower memory usage and execution time across both factorial calculations and AreWeFastYet-style microbenchmarks. Both benchmarks were run on Linux machines with an AMD Ryzen 7 7840HS and 32GB RAM.

Computing factorial(10) 1,000,000 times












Iteration GOJA ModerncQuickJS QJS
1 1.128s 1.897s 737.635ms
2 1.134s 1.936s 742.670ms
3 1.123s 1.898s 738.737ms
4 1.120s 1.900s 754.692ms
5 1.132s 1.918s 756.924ms
Average 1.127s 1.910s 746.132ms
Total 5.637s 9.549s 3.731s
Speed 1.51x 2.56x 1.00x

AreWeFastYet V8-V7














Metric GOJA ModerncQuickJS QJS
Richards 345 189 434
DeltaBlue 411 205 451
Crypto 203 305 393
RayTrace 404 347 488
EarleyBoyer 779 531 852
RegExp 381 145 142
Splay 1289 856 1408
NavierStokes 324 436 588
Score (version 7) 442 323 498
Duration (seconds) 78.349s 97.240s 72.004s

With this design, QJS targets Go developers who need secure plugin systems, user-provided scripting, or embedded business logic written in JavaScript, without bringing a C toolchain or CGO into their build and deployment pipeline.

Sign Up For Daily Newsletter

Be keep up! Get the latest breaking news delivered straight to your inbox.
By signing up, you agree to our Terms of Use and acknowledge the data practices in our Privacy Policy. You may unsubscribe at any time.
Share This Article
Facebook Twitter Email Print
Share
What do you think?
Love0
Sad0
Happy0
Sleepy0
Angry0
Dead0
Wink0
Previous Article Meet the team that hunts government spyware Meet the team that hunts government spyware
Next Article I ran 1,000km to test the best running watches in the UK – here are my favourites I ran 1,000km to test the best running watches in the UK – here are my favourites
Leave a comment

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Stay Connected

248.1k Like
69.1k Follow
134k Pin
54.3k Follow

Latest News

iPhone 18 Pro: Six new features are coming next year – 9to5Mac
iPhone 18 Pro: Six new features are coming next year – 9to5Mac
News
Could Earth defend itself if aliens paid us all a visit?
Could Earth defend itself if aliens paid us all a visit?
News
Apple COO Sabih Khan tells China the company is committed to long-term partnerships
Apple COO Sabih Khan tells China the company is committed to long-term partnerships
News
Sky fans can unlock freebies as list of 2025 upgrades you’ve missed revealed
Sky fans can unlock freebies as list of 2025 upgrades you’ve missed revealed
News

You Might also Like

iPhone 18 Pro: Six new features are coming next year – 9to5Mac
News

iPhone 18 Pro: Six new features are coming next year – 9to5Mac

6 Min Read
Could Earth defend itself if aliens paid us all a visit?
News

Could Earth defend itself if aliens paid us all a visit?

11 Min Read
Apple COO Sabih Khan tells China the company is committed to long-term partnerships
News

Apple COO Sabih Khan tells China the company is committed to long-term partnerships

1 Min Read
Sky fans can unlock freebies as list of 2025 upgrades you’ve missed revealed
News

Sky fans can unlock freebies as list of 2025 upgrades you’ve missed revealed

7 Min Read
//

World of Software is your one-stop website for the latest tech news and updates, follow us now to get the news that matters to you.

Quick Link

  • Privacy Policy
  • Terms of use
  • Advertise
  • Contact

Topics

  • Computing
  • Software
  • Press Release
  • Trending

Sign Up for Our Newsletter

Subscribe to our newsletter to get our newest articles instantly!

World of SoftwareWorld of Software
Follow US
Copyright © All Rights Reserved. World of Software.
Welcome Back!

Sign in to your account

Lost your password?