# Code Standards and Conventions (/docs/development/conventions)

## Workspace Boundaries

LibreChat is a monorepo. All new code should target the correct workspace:

| Workspace | Language | Side | Purpose |
|---|---|---|---|
| `/api` | JS (legacy) | Backend | Express server — minimize changes here |
| `/packages/api` | **TypeScript** | Backend | New backend code lives here (TS only, consumed by `/api`) |
| `/packages/data-schemas` | TypeScript | Backend | Database models/schemas |
| `/packages/data-provider` | TypeScript | Shared | API types, endpoints, data-service — used by frontend and backend |
| `/client` | TypeScript/React | Frontend | Frontend SPA |
| `/packages/client` | TypeScript | Frontend | Shared frontend utilities |

- **All new backend code must be TypeScript** in `/packages/api`.
- Keep `/api` changes to the absolute minimum (thin JS wrappers calling into `/packages/api`).
- Database-specific shared logic goes in `/packages/data-schemas`.
- Frontend/backend shared API logic (endpoints, types, data-service) goes in `/packages/data-provider`.
- Build all compiled code from project root: `npm run build`.

---

## General Guidelines

- Use "clean code" principles: keep functions and modules small, adhere to the single responsibility principle, and write expressive and readable code.
- Use meaningful and descriptive variable and function names.
- Prioritize code readability and maintainability over brevity.
- Use the provided `.eslintrc` and `.prettierrc` files for consistent code formatting.
- Fix all formatting lint errors using auto-fix when available. All TypeScript/ESLint warnings and errors must be resolved.

### Code Structure

- **Never-nesting**: use early returns, flat code, minimal indentation. Break complex operations into well-named helpers.
- **Functional first**: pure functions, immutable data, `map`/`filter`/`reduce` over imperative loops. Only reach for OOP when it clearly improves domain modeling or state encapsulation.
- **No dynamic imports** unless absolutely necessary.
- Extract repeated logic into dedicated utility functions (DRY).

### Iteration and Performance

- **Minimize looping** — especially over shared data structures like message arrays, which are iterated frequently. Every additional pass adds up at scale.
- Consolidate sequential O(n) operations into a single pass whenever possible; never loop over the same collection twice if the work can be combined.
- Choose data structures that reduce the need to iterate (e.g., `Map`/`Set` for lookups instead of `Array.find`/`Array.includes`).
- Avoid unnecessary object creation; consider space-time tradeoffs.
- Prevent memory leaks: be careful with closures, dispose resources/event listeners, avoid circular references.

### Type Safety

- **Never use `any`**. Explicit types for all parameters, return values, and variables.
- **Limit `unknown`** — avoid `unknown`, `Record<string, unknown>`, and `as unknown as T` assertions. A `Record<string, unknown>` almost always signals a missing explicit type definition.
- **Don't duplicate types** — check whether a type already exists in the project (especially `packages/data-provider`) before defining a new one. Reuse and extend existing types.
- Use union types, generics, and interfaces appropriately.

### Comments and Documentation

- Write self-documenting code; no inline comments narrating what code does.
- JSDoc only for complex/non-obvious logic or intellisense on public APIs.
- Single-line JSDoc for brief docs, multi-line for complex cases.
- Avoid standalone `//` comments unless absolutely necessary.

### Import Order

Imports are organized into three sections (in order):

1. **Package imports** — sorted from shortest to longest line length (`react` is always the first import).
2. **`import type` imports** — sorted from longest to shortest (package types first, then local types; length sorting resets between sub-groups).
3. **Local/project imports** — sorted from longest to shortest.

- Consolidate value imports from the same module as much as possible.
- Always use standalone `import type { ... }` for type imports; never use inline `type` keyword inside value imports (e.g., `import { Foo, type Bar }` is wrong).

### Loop Preferences

- **Limit looping as much as possible.** Prefer single-pass transformations and avoid re-iterating the same data.
- `for (let i = 0; ...)` for performance-critical or index-dependent operations.
- `for...of` for simple array iteration.
- `for...in` only for object property enumeration.

---

## Node.js API Server

### API Design

- Follow RESTful principles when designing APIs.
- Use meaningful and descriptive names for routes, controllers, services, and models.
- Use appropriate HTTP methods (GET, POST, PUT, DELETE) for each route.
- Use proper status codes and response structures for consistent API responses (2xx for success, 4xx for bad request from client, 5xx for server error).
- Use try-catch blocks to catch and handle exceptions gracefully.
- Implement proper error handling and consistently return appropriate error responses.
- Use the logging system included in the `utils` directory to log important events and errors.
- Do JWT-based, stateless authentication using the `requireJWTAuth` middleware.

### File Structure

New backend code goes in `/packages/api` as TypeScript. The legacy `/api` directory follows this structure:

#### Routes

Specifies each HTTP request method, any middleware to be used, and the controller function to be called for each route.

- Define routes using the Express Router in separate files for each resource or logical grouping.
- Use descriptive route names and adhere to RESTful conventions.
- Keep routes concise and focused on a single responsibility.
- Prefix all routes with the `/api` namespace.

#### Controllers

Contains the logic for each route, including calling the appropriate service functions and returning the appropriate response status code and JSON body.

- Create a separate controller file for each route to handle the request/response logic.
- Name controller files using the PascalCase convention and append "Controller" to the file name (e.g., `UserController.js`).
- Keep controllers thin by delegating complex operations to service or model files.

#### Services

Contains complex business logic or operations shared across multiple controllers.

- Name service files using the PascalCase convention and append "Service" to the file name (e.g., `AuthService.js`).
- Avoid tightly coupling services to specific models or databases for better reusability.
- Maintain a single responsibility principle within each service.

#### Models

Defines Mongoose models to represent data entities and their relationships.

- Use singular, PascalCase names for model files and their associated collections (e.g., `User.js` and `users` collection).
- Include only the necessary fields, indexes, and validations in the models.
- Keep models independent of the API layer by avoiding direct references to request/response objects.

### Database Access (MongoDB and Mongoose)

- Use Mongoose ([https://mongoosejs.com](https://mongoosejs.com)) as the MongoDB ODM.
- Create separate model files for each entity and ensure clear separation of concerns.
- Use Mongoose schema validation to enforce data integrity.
- Handle database connections efficiently and avoid connection leaks.
- Use Mongoose query builders to create concise and readable database queries.

---

## React Client

### General TypeScript and React Best Practices

- Use [TypeScript best practices](https://onesignal.com/blog/effective-typescript-for-react-applications/) to benefit from static typing and improved tooling.
- Group related files together within feature directories (e.g., `SidePanel/Memories/`).
- Name components using the PascalCase convention.
- Use concise and descriptive names that accurately reflect the component's purpose.
- Split complex components into smaller, reusable ones when appropriate.
- Keep the rendering logic within components minimal.
- Extract reusable parts into separate functions or hooks.
- Apply prop type definitions using TypeScript types or interfaces.
- Use form validation where appropriate (we use [React Hook Form](https://react-hook-form.com/) for form validation and submission).

### Localization

- All client-facing text must be localized using the `useLocalize()` hook.
- Only update English keys in `client/src/locales/en/translation.json` (other languages are automated externally).
- Use semantic localization key prefixes: `com_ui_`, `com_assistants_`, etc.
- Always provide meaningful fallback text for new localization keys.

### Data Services

- Create data provider hooks in `client/src/data-provider/[Feature]/queries.ts`.
- Export all hooks from `client/src/data-provider/[Feature]/index.ts`.
- Add feature exports to main `client/src/data-provider/index.ts`.
- Use React Query (`@tanstack/react-query`) for all API interactions.
- Implement proper query invalidation on mutations.
- Add QueryKeys and MutationKeys to `packages/data-provider/src/keys.ts`.

When adding shared API integration, update:

- `packages/data-provider/src/api-endpoints.ts` (endpoints)
- `packages/data-provider/src/data-service.ts` (data service functions)
- `packages/data-provider/src/types/queries.ts` (TypeScript types)

### Performance

- Prioritize memory and speed efficiency at scale.
- Implement proper cursor pagination for large datasets.
- Avoid unnecessary re-renders with proper dependency arrays.
- Leverage React Query's caching and background refetching features.

---

## Testing and Documentation

- Write unit tests for all critical and complex functionalities using Jest.
- Write integration tests for all API endpoints using Supertest.
- Write end-to-end tests for all client-side functionalities using Playwright.
- Use descriptive test case and function names to clearly express the test's purpose.
- Run tests from their workspace directory: `cd api && npx jest <pattern>`, `cd packages/api && npx jest <pattern>`, etc.
- Cover loading, success, and error states for UI/data flows.
- Use `test/layout-test-utils` for rendering components in frontend tests.
