Marijn Haverbeke

marijnhaverbeke.nl · Personal blog · on HN since 2010

Marijn Haverbeke, creator of CodeMirror, ProseMirror and author of Eloquent JavaScript, writes about editors and programming tools.

What HN saysHN commenters link it as the home of ProseMirror and CodeMirror, which power editors like Obsidian's and Nuclino's, and praise his book.
111HN people shared it
70linked it in comments
50stories submitted
1.5Kstory points
4 months agolast shared
2010people per year2026

Most-shared posts

  1. 1
    Lezer
    10 people · 355 points · first shared 2019 · 42 comments on HN
  2. 2
    Collaborative Editing in ProseMirror
    10 people · 86 points · first shared 2015 · 34 comments on HN
  3. 3
    Bouncing Beholder, my winning JS1K entry (2012)
    10 people · 77 points · first shared 2011 · 21 comments on HN
  4. 4
    CL-JavaScript: add user scripting to your Common Lisp App
    9 people · 25 points · first shared 2010 · 2 comments on HN
  5. 5
    Collaborative Editing in CodeMirror
    9 people · 8 points · first shared 2020 · discussion on HN
  6. 6
    Postmodern
    8 people · first shared 2010
  7. 7
    Prosemirror
    8 people · first shared 2015
  8. 8
    Fund
    6 people · first shared 2015
  9. 9
    A Gentle Introduction to Machine Fundamentals
    5 people · 111 points · first shared 2011 · 5 comments on HN
  10. 10
  11. 11
    Tern.js: Flows of Energy
    5 people · 7 points · first shared 2013 · discussion on HN
  12. 12
  13. 13
    Homepage
    4 people · first shared 2019
  14. 14
    CodeMirror 6 Enters Beta (2020)
    3 people · 4 points · first shared 2020 · 1 comments on HN
  15. 15

What HN people wrote when they linked it

