v0.3.14

Express, but your folder
is your router.

Drop a file in src/api/ and it's a route. Every CPU core serves traffic by default. Heavy work gets its own queue. One ignite() call. No ceremony.

terminal
$ npx create-efc-app my-api
$ cd my-api && efc start dev

✔ Worker 1 ready on :3000
✔ Worker 2 ready on :3000
✔ Worker 3 ready on :3000
✔ Worker 4 ready on :3000
→ GET  /health         src/api/health.ts
→ GET  /users          src/api/users/index.ts
→ POST /users          src/api/users/index.ts
→ GET  /users/:id      src/api/users/[id].ts

Three things Express
never gave you out of the box.

Most Express apps end up with the same three pain points. EFC solves all three at the convention level.

Routing by filesystem

src/api/users/[id].ts becomes /users/:id. No router files, no app.use() chains. Add a file, get a route. Rename it, the URL renames too.

CPU-aware from day one

Node runs on one core by default. EFC forks one worker per CPU at startup, lets the OS distribute connections, and respawns crashed workers before you notice.

Tasks aren't routes

Sending an email or resizing an image shouldn't block a response. Files in src/tasks/ run off the request path — in a queue, with retries, optionally in their own thread.

Auth picked at scaffold time

You choose http-only cookies or Bearer tokens once, during create-efc-app. A real JWT_SECRET lands in .env automatically. export const middlewares = [requireAuth] is all protection takes.

Same model, any database

defineModel gives you identical .find(), .create(), .delete() calls on MongoDB today — PostgreSQL is scaffoldable but the adapter itself lands in Phase 2.

efc doctor ships with it

Run efc doctor to check config, env vars, DB connectivity, and worker setup before you deploy. efc routes prints the resolved route table if something looks wrong.

Mailer, without the SMTP guesswork

Pick Gmail and the scaffolder preconfigures smtp.gmail.com — no host or port to type. It walks you straight to generating a 16-character App Password instead of your real one, and wires a working nodemailer task on the other end.

Roles, generated not hand-rolled

Toggle RBAC at scaffold time and every protected route swaps in requireRole(...roles) automatically, backed by a real Role model — instead of an inline if (user.role !== 'admin') check.

A whole app, not a hello-world

Enable User and Admin portal and get 15+ models — sessions, notifications, files, subscriptions, invoices, coupons, FAQs — and 80+ working routes to match. Not stubs: real auth, billing, and content endpoints.

Less setup.
More shipping.

Your folder structure is your API

EFC walks src/api/ at boot and registers every file as a route. [id].ts:id. index.ts → the directory path. Unregistered HTTP verbs get a 405 back — you don't write that logic.

  • Rename a file → rename the route
  • Per-file middleware: export const middlewares = [...]
  • Per-handler guards via compose()
src/api/users/[id].ts
import type { Request, Response } from 'express';
import { User } from '../../model/User.js';
import { HttpError } from 'express-file-cluster';

export const GET = async (req: Request, res: Response) => {
  const user = await User.findById(req.params.id);
  if (!user) throw new HttpError(404, 'User not found');
  res.json(user);
};

export const DELETE = async (req: Request, res: Response) => {
  await User.delete(req.params.id);
  res.status(204).send();
};

202 now, do the work later

A file in src/tasks/ is a named job. Call enqueue('SendEmail', payload) from any handler and return immediately. EFC picks the right execution model — event loop for I/O, worker_threads for CPU.

  • BullMQ (Redis) today — pg-boss is scaffoldable but not yet implemented
  • Automatic retries + exponential backoff
  • Cron scheduling via schedule in defineTask (planned, not yet executed)
src/tasks/SendEmail.ts
import { defineTask } from 'express-file-cluster/tasks';

// Task name = filename
export default defineTask<{ to: string; subject: string }>(
  async (payload) => {
    await mailer.send(payload);
  }
);

// Trigger from a route — respond immediately
export const POST = async (req, res) => {
  const user = await User.create(req.body);
  await enqueue('SendEmail', { to: user.email });
  res.status(202).json({ id: user.id, queued: true });
};

Pick once, forget about it

Answer one question during scaffolding: SSR app or SPA? EFC writes the login/logout route stubs, sets the cookie flags, generates a real JWT_SECRET, and puts requireAuth in scope. You protect a route with a single export.

  • HttpOnly + Secure + SameSite=Strict out of the box
  • No secret management ceremony — it's in .env
  • Role payload baked into the token, readable in any handler
