Core principles
The KJ style guide describes suggestions, not absolute rules. Consistency matters, but pragmatic exceptions are acceptable when justified.Read the full KJ style guide and KJ tour before contributing.
Use KJ types, not STL
The project uses the KJ library instead of the C++ standard library for most types:| Instead of | Use |
|---|---|
std::string | kj::String (owned) / kj::StringPtr (view) |
std::vector | kj::Array<T> (fixed) / kj::Vector<T> (growable) |
std::unique_ptr | kj::Own<T> |
std::shared_ptr | kj::Rc<T> / kj::Arc<T> (thread-safe) |
std::optional | kj::Maybe<T> |
std::function | kj::Function<T> |
std::variant | kj::OneOf<T...> |
std::span | kj::ArrayPtr<T> |
std::exception | kj::Exception |
std::promise/future | kj::Promise<T> |
Memory management
Never writenew or delete directly. Use KJ heap allocation:
Ownership model
- Every object has exactly one owner (another object or a stack frame)
kj::Own<T>transfers ownership when moved- Raw C++ pointers and references are borrowing only, never owned
- An object can never own itself, even transitively (no reference cycles)
Error handling
Never usethrow directly. Use KJ assertion macros:
These macros automatically capture file/line, stringify operands, and generate stack traces.
kj::Maybe values:
Exception philosophy
- Exceptions are for fault tolerance, not control flow
- They represent things that “should never happen” - bugs, network failures, resource exhaustion
- Never declare anything
noexcept- bugs can happen anywhere - Destructors must use
noexcept(false)if they can throw
Naming conventions
| Kind | Style |
|---|---|
| Types (classes, structs) | TitleCase |
| Variables, functions, methods | camelCase |
| Constants, enumerants | CAPITAL_WITH_UNDERSCORES |
| Macros | CAPITAL_WITH_UNDERSCORES with prefix |
| Namespaces | oneword (keep short) |
| Files | module-name.c++, module-name.h |
File extensions
- C++ source files:
.c++(not.cpp) - Header files:
.h - Test files:
module-name-test.c++(hyphenated suffix)
Lambda capture rules
Formatting
Runjust format before committing. Key rules:
- 2-space indents, never tabs
- Max 100 characters per line
- Space after keywords:
if (foo),for (...),while (...) - No space after function names:
foo(bar) - Always use braces for blocks (unless the entire statement fits on one line)
- Strip trailing whitespace
Comments
workerd follows common C++ comment conventions:Text encoding
- All text is UTF-8
- Never assume text is valid UTF-8 - be tolerant of malformed sequences
- Use
kj::str()for string formatting - Never use
FILE*,iostream, or C stdio
RAII and cleanup
Always prefer RAII for resource management:No singletons
Never use mutable globals or global registries. Themain() function or high-level code should explicitly construct components and wire dependencies via constructor parameters.
Lazy validation
Validate data at time-of-use, not upfront:C++ standard
The project uses C++23 (-std=c++23). You can use modern C++ features, but prefer KJ idioms when available.
Next steps
Testing guidelines
Learn about testing requirements
JSG architecture
Understand the JavaScript binding layer