Grain: a WebAssembly-first language with its own compiler toolchain
The Grain compiler toolchain and CLI. Home of the modern web staple. 🌾
At a glance
- What is it?
- Grain compiles to WebAssembly through Binaryen. The repository is a monorepo holding the compiler, the CLI and the standard library, and the README points newcomers at the online guide rather than at a package manager.
- Who is it for?
- Grain fits developers who want a functional language whose only compilation target is WebAssembly and who are willing to build the toolchain from a Node monorepo, or to follow the online guide for a supported path. It does not fit anyone who needs a native binary, a large third-party package ecosystem, or a language whose documentation covers the CLI surface in the repository itself.
- Can I use it commercially?
- Yes, with conditions. LGPL-3.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 4 days ago.
- What is it written in?
- Mainly Reason, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Who Grain is for, and what it replaces
Grain is a functional programming language whose compiler emits WebAssembly. The README states this plainly: Grain compiles to WebAssembly via Binaryen. That single sentence defines the audience. If your deployment target is a browser, a WASM runtime, or an edge host that accepts a .wasm module, Grain is a candidate. If your target is a native executable, it is not, because the repository describes no native backend.
The pitch is not "write JavaScript faster". It is that you get a functional language with its own type system and its own standard library, and the artifact you ship is a WebAssembly module. That matters for teams already running WASM for isolation or portability reasons, and for people who want to write browser code without adopting the JavaScript toolchain.
The repository is a monorepo with three workspaces declared in package.json: cli, stdlib and compiler. They are published under the @grain scope, so the CLI package is @grain/cli and the compiler is @grain/compiler. The root package is marked private, which tells you the root is a build orchestrator, not something you install. The language itself is written in Reason, according to the repository metadata, which is worth knowing if you intend to read or patch the compiler rather than just use it.
The compiler, the CLI and the standard library as separate pieces
The build graph is visible in the root package.json scripts. Three workspace scripts fan out: cli, compiler and stdlib. A postcompiler hook runs the stdlib clean step after the compiler script finishes, which means compiler work and standard library work are sequenced rather than independent. If you are building from source, expect the compiler to be the expensive step and the stdlib to be coupled to it.
The Dockerfile in the repository root shows how the pieces fit together in a clean environment. It starts from node:22, copies the whole repository to /grain, runs npm ci with --ignore-scripts, then copies an esy installation from an ospencer/esy:0.9.2 stage into node_modules/esy. The comment in the file explains why: esy does not currently ship linux/arm64 binaries, so the Dockerfile patches it in manually. After that it runs npm run prepare and npm run compiler build. This is the clearest statement of the real dependency chain: Node, npm workspaces, and esy as the build tool for the compiler.
There is also a Dockerfile-slim alongside it, which suggests the maintainers care about image size for at least some use cases. The repository does not document what the slim variant drops, so treat that as an open question rather than a feature.
The engines field requires Node >=22.13. That is a hard floor, not a suggestion. If you are on an older LTS line, the install will not match what the repository expects.
Installing Grain and running your first build
The README does not give install commands. It says that if it is your first time, you should follow the Grain guide at grain-lang.org/docs to get up and running, and that building from source is documented at grain-lang.org/docs/getting_grain under the Building Grain from Source section. So the supported install path lives outside the repository. What the repository does give you is the contributor workflow.
To work from a checkout, install dependencies and link the CLI. The prepare script runs the CLI link automatically, but you can run it directly:
npm ci
npm run cli linkThe link step is what puts the grain command on your path for the current project. If the command is not found afterwards, the link did not take, and that is the first thing to check.
To build the compiler:
npm run compiler buildThis is the long step. The Dockerfile runs the same command as its final build action, so it is the canonical way to produce a working compiler from source.
If a build goes wrong and you want to start over, the README lists a reset command:
npm run compiler cleanRunning tests goes through the compiler workspace:
npm testWhat you should see after a successful build is a linked CLI and a compiler you can invoke. The README does not show sample compiler output, so there is no expected console transcript to compare against. The repository also ships a .gitpod.yml and a .gitpod.Dockerfile, so a hosted Gitpod workspace is one of the intended ways to get a working environment without building locally.
What the repository does not tell you
The README is short, and the gaps are worth naming before you commit time to it. There is no install command, no example program, no CLI flag reference and no explanation of what the compiler emits or where it writes it. The two links it does give, to grain-lang.org/docs and to the getting-started page, mean the repository alone is not a sufficient onboarding document. That is a deliberate split, and it is a reasonable one for a project with a separate docs site, but it does mean you cannot evaluate the language by reading the repository.
The CLI surface is similarly undocumented here. The README mentions npm run cli link, npm run compiler clean and npm run compiler build, all of which are npm scripts, not the grain binary's own interface. Nothing in the repository README describes what subcommands the linked CLI exposes. If you need to know how to compile a specific file or pass options, that information is not in this repository's README.
The release history is also uneven. The most recent releases listed are grain-v0.7.2 and stdlib-v0.7.2, both dated 2026-02-08, with a preview tag from 2023-03-22. The compiler and the standard library version in lockstep, which is good for compatibility reasoning, but the preview tag sitting years behind the numbered releases suggests the prerelease channel is not the primary distribution route. The last push to the repository was on 2026-09-21.
Where Grain is the wrong choice
Pick something else if you need a native binary. Grain's compiler targets WebAssembly through Binaryen, and the repository describes no other backend. A project that needs to ship a Linux executable, call into system libraries directly, or produce a static binary for a server without a WASM runtime is outside what this toolchain does.
Pick something else if ecosystem size is your deciding factor. The monorepo has three workspaces: the CLI, the compiler and the standard library. There is no package registry described in the README, no third-party library index, and no mention of how you would consume external Grain code. A language whose standard library is versioned alongside the compiler at 0.7.2 is early in its lifecycle, and the release numbering reflects that.
Pick something else if you need the documentation to live next to the code. The README defers to an external site for the guide and for build instructions, and the repository does not restate them. Teams that vendor their dependencies and read docs from a checkout will find the in-repo documentation thin.
There is also a platform caveat visible in the Dockerfile. The comment notes that esy does not currently ship linux/arm64 binaries, which is why the build patches esy in from a separate stage. That workaround is in the official Dockerfile, which means arm64 container builds are a known rough edge rather than a solved problem.
Grain against compiling Rust or C to WebAssembly
The obvious alternative is a systems language with a mature WASM target, most commonly Rust. The difference is not just syntax. With Rust you get a large crate ecosystem, a native backend for the same source, and a toolchain that many engineers already have installed. With Grain you get a functional language designed around WebAssembly from the start, with its own standard library and no native path at all.
That trade cuts both ways. Grain's single-target design means there is no ambiguity about what you are building, and no conditional compilation between native and WASM code paths. A Rust project that targets both native and wasm32 usually needs feature flags or cfg attributes to reconcile the two; Grain has nothing to reconcile because there is only one target. The cost is that you cannot reuse the language for a server-side binary, and you cannot fall back to native when a WASM runtime is inconvenient.
The second alternative is to write the JavaScript or TypeScript you were going to write anyway. That avoids a build toolchain entirely. Grain's argument against it is a type system and a functional style, but if your team is already fluent in TypeScript and your performance needs are modest, adding a compiler, a Node-based build with esy, and a separate standard library version to track is a real cost. The right question is whether you want a different language, not whether you want WebAssembly.
Licence, maintenance and the cost of upgrading
Grain is licensed under LGPL-3.0, per the repository's LICENSE file and the licence badge in the README. That is a copyleft licence with a linking exception tradition, and it is different in character from the MIT or Apache-2.0 licences most language toolchains use. If you are embedding the compiler or the standard library into a product, the terms are worth reading in full rather than assuming they match a permissive licence. This is not legal advice; the point is only that LGPL-3.0 is a deliberate choice with obligations attached.
On maintenance, the last push to the repository was on 2026-09-21, and the repository is not archived. The most recent numbered releases are grain-v0.7.2 and stdlib-v0.7.2 from 2026-02-08. The repository uses release-please, visible in release-please-config.json and .release-please-manifest.json, which means release notes and version bumps are generated from commit history rather than written by hand. That is a reasonable signal about process, though it says nothing about how often releases land.
The upgrade cost has one structural feature worth noting: the compiler and the standard library are versioned together at 0.7.2. That reduces the chance of a version skew between language and library, but it also means a compiler upgrade is a standard library upgrade. The postcompiler script that cleans the stdlib after a compiler build reinforces that coupling. Plan upgrades as whole-toolchain events, not as independent bumps.
Editorial conclusion
Grain fits developers who want a functional language whose only compilation target is WebAssembly and who are willing to build the toolchain from a Node monorepo, or to follow the online guide for a supported path. It does not fit anyone who needs a native binary, a large third-party package ecosystem, or a language whose documentation covers the CLI surface in the repository itself. Before committing, verify that your Node version satisfies the >=22.13 engine field, check whether the CLI link step succeeds on your platform, and confirm that the LGPL-3.0 licence terms are acceptable for how you plan to distribute compiled output.
Frequently asked questions
How do I install the Grain compiler?
The README does not give install commands. It directs first-time users to the Grain guide at grain-lang.org/docs, and points to grain-lang.org/docs/getting_grain for building from source. From a checkout, the repository's own workflow is npm ci followed by npm run cli link and npm run compiler build.
What does Grain compile to?
Grain compiles to WebAssembly via Binaryen, according to the README. The repository describes no other compilation target.
Which Node version does the Grain repository require?
The root package.json sets an engines field of node >=22.13. The Dockerfile builds from the node:22 image, consistent with that floor.
Is the Grain repository still being updated?
The repository is not archived, and the last push was on 2026-09-21. The most recent numbered releases are grain-v0.7.2 and stdlib-v0.7.2, both dated 2026-02-08.
What licence does Grain use?
Grain is licensed under LGPL-3.0, per the LICENSE file and the licence badge in the README. That is a copyleft licence, not a permissive one.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/grain-lang-grain)