# masto: A TypeScript Client for the Whole Mastodon API

> masto is an MIT licensed TypeScript client for the Mastodon REST API that runs in Node, browsers and Deno, adds only three runtime dependencies and weighs about 6kB minified and gzipped. It suits anyone building a bot, a timeline viewer or an app against a Mastodon instance.

**neet/masto.js** — 🐘 Universal Mastodon API client for JavaScript

- Repository: https://github.com/neet/masto.js
- Website: https://neet.github.io/masto.js/
- Stars: 785 · Forks: 57
- Language: TypeScript
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/neet-masto-js

## What the client is for, and what it deliberately leaves out

masto is a universal Mastodon API client for JavaScript, written in TypeScript and providing type definitions. The interesting constraint is not the feature list but the dependency count. The package manifest lists three runtime dependencies, change-case, events-to-async and ts-custom-error, and the readme puts a number on the result: 6kB or more minified and gzipped, with a link to bundlephobia for the current figure. For a client that ships to a browser and runs in Node, Deno and browser bundles alike, that is the design goal stated plainly, less runtime code. The package is published under the name masto rather than masto.js, and it is marked with sideEffects false, which lets a bundler drop the module entirely when nothing is imported from it.

## One client across Node, browsers and Deno

The universality claim is about runtimes, not about servers. The readme states it works in Node.js, in browsers and in Deno, and the packaging supports it: the manifest is type module, the main entry is an ES module with a separate types file, and the exports map carries a wildcard subpath so individual API modules can be imported directly rather than only through the barrel file. A browser build cannot depend on Node built-ins, so a client that genuinely runs in all three places has to be written against web platform primitives, which is what keeps the dependency count at three. The minimum versions are Node 22 or newer and npm 9 or newer, with TypeScript 5.0.0 or newer as an optional peer dependency, and yarn, pnpm or other package managers are supported for installation.

## The test suite runs against a real Mastodon

The test claim is specific: 100 percent test coverage using a real Mastodon server, and the repository has the infrastructure for it. The compose file in the root spins up a Postgres service with a healthcheck on pg_isready, a Redis service checked with redis-cli ping, and a Mastodon service built from a development image, exposed on ports 3000 and 4000, with its own healthcheck that wgets the health endpoint with the proxy off, and it depends on both the database and Redis before it starts. The environment for that service comes from a .env.test file in the root, with RAILS_ENV set to development and a command that runs the Rails database setup before foreman start. Running the client against a real instance rather than a mock is a meaningful choice, because it means the tests exercise the actual API surface including the parts a mock would have to guess.

## Creating a bot: install, token, then post

The quick start walks through a bot that publishes a post. You initialise the project as an ES module project first.

```sh
npm init --yes
npm pkg set type=module
```

Then install the client.

```
npm install masto
```

The next step is on the Mastodon side rather than the code side. You go to your settings page, open Development and click New Application to obtain a personal access token, filling in the application name and leaving the rest at defaults, and selecting the scopes your bot needs, with read and write covering most functionality. Then you write the program.

```ts
import { createRestAPIClient } from "masto";

const masto = createRestAPIClient({
  url: process.env.URL,
  accessToken: process.env.TOKEN,
});

const status = await masto.v1.statuses.create({
  status: "Hello from #mastojs!",
});

console.log(status.url);
```

## The versioned API surface and how the client is organised

The client is named for the API version it targets, which is the masto.v1 namespace, so the version of the Mastodon API in use is visible in the code rather than implied. Within it, resources are grouped as you would expect, with statuses under v1.statuses, and the method names are verbs, create being the obvious one. The examples directory in the repository shows the range of what is available: creating a status, creating a status with an image, moderating reports, updating a profile, registering a new application, using a raw method, and two timeline examples, one consuming an iterable and one consuming a stream. The presence of a raw-method example and the streaming timeline example tells you two things about the design, that the library does not hide the HTTP layer entirely, and that streaming is treated as a first-class consumption pattern rather than an afterthought.

