Marko – a Declarative, Html‑based Language
Key topics
The introduction of Marko, a declarative HTML-based language, sparked a heated discussion on HN about the merits of mixing HTML and JavaScript, with some praising its performance and others criticizing its syntax and the fragmentation of JavaScript frameworks.
Snapshot generated from the HN discussion
Discussion Activity
Very active discussionFirst comment
20m
Peak period
110
0-12h
Avg / period
16
Based on 160 loaded comments
Key moments
- 01Story posted
Nov 8, 2025 at 1:43 PM EST
2 months ago
Step 01 - 02First comment
Nov 8, 2025 at 2:03 PM EST
20m after posting
Step 02 - 03Peak activity
110 comments in 0-12h
Hottest window of the conversation
Step 03 - 04Latest activity
Nov 15, 2025 at 11:21 AM EST
about 2 months ago
Step 04
Generating AI Summary...
Analyzing up to 500 comments to identify key contributors and discussion patterns
Want the full context?
Jump to the original sources
Read the primary article or dive into the live Hacker News thread when you're ready.
The intro is also incorrect in my opinion. It writes a "HTML-based language", but this is more a hybrid of HTML and JavaScript. Why is JavaScript not mentioned in the intro?
ITS just bizzare people want to parse JavaScript at the same instance they're parsing html.
Also, LLMs are going to destroy any new framework. Someone's gonna need to figure out how to integrate these things into new tools. LLMs suck but it'll be much worse if they freeze innovations cause they're too expensive to chase the new hotness.
Terseness is good for code golf [1]. I disliked CoffeeScript after writing it for some time: nearly any typo can result in another syntactically correct program which, of course, does not what you wanted the original program to do, or fails the compilation in an unrelated place. A practical language has safety margins, aka some redundancy.
[1]: https://en.wikipedia.org/wiki/Code_golf#Dedicated_golfing_la...
This snippet works with any framework and any build step.
I'll concede that Alpine.js is harder to understand and more verbose than Marko's syntax, but in order to use Marko you have to commit to the Marko framework. If you're willing to choose a framework solely for its JS-in-HTML capabilities, there are much better choices (like SvelteKit that handles JS-in-HTML wonderfully).It was originally created by eBay iirc, back in 2014 or so.
It's syntax was even stranger back then, like writing "h1.myClass my header" to create a <h1 classes=myClass>my header</h1> and similar
And so your script is broken when someone else in your team (or maybe even yourself) renames or removes the ID and forgets to search in the whole project if some piece of code depends on this ID. JSX fixed all that mess 10+ years ago.
https://markojs.com/docs/explanation/separation-of-concerns
At that point I think I'd have a skeleton html file that fetches a JS that does it all. I'd take JS with embedded HTML over HTML with embedded JS.
But you can write dreadful code in any language
marko is not comparable to php
it is much closer to svelte
i used to sympathize with people complaining about js-fatigue, but at some point its a skill issue
That looks like a pretty normal template to me and nothing like plain PHP templates? What do you mean by "spaghetti mesh-up"?
January 2023, 125 comments - https://news.ycombinator.com/item?id=34591625
August 2017, 150 comments - https://news.ycombinator.com/item?id=15057371
February 2015, 10 comments - https://news.ycombinator.com/item?id=9065447
1. There is HTML (tags) with, but without interpolation {...} you can put string literals, variables and everything that type checks as HTML children.
2. There is CSS but only in style blocks where you can interpolate any expression you need and put in if and case expressions too.
3. There is the normal Mint code you write the logic in (this would be the JavaScript in other languages).
Here is an example which have all three: https://mint-lang.com/examples/7guis/flight-booker
The challenge was to make it seamless enough that so it doesn't look like that we tried to mash languages up, but to make them form a different language that is consistent and simple at the same time.
For example, with react-router, my root route object array I define by spreading out other route object arrays that I've imported from other modules in my project. And each of those do the same thing, recurring as necessary until I get to the full depth of my route tree.
1. The one feature I prefer in Marko when compared to Mint is Marko’s nice ID and class syntax, rather than your custom selectors, so you can just use regular CSS (which seems to be advancing faster than the JS & HTML specs combined). You could get the scoping using shadow roots for your components (I’m sure this has flow on consequences, but given you own the language it’s probably better case than many others.)
2. Interpolating values directly in CSS blocks is something that a lot of HTML templating systems sort of give up on (see Astro going out of it’s way to make interpolating variables super verbose [0]), so I’m glad to see you do it. Does the value interpolation compile to CSS variables that are set on the component root (or somewhere else I suppose) as in Astro [0], or is it just simple interpolation? Additionally, I can’t help but notice your hash symbol would conflict with ID selectors, so is CSS nesting available?
Please don’t take this as criticism! I really like what you’ve done here and am very curious.
[0]: https://docs.astro.build/en/guides/styling/#css-variables
2. CSS definitions without interpolation compile down to static CSS while the ones with interpolation compile down to CSS variables which are set on the element where the style is assigned. This also allows for passig arguments to styles [0].
CSS nesting is supported and the interpolation doesn't conflict with the id selectors because interpolation is not supported in selectors.
[0]: https://mint-lang.com/reference/styling/arguments
Edit: typo
Working with HAML really did make building web app fun IMO. I can’t be the only one!
I like HAML a lot, it was the most pleasant to develop with. And it shares a lot in common with Stylus. They both shared things in common.
NO NEED FOR: Curly braces, parentheses and semicolons. The cool thing, it was all optional and I wasn't forced to make use of all shortcuts!
I developed my own CSS Framework in 2003, shared with some UX guy at Yahoo, who incorporated it into YUI mostly as is, after I waived all rights. Most of that became internet standard. Later I had my own PHP based CSS scaffolding framework in 2005 that could also generate grids (before flex-box). SCASS/LESS was really similar to my framework, when it came out.
But I disliked it, it just looked like PHP mixed with CSS. I thought why accept the ugly syntax, despite a compiler being available?
The best ever existed is: HAML + Stylus + (HARC?)
See the beauty of it: https://stylus-lang.com/docs/selectors.html
Now compare with HAML https://haml.info/
I think https://harcstack.org/ makes a good successor.
I used to use it years ago. So much nicer than HTML.
As I understand it, Ryan Carniato was a major part of this project, and later went on to lead SolidJS, which goes back to the React style HTML in JS. Has he spoken at all about why he went back to that templating style?
• JSX is well understood by a lot of developers • support is already built in to text editors • it is understood by typescript
He eventually got the opportunity to work on Solid in a more full-time capacity and decided to take it, but still talks with the Marko team from time to time
Looking at the Marko examples I feel the same way I do whenever similar stuff gets showcased: it’s trying to focus too hard on brevity and/or cutesiness and doesn’t seem like it would scale well to a full, complex web app. But maybe it’s not supposed to and maybe that’s fine.
React and Svelte and the rest can read clunkily at times but they have a clear separation of concerns and I’m glad for that.
marko6 which is currently in public beta is resumable by default, and does some similar things to the also public beta qwik2
I was not surprised for example that Marko came out very well in this performance comparison: https://www.lorenstew.art/blog/10-kanban-boards
I probably shouldn’t care. I’m just not looking forward to the chaos of another full “turn” in JavaScript, akin to query->backbone or backbone->react.
Maybe I shouldn’t fear it. I’ve just yet to see an idea that feels valuable enough to move an entire ecosystem. Svelte, HTMX, etc… where is the “disruptive” idea that could compel everyone to leave React?
It's a shame because the core of Marko looks phenomenal: streaming, fine-grained bundling, rendering performance, etc.
Also not sure about the file-based routing of Marko Run. That was a big reason why I abandoned SvelteKit.
JSX is amazing for stateless rendering of templates. Not so much for state management. That should really have been given a dedicated DSL. Here I think Marko did the right thing, why they then made even for-loops a dsl is more questionable.
https://www.devtools.fm/episode/146
> A lot of people are coming to eBay from a link that someone shared or from a search engine... This whole "amortized cost savings" you get from a Single-Page App (SPA) you don't necessarily get with eBay. Or people might go to eBay and open up ten [browser] tabs... If that's ten SPAs you're opening you're not really saving that much.
> At the same time in 2012 people are coming out with React, Angular... the question was "can we just use these tools?" and the answer was "kinda no"... Initially React was considered but the things we needed right out of the gate was streaming [sending as much HTML as... available without waiting for services responding with loaded data for the specific page]... With streaming you can send out stuff to the browser and have the browser [start] showing content to user without having to wait for your slowest service. At eBay there are a lot of services... Essentially if we were to adopt React or Angular the fact that there wasn't streaming would essentially mean that we're throwing away two seconds or so... which is not acceptable.
This `<let/variable=...>` and `<for ...>` syntax is awful.
<for ...>
In JSX I write JavaScript that returns JSX:
{data.map(node => <Element {...node} />)}
^ ----- JS ----^ ^ ------ JSX -------^
or
const elements = data.map(node => <Element {...node} />) ... <div>{elements}</div>
Really the most obscure syntax there is the splatting but it makes sense to you when you realize that JSX is just syntactic sugar for JS:
data.map(node => React.createElement(Element, { ...node }))
What people mean when they say “React is just JavaScript” is…
1) JSX, more than any other templating system, is just HTML interleaved with JavaScript. It’s HTML, and anything between { and } is evaluated as JavaScript.
2) Inserting a React component’s “HTML tag” in your JSX is _actually_ the same as calling the JavaScript function. The HTML attributes are the function arguments. Yes, inside your function there can be state, and there can be contexts, and there are refs. But you get at all of those things by calling JavaScript functions.
Like,
is literally identical to: It’s the tiniest bit of syntactic sugar.I feel like too many people think “React is Just JavaScript” is some kind of lie people tell to make React sound cool.
It’s not a lie. There’s a _small_ amount of hand waving around the word “just” but the point is, it’s WAY smaller than what you need to explain the ways Svelte or Vue or Angular diverge from plain JavaScript.
Regardless of whether you use JSX or createElement, you can't just call MyComponent({ attr: “yes” }) directly, is the main point.
That’s not true though and IMO is one of the weaknesses of JSX: it looks like something it is not. Having to use className instead of class is one of the most obvious tells. But in theory if it was just HTML with {}s I should be able to do:
and many other things you’re actually not able to do. Not to mention that things like onClick aren’t actually HTML attributes and are instead event listeners, etc etc.Once you grasp that what you’re actually doing is a function call with an object of arguments it makes sense. But it isn’t HTML. It’s a chain of function calls.
We’re all really used to it so we don’t think about it a lot. But I always try to remind myself of that when I look at a new unfamiliar syntax.
(not to mention, your example isn’t correct! <Component/> don’t map to Component(), it maps to previouslyUnknownFunction(Component()), which is another confusing factor)
JSX (react flavor) is lazy. <My component> is not rendered/evaluated until it's needed.
You can't just call a react component. It's not a regular function call.
This is unlike a lot of other templating languages where, even if the expression part of the language is pure JavaScript (or PHP or Python or whatever), it's still interleaved with arbitrary text which will get printed out according to its own rules. This makes the whole thing much harder to reason about (leading to the philosophy that you should put as little logic as possible in your templates because it makes them harder to understand, _even when that logic is directly related to the templating process_.
A good example is for-loops. In a lot of templating languages, you start in text-land, then you enter expression-land to write the opening {% for (const X of ...) %} line, then you're back in text-land again. You sprinkle in a couple of expressions, and then at the end you go back to expression-land to close the loop. You're jumping backwards and forwards between the two worlds, but there's no real syntactical or structural support for mixing them.
Meanwhile, in JSX, you start in text-land, then you open up an expression between two curly braces, and in that expression you write the entirety of your loop. If you need to go back to text-land within that loop, you can create a _new_ set of text nodes, but you're not interleaving expressions and text in the same way.
The result of this is that, once you understand how your JSX will get compiled, it's very easy to read it as if it were the JavaScript that it will get compiled to, rather than as a separate templating language. Which in turn makes it very easy to think of it as "just JavaScript", even if it's technically a syntax extension.
Speaking of writing JS instead of JSX or your example, I like the vanjs.org approach:
https://github.com/jon49/Soccer
But that was also back in the days when trailing commas at the end could break things, JavaScript editor support was relatively poor, and tooling wasn't where it is now (knowing your code is once again valid because the autoformatter just kicked in).
I have found aberdeenjs a better dx than hyperscript.
https://aberdeenjs.org/
For Marko, that doesn't seem to be the case, but it also doesn't really make sense given the problems that Marko is trying to solve.
Another thing people might mean by "it's just JavaScript" is a much more subjective notion about how similar the overal syntax, control flow, etc. feels to whatever previous JavaScript experience the person has. This meaning is a lot harder to pin down, and in most cases reasonable people could disagree on what is and isn't "just JavaScript" according to this meaning. That said, I would tend to agree that React's templating uses normal JavaScript control flow and composition primitives more so than Marko.
BTW - with Vue you can use entirely JSX of you dislike HTML component syntax (I don’t know enough about Svelte to know if it allows the same).
But no, JSX isn’t that great either:
</each> is about control flow, so it's a conceptually different thing.
I can't tell how convincing that argument is to be honest, and how much I'm just rationalising familiarity.
Where they aren't two different things, you have some kind of component configuration language, like WPF on .NET. There is no control language, the instantiated components have behaviours and are responsible for any control logic, like rendering a list of items. This isn't a template language though.
HTML now has web components and so you can think of it in the latter way. I'm not sure if anyone has take this approach though.
But as I just said, in the end their function actually doesn't seem overly different (to me at least) so a visual distinction with curly brackets rather than angle brackets is perhaps not necessary.
SGML (XML, HTML) is for content (text) authors not developers, but webdevs just don't get it and look at it as a solution to developer problems.
I like vue a lot more;
It started as a project at eBay and then got spun out to an open project around 2015
It was my reason for switching to React when I learned TypeScript after getting more into JS frameworks via Vue.JS.
My starting point was Vue 2.7, and I started out using string templates haha :)
Even wrote some reactive custom code (without Vue, just regular DOM code) in a customer widget that utilized Object.defineProperty et al, inspired by Vue.
And today, while I'm using React at $job, I also think Vue 3 is probably a solid framework as well.
Last time I checked, they improved on DX of their component and templating system. But I'm not even sure whether they still recommend the v-if etc helper tags.
For what it's worth, even Vue 2 always also supported JSX and later TSX
It is exciting to see what the ingenuity of the next group brings, even though some existing things are lost, but hopefully not forgotten.
Also it cannot be understated: apis, language and tooling are miles ahead better they were a decade ago or more.
Saying this feels like advocating for a return to horse carriages though, when the right analogy would be the brief electric car era of the early 1900s, and React as the Model T.
The dream of scripting languages you can just throw somewhere is great, but in an IDE, they really struggle. They're editor languages - you can understand them without extra context and tools, but your level of understanding is baseline more wishy-washy.
TS embodies this. It directly trades off that scriptability and ease for... really nothing. The compilation isn't a side effect, it's the entire draw. People WANT a compiler, or, at least, something similar.
The only problem is that it won't necessarily scale to some insane numbers without some care.
(Not sure why the past tense, it does work and developed still)
Debateable.
Oh man, I wish people would stop attributing picking SPA's to not wanting to use "lame" technology. It makes them sound myopic and naive. Really naive.
You may not have been around at the time, but I certainly was. And the idea that SPAs don't (or didn't) have their place is just plain absurd.
Like "Tell me you're a backend dev who is made they have to learn new stuff to stay current" without telling me.
In fact, I'm not even sure what your argument actually is. Is it MSP vs SPA? Is it JSP vs any of the other backend languages you can still use with React? Is it templates vs JSX? What are you actually trying to argue?
Are your rose-colored glasses ignoring what a pain a decent UX was to build in those technologies? That mobile apps pushed backends to an api-only version and SPAs took over for the frontend? Are you saying people should pick old technologies wtih old tooling just because you didn't get on board with it the first time?
It's not swinging back to JSP, it's finding a middle-ground between the 2. THAT'S what progress is.
Most other template languages hits serious limitations really fast. I tried and hated (for non trivial things): Angular, Handlebars, Razor (dotnet) and Vue (which does support JSX optionally).
E.g., Why do you think JSX is the best? What limitations did you hit with those other template languages?
https://markojs.com/docs/reference/core-tag#define
1. Jsx is nicer to write but that's a non issue
2. vue's and angular's directives and bindings lend themselves to much saner and lighter rendering (performance does matter)
3. Vue is much easier to tame, it's reactivity model does not require a PhD in hooks or a deep understanding of React's internals. It just works out of the box as it should and is much easier to control the rendering lifecycle.
At the end of the day, after many years, my preference goes with Vue and Nuxt especially which is tremendously better than the monsters of Next or RR. That's what pays the bill the easiest and is eventually easier to maintain and optimize.
I wrote a Rust library with a more restricted/verbose API, and I've been enjoying using that. Unfortunately, I find it really hard to make it as fast as I want. It's really the perfect use case for arena allocation, but doing that and keeping the API as function calls mirroring HTML is not trivial, and probably requires macros to rewrite the tree as a series of stack pushes.
1. https://pypi.org/project/dominate/
I especially love the pug style concise syntax which for some reason they have buried deep into the docs rather than showcasing front and center.
https://markojs.com/docs/reference/concise-syntax
If I may ask, what made you settle on the double dash to disambiguate content from tags? Like is it some sort of nod to SGML from way back when? It seems like an odd choice to me at first glance, but I bet it was thought about long and hard so I’d love to hear some background about what alternatives you considered.
The example on that page with leading commas to separate tag attributes, and a number of other choices across the framework are also a turn off for me personally.
I’ve mostly been using Svelte for the past half-decade instead but still hope for something more elegant to come along.
20 more comments available on Hacker News