# Organizing a Node.js File Structure: Best Practices for Scalable and Maintainable Projects

> Master Node.js file structure best practices. Organize your code scalably with dedicated src and test folders, a clear entry point, and root config files for maintainability.

- Repository: [Node.js/node](https://github.com/nodejs/node)
- Tags: best-practices
- Published: 2026-02-16

---

**Organizing a Node.js file structure requires isolating source code in a dedicated `src/` directory, mirroring tests in a separate `test/` folder, exposing a single [`index.js`](https://github.com/nodejs/node/blob/main/index.js) entry point, and keeping configuration files at the repository root to ensure tooling compatibility and long-term maintainability.**

A clean directory layout is the foundation of any maintainable Node.js application. By following the conventions established in the official `nodejs/node` repository, developers can create scalable project structures that isolate concerns, simplify onboarding for new contributors, and integrate seamlessly with automated testing and linting tools.

## Core Principles for Organizing a Node.js File Structure

### Isolate Source Code from Configuration

The Node.js source tree demonstrates the importance of separating runtime code from project metadata. In the `nodejs/node` repository, all C++ and JavaScript implementation files reside in [`src/`](https://github.com/nodejs/node/tree/main/src), while configuration files like [[`package.json`](https://github.com/nodejs/node/blob/main/package.json)](https://github.com/nodejs/node/blob/main/package.json) and [[`.eslintrc.js`](https://github.com/nodejs/node/blob/main/.eslintrc.js)](https://github.com/nodejs/node/blob/main/.eslintrc.js) remain at the root. This separation prevents accidental deployment of build tools and makes the codebase navigable for new contributors.

### Mirror Test Structure to Source Code

Maintainability requires that test suites follow the same directory hierarchy as the implementation. The `nodejs/node` repository places all tests in [`test/`](https://github.com/nodejs/node/tree/main/test), with subdirectories like `test/parallel/` and `test/sequential/` that correspond to specific runtime behaviors. When organizing your Node.js file structure, create a `test/` folder that mirrors your `src/` layout, using naming conventions like `*.test.js` to enable automatic test discovery by runners such as Jest or Mocha.

## Recommended Directory Layout for Scalable Node.js Projects

The following structure reflects the proven organization used in the `nodejs/node` repository and scales from small utilities to large applications:

```text
my-node-app/
├─ src/                 # Core implementation

│  ├─ http/             # HTTP server utilities

│  │  ├─ server.js
│  │  └─ router.js
│  └─ utils/            # Re‑usable helpers

│     └─ logger.js
├─ test/                # Test suites

│  ├─ http/
│  │  └─ server.test.js
│  └─ utils/
│     └─ logger.test.js
├─ examples/            # Sample usage

│  └─ simple-server/
│     └─ index.js
├─ docs/                # Markdown documentation

│  └─ guide.md
├─ tools/               # Build utilities and scripts

│  └─ build.js
├─ .eslintrc.js         # Linter configuration

├─ .prettierrc          # Formatter configuration

├─ package.json
├─ README.md
└─ index.js             # Public API entry point

```

## Key Files and Their Roles in Node.js Organization

Understanding the purpose of specific configuration and entry files helps maintain consistency across projects. The `nodejs/node` repository demonstrates these patterns:

- **[[`package.json`](https://github.com/nodejs/node/blob/main/package.json)](https://github.com/nodejs/node/blob/main/package.json)** – Declares dependencies, scripts, and the main entry point. Located at the root to enable `npm` and `yarn` discovery.
- **[[`index.js`](https://github.com/nodejs/node/blob/main/index.js)](https://github.com/nodejs/node/blob/main/index.js)** – Primary public API that re‑exports core modules. Serves as the single entry point for consumers while hiding internal implementation details.
- **[`src/`](https://github.com/nodejs/node/tree/main/src)** – Contains the C++ and JavaScript implementation of Node.js core features. In application projects, use this for all business logic.
- **[`test/`](https://github.com/nodejs/node/tree/main/test)** – Comprehensive test suite covering all core modules. Mirrors the source structure for maintainability.
- **[`doc/`](https://github.com/nodejs/node/tree/main/doc)** – Detailed design documents, API references, and proposals. Centralizes knowledge outside of code comments.
- **[`tools/`](https://github.com/nodejs/node/tree/main/tools)** – Build utilities, documentation generators, and linting helpers. Isolates development tooling from runtime code.
- **[`examples/`](https://github.com/nodejs/node/tree/main/examples)** – Small programs demonstrating common Node.js patterns. Serves as living documentation for newcomers.
- **[[`.github/workflows/ci.yml`](https://github.com/nodejs/node/blob/main/.github/workflows/ci.yml)](https://github.com/nodejs/node/blob/main/.github/workflows/ci.yml)** – CI pipeline definition ensuring every change is tested. Version‑controlled alongside the code.
- **[[`.eslintrc.js`](https://github.com/nodejs/node/blob/main/.eslintrc.js)](https://github.com/nodejs/node/blob/main/.eslintrc.js)** – ESLint configuration enforcing code style consistency across the entire codebase.

## Practical Implementation Tips for Maintainable Node.js Projects

When organizing a Node.js file structure, follow these proven practices derived from the `nodejs/node` repository:

- **Keep modules small** – Each file should implement a single, well‑defined responsibility. The Node.js core separates HTTP handling, file system operations, and utilities into distinct modules within [`src/`](https://github.com/nodejs/node/tree/main/src).

- **Prefer `src/` over flat roots** – A flat root directory becomes cluttered as projects grow. The `nodejs/node` repository uses [`src/`](https://github.com/nodejs/node/tree/main/src) to isolate runtime code from configuration, following the same pattern in your projects prevents root sprawl.

- **Use index files sparingly** – Only expose what the public API needs via [[`index.js`](https://github.com/nodejs/node/blob/main/index.js)](https://github.com/nodejs/node/blob/main/index.js). Avoid “barrel” imports that re‑export everything, as they hide dependency graphs and complicate tree‑shaking.

- **Document folder purpose** – Add a short [`README.md`](https://github.com/nodejs/node/blob/main/README.md) inside major directories (e.g., `src/`, `test/`) to explain their role. The `nodejs/node` repository uses this practice in [`doc/`](https://github.com/nodejs/node/tree/main/doc) to guide contributors.

- **Align with tooling defaults** – Most linters, formatters, and test runners assume conventional locations. Placing [[`.eslintrc.js`](https://github.com/nodejs/node/blob/main/.eslintrc.js)](https://github.com/nodejs/node/blob/main/.eslintrc.js) at the root and tests in `test/` reduces configuration overhead and ensures immediate compatibility with `npm test` and CI systems.

## Summary

Organizing a Node.js file structure effectively requires separating concerns through clear directory boundaries. The key takeaways include:

- Isolate source code in a dedicated `src/` directory to prevent root clutter and clearly distinguish runtime logic from configuration.
- Mirror your test hierarchy to your source structure within a `test/` folder to maintain navigability and enable automatic test discovery.
- Expose a single entry point through [`index.js`](https://github.com/nodejs/node/blob/main/index.js) that re‑exports only the public API, hiding internal implementation details.
- Keep tooling configuration ([`.eslintrc.js`](https://github.com/nodejs/node/blob/main/.eslintrc.js), `.prettierrc`) and CI workflows (`.github/workflows/`) at the repository root for immediate tool recognition.
- Document each major directory with a [`README.md`](https://github.com/nodejs/node/blob/main/README.md) and provide runnable examples in an `examples/` folder to accelerate onboarding.

## Frequently Asked Questions

### What is the best folder structure for a Node.js project?

The optimal folder structure separates source code into a `src/` directory, tests into a `test/` folder mirroring the source hierarchy, and keeps configuration files at the root. This approach, used by the `nodejs/node` repository, prevents root clutter while making the codebase navigable for new contributors and compatible with automated tooling.

### Should I use `src/` or `lib/` for my Node.js source code?

While both conventions are valid, `src/` is preferred for modern Node.js projects as it clearly indicates "source" versus compiled or distributed code. The `nodejs/node` repository uses [`src/`](https://github.com/nodejs/node/tree/main/src) to house all core implementation files, distinguishing them from build tools in `tools/` and documentation in `doc/`.

### How do I organize tests in a Node.js project?

Organize tests by mirroring your source directory structure within a dedicated `test/` folder, using naming conventions like `*.test.js` or `*.spec.js`. The `nodejs/node` repository follows this pattern in [`test/`](https://github.com/nodejs/node/tree/main/test), with subdirectories like `test/parallel/` and `test/sequential/` that correspond to specific runtime behaviors, enabling automatic discovery by test runners.

### Where should I put configuration files in a Node.js project?

Place environment‑specific configuration files such as [`.eslintrc.js`](https://github.com/nodejs/node/blob/main/.eslintrc.js), `.prettierrc`, and [`tsconfig.json`](https://github.com/nodejs/node/blob/main/tsconfig.json) at the repository root where linters, formatters, and compilers expect to find them. The `nodejs/node` repository demonstrates this by keeping [[`.eslintrc.js`](https://github.com/nodejs/node/blob/main/.eslintrc.js)](https://github.com/nodejs/node/blob/main/.eslintrc.js) and [`package.json`](https://github.com/nodejs/node/blob/main/package.json) at the root level, ensuring immediate tool recognition without additional path configuration.