S
Get Started

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:

TypeScript
// 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:

Bash
curl http://localhost:5000/api/v1/health
Text
HTTP/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"
  }
}
Coming from 1.x

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

AreaWhat you get
CRUD collectionsCreate, read, list, update and delete routes generated from a schema
ValidationZod rules for every request body, with per-field error details
AuthenticationSign-up and sign-in with passwords, one-time email codes, magic links, Google, GitHub and authenticator-app codes
AuthorizationAccess levels, roles and per-user ownership on every route
UploadsImage, video and document uploads stored on Cloudinary, with file type checks
Emails45 built-in templates, sent through Resend
ErrorsOne JSON error shape with a stable code for every failure
Security defaultsRate 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:

TypeScript
// 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.

:::