Ash has a lot of features that can sometimes speed up development, but it isn’t for everyone or every team—largely because it comes with significant drawbacks that aren’t immediately obvious. For context, I’ve been programming for over a decade, I’ve used Elixir for about eight years, and I’ve been working with Ash on a daily basis for the past four months.
In my opinion, viewing Ash as just another framework is misguided. While I don’t want to get mired in the “What is a framework?” debate, a good framework provides a supportive structure without imposing rigid constraints on how you build. Phoenix illustrates this well: it suggests a broad outline but lets you shape and even deviate from that outline however you need. Ash, on the other hand, feels more like its own language—a comprehensive DSL that’s powerful but also highly opinionated. Often, it feels like a straitjacket: you don’t fully realize how it limits you until you attempt something ordinary and run into cryptic errors. It’s also unclear when and how you’re supposed to deviate from “the Ash way,” which isn’t well documented.
This dynamic reminds me of my experiences with front-end frameworks: Vue and React. I like Vue because it provides a skeleton and guidance but mostly stays out of the way—you’re still basically writing JavaScript. In contrast, React is always in your face, and straying from “the React way” can be painful. In that sense, Vue is like Phoenix, and React is like Ash.
My team recently began to “Ashify” our codebase at work. Initially, I was open-minded, especially since it was pitched as a way to reduce our tech debt by standardizing common operations, but once I built a new feature with it, I realized it drastically reduced both my productivity and my enjoyment of programming. I’m not the only team member who feels this way. The extensive “magic” also brings Rails to mind, which I used early in my career but left for Elixir. In fact, coding with Ash doesn’t really feel like writing Elixir at all, given that the DSL seems to be heavily macro-driven. For a rough (and admittedly unscientific) comparison, the Phoenix repo has only 19 defmacro statements, whereas Ash—around the same size—has 62. That’s disappointing, especially since one of Elixir’s guiding principles is to use macros sparingly:
Even though Elixir attempts its best to provide a safe environment for macros, most of the responsibility of writing clean code with macros falls on developers. Macros are harder to write than ordinary Elixir functions, and it’s considered to be bad style to use them when they’re not necessary. Write macros responsibly.
Elixir already provides mechanisms to write your everyday code in a simple and readable fashion by using its data structures and functions. Macros should only be used as a last resort. Remember that explicit is better than implicit. Clear code is better than concise code.
Or, as computer scientist David J. Wheeler put it, “All problems in computer science can be solved by another level of indirection, except for the problem of too many layers of indirection.”
Yeah, in my experience this is broadly one of the primary criticisms of Rails more broadly: the magic is great when you’re first starting a project because you can move at what feels like light speed, as a lot of common and generic stuff like sorting, filtering and pagination are included. Eventually though you find yourself having to actually know and think about what is going on under the hood, and having to deviate away from the “Rails way”, and complexity skyrockets and the cognitive load becomes too much.
By way of constructive criticism, Ash’s documentation could stand significant improvement. It often feels auto-generated, with crucial details added as an afterthought. Maybe I’m spoiled by Elixir and Ecto’s excellent docs, but it’s not encouraging when my teammates say, “The docs aren’t clear, but check the Ash book instead.” I’ve also sought help on the Elixir Slack’s Ash channel, only to be advised to join the Ash Discord, which itself is separate from the main Elixir Discord. This is both puzzling and somewhat emblematic of my broader point that Ash feels more like its own language. ![]()






