svat · 2024-03-07
I love this book, even since its first edition. It's very clear even on elementary stuff, e.g. see the section on bindings/variables: https://eloquentjavascript.net/02_program_structure.html#h-lnOC+GBEtu — avoids the pitfall of thinking of variables as “boxes”. I was trying to find what's new in the 4th edition, and following links from the author's website https://marijnhaverbeke.nl/ found this on Mastodon (https://mastodon.social/@marijn/112020092273623390): > The FOURTH EDITION of Eloquent JavaScript is now online, adjusted to the realities of 2024 and generally touched up.
keybits · 2019-01-14
I love Nuclino too. Their editor uses the wonderful ProseMirror (https://discuss.prosemirror.net/t/nuclino-a-lightweight-real-time-wiki… by Marijn Haverbeke (https://marijnhaverbeke.nl/) of CodeMirror and Tern fame.
exceptione · 2026-07-03
I think most people would love to the know the 'why'. This page discusses differences with prosemirror and is the closest I got to that question: (https://wordgard.net/docs/prosemirror/). One thing to note is that there is not an upgrade path. Many concepts are shared with prosemirror, but it seems that switching means doing quite some work (correct me if I am wrong). Obsidian is based on Code Mirror so I guess they won't be switching, but tiptap.dev and others do. @merijn, maybe you could address why wordgard is worth the switching cost? EDIT: I see many points are addressed in Merijns personal blog. I submitted (https://marijnhaverbeke.nl/blog/wordgard-0.1.html) to HN for better context.
ericax · 2022-06-08
Obsidian developers here! (https://obsidian.md/) The new editor in Obsidian was made possible by CodeMirror 6, and it has been powering both the Live Preview mode (like Typora) and the source mode in Obsidian ever since. It can be a bit overwhelming to get into first, but as we experimented more with it, we found it to be extremely extensible and powerful. It's also highly performant for large documents. Another major reason we chose CM 6 is that it's also one of the only code editors that work decently on mobile. While developing the new editor, Marijn was also amazingly responsive in investigating and fixing all the big and little things we ran into, even relatively niche issues like IME input bugs. If you find CM 6 useful, consider what you can to support the project! Funding link is here: https://marijnhaverbeke.nl/fund/
qbasic_forever · 2021-03-24
Any thoughts on adding codemirror 6 as an editor component too? It's recently in beta and looks like a fantastic complement to prosemirror: https://marijnhaverbeke.nl/blog/codemirror-6-beta.html
pier25 · 2020-07-13
It's actually a single guy, Marijn Haverbeke. He is also the author of "Eloquent JavaScript". https://marijnhaverbeke.nl/
degenerate · 2019-10-10
If you want to see what a 1kb game looks like, here is the full writeup of the original 2010 JS1K winning entry: http://marijnhaverbeke.nl/js1k/ (use arrow keys to move and space to jump) The smoothness in the graphics of the winning Js13k game blow me away. I love the way it "rolls back" after the timer ends, and would love to see a dev blog writeup from the authors.
aerique · 2019-01-25
Let us not forget his Common Lisp work or his winning JS1K entry: https://marijnhaverbeke.nl/
lewisjoe · 2018-12-05
> XML is superior to JSON for text documents. Far superior. Why do you think so? Is it because most structured texts are Trees? If so I understand the appeal. Because hey, HTML is perfect isn't it? Except, it's really not. While HTML is great for rendering, it sucks at WYSIWYG editing. Example: <p> This is <span style="font-weight:underline;">a <b><i>formatted </b>text</i>content </span> </p> Now good luck, finding/changing the formatting information for the 9th character ;) The funda is - rendering is easy with trees, nodes and children. Editing though is easier with working with indices than traversing trees. https://prosemirror.net/docs/guide/#doc.structure http://marijnhaverbeke.nl/blog/prosemirror.html#the-document These write-ups are interesting reads on the topic.
marijn · 2018-10-16
Nice! I too, would love to read more on the OT/CRDT trade-off. Companion reading (the approach taken in ProseMirror, which was implemented in significantly less person-years): http://marijnhaverbeke.nl/blog/collaborative-editing.html
ned · 2016-03-17
Very exciting project, specially the support for custom document schemas. If the authors are around, I'd love to hear what was their thinking regarding implementing focus and selection, with regards to the inconvenients outlined by the author of ProseMirror here: http://marijnhaverbeke.nl/blog/prosemirror.html#general-approach In a nutshell, ProseMirror chose to keep contentEditable in order to have browser-level support for spell-checking, screen-readers, RTL, etc. What are the tradeoffs exactly? Thanks.
jwmerrill · 2015-12-02
Beautiful description. Marijn Haverbeke has been writing some great material about his experiences creating ProseMirror [1]. I wonder how the two systems compare. [1] http://prosemirror.net/ [2] http://marijnhaverbeke.nl/blog/collaborative-editing.html
oneeyedpigeon · 2015-04-06
Two possible sources of inspiration; you're probably already familiar with them, but just in case you - or anyone else - isn't: Empty Black by Mary Rose Cook [1] is a great example of a highly playable game that is about as simple as it gets when it comes to graphics. Bouncing Beholder [2] is more about the 'code golf', but it's easy to read and understand the code once you go through the explanation, and it contains some useful techniques that would be applicable to a 'real' game. Good luck! [1] http://emptyblack.com/ [2] https://marijnhaverbeke.nl/js1k/
p_l · 2015-02-26
In Ruby World, Sequel (http://sequel.jeremyevans.net/) probably gives a bit of best of both ORM and direct SQL use, because what it really does is an object-oriented ("native" to language) interface to SQL database. And yes, it can build models like ActiveRecord, too! In Common Lisp, postmodern (http://marijnhaverbeke.nl/postmodern/) serves a similar role, with both DAO and lower-level access methods that compose pretty well. The 'perec' ORM from DWIM project was based on Postmodern, and among some weirder things I did quite easily was embedding custom SQL into query builder, so that the object-based accesses would use the advanced SQL. Really nifty feature :)
mrspeaker · 2013-11-18
30 not counting the (block * lines) of HTML ;) If you're comparin' code size - my favourite was from the first JS1K comp - a nice looking platformer in 1K!: http://marijnhaverbeke.nl/js1k/
felideon · 2013-09-11
And before that, the author of the best postgres library on the planet: Postmodern. http://marijnhaverbeke.nl/postmodern/
kevinjahns · 2026-03-17
Hi, the author of Yjs here. Thanks, Nick, for chiming in! As this article is blowing up now, I want to address a few points. I, too, feel the need for simplicity over overly complex solutions - and I found it in CRDTs. They beautifully allow me to reason about conflicts - so that my users don't have to. Very few people can design a custom conflict resolution algorithm for an application. Yjs is a general-purpose framework that enables you to make EVERYTHING collaborative. That's the goal. It's fine if you want to explore different solutions. I don't understand the need to put down one framework in favor of another. It doesn't have to be "OT vs CRDT". Hey, if you found something that works for you - great! But let me tell you that neither solution magically makes everything simpler. There is still a lot to learn. Different solutions to conflict resolution have different tradeoffs. It's unfortunate that the author of the article attributes all complexity to Yjs. It's just that collaborative editing is a very complex problem and requires a lot of attention to detail. In many regards, Yjs has done very well for the larger ecosystem. In other regards there is room for improvement. The only thing I acknowledge from the article is the criticism about y-prosemirror "replacing the whole document". Unfortunately, the author extrapolated some false assumptions. This is not a performance issue. y-prosemirror runs at 60 fps even on large documents. We leverage ProseMirror's…
antics · 2026-03-16
Author here. I think it depends what you're doing! OT is a true distributed systems algorithm and to my knowledge there are no projects that implement true, distributed OT with strong support for modern rich text editor SDKs like ProseMirror. ShareJS, for example, is abandoned, and predates most modern editors. If you are using a centralized server and ProseMirror, there are several OT and pseudo-OT implementations. Most popularly, there is prosemirror-collab[4], which is basically "OT without the stuff you don't need with an authoritative source for documents." Practically speaking that means "OT without T", but because it does not transform the ops to be order-independent, it has an extra step on conflict where the user has to rebase changes and re-submit. This is can cause minor edit starvation of less-connected clients. prosemirror-collab-commit[5] fixes this by performing the rebasing on the server... so it's still "OT without the T", but also with an authoritative conflict resolution pseudo-T at the end. I personally recommend prosemirror-collab-commit, it's what we use, and it's extremely fast and predictable. If you just want something pedogocically helpful, the blessed upstream collaborative editing solution for CodeMirror is OT. See author's blog post[1], the @codemirror/collab package[2], and the live demo[3]. In general this implementation is quite good and worth reading if you are interested in this kind of thing. ShareJS and OTTypes are both very readable and…
potholereseller · 2025-06-01
It would probably depend on the Scheme/Lisp implementation and how it was secured. If it used a Scheme implementation like in Halo:CE, then people would have justifiably hated it. If it used something more like MIT-Scheme, people might've been okay with it. But I suspect it would get the same hate that JS gets, since there is a lot of low-quality JS code floating around -- even though JS itself isn't remotely that bad -- and you would instead have a lot of low-quality Scheme code floating around. Damned if you do, damned if you don't. FWIW, it is feasible to put Scheme/Lisp in a browser today, and it might even be fun. Take a browser that lacks JS (e.g. Dillo, w3m); figure out how to add Firefox's or Chromium's approach to isolating each Javascript instance; and embed a Scheme or Common Lisp implementation (e.g. Chez Scheme [1] or ECL [2]). You will need to decide what Scheme/Lisp functions/macros to include/exclude. It may seem obvious to exclude file operations, but they did that with JS and now we have IndexedDB; a restricted, virtual file system might be fun to play with. Multithreading might seem like a great thing to include, until you start trying to implement secure multithreading. I would start with whatever cl-isolated [3] allows and expand/contract from there. And before anyone asks, "would this actually be worth implementing in 2025?", the answer is decidely "yes". You could build powerful desktop applications without the full weight of Electron. You could…
spankalee · 2024-03-06
This talk makes a really important point for multiplayer app implementations! But I don't love how he separates the global order approach from operational transform. Those two approaches go very well together in my experience: - Global ordering eliminates much of the complexity of OT - OT enables optimistic, offline edits and fine-grained merging on top of global ordering Most SaaS editors are not truly peer-to-peer: edits are sent to a central server before being broadcast back to clients. The service can define the global ordering then - the point of this talk. But you need the server to be able to reconcile and merge concurrent edits from clients that haven't fully sync'ed yet, and you want clients to be able to locally apply edits before receiving the latest state from the server, so you need some way to undo and replay edits on top of newly discovered edits that happened before (like a Git rebase). This is the basic operational transform function. The knock on OT has been complexity - the claim that you need n^2 merge functions for n operations. But... most operations in a real app don't collide in ways that require merges so in reality you need far fewer than than n^2. You generally need text and collection merges. Marijn Haverbeke, the author of ProseMirror and CodeMirror, has a great blog post on a lot of this here: https://marijnhaverbeke.nl/blog/collaborative-editing-cm.html
qwertox · 2022-08-18
Related to this is also an example from ProseMirror (which TipTap uses as the editing component) [0][1] I'm not completely sure, but I think at ProseMirror they're using Yjs [2] for the collaborative editing part. If not, checking out Yjs is worth it in and of itself. > Yjs is a CRDT implementation that exposes its internal data structure as shared types. Shared types are common data types like Map or Array with superpowers: changes are automatically distributed to other peers and merged without merge conflicts. > Yjs is network agnostic (p2p!), supports many existing rich text editors, offline editing, version snapshots, undo/redo and shared cursors. It scales well with an unlimited number of users and is well suited for even large documents. > Conflict-free replicated data types (CRDT) for collaborative editing are an alternative approach to operational transformation (OT). [3] OT was what Google Wave was based on and I think current colab editing in Google Docs and other of their office products use this. [0] https://prosemirror.net/examples/collab/#edit-Example [1] https://marijnhaverbeke.nl/blog/collaborative-editing.html [2] https://github.com/yjs/yjs [3] https://github.com/yjs/yjs#Yjs-CRDT-Algorithm
yogthos · 2017-10-02
A lot of the same refactoring is possible in dynamic languages as in static ones. I recommend reading up on Term to see what's possible to do with JavaScript http://marijnhaverbeke.nl/blog/tern.html I use Cursive https://cursive-ide.com/ for working with Clojure, and it can do safe refactoring for symbols by doing static analysis of the source. It can show all usages of a symbol, rename it, do automatic imports, and so on. Another piece of tooling that's not available in any statically typed languages at the moment is REPL integration with the editor seen here http://vvvvalvalval.github.io/posts/what-makes-a-good-repl.html I find that the REPL driven workflow found in Lisps is simply unmatched. When you have tight integration between the editor and the application runtime, you can run any code you write within the context of the application immediately. This means that you never have to keep a lot of context in your head when you're working with the application. You always know what the code is doing because you can always run and inspect it. Having the runtime available during development gives you feedback much faster than the compile/run cycle. I write a function, and I can run it immediately within the context of my application. I can see exactly what it's doing and why. The main cost of static typing is that it restricts the ways you can express yourself. You're limited to the set of statements that can be verified by the type checker. This is necessarily a subset…
jlg23 · 2016-07-27
> I don't see how recursive queries are going to help you You construct a graph of objects with very few queries, transform it and write it back; with knowledge of the db-schema this will outperform any ORM-based solution and give much greater flexibility. > As for building queries [...] The problem is that it composes very badly. [...] the best you can do is concatenating partial queries and hoping you got the parentheses count right. There is an area between full-fledged ORMs and string concatenation. In a purely functional approach queries are composed by composing functions that compile to queries. Postmodern[1][2] is a good, open source example, though in most commercial projects we just built our own wrappers for the tasks and databases at hand. This also allows for much better performing code since for a lot of tasks hooking up the db-reader to the json emitter without going through object instantiation reduces memory and cpu consumption by an order of magnitude (or two), while in the same project, some code benefits from a OOP approach (for which you just use a reader that constructs the objects on the fly). [1] http://marijnhaverbeke.nl/postmodern/ [2] http://marijnhaverbeke.nl/postmodern/s-sql.html (yes, it does string concatenation at run time, but it does it for you, you don't worry about getting the parenthesis count right)
Udo · 2013-12-08
I was glad when the author of the article advised against learning Monads by analogy, because it's one of those subjects where analogies serve only to confuse people. Personally, my brain maps badly to Haskell syntax, so let's do this in JavaScript (I know, I know, not so powerful and everything): In fact if you used jQuery, you already know what a Monad is, probably without realizing it. Consider the following code: $('.myelements').filter(filterFunction).css('color', '#ff0'); You can follow along what this code does by following the dots. First, all elements matching the ".myelements" class are returned, these are then filtered, and the result of that gets a css modification. Every time you wrote a method that returns an object, you already did monads in principle. They can be used to chain things together. While Haskell provides semantics that explicitly deal with the mechanics of monads, pretty much every dynamic language has them. Here's what it looks like in PHP, for example: $obj ->bla() ->beep() ->borp(); You can use monads to make your code more concise, to simply chain function calls, or to iterate over a list, but they're also often used when sifting through databases since filtering and applying attributes to items. For example, an SQL-like database query might be expressed like this: table1.select(all).where({ ref : 1 }).orderby('id'); Of course, that's an API which is a bit dishonest since it acts as if the code really goes through…
straws · 2025-05-21
Both ProseMirror and the newer version of CodeMirror have a pretty elegant solution to this: each modification to the document is modeled as a step that keeps track of indices instead of node/text identities, and uses a data structure called a "position map" that the buffered steps can be mapped through to create steps with updated positions, which are then applied to your document. In practice, it works quite well. Here's more info: https://marijnhaverbeke.nl/blog/collaborative-editing.html https://marijnhaverbeke.nl/blog/collaborative-editing-cm.html
dugmartin · 2024-03-20
If you want or need to stay totally within the JavaScript ecosystem, Marijn Haverbeke (author of CodeMirror, ProseMirror, and more) created Lezer which is tree-sitter like and is grammar driven with optional external tokenizers also: Announcement: https://marijnhaverbeke.nl/blog/lezer.html Homepage: https://lezer.codemirror.net/
meitros · 2023-07-24
I'm looking into client-side syntax highlighting as well at the moment and lezer popped up: https://lezer.codemirror.net/. It's directly based on tree-sitter but tailored to be more web friendly (and written by the same author as codemirror) - https://marijnhaverbeke.nl/blog/lezer.html
jdorfman · 2022-11-02
I just want to say what a pleasure it is working with the maintainer Marijn Haverbeke. If you use CodeMirror consider supporting his work: https://marijnhaverbeke.nl/fund/
eatonphil · 2022-04-18
I was wondering why they didn't use tree-sitter since this sounds very similar to tree-sitter, tree-sitter is written in C (and thus hopefully faster than a similar project written in TypeScript), and there's even officially support wasm build steps for if you need to run it in the browser. The linked blog post [0] answered my question though: > Unfortunately, tree-sitter is written in C, which is still awkward to run in the browser (and CodeMirrror targets non-WASM browsers). It also generates very hefty grammar files because it makes the size/speed trade-off in a different way than a web system would. [0] https://marijnhaverbeke.nl/blog/lezer.html
fiddlerwoaroof · 2022-03-26
If you’re fine with ES3, there’s https://marijnhaverbeke.nl/cl-javascript/ (I’ve been intending to use Babel to compile modern JS to ES3 and then load it into CL, but no time) Or parenscript: https://parenscript.common-lisp.dev/ Or CLOG: https://github.com/rabbibotton/clog And, there’s always the option of writing an HTTP or websocket server and serving JSON. I personally use the SLIME repl in emacs for a ton of things I used to use bash one-liners for and you can push it pretty far (this is an experiment, I’ve wrapped it up more nicely into my .sbclrc since): https://twitter.com/fwoaroof/status/1502881957012668417?s=21&t=81O…

Keyboard shortcuts

/Search
j kNext / previous blog
EnterOpen selected blog
vVisit the blog site
fFollow / unfollow
lSwitch grid / list view
dSwitch dark mode
g hHome
g pTop posts
g tTopics
g fFollowing
g lLiked
g yHistory
g qFAQ
EscBack / close