## The v8 rewrite and the migration guides

The version history shows a project that has changed shape recently. v8.0.0 was published on 2026-07-27, immediately after v7.13.0 the day before, and v7.12.1 a week earlier. The readme links a migration guide for every major step, from v7 to v8 back to v4 to v5, and each guide is a release note. That pattern is worth reading as a signal about maintenance: a client for a versioned remote API has to change when the remote API changes, and a major version every so often is the honest way to express that rather than accumulating breaking changes silently. The readme also describes the project as actively maintained by a fediverse lover since 2018, and the last push was on 2026-08-01, so the code is current even though the releases come in bursts.

## How the package is built and checked

The manifest scripts show a complete toolchain rather than a minimal one. Tests are run through npm-run-all across all the test scripts, with a typecheck pass using a dedicated tsconfig.test.json, a unit test project and an e2e test project, both driven by vitest with the v8 coverage provider. Linting is eslint with the report-unused-disable-directives flag, formatting is checked with prettier, and there is a separate spellcheck with cspell over the TypeScript and JavaScript sources. The build is tsc against a separate ESM config, and the docs are generated with typedoc from the entry point. There is also a size-limit preset for a small library in the dev dependencies, which is the tool that enforces the bundle size claim, and a purge:cache script that clears a node_modules cache directory for the package. The repository also carries a compose file, test-utils, an EXTENSIONS.md and a CHANGELOG.md.

## Who depends on it, and where to look next

The readme names the projects using it, and they say something about the intended audience. Elk is described as a nimble Mastodon web client and Phanpy as a minimalistic and opinionated Mastodon web client, with a link to the dependency graph for the rest. Both are browser clients, which is consistent with the size constraint: a front end that has to fetch a large timeline cannot also carry a large client library, and the 6kB figure is what makes the library viable in that setting. The project also links Q&A discussions, an examples directory, generated documentation at neet.github.io/masto.js and the releases page, and the licence is MIT. The documentation site is generated by typedoc from the source, which means the reference you read is the same code you install rather than a hand-written subset that can drift.

## Conclusion

masto fits a developer who wants typed access to the Mastodon API in a project that runs in more than one runtime, and who does not want a large dependency tree in a client that ships to a browser. It is the wrong choice if your application also talks to other ActivityPub implementations with different API surfaces, since it targets Mastodon specifically, and the wrong choice if you need the streaming endpoints and cannot deal with their connection model. Before you upgrade across a major version, read the migration guide, because the project publishes one for every major bump.

## FAQ

### What runtimes does masto work in?

It works in Node.js, in browsers and in Deno. The minimum versions are Node 22 or newer and npm 9 or newer, with TypeScript 5.0.0 or newer as an optional peer dependency, and yarn, pnpm or other package managers work for installation.

### How heavy is the masto dependency?

The package has three runtime dependencies, change-case, events-to-async and ts-custom-error, and the readme states 6kB or more minified and gzipped. The manifest also marks the package as sideEffects false so bundlers can drop it when unused.

### How do I get an access token for the masto client?

In Mastodon's settings, open the Development section and click New Application, fill in the application name and choose the scopes your bot needs, with read and write covering most functionality. The resulting access token is what the client authenticates with.

### How are the masto tests run?

Against a real Mastodon server, with the compose file in the repository providing Postgres, Redis and a Mastodon development image. The claim is 100 percent test coverage, and the manifest splits the suites into a typecheck, a unit project and an e2e project.

### Is there a guide for upgrading masto across major versions?

Yes. The readme links a migration guide for each major step, from v7 to v8 back to v4 to v5, and each guide is published as a release note alongside the version it describes.

## Sources

- [License: MIT](https://github.com/neet/masto.js/blob/main/LICENSE)
- [neet/masto.js on GitHub](https://github.com/neet/masto.js)
- [Project website](https://neet.github.io/masto.js/)
- [README](https://github.com/neet/masto.js/blob/main/README.md)
- [Releases](https://github.com/neet/masto.js/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/neet-masto-js
