backend-toolkit
Small, dependency-light utilities for Node.js backend developers — response helpers, async error handling, JWT, password hashing, dates, pagination, validation, logging, and env loading. One package, no boilerplate.
Install
npm install backend-toolkit
Quick start
const { success, error, asyncHandler } = require("backend-toolkit");
app.get(
"/users/:id",
asyncHandler(async (req, res) => {
const user = await findUser(req.params.id);
if (!user) return res.status(404).json(error("User not found", 404));
res.json(success(user, "User fetched"));
})
);
Everything is also available as named imports (works via Node's ESM interop for CommonJS packages):
import { success, error, asyncHandler } from "backend-toolkit";
Modules
Response
Consistent success/error response envelopes for your API.
const { success, error } = require("backend-toolkit");
success({ id: 1 }, "User fetched");
// { success: true, statusCode: 200, message: "User fetched", data: { id: 1 }, timestamp: "..." }
error("Invalid credentials", 401);
// { success: false, statusCode: 401, message: "Invalid credentials", errors: null, timestamp: "..." }
success(data?, message?, statusCode?)error(message?, statusCode?, errors?)
Async handling
Wraps an async route handler so thrown errors and rejected promises are
forwarded to next() instead of crashing the process or requiring a
try/catch in every controller.
const { asyncHandler } = require("backend-toolkit");
app.get(
"/orders",
asyncHandler(async (req, res) => {
const orders = await Order.find();
res.json(orders);
})
);
JWT
Thin wrapper around jsonwebtoken.
const { signToken, verifyToken, decodeToken } = require("backend-toolkit");
const token = signToken({ userId: 1 }, process.env.JWT_SECRET, { expiresIn: "1h" });
const payload = verifyToken(token, process.env.JWT_SECRET); // throws on invalid/expired
const claims = decodeToken(token); // reads claims without verifying the signature
Password
Thin wrapper around bcryptjs.
const { hashPassword, comparePassword } = require("backend-toolkit");
const hash = await hashPassword("Sup3rSecret!"); // default 10 salt rounds
const matches = await comparePassword("Sup3rSecret!", hash); // true
Date
Thin wrapper around dayjs.
const {
now,
formatDate,
addTime,
subtractTime,
diff,
isBefore,
isAfter,
} = require("backend-toolkit");
formatDate(new Date(), "YYYY-MM-DD");
addTime(new Date(), 7, "day");
diff("2024-01-10", "2024-01-01", "day"); // 9
isBefore("2024-01-01", "2024-02-01"); // true
Pagination
const { paginate, getPaginationParams } = require("backend-toolkit");
const { page, limit } = getPaginationParams(req.query); // parses & clamps req.query
const meta = paginate({ page, limit, totalItems: await User.countDocuments() });
// { page, limit, offset, totalItems, totalPages, hasNextPage, hasPrevPage }
Validation
Built on zod. validate() never throws — it returns a normalized result.
const { validate, rules } = require("backend-toolkit");
const { z } = require("zod");
const schema = z.object({ email: rules.email, password: rules.password });
const result = validate(schema, req.body);
if (!result.success) {
return res.status(400).json(error("Validation failed", 400, result.errors));
}
// result.data is the parsed, type-coerced payload
Built-in rules: email, password (min 8 chars, 1 uppercase, 1 number),
mongoId, uuid, pagination ({ page, limit } with defaults).
Logger
Structured JSON logging (pino) in production; colorized, readable console
output in development — no extra pino-pretty dependency required.
const { logger, createLogger } = require("backend-toolkit");
logger.info("Server started");
logger.error("Something went wrong", err);
const requestLogger = createLogger({ level: "debug" });
Controlled by NODE_ENV (production → pino JSON) and LOG_LEVEL
(defaults to info).
Env
Loads .env via dotenv and, optionally, validates process.env against a
Zod schema — so misconfiguration fails fast at startup.
const { loadEnv } = require("backend-toolkit");
const { z } = require("zod");
const env = loadEnv(
z.object({
PORT: z.coerce.number().default(3000),
JWT_SECRET: z.string().min(1),
})
);
// throws a descriptive error if PORT/JWT_SECRET are missing or invalid
Full runnable examples
See examples/express.js and
examples/fastify.js for complete apps wiring
several modules together (signup with validation + password hashing + JWT,
paginated listing, centralized error handling).
Development
npm install
npm test # run the test suite
npm run lint # lint
npm run format # format with prettier
npm run build # bundle to dist/ (CJS + type declarations)
License
ISC Owskar