# Using Macros to make docopt faster. Like, 75x faster

**URL:** https://forum.crystal-lang.org/t/using-macros-to-make-docopt-faster-like-75x-faster/9164
**Category:** Community
**Created:** [September 24, 2026, 12:17pm UTC](https://forum.crystal-lang.org/t/using-macros-to-make-docopt-faster-like-75x-faster/9164 "2026-09-24T12:17:55Z")
**Posts on this page:** 3
**Page:** 1

<div class="post-metadata">

### Author: ![ralsina](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/ralsina/32/2139_2.png) [@ralsina](https://forum.crystal-lang.org/u/ralsina)
#### Post date: [September 24, 2026, 12:17pm UTC](https://forum.crystal-lang.org/t/using-macros-to-make-docopt-faster-like-75x-faster/9164/1 "2026-09-24T12:17:55Z")

</div>

Every docopt program carries its own help text, and that text is the parser’s spec. When the program starts, docopt reads the usage section, figures out which words are commands, which are arguments, which options take values, builds a little grammar out of all that, and only then looks at what you actually typed. It’s a great trade for the programmer: you write the help once and get argument parsing for free. But the grammar-building part is real work, and it happens on every single run, even though the help text hasn’t changed since the binary was compiled.

How much work? For tartrazine’s usage text, which has 17 usage lines and 21 options, about 1.6 milliseconds. That sounds like nothing until you notice that tartrazine itself, highlighting a small file, takes about 12 milliseconds total, so the argument parser was eating a sixth of the run before any highlighting happened. Most of it turned out to be the pattern tree comparing nodes by building their string representations over and over, but even with that fixed, parsing a grammar at startup is a strange thing to do when the grammar is a compile-time constant.

The fix is to stop doing it at runtime. Crystal macros can run a program during compilation and paste its output into the source, and the run macro is exactly that. So Docopt.compile(HELP) hands the help text to a small script at build time, that script runs the normal docopt parser, and then serializes the finished pattern tree back out as plain Crystal constructor calls. The compiler sees a literal tree of Required, Either, Option and Argument objects, already fixed up, and embeds it in the binary. At runtime, Docopt.match takes that tree and your ARGV and does only the matching. Nothing new was written for parsing; the same parser that has passed the same tests for years just runs a little earlier than it used to. As a bonus, a broken usage text now fails the build instead of failing on runtime.

The result is that the argument parser essentially disappears from the startup profile: 1.6 milliseconds becomes 0.02. A minimal program that parses arguments and prints one of them went from 3.4 milliseconds to 1.3, and an empty Crystal program is 1.1, so what’s left is the cost of being a process at all.

And this is 100% backwards compatible! I know this sort of optimization is unimportant in 99.99% of the cases but it’s fun. It’s available in version 0.4.0 of ralsina/docopt.cr

**NOTE:** huge thanks to [chenkovsky (Chen Chongchen) · GitHub](https://github.com/chenkovsky) for the original docopt.cr :-)

---

<div class="post-metadata">

### Author: ![anykeyh](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/anykeyh/32/726_2.png) [@anykeyh](https://forum.crystal-lang.org/u/anykeyh)
#### Post date: [September 25, 2026, 4:10am UTC](https://forum.crystal-lang.org/t/using-macros-to-make-docopt-faster-like-75x-faster/9164/2 "2026-09-25T04:10:14Z")

</div>

That’s seems promising, but you haven’t shared the link to the fork/repo 🙂

---

<div class="post-metadata">

### Author: ![ralsina](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/ralsina/32/2139_2.png) [@ralsina](https://forum.crystal-lang.org/u/ralsina)
#### Post date: [September 25, 2026, 11:02am UTC](https://forum.crystal-lang.org/t/using-macros-to-make-docopt-faster-like-75x-faster/9164/3 "2026-09-25T11:02:32Z")

</div>

ralsina/docopt.cr
