The simplest web framework and site generator yet.
🤗 For people who care about their users and web standards.
👨🍳 Build directly on top of the browser and Node.js, Deno, Bun, or Workers.
Mastro was designed from the ground up to use modern browser and runtime built-ins, enabling a radically simpler design where everything is a route.
Get started Docs ☆ Mastro on GitHub
As seen on the Internet!
Mastro's source code is extremely readable.
– Erik Onarheim
A library worth checking out!
– Jared White
Minimal yet powerful
- Static site generation – ideal for blogs, marketing sites or webshops that are fast.
- Server-side rendering – use Mastro’s composable primitives as a full-stack web framework.
- Everything is a route: serve HTML, JSON REST APIs, CSS, and images with the same API.
- Adopt incrementally: use templates in your existing codebase or migrate route by route.
No dependencies, no build step
- No bloat: implemented in just ~800 lines of TypeScript, Mastro is fast.
- No build step (until you add one): your code ships exactly how you wrote it.
- No JavaScript (until you ship some): create MPA websites that load extremely fast.
- No dependencies: use web standards instead of keeping up with the frontend treadmill.
- No VC-money: no eventual enshitification – selling is none of our business.
- No lock-in: swap out Mastro later or fork it – it’s only ~800 lines.
// Respond to a HTTP GET with plain text
export const GET = () => {
return new Response("Hello World");
}
import { jsonResponse } from "@mastrojs/mastro";
import { addComment } from "../models/comments.ts";
// Respond to a HTTP POST with JSON
export const POST = async (req: Request) => {
const data = await req.json();
const comment = await addComment(data);
return jsonResponse(comment);
};
import { readMarkdownFiles } from "@mastrojs/markdown";
import { html, htmlToResponse } from "@mastrojs/mastro";
import { Layout } from "../components/Layout.ts";
// Respond with HTML
export const GET = async () => {
const posts = await readMarkdownFiles("posts/*.md");
return htmlToResponse(
Layout({
title: "My blog",
children: posts.map((post) => html`
<p>${post.meta.title}</p>
`)
})
);
};
import { html, type Html } from "@mastrojs/mastro";
interface Props {
title: string;
children: Html;
}
export const Layout = (props: Props) =>
html`
<!DOCTYPE html>
<html lang="en">
<head>
<title>${props.title}</title>
</head>
<body>
<h1>${props.title}</h1>
${props.children}
</body>
</html>
`;
More examples Source of this website
Easy for beginners
With Mastro, there is very little to learn – except for the web standards HTML, CSS, and JavaScript.
No installation needed
The popular VS Code editor also runs in the browser: put your first website live without installing anything on your computer.
Learn the fundamentals
Start with HTML and CSS. Then build a static blog, a to-do list app with JavaScript. Finally, run a server with a REST API.
Powerful for experienced developers
I’ve seen things you wouldn’t believe. Megabytes of JavaScript on fire in the browser. I watched towers of complex abstractions collapse upon themselves. All those websites will be lost in time, like tears in rain. Time to let them die.
There are various ways to run Mastro and deploy to production. To get started, the easiest is Deno.
Install Deno and copy and paste into your terminal (or use the template repo):
deno run -A npm:@mastrojs/create-mastro@0.1.6
Install pnpm (although npm and yarn also work). Then install Node.js (if you haven’t already) with pnpm runtime set node lts -g Finally, use the template repo or run:
pnpm create @mastrojs/mastro@0.1.6
Copy and paste into your terminal (or use the template repo):
bun create @mastrojs/mastro@0.1.6
However, to run code on-demand in a Cloudflare Worker, (use the template repo) or run:
pnpm create @mastrojs/mastro@0.1.6 --cloudflare
Finally, Mastro can also run code on-demand inside a Service Worker in the user’s browser.
☆ Mastro on GitHub Docs Launch Mastro in your browser
Fast for everyone
Great UX: websites built with Mastro are fast – even on low-end devices on 3G.
Performance
Accessibility
SEO
Great DX: dev server starts instantly, and SSG is fast – e.g. for 500 markdown files:
| Mastro | 0.5s | 🏁 |
| 11ty | 0.7s | |
| Astro | 2.2s | |
| Next.js | 16.3s |
Why Mastro instead of…
Next.js
Next.js creates bloated SPAs: every feature you add increases the amount of JS your users have to download. Running your code on the server, then running it again on the client, also adds a lot of complexity.
Astro
Astro was a big inspiration for Mastro (the name originated from “minimal Astro”). But Astro currently has 246 dependencies weighing 87 MB. Astro is also heavily coupled to its bundler, which makes some simple things surprisingly complex.
11ty
Eleventy has a lot of options around static site generation, but it doesn’t run as a server. It is not TypeScript-first, and currently still has 116 dependencies weighing 14 MB.
Hono
Hono is almost as minimal as Mastro. But it is more backend focused (e.g. it doesn’t come with a file-based router).
Escape the frontend treadmill
With today’s browsers and engines, there is no need for complex frameworks and build systems anymore.
A foundation to build upon
The minimal Mastro core package doesn’t come “batteries included”, but it is built to be extended.
Extensions
- Tiny libs in the
@mastrojsnamespace: - Install 3rd-party packages like:
- Kysely – type-safe SQL query builder
- Sveltia CMS – git-based CMS
Client-side interactivity
When you need interactivity in the browser, use plain JavaScript, or add a library such as HTMX, Alpine, Unpoly, ArrowJS, etc.
To share templates with the server, use Reactive Mastro – a tiny reactive GUI lib.
Join the community
We’re building an inclusive community, where people of all kinds of backgrounds and experience levels feel welcome and safe, and help each other. A place to ask questions and learn new things.
This is the end of the page. Yet it may be the beginning of your journey with Mastro.
