Frontend Patterns

Pattern

Public API

Expose only necessary interfaces while keeping implementation details private and flexible.

Public API

Problem

Consumers import implementation details directly from deep within modules, creating tight coupling that makes refactoring dangerous. Any internal reorganization or implementation change breaks dozens of imports across the codebase. There’s no clear boundary between public interfaces and private implementation, leading to unintended dependencies.

Solution

Explicitly designate which exports are intended for external use versus internal implementation. This communicates stability guarantees and helps consumers avoid depending on internals that might change.

Example

This example shows defining a public API through an index file that re-exports only the components intended for external use, keeping internals private.

// index.js - Public API surface
// Only these exports are part of the stable public API
export { Button } from './Button';
export { Input } from './Input';
// Internal components like ButtonBase, InputCore are NOT exported
// Consumers can only import what's explicitly exposed

// Usage - consumers import from the public API
import { Button, Input } from 'my-library';

Benefits

  • Provides clear boundaries between public interfaces and private implementation.
  • Enables safe refactoring by controlling what consumers can access.
  • Communicates stability guarantees and versioning expectations.
  • Makes it easier to evolve internals without breaking consumers.

Tradeoffs

  • Requires discipline to maintain the public API boundary.
  • Can limit flexibility if consumers need access to internal utilities.
  • Needs careful API design to expose the right level of abstraction.
  • May require versioning and deprecation strategies for API changes.
Stay Updated

Get New Patterns
in Your Inbox

Join thousands of developers receiving weekly insights on frontend architecture patterns

No spam. Unsubscribe anytime.