Marko in January 2026
- A large batch of compiler fixes for variable hoisting and cross-section scope analysis
- Correct handling of known rest and spread inputs
- Steadier type checking in the language server, plus pnpm project discovery
- Interop and controllable-input fixes for mixed Class API and Tags API apps
January was a stabilization month. Rather than new syntax, the work went into the parts of the Marko 6 compiler that decide where variables live and how scopes connect, into the language server's understanding of those same scopes, and into the seams where Class API and Tags API code meet. The result is a compiler that handles more real-world templates correctly and an editor that keeps up with them.
Compiler Reliability
The largest theme was variable hoisting and section analysis. A regression that caused the compiler to error while writing out the reads for some signals was fixed, alongside a refactor of signal construction and side-effect tracking (marko#3032). Hoisting itself was corrected so that custom tag hoists and native tag references are unified under one path (marko#3064).
A cluster of related fixes tightened how the compiler reasons about scopes that span sections: assignments that were missing their section, declared non-nullable aliases used in a different section, the canonical signal used for closure references, and assignments to bindings that are never read (marko#3052, marko#3051, marko#3048, marko#3049). Scriptlet variables no longer collide with compiler-generated names (marko#3028).
Rest and Spread
Optimizations for known spread and rest inputs were corrected. A known tag with a ...rest input reference could create a circular serialize reason and overflow the call stack, and serializing nested rest bindings is now handled correctly (marko#3035, marko#3040, marko#3053).
Event Handlers
Default event handlers registered before a spread on a native tag now apply correctly (marko#3036). A separate fix resolves a serialization error when a Class API component is used from the Tags API with a handler that reads nothing from scope.
// use tags
<my-class-api-button onClick() { console.log("no state used") }/>Previously this produced a "scope is undefined" error; the stateless handler now serializes cleanly (marko#3039).
Controllable Inputs
A controllable text input driven through a spread value or valueChange now updates correctly, closing a gap in two-way binding when the controlling attributes arrive by spread rather than directly (marko#3042).
Type Checking
The language server caught up with several Marko 6 scope behaviors. Tag variable hoisting aligns with the runtime, scope hoisting and attribute tag types are more accurate, and the extractor's mutation output was reworked (language-server#433, #435, #442, #444, #437). Identifier attribute binds in a nested scope and define tag variable hoisting were both fixed, along with broken type checks in recent versions (#439, #448).
On the runtime side, the <await> tag types improved and the native tag types now line up between the Class API and Tags API (marko#3055, marko#3062).
Editor Tooling
The language server discovers @marko/compiler more reliably under pnpm. Because pnpm stores transitive dependencies in its .pnpm directory, the compiler was not found when it was not a direct dependency. When no compiler is found, the server now falls back to the one resolved from the installed marko version (language-server#431). The full set of supported editors lives in Tooling Integrations.
Interop
Mixed Class API and Tags API applications gained two fixes. Components initialize correctly when bundled with lasso-marko, and dynamic native tags route through the compatibility layer as expected (marko#3030, marko#3057). Projects combining both APIs can follow Marko 5 Interop for the conventions that select each compiler.
Build Integration
The Vite integration tracks optional watch files more accurately, so changes to files that may or may not exist are picked up without over-watching (vite#242). The compiler also allows overriding how template ids are generated, giving build tooling control over those identifiers (marko#3061).
Playground
The playground gained starter templates when adding a new tab, so a new file can begin from an example instead of an empty editor, along with a handful of smaller editor refinements (website#129).
Full details for every change are in the release notes of each package on GitHub.
Contributors
Helpful? You can thank these awesome people! You can also edit this doc if you see any issues or want to improve it.