Skip to main content
Semola has zero runtime dependencies. This is not a coincidence—it’s a core design principle that makes your applications more secure, faster, and easier to maintain.

Why zero dependencies matter

No supply chain attacks

Every dependency you add is a potential security risk. The 2024 left-pad incident and the event-stream compromise showed how quickly malicious code can propagate through npm’s dependency tree. With Semola, you only audit one package: Semola itself. There are no transitive dependencies to worry about.
# Traditional framework
npm install express
# Installs 50+ packages you didn't ask for

# Semola
bun add semola
# Installs exactly 1 package

Smaller bundle sizes

Zero dependencies means smaller bundle sizes. Your production builds stay lean because you’re not shipping unused code from deep dependency chains.
{
  "dependencies": {
    "semola": "^0.5.0"
  }
}
The Semola package.json shows this commitment:
{
  "name": "semola",
  "version": "0.5.1",
  "peerDependencies": {
    "typescript": "^5"
  }
}
No runtime dependencies. TypeScript is a peer dependency because it’s only needed during development.

Faster installs

No dependencies means no dependency resolution. Your bun install or npm install completes in milliseconds, not minutes.

Tree-shakeable by design

Semola exports modules as separate entry points, so bundlers can eliminate unused code:
// Only imports the errors module
import { ok, err } from 'semola/errors';

// Your bundle won't include code from semola/api, semola/queue, etc.
This modular architecture is defined in package.json:
"exports": {
  "./errors": {
    "import": "./dist/lib/errors/index.js",
    "types": "./dist/lib/errors/index.d.ts"
  },
  "./cache": {
    "import": "./dist/lib/cache/index.js",
    "types": "./dist/lib/cache/index.d.ts"
  }
}

How Semola achieves zero dependencies

Native Bun APIs

Semola leverages Bun’s native APIs instead of pulling in third-party packages:
  • HTTP server: Uses Bun.serve() instead of Express or Fastify
  • Cookie parsing: Uses Bun.CookieMap instead of cookie-parser
  • JSON handling: Native Response.json() instead of body-parser
const cookieHeader = req.headers.get("cookie") ?? "";
const cookieMap = new Bun.CookieMap(cookieHeader);
const cookies = Object.fromEntries(cookieMap);

Simple implementations

Semola keeps implementations minimal. The entire errors module is 28 lines:
src/lib/errors/index.ts
export const ok = <T>(data: T) => {
  return [null, data] as const;
};

export const err = <T extends CommonError>(type: T, message: string) => {
  return [{ type, message }, null] as const;
};

export const mightThrow = async <T>(promise: Promise<T>) => {
  try {
    const data = await promise;
    return [null, data] as const;
  } catch (error) {
    return [error, null] as const;
  }
};
No need for a heavyweight error handling library when 28 lines does the job.

Framework-agnostic validation

Instead of depending on a specific validation library, Semola uses Standard Schema, an interface that works with any validation library:
src/lib/api/core/types.ts
import type { StandardSchemaV1 } from "@standard-schema/spec";

export type RequestSchema = {
  params?: StandardSchemaV1;
  body?: StandardSchemaV1;
  query?: StandardSchemaV1;
  headers?: StandardSchemaV1;
  cookies?: StandardSchemaV1;
};
@standard-schema/spec is a type-only package with zero runtime code. It adds 0 bytes to your bundle.

The tradeoffs

Zero dependencies isn’t free:
  • More code to maintain: Semola implements functionality that could be imported
  • Limited scope: Semola focuses on what Bun does best and avoids complex features
  • Peer dependencies: You bring your own validation library (Zod, Valibot, etc.)
But for most applications, these tradeoffs are worth it. You get a more secure, performant, and maintainable foundation.

Comparison with other frameworks

FrameworkDependenciesInstall sizeSecurity surface
Semola0~50KB1 package
Express31~1.2MB32 packages
Fastify12~800KB13 packages
Hono0~40KB1 package
Elysia3~200KB4 packages
Want to see what’s in your node_modules? Run npm ls --all in an Express project vs. a Semola project. The difference is stark.

Build docs developers (and LLMs) love