MUD: a TypeScript and Solidity framework for EVM applications
MUD is a framework for building autonomous worlds
At a glance
- What is it?
- MUD is a monorepo framework for Ethereum applications that hands EVM developers storage, upgrades, delegations and frontend data sync as composable pieces, with a pnpm quickstart, Foundry tooling and a Docker image for local services. The newest published packages are from 2025-08-26 and the last push was on 2026-04-10.
- Who is it for?
- Adopt MUD if you are building an Ethereum application whose state lives in contracts and whose frontend needs to read and write that state, and you would rather take storage, upgrade handling, delegations and data sync from a framework than rebuild them, especially since the store-indexer and faucet services ship as part of the same repository.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Activity is slowing. The repository last received commits 6 months ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
MUD is described as a composable foundation for EVM developers
The repository describes itself as MUD, a framework for building autonomous worlds, and the README frames it as a framework for ambitious Ethereum applications with the subtitle of a battle-tested onchain framework for developers. The topics list the intended ground: ethereum, evm, solidity, typescript, game-development, sdk and autonomous-worlds.
The functional claim is one sentence, and it is worth unpacking: MUD offers a composable foundation to EVM developers that handles data storage, upgrades, delegations, data-sync with frontends, etc.
Those four items are the product. Writing directly against the EVM means deciding yourself how contract state is laid out and indexed, what happens when a contract needs a new version, how a delegated account is represented, and how a frontend learns that something changed. MUD packages that work as components you assemble rather than as a single application framework you adopt wholesale, and the word composable in the README is doing the load-bearing work there.
The licence is MIT, with a LICENSE file at the root of the repository, and the primary language of the codebase is TypeScript with Solidity in the same tree. The frontend story is the one that shapes most of the architecture, because a data-sync layer is only useful if a browser client can consume it, which is why the repository contains a store-indexer service and a faucet service alongside the contract packages.
The quickstart is one command and the onscreen directions
Getting started is unusually short, which is what you want from a scaffold tool:
pnpm create mud@latestThen follow the directions onscreen, and the README points at the MUD quickstart page for the longer version. The command name says everything about the intended workflow. It is a create scaffolder in the pnpm family, so it is invoked the same way as any other pnpm create template, and the generated project is a workspace rather than a single package.
The README also makes the scope of the repository explicit in a way that matters for contributors: this monorepo includes all of MUD's source code, and pull requests are always welcome. Contributing instructions live at mud.dev/contribute, and discussion happens on the project's Discord, which is linked from both the contribute and the community support sections.
The documentation itself is not in the repository. The README links to mud.dev/introduction for what MUD is and to mud.dev/quickstart for setup, and the docs/ directory in the repository is a site source rather than the published documentation. For a framework this size that is a normal arrangement, but it does mean the version of the guidance you read may be newer than the version of the code in a given checkout, so the two have to be matched deliberately.
One repository, many packages, and a set of worked examples
The top-level directory of the repository is a large one: apps/, packages/, docs/, examples/, e2e/, templates/, scripts/, test/, test-data/, test-setup/, alongside a pnpm-workspace.yaml, pnpm-lock.yaml, turbo.json, vitest.config.ts, tsup.config.base.ts, tsconfig.json, a Dockerfile, a CHANGELOG.md, a CODEOWNERS file, a .changeset/ directory and a .husky/ directory.
The package.json names the workspace mud-monorepo and marks it private, with a build script that is a turbo run. The package directories visible in the build scripts are the ones that matter: packages/store, packages/world, packages/world-modules and packages/cli, plus test/mock-game-contracts, test/puppet-modules, e2e/packages/contracts, the contracts inside each templates directory, and the contracts inside each examples directory.
The examples/ directory is the most useful part of the tree for a newcomer, because it shows the same framework used for different purposes. There is a minimal example, a custom-world example, a faucet-client, an indexer-client, a local-explorer, multiple-accounts, and multiple-namespaces. Read in order, those cover the progression from one contract to a world with several namespaces and several accounts, and each one is a working project rather than a fragment.
The separation between packages and templates is worth noting. Packages are the framework itself, published to npm under scoped names, and templates are the starting points that pnpm create mud@latest serves. The examples are neither: they sit in the repository as test fixtures and as documentation.
Turbo, pnpm workspaces, and a build that loops over directories
The build system is a good indicator of how large the project is. Two scripts in package.json do the heavy lifting:
"build": "turbo run build --concurrency=100%",
"dev": "turbo run dev --concurrency=999",Turbo runs the tasks across the workspace, and the concurrency figures are set to the maximum in both cases, so a local build fans out across every package that declares a build task. The all-build script does something more manual, walking a list of directories and running pnpm build in each, which covers the contract packages, the examples, the templates and the end-to-end contracts in one sweep.
The rest of the scripts show the toolchain the project assumes. The lint script runs a prettier check and then eslint over TypeScript and TSX files, with a prettier script that formats TypeScript, TSX, CSS, Markdown, MDX and Solidity in one pass. Changelogs and API documentation are generated by scripts run through tsx, with changelog:generate pointing at scripts/changelog.ts and docs:generate:api at scripts/render-api-docs.ts.
Two entries tell you the project expects a Solidity toolchain even before you write a contract. The prepare script runs husky install and then checks for forge, running the project's foundryup task if the Forge binary is missing, and there is a separate foundryup script that installs the Foundry toolchain directly. The .husky/ directory and the commitlint configuration are consistent with that: commits are validated, and the toolchain is prepared by a Git hook.
Release handling goes through the .changeset/ directory and a release:check script that runs changeset status, so version bumps are described in a changeset file rather than edited into package.json by hand. A dist-tag-rm script exists to move an existing npm tag when a release is rolled back, which is a small detail that tells you the maintainers publish to a public registry.
A Debian image with Node 18, Foundry and pnpm baked in
The Dockerfile is a development environment, and reading it tells you the prerequisites in a single pass. It starts from docker.io/library/debian:bookworm-slim and installs the usual build tooling, then adds Node from the NodeSource repository, pinned to the node_18.x line, and checks the versions it installed with node --version and npm --version.
Foundry is installed next, with the individual tools verified one by one, forge --version, cast --version, anvil --version and chisel --version, and the Foundry bin directory added to PATH. pnpm comes after that, pinned to an exact version:
ENV PNPM_HOME /pnpm
ENV PATH $PATH:$PNPM_HOME
RUN npm install [email protected] --global && pnpm --versionThe final stages are the services. The build stage installs the workspace with a frozen lockfile and runs the build with a raised heap limit, and the two service stages then move into the individual package directories:
FROM mud AS store-indexer
WORKDIR /app/packages/store-indexer
EXPOSE 3001The same pattern produces a faucet stage that exposes port 3002. So a local environment gives you a contract workspace, a state indexer on 3001, and a faucet on 3002, which is the pair of services an example application needs before it can mint test assets and read state back.
The container is also the path to a self-hosted version of those services, and the presence of the Dockerfile at the root of a public repository means the deployment path is documented by the image itself rather than by a separate set of instructions.
Releases are published per package, not as a framework version
The three most recent releases are all at version 2.2.23 and all share the same date, 2025-08-26: [email protected], [email protected] and [email protected].
That is the shape of a monorepo release, and it has a practical consequence for anyone pinning dependencies. The published versions are per package, and the two solhint packages plus the vite plugin at the same version number on the same day suggest a coordinated release of a group of packages rather than a framework release. Nothing in that list tells you the version of packages/store, packages/world or packages/cli, so you cannot infer what the framework itself is at from the release feed alone. You have to look at the package you intend to install.
That is also a reason the repository uses changesets. Each package carries its own version, and a changeset describes the bump for the next release, so the release feed looks like a stream of package bumps rather than a single framework version. The CHANGELOG.md at the root and the changelog:generate script exist to give that stream a readable form.
On maintenance, the honest statement is the date. The last push to the repository was on 2026-04-10, and the repository is not archived. That leaves a gap of roughly six months between the newest source change and the newest published packages, so a new project should pin the versions it tested and expect to read the current documentation at mud.dev rather than infer the state of the framework from the tags.
When MUD is the wrong size of answer
The case against MUD is mostly about weight. The README's own framing, a framework for ambitious Ethereum applications, is the clue. To get a project running you need pnpm, a workspace with a turbo build, Foundry for the Solidity side, and a Node 18 toolchain, and the container image pulls in a large set of system packages for that. For an application that is a handful of contracts with a simple frontend, that is a lot of infrastructure to answer a question you might answer directly against the EVM.
The other case is when you need the frontend and the contract state to move in lockstep and you have already chosen how. MUD's value is concentrated in storage, upgrades, delegations and data sync, and if a project needs none of those four, the framework adds a build system and a set of conventions without removing any work.
There is a third consideration, and it is about who else has to run the thing. The store-indexer and faucet services are part of the repository, which is convenient for a local environment and a burden for a deployment: a team that adopts MUD inherits two services to operate, with their own ports, their own images and their own upgrade path, on top of the contracts.
Finally, the documentation split. The README is a short index that sends you to mud.dev for anything beyond a one-line quickstart, so the projects that depend on MUD tend to depend on the website staying in step with the code. Given that the last push was on 2026-04-10, that is a dependency worth watching, and it is the reason to read the pinned versions in the packages you use rather than trusting the latest tag.
Editorial conclusion
Adopt MUD if you are building an Ethereum application whose state lives in contracts and whose frontend needs to read and write that state, and you would rather take storage, upgrade handling, delegations and data sync from a framework than rebuild them, especially since the store-indexer and faucet services ship as part of the same repository. Do not adopt it for a small set of contracts where the toolchain alone is larger than the project, because a working setup needs pnpm, Foundry, a Node 18 based image and a workspace build. Before you start, read the pinned versions in the packages you plan to depend on, since the release list publishes per-package versions rather than a framework version, and check mud.dev for the current documentation, because the last push to the repository was on 2026-04-10 and the README itself points out that the documentation lives on the website.
Frequently asked questions
How do I start a new MUD project?
Run pnpm create mud@latest and follow the directions onscreen. The README also links to the MUD quickstart page on mud.dev for the longer version, and the repository's examples directory holds a minimal example plus custom-world, multiple-accounts and multiple-namespaces variants.
What does the MUD framework provide to EVM developers?
The README describes it as a composable foundation to EVM developers that handles data storage, upgrades, delegations, data-sync with frontends, and similar concerns. The repository is a pnpm workspace with packages for the store, the world, world modules and a CLI, and it ships a store-indexer service alongside a faucet.
What licence is MUD released under?
MIT, with a LICENSE file in the repository root. The README states that MUD is open-source software under the MIT license, and contributions are handled through the process described at mud.dev/contribute.
How do I run the MUD indexer and faucet locally?
The repository's Dockerfile builds a Node 18 image with Foundry and pnpm, then defines a store-indexer stage that exposes port 3001 and a faucet stage that exposes port 3002. Running those images gives you the two services that the example applications expect.
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/latticexyz-mud)Was this useful?