src/api/auth/login.ts
import { issueToken, requireAuth }
  from 'express-file-cluster/auth';

export const POST = async (req, res) => {
  const user = await verifyCredentials(req.body);
  issueToken(res, { sub: user.id, role: user.role });
  res.json({ message: 'Logged in' });
};

// src/api/users/index.ts — protect with one line
export const middlewares = [requireAuth];

export const GET = async (req, res) => {
  res.json(await User.find());
};

Gmail, without the password mistake

Choose Gmail and the scaffolder skips host/port entirely — smtp.gmail.com is preconfigured. It then walks you to generating a 16-character App Password and rejects anything that isn't one, so you don't discover the hard way that Google blocks real passwords over SMTP.

  • Gmail or any custom SMTP provider — your choice
  • App-password length validated at scaffold time
  • Real nodemailer transport, not a stub
src/tasks/SendEmail.ts
import { defineTask } from 'express-file-cluster/tasks';
import nodemailer from 'nodemailer';

// .env — SMTP_PASS must be a 16-char Gmail App Password,
// not your normal Gmail login password
const transporter = nodemailer.createTransport({
  host: process.env.SMTP_HOST,
  port: Number(process.env.SMTP_PORT ?? 587),
  secure: Number(process.env.SMTP_PORT) === 465,
  auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASS },
});

export default defineTask(async (payload) => {
  await transporter.sendMail({
    from: process.env.SMTP_FROM ?? process.env.SMTP_USER,
    to: payload.to,
    subject: payload.subject,
    html: payload.body,
  });
});

ignite() — one entry point

Pass cluster and tasks. Everything else — port, database, auth, secrets, CORS — is read from .env and efc.config.ts. EFC runs the Pre-Flight sequence on every worker: connect → configure auth → scan routes → register tasks → listen.

  • Worker count defaults to os.cpus().length
  • Crashed workers are replaced before the next request lands
  • dev mode: single process, hot reload, source maps
src/index.ts
import { ignite, gracefulShutdown } from 'express-file-cluster';

// PORT, DATABASE_URL, JWT_SECRET, CORS_ORIGINS → read from .env
// authStrategy, globalMiddlewares → efc.config.ts
ignite({
  cluster: true,
  tasks: { backend: 'bullmq' },
}).then(gracefulShutdown).catch(console.error);

Read the spec.
Then build.

Changelog

express-file-cluster v0.3.14
Jul 19, 2026
SCHEMA

Schema Default Operators, Auto-Increment Fields & Request Context

defineModel field defaults now accept sentinel operator codes resolved fresh per document instead of a static value: '$now', '$uuid', '$objectId', '$timestamp', '$shortId', and '$currentUser' / '$currentUser.<key>' — the latter reads the authenticated request's JWT payload via a new AsyncLocalStorage-backed context, exposed as getCurrentUser() from express-file-cluster/auth. A new sequence field option adds real auto-incrementing counters (backed by an atomic, upsert-safe internal collection) for cases default can't handle, since it resolves synchronously. defineModel also takes an optional third ModelOptions argument to control mongoose's timestamps behavior per model instead of it being hardcoded on.

Also fixed two CLI bugs found while reviewing Phase 1: efc doctor was checking process.env directly and reporting DATABASE_URL/ JWT_SECRET as missing even when they were set in .env, since nothing had loaded it into the process; and efc start dev could silently fail to force development mode if the parent shell already exported NODE_ENV=production, undermining the documented single-process dev guarantee.

express-file-cluster v0.3.12 / create-efc-app v0.3.12
Jul 10, 2026
SCAFFOLDER

Granular Portal Features, Request Timeouts & Structured Errors

The create-efc-app wizard now lets you toggle individual sub-features within the User and Admin portals — analytics, billing, support tickets, content management, and more — instead of an all-or-nothing switch, and only scaffolds the models and routes each selection actually needs. express also moved to a peer dependency so your project controls its own Express version.

On the framework side, EFCConfig gained a requestTimeout option (milliseconds) — requests that run longer are terminated with a 408 instead of hanging indefinitely — and HttpError now implements toJSON(), so it serializes consistently whether it's caught by the global error interceptor or passed straight to res.json().

express-file-cluster v0.3.1 / create-efc-app v0.4.1
Jul 2, 2026
DASHBOARD

Per-Method Route Documentation

