Introduction
An opinionated Node.js and Express framework for building production ready backends with less boilerplate
Welcome to StarkForge, a backend framework built on top of Node.js and Express. You describe your data and who may use it, and StarkForge turns that description into a working REST API with validation, sign-in, permissions, file uploads, email and consistent errors.
Why StarkForge?
Most backends begin the same way. You connect to the database, validate request bodies, hash passwords, issue sessions, check permissions and shape error responses. Then you repeat all of it in the next project.
StarkForge does that work once, with safe defaults, so a new project starts from a secure base instead of an empty Express file. It is opinionated on purpose: there is one way to declare a resource, one shape for every response and one list of error codes. That keeps your API predictable for the front-end developers who call it, and for you when you come back to it months later.
Built on Express
StarkForge builds a standard Express app. It does not replace the tools you may already know:
- Node.js 20 or newer
- Express 5 for HTTP
- MongoDB with Mongoose for storage
- Zod for request validation
- JWT for sessions
- Cloudinary for file uploads
- Resend for email
You bring your own accounts for the services you use, and you pass their credentials to StarkForge in code.
Start a Server
The smallest StarkForge program creates a Forge and starts it:
// src/server.ts
import { Forge } from "@starklabs/forge";
const forge = new Forge();
await forge.start();Forge is the class that holds your whole API. The start() method connects to the database, mounts the routes and listens on port 5000. In development StarkForge looks for MongoDB at mongodb://127.0.0.1:27017, so MongoDB must be running before you start. Without it, start() fails with DATABASE_UNAVAILABLE after about 10 seconds.
Even with no collections, the server answers one route, a health check:
curl http://localhost:5000/api/v1/healthHTTP/1.1 200 OK
Content-Type: application/json
{
"success": true,
"message": "Service is healthy.",
"data": {
"status": "ok",
"method": "GET",
"uptimeSeconds": 0,
"database": "up",
"timestamp": "2026-01-15T10:30:00.000Z"
}
}Version 2 starts with new Forge(). The 1.x startServer() still works but is deprecated, so new projects should not use it.
What StarkForge Provides
| Area | What you get |
|---|---|
| CRUD collections | Create, read, list, update and delete routes generated from a schema |
| Validation | Zod rules for every request body, with per-field error details |
| Authentication | Sign-up and sign-in with passwords, one-time email codes, magic links, Google, GitHub and authenticator-app codes |
| Authorization | Access levels, roles and per-user ownership on every route |
| Uploads | Image, video and document uploads stored on Cloudinary, with file type checks |
| Emails | 45 built-in templates, sent through Resend |
| Errors | One JSON error shape with a stable code for every failure |
| Security defaults | Rate limits, secure headers, CORS, input sanitizing and Argon2id password hashing |
Less Boilerplate
With StarkForge a resource is a description, not a set of files. The routes, the model, the validators and the error handling all come from one object, so you do not write:
- Express routers and controllers
- Mongoose models
- Validation middleware
- Password hashing and token handling
- A central error handler
More Control
Less code does not mean less control. A collection lists exactly which routes exist, and every route chooses its handler, its access level and its validation. This products collection lets anyone list products, lets signed-in users create them and lets only administrators delete them:
// src/collections/products.ts
import { collection, defineRoutes, fields } from "@starklabs/forge";
import { z } from "zod";
export const products = collection({
type: "crud",
route: "products",
model: "Product",
schema: {
name: fields.requiredString,
price: fields.requiredNumber,
},
validations: {
create: { name: z.string().min(1).max(120), price: z.number().min(0) },
},
routes: defineRoutes([
{ method: "get", path: "/", handler: "readAll", auth: "public" },
{ method: "post", path: "/", handler: "create", auth: "authenticated", validation: "create" },
{ method: "delete", path: "/delete/:id", handler: "remove", auth: "admin" },
]),
});You pass the collection to new Forge({ collections: [products] }), and StarkForge mounts the three routes under /api/v1/products. The Collections page explains every key, and CRUD Collections lists every handler you can use.
What You Can Build
StarkForge suits REST APIs that store their data in MongoDB:
- Backends for web and mobile apps that need sign-in and roles
- Product catalogs and content sites with image or document uploads
- Dashboards and internal tools with administrator-only routes
- APIs for a Next.js, React or mobile front end
StarkForge speaks HTTP and JSON. It does not generate a front end.
Where to Go Next
Quickstart
Build a small API with sign-in and a protected route.
How StarkForge Works
Follow a request from the network to the database and back.
:::