Skip to main content

Commodity

The first fully type-inferred, type-safe and hyper-minimalistic DI solution for Typescript!
No OOP, reflect-metadata, decorators, annotations or compiler magic, just simple functions.

~3KBBundle size
0Dependencies
100%Type safe
commodity-demo.ts
import { createMarket, index } from "commodity"

// Create market and define suppliers
const market = createMarket()
const $$session = market.offer("session").asResource<{ userId: string }>()
const $$api = market.offer("api").asProduct({
suppliers: [$$session],
factory: ($) => new ApiClient($($$session).userId)
})

// Assemble with type safety
const api = $$api
.assemble(index($$session.pack({ userId: "123" })))
.unpack()

// Use it!
const users = await api.getUsers()
Commodity Logo

Why choose Commodity?

Built for modern TypeScript applications that demand performance, safety, and simplicity.

πŸ’‘

Fully Type-Inferred

Zero type boilerplate. End-to-end type safety with compile-time dependency validation and no extra type definitions.

✨

No Magic

Just functions and closures. No OOP, reflect-metadata, decorators, or compiler magic. What you see is what you get.

πŸš€

Performance Focused

Smart memoization, lazy loading, and a tiny bundle size (~3KB). Designed for minimal runtime overhead.

πŸ§ͺ

Testing Friendly

Easy mocking and dependency swapping. Swap implementations effortlessly to achieve perfect test isolation.

πŸ—οΈ

Scalable Architecture

Promotes SOLID, clean, and code-splittable design patterns that grow with your application.

🌍

Framework Agnostic

Works anywhere TypeScript works. Use it in React, Node.js, Deno, or Bunβ€”from frontend to backend.

πŸ”„

Stateless

Dependencies are resolved via closures, not global state. This ensures clean, predictable, and easy-to-reason-about behavior in any environment.

πŸ“–

Intuitive Terminology

A supply chain metaphor (Market, Product, Resource) that makes dependency injection feel natural and easier to understand.

πŸ†•

A New DI Paradigm

Don't let your past experiences with DI prevent you from trying this solution!

Commodity Logo

Fully Type-Inferred from End to End

Catch dependency errors before they reach production. Commodity's architecture provides end-to-end type inference, eliminating entire classes of bugs and ensuring your dependency graph is always valid.

const $$config = market.offer("config").asResource<{
api: { baseUrl: string };
}>();

const $$db = market.offer("db").asProduct({
factory: () => new DatabaseClient() // Returns a DatabaseClient instance
});

const $$userService = market.offer("userService").asProduct({
suppliers: [$$config, $$db],
factory: ($) => {
// No explicit types needed! They are all inferred.

const config = $($$config);
// ^? const config: { api: { baseUrl: string } }
// (Inferred from the .asResource<T>() definition)

const db = $($$db);
// ^? const db: DatabaseClient
// (Inferred from the $$db's factory return type)

return {
getUser: (id: string) => db.fetchUser(id, config.api.baseUrl)
};
}
});
Commodity Logo

Unmatched Performance

Smart memoization: dependencies are created in parallel once per context eagerly, and cached. Or choose lazy loading to defer the creation of expensive services until they are first accessed.

// An expensive service, lazy-loaded for on-demand performance.
const $$reportGenerator = market.offer("reporter").asProduct({
factory: () => {
// This expensive logic runs only ONCE, the first time it's needed.
console.log("πŸš€ Initializing Report Generator...");
return new ReportGenerator();
},
lazy: true
});

const $$app = market.offer("app").asProduct({
suppliers: [$$reportGenerator],
factory: ($) => (userAction: "view_dashboard" | "generate_report") => {
if (userAction === "generate_report") {
// The generator is created on the first call thanks to lazy loading.
// Subsequent calls within the same context will reuse the
// same, memoized instance without running the factory again.
const reporter = $($$reportGenerator);
reporter.generate();
}
}
});
Commodity Logo

Effortless Testing

Isolate components completely. With .prototype(), you can create alternative implementations for testing that remove entire dependency trees, leading to cleaner and more robust tests.

// A product that depends on a real database.
const $$userProfile = market.offer("userProfile").asProduct({
suppliers: [$$db],
factory: ($) => ({
bio: $($$db).fetchBio()
})
});

// For tests, create a prototype with no dependencies.
const mockUserProfile = $$userProfile.prototype({
suppliers: [], // <-- No database needed!
factory: () => ({
bio: "This is a mock bio for testing."
})
});

// The component we want to test.
const $$app = market.offer("app").asProduct({
suppliers: [$$userProfile],
factory: ($) => `<div>${$$(userProfile).bio}</div>`
});

// In the test, just .try() the prototype.
// No need to provide a database connection!
const app = $$app.try(mockUserProfile).assemble().unpack();
Commodity Logo

Perfect for modern apps

From React components to API servers, Commodity adapts to your architecture.

βš›οΈ

React Applications

Eliminate prop drilling. Share context across components without global state or complex providers.

SSRClientNext.js
πŸ–§

APIs & Microservices

Request-scoped context propagation. Clean service layers. Perfect for Express, Fastify, or any framework.

ExpressFastifyGraphQL
πŸ§ͺ

Testing & A/B Testing

Swap implementations on the fly. Test different strategies. Mock external services with ease.

JestVitestPlaywright
Commodity Logo

Ready to revolutionize your DI?

Join developers who've already made the switch to type-inferred dependency injection!

πŸš€ Install with npm install commodity