RouteMeta is now keyed by HTTP method — { GET: { description, request?, response? }, PUT: { ... } } — so each verb on a multi-method route gets its own doc block in the dashboard instead of sharing one flat description. The new RouteMethodMeta interface is exported from express-file-cluster.

The dashboard renderer was updated to show one collapsible block per implemented method. All 76 routes in the example app and every template in create-efc-app were converted — including the full CRUD generators for admin/content/* and admin/billing/*. Routes that previously had no meta at all (sessions, notifications, files, favorites, bookmarks, api-keys, roles, billing, admins) now have real per-method examples.

express-file-cluster v0.2.11 / create-efc-app v0.3.7
Jul 2, 2026
AUTH

Real Password Reset, Email Verification & Refresh Tokens

forgot-password, reset-password, verify-email, and refresh now ship with real MongoDB-backed logic instead of // TODO stubs — token generation, expiry checks, and a rotating, DB-stored refresh token — in both the example app and everything create-efc-app scaffolds. register and login were updated to issue the verification and refresh tokens these routes consume.

requireAuth also gained a role-check shorthand: requireAuth('admin') now verifies the JWT and checks the role in one call, replacing the old separate requireRole middleware pattern everywhere — see RBAC. When Mailer is also enabled, the reset/verification routes call enqueue('SendEmail', ...) automatically.

create-efc-app v0.3.5
Jul 2, 2026
MAILER

Gmail App-Password Wizard

The mailer setup no longer asks for a raw SMTP host/port. Pick Gmail and smtp.gmail.com is preconfigured automatically — you're walked straight to generating a 16-character App Password, and the wizard rejects anything that isn't one. Picking Other still lets you enter a custom SMTP host and port.

mcp v0.2.0
Jun 30, 2026
TOOLING

efc-docs-mcp Server

Added a companion MCP server (mcp/) exposing this documentation as 10 resources, 12 tools, and 6 prompts to MCP-compatible AI assistants — scaffold routes/tasks, resolve file-to-URL mappings, and check known EFC gotchas without leaving your editor.

v0.2.3
Jun 25, 2026
DASHBOARD

Dev Dashboard & Route Metadata

Added a live API documentation page (set dashboard: true) that auto-generates from route meta exports in development. Response bodies render as type names. Added basePath config option and fixed NODE_ENV to be a default overridable by .env.

v0.2.2
Jun 24, 2026
CONVENTIONS

Strict API Paths & Default Dashboards

Removed apiDir and tasksDir configurations to strictly enforce directory conventions. Scaffolding tool now automatically generates standard admin and user dashboards, alongside default authentication endpoints.

v0.2.1
Jun 23, 2026
CORE

Native Async Web Crypto & Optimizations

Migrated to native async Web Crypto via jose, removed legacy dotenv runtime execution, and replaced chalk with picocolors for faster CLI performance.

v0.1.8
Jun 23, 2026
TOOLING

Diagnostic Commands & Live Reloading

Added efc doctor diagnostics, efc routes, and efc tasks commands. Stabilized cluster scaffolding with proper .env injection and integrated local file change monitoring.

v0.1.5
Jun 23, 2026
CI/CD

Automated Workflows & Build Stability

Added automated NPM publishing via GitHub Actions and fixed production build configuration issues to ensure seamless developer experience for new projects.

v0.1.0
Jun 23, 2026
ARCHITECTURE

Core Framework Release

Initial core MVP framework release featuring zero-boilerplate file-based routing, multi-core CPU clustering, authentication adapters, and background task processing.

Phase 1 shipped.
Beta next.

Phase 0
Done

Design & Planning

  • API surface design
  • Architecture documentation
  • Monorepo scaffold
Phase 1
Done ✓

Core MVP

  • File-based router
  • Multi-core clustering
  • Auth + MongoDB adapter
  • Background tasks (BullMQ)
  • npx create-efc-app
  • Per-method API dashboard
  • MCP docs server
Phase 2
Now

Beta

  • PostgreSQL adapter
  • Zod validation integration
  • Structured logging
  • Cron task scheduling
Phase 3
Q1 2027

Stable v1.0

  • Plugin / adapter API
  • WebSocket support
  • OpenAPI spec generation
  • OpenTelemetry tracing

Phase 1 is live.
Phase 2 starts now.

File-based routing, multi-core clustering, auth, background tasks, the scaffolder, and a live per-method API dashboard are all shipped. Phase 2 — PostgreSQL adapter, Zod validation, and cron scheduling — is next. Come build it.