File
Blob: src/workerd/jsg/AGENTS.md
JSG (JavaScript Glue)
See README.md for terse reference (type mappings, macro catalog, error catalog).
See docs/jsg.md for narrative tutorial.
OVERVIEW
Macro-driven C++/V8 binding layer: declares C++ types as JS-visible resources/structs with automatic type conversion.
KEY FILES
| File | Purpose |
|---|---|
jsg.h |
Core header (3115 lines): all macros (JSG_RESOURCE_TYPE, JSG_METHOD, etc.), type mappings, Lock, V8Ref, GcVisitor |
resource.h |
Template metaprogramming: V8 callback generation, FunctionCallbackInfo dispatch, prototype/constructor wiring |
struct.h |
JSG_STRUCT value-type mapping: deep-copies C++ structs to/from JS objects |
wrappable.h |
GC integration: Wrappable base class, CppGC visitor hooks, ref marking, weak pointers |
promise.h |
jsg::Promise<T> wrapping KJ promises ↔ JS promises; resolver pairs, coroutine integration |
modules.h |
ModuleRegistry: ESM/CJS module resolution, evaluation, top-level await handling |
modules-new.h |
Replacement module system (new design) |
setup.h |
V8System, IsolateBase, JsgConfig; process-level V8 init; JSG_DECLARE_ISOLATE_TYPE |
function.h |
jsg::Function<Sig> wrapping C++ callables ↔ JS functions |
memory.h |
MemoryTracker, JSG_MEMORY_INFO macro; heap snapshot support |
rtti.capnp |
Cap'n Proto schema for type introspection; consumed by types/ for TS generation |
rtti.h |
C++ RTTI builder: walks JSG type graph → rtti.capnp structures |
jsvalue.h |
JsValue, JsObject, JsString, etc. — typed wrappers over v8::Value |
type-wrapper.h |
TypeWrapper template: compile-time dispatch for C++ ↔ V8 conversions |
meta.h |
Argument unwrapping, ArgumentContext, parameter pack metaprogramming |
fast-api.h |
V8 Fast API call optimizations |
ser.h |
Structured clone: Serializer/Deserializer |
web-idl.h |
Web IDL types: NonCoercible<T>, Sequence, etc. |
observer.h |
IsolateObserver, CompilationObserver — hooks for metrics/tracing |
BINDING PATTERN
class MyType: public jsg::Object {
static jsg::Ref<MyType> constructor(kj::String s);
int getValue();
void doThing(jsg::Lock& js, int n);
JSG_RESOURCE_TYPE(MyType) { // or (MyType, CompatibilityFlags::Reader flags)
JSG_METHOD(doThing);
JSG_PROTOTYPE_PROPERTY(value, getValue, setvalue);
JSG_NESTED_TYPE(SubType);
JSG_STATIC_METHOD(create);
}
void visitForGc(jsg::GcVisitor& visitor) {
visitor.visit(ref, v8ref); // MUST trace all Ref<T>/V8Ref<T>/JsRef<T>
}
jsg::Ref<Other> ref;
jsg::V8Ref<v8::Object> v8ref;
};- Allocate resource objects:
js.alloc<MyType>(args...) - Value types:
JSG_STRUCT(field1, field2)— auto-converted by value jsg::Lock&is the JS execution context; thread via method paramsTypeHandler<T>&as trailing param gives manual conversion access- Compat flags param on
JSG_RESOURCE_TYPEgates members conditionally
ANTI-PATTERNS
- NEVER opaque-wrap
V8Ref<T>— use handle directly - NEVER use v8::Context embedder data slot 0 (
ContextPointerSlot::RESERVED) - NEVER hold traced handles (
Ref<T>/V8Ref<T>) without marking invisitForGc— causes GC corruption - NEVER use
FastOneByteStringin Fast API calls (GC corruption risk) - NEVER unwrap
Ref<Object>— useV8Ref<v8::Object>instead JSG_CATCHis NOT a true catch — cannot rethrow withthrowNonCoercible<T>runs counter to Web IDL best practices; avoid in new APIs- Rust JSG bindings: see
src/rust/jsg/andsrc/rust/jsg-macros/; full macro reference insrc/rust/AGENTS.md; GC tracing (Traced+GarbageCollected) documented insrc/rust/jsg-macros/README.md
INVARIANTS
These rules MUST be followed when writing or modifying JSG code:
- MUST implement
visitForGc()on any Resource Type holdingRef<T>,V8Ref<T>,JsRef<T>,Function<T>,Promise<T>,Promise<T>::Resolver,BufferSource, orName— seeREADME.md§GC-Visitable Types for the complete list - MUST visit ALL GC-visitable fields — missing one causes GC corruption
- MUST NOT store
v8::Local<T>orJsValuetypes as class members — useV8Ref<T>orJsRef<T>for persistence - MUST NOT put
v8::Global<T>orv8::Local<T>inJSG_STRUCTfields — usejsg::V8Ref<T>orjsg::JsRef<T> - MUST NOT put
v8::Global<T>orv8::Local<T>inkj::Promise— compile-time deleted - MUST NOT pass
jsg::Lockinto KJ promise coroutines JSG_SERIALIZABLEMUST appear AFTERJSG_RESOURCE_TYPEblock, not inside it- Serialization tag enum values MUST NOT change once data has been serialized
Ref<T>ownership MUST flow owner→owned; backwards refs use rawT&orkj::Maybe<T&>- Prefer
JSG_PROTOTYPE_PROPERTYoverJSG_INSTANCE_PROPERTYunless there's a specific reason — instance properties break GC optimization
CODE REVIEW RULE
When reviewing changes to JSG code, check whether the change requires updates to any of these documentation files:
README.md— if the change adds/modifies type mappings, macros, error types, serialization patterns, or reference tablesdocs/jsg.md— if the change affects tutorial content, adds new patterns, or changes API usage examples- This file (
AGENTS.md) — if the change adds/removes files, changes the architecture summary, or introduces new invariants
Flag any needed doc updates in the review. Do not let behavioral or architectural changes land without corresponding documentation updates.