Skip to content

Minima.jsThoughtfully Designed for Modern Runtimes

Most frameworks optimize features. Minima.js optimizes how it feels to work every day.

Minima.js

How It Feels to Build

Watch how little code you need to write. Notice what you DON'T see—no imports, no registration, no wiring.

typescript
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 point
typescript
import { type Meta } from "@minimajs/server";
import { cors } from "@minimajs/server/plugins";

// Global config - applies to every route
export const meta: Meta = {
  prefix: "/api",
  plugins: [cors()],
};

// sync / async supported
export default async function (app) {
  app.get("/health", () => ({ status: "ok" }));
}
typescript
// Auto-loaded as /api/users/*

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 default function (app) {
  app.get("/list", getUsers);
  app.post("/create", createUser);
}
typescript
// Auto-loaded as /api/posts/*

function getLatestPosts() {
  return { posts: [] };
}
export default function (app) {
  app.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 user
  • GET /api/posts/latest{"posts":[]}

Add Authentication in Seconds

Protected routes? Just add a plugin to meta.plugins:

typescript
import { type Meta } from "@minimajs/server";
import { authPlugin, guardPlugin, getUser } from "../auth/index.js";

export const meta: Meta = {
  plugins: [
    authPlugin, // Makes getUser() available
    guardPlugin, // Requires authentication
  ],
};

export default async function (app) {
  app.get("/profile", () => {
    const user = getUser(); // Guaranteed to exist (guard ensures it)
    return { user };
  });
}

No decorators. No middleware chains. Just declare what you need.

See full JWT authentication tutorial →


True Module Encapsulation

Each module creates an isolated scope. Plugins, hooks, and configuration stay contained—no accidental global state, no sibling interference.

typescript
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()],
};
typescript
import { type Meta } 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"))],
};

export default async function (app) {
  app.get("/list", () => [
    /* users */
  ]);
}
typescript
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 default async function (app) {
  app.get("/latest", getPosts);
}

How it works:

  • ✅ Root module plugins → Inherited by all children
  • ✅ Parent module plugins → Inherited by their children only
  • ✅ Sibling modules → Completely isolated from each other
  • ✅ Child can override or extend parent behavior
  • ✅ No global state pollution

Request to /api/users/list:

→ Root plugins run (cors)
→ Users plugins run (logging hook)
→ Route handler executes

Request to /api/posts/latest:

→ Root plugins run (cors)
→ Route handler executes
✅ Users logging hook DOES NOT run (isolated)

REST API with Auth

src/
├── module.ts           # Global auth, body parsing, CORS
├── auth/
│   └── module.ts       # POST /auth/login (public)
└── users/
    └── module.ts       # GET/POST /users/* (protected)