Web Standards First
Use Request, Response, File, Blob, URL, and ReadableStream directly. Less framework-specific code, easier portability.
Build APIs with Web standards, file-based modules, and context-aware helpers that reduce boilerplate.
Watch how little code you need to write. Notice what you DON'T see—no imports, no registration, no wiring.
import { createApp } from "@minimajs/server/bun";
// import { createApp } from "@minimajs/server/node"; // for node
const app = createApp();
await app.listen({ port: 3000 });
// That's your entire entry pointimport type { Meta, Routes } from "@minimajs/server";
import { cors } from "@minimajs/server/plugins";
// Global config - applies to every route
export const meta: Meta = {
prefix: "/api",
plugins: [cors()],
};
function getHealth() {
return { status: "ok" };
}
export const routes: Routes = {
"GET /health": getHealth,
};// Auto-loaded as /api/users/*
import type { Routes } from "@minimajs/server";
import { body } from "@minimajs/server";
function getUsers() {
return [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" },
];
}
function createUser() {
const user = body();
return { created: user };
}
export const routes: Routes = {
"GET /list": getUsers,
"POST /create": createUser,
};// Auto-loaded as /api/posts/*
import type { Routes } from "@minimajs/server";
function getLatestPosts() {
return { posts: [] };
}
export const routes: Routes = {
"GET /latest": getLatestPosts,
};Your API is ready:
GET /api/health → {"status":"ok"}GET /api/users/list → [{"id":1,"name":"Alice"}...]POST /api/users/create → Creates userGET /api/posts/latest → {"posts":[]} Most frameworks optimize features.
Minima.js optimizes how it feels to work every day.
Upload handling with @minimajs/multipart gives you native File instances—no custom wrappers, no learning curve.
import type { Routes } from "@minimajs/server";
import { multipart, helpers } from "@minimajs/multipart";
export async function uploadAvatar() {
// Returns native File instance - holds data in memory
const avatar = await multipart.file("avatar");
// Or use streaming without memory overhead
// const avatar = streaming.file("avatar");
// Move file to destination
await helpers.save(avatar, "./uploads/avatars");
// File is a valid Response - renders with correct content-type
return avatar;
}
export const routes: Routes = {
"POST /avatar": uploadAvatar,
};What you get:
File instances (Web Standards API)multipart.file() reads entire file into memoryFile works as Response automatically@minimajs/multipart/schema Zod guards your uploads, disk handles the weightEach module creates an isolated scope. Plugins, hooks, and configuration stay contained—no accidental global state, no sibling interference.
import { type Meta } from "@minimajs/server";
import { cors } from "@minimajs/server/plugins";
// Root module - these plugins apply to ALL children
export const meta: Meta = {
prefix: "/api",
plugins: [cors()],
};import type { Meta, Routes } from "@minimajs/server";
import { hook } from "@minimajs/server";
// Users module - this hook ONLY affects /api/users/* routes
export const meta: Meta = {
plugins: [hook("request", () => console.log("Users accessed"))],
};
function listUsers() {
return [
/* users */
];
}
export const routes: Routes = {
"GET /list": listUsers,
};import type { Routes } from "@minimajs/server";
import { searchParams } from "@minimajs/server";
// Posts module - no logging hook here
// Completely isolated from users module
function getPosts() {
// contexts will be available everywhere
const page = searchParams.get("page", Number); // cast page to number
return {
page,
data: [], // posts
};
}
export const routes: Routes = {
"GET /latest": getPosts,
};How it works:
Request to /api/users/list:
→ Root plugins run (cors)
→ Users plugins run (logging hook)
→ Route handler executesRequest to /api/posts/latest:
→ Root plugins run (cors)
→ Route handler executes
✅ Users logging hook DOES NOT run (isolated)Choose the path that matches what you need right now:
Minima.js is open-source and community-driven.
If you are evaluating frameworks right now, start with Getting Started and build one real route module before deciding.