nesting structure

rule

use nesting only when it reveals multiple focused parts of one concept. a folder's index.ts is encouraged as that folder's pure barrel — the only allowed purpose for an authored index file. collocation precedes nesting: a block with exactly one consumer lives inside or beside that consumer; no folder is earned until a second consumer or a set of focused parts appears.

why nesting must be earned

a folder is navigation cost: every reader pays one hop to enter it, and a tree of single-file folders makes humans open wrappers before behavior. a folder exists only when it names one concept whose parts are independently understandable — a schema, a mapper, an operation that change for different reasons. symmetry with a sibling folder is not a reason to nest.

observed shapedecisionreason
one concept, one authored filedenest to the parent as one file.the folder hop buys nothing.
a block only its one consumer importskeep it inside or beside that consumer.collocation precedes nesting.
one concept, several independently changing leavesnest under the concept name with a pure barrel.the folder names the concept; leaves stay focused.
a wrapper folder that only forwards to one leafremove it.the reader opens a layer with no behavior.
files grouped only by visual symmetrykeep them flat.nesting must reflect ownership, not layout taste.

barrel rule

index.ts exports the folder's public canonical symbols without renaming, wrapping, side effects, or implementation. consumers import the folder's public API; leaf files remain the direct owners of behavior.

workflowStep/
index.ts
readWorkflowStep.ts
workflowStepMapper.ts
workflowStepSchema.ts

denest a single-file folder

one authored file in a folder → remove the folder, promote the file to its parent: workflowStep.ts, not workflowStep/index.ts. nesting earns its navigation cost only by exposing multiple real leaves.

break down an oversized file

when one file owns independently understandable responsibilities, create a same-named folder, move each responsibility to a focused leaf, add a pure index.ts barrel: split workflowStep.ts into workflowStep/readWorkflowStep.ts, workflowStep/workflowStepSchema.ts, workflowStep/workflowStepMapper.ts.

the same promotion applies to a consumer file that has accumulated single-consumer blocks: checkout.ts becomes checkout/ with its extracted parts as leaves — structure grows from usage instead of being imposed.

good and bad

bad

workflowStep/
index.ts // only forwards to the single leaf
workflowStep.ts
charge/
charge.ts // nested for symmetry with a sibling folder

each folder adds one navigation hop while exposing a single leaf — nesting has not earned its cost. wrapper layers carry no behavior, every move and import gains a path segment, and readers learn to skip folders because half contain nothing — exactly when real structure stops being trusted and grep replaces navigation.

good

workflowStep.ts # one concept, one file: denested
workflowStep/ # multiple independently changing leaves
index.ts
readWorkflowStep.ts
workflowStepMapper.ts
workflowStepSchema.ts

nesting appears only where one concept has several focused parts; index.ts stays a pure barrel of those leaves. every hop lands on real behavior, the folder name carries meaning the leaves share, consumers get one import path per concept while leaves keep direct ownership — the tree stays an honest index of ownership.

do not

  • put implementation, side effects, or a second unrelated concept in index.ts.
  • add a folder for visual symmetry or one leaf file.
  • create nested layers that make a human open wrappers before real behavior.
  • rename a re-exported symbol; the barrel preserves the leaf symbol exactly.

search pages

go to any page