Import and Export Strategy
This project uses strict import/export rules to keep package APIs explicit and stable.
Core Rules
- Package public entrypoints (
packages/*/src/index.ts) must use explicit named exports. - Do not use
export *in package public entrypoints. - Use
export type { ... }for type-only exports. - Keep ESM path suffixes (
.js) in re-export paths. - Import from package roots (
@repo/ui) in consumers, not deep private paths.
Why
- Prevent accidental API growth
- Reduce export name collisions
- Make reviews and refactors safer
- Keep package contracts readable
Public Entrypoint Pattern
// packages/ui/src/index.ts
export { Button } from "./components/button/Button.js";
export { buttonVariants } from "./components/button/buttonVariants.js";
export type { BadgeProps, BadgeVariant } from "./components/badge/Badge.js";
Avoid:
// Do not use this in package public APIs
export * from "./components/button/Button.js";
Type Exports
Use explicit type exports so runtime bundles stay clean and API intent is obvious.
export type { SidebarProps } from "./components/widgets/sidebar/Sidebar.js";
export type { BadgeVariant } from "./components/badge/Badge.js";
Consumer Imports
Preferred:
import { Card, CardHeader, CardTitle } from "@repo/ui";
import type { BadgeVariant } from "@repo/ui";
Not preferred in app/package code:
import { Card } from "@repo/ui/src/components/card/Card";
Internal Barrels
Internal barrels are allowed when they improve local module structure, but:
- they are not public package contract files
- they should still avoid broad wildcard exports when ambiguity is likely
PR Checklist
- No
export *in package public entrypoint files - New public symbols are explicitly exported
- Type-only symbols use
export type - Consumer imports remain package-root based (
@repo/<pkg>)