A package that only exports a single default namespace object forces bundlers to include the entire package in every consumer's bundle, regardless of which methods they actually use. ISO 25010 resource-utilization degrades linearly with how much dead code consumers are forced to carry. Tools like webpack, Rollup, and Vite perform tree-shaking on named exports but cannot eliminate unused properties of a default export object. For frontend consumers, this directly inflates page weight and Lighthouse scores.
High because default-only exports defeat tree-shaking across all major bundlers, forcing consumers to ship your entire API surface even when they use one function.
Replace or supplement a default namespace export with named exports from src/index.ts.
// Before — single default object, not tree-shakeable:
const sdk = { createClient: () => {}, parseResponse: () => {} }
export default sdk
// After — named exports, each independently shakeable:
export function createClient() {}
export function parseResponse() {}
export function formatError() {}
A default export alongside named exports is acceptable if the class or factory function is the natural primary API. The key requirement: import { specificFunction } from 'your-package' must work without importing the rest.
ID: sdk-package-quality.api-surface.named-exports
Severity: high
What to look for: List all exports from the SDK entry point. For each export, check the main entry point and any sub-path exports for their export style. Look for:
export function, export class, export const, export { ... })export default bigObject with all API methods on one object)export * from (acceptable if the re-exported modules use named exports)Pass criteria: The package primarily uses named exports. Consumers can import only what they need: import { specificFunction } from 'your-package'. A default export alongside named exports is acceptable — at least 80% of public API should use named exports rather than default exports. Report: "X named exports found."
Fail criteria: The package only exports a single default object or namespace that contains all functionality. Consumers must import everything to use anything: import SDK from 'your-package'; SDK.specificFunction(). This defeats tree-shaking.
Skip (N/A) when: The package has a single primary export by design (e.g., a single class like Stripe or Prisma that is the entire API surface). Also skip for Go (no default exports concept) and Rust (module system handles this differently).
Do NOT pass when: The package uses only export default for its entire public API — this breaks tree-shaking and auto-import.
Detail on fail: "The entry point only has 'export default' with a single object containing 15 methods. Consumers cannot tree-shake unused methods. Use named exports: export { method1, method2 } to enable tree-shaking."
Remediation: Named exports let bundlers eliminate unused code. This matters for packages used in browser bundles.
// Before — single default object (not tree-shakeable):
const sdk = {
createClient: () => {},
parseResponse: () => {},
formatError: () => {},
}
export default sdk
// After — named exports (tree-shakeable):
export function createClient() {}
export function parseResponse() {}
export function formatError() {}
If your API is a class instance, you can still export the class as a named export alongside utility functions.