Twenty follows a modular and organized file structure that promotes maintainability and scalability. This document outlines our file organization conventions and best practices.
- Each component should have its own file
- File name should match component name
// ✅ Correct // UserProfile.tsx export const UserProfile = () => { return <div>...</div>; }; // ❌ Incorrect // users.tsx export const UserProfile = () => { return <div>...</div>; }; export const UserList = () => { return <div>...</div>; };
- Place features in
modules/
directory - Group related components and logic
modules/ ├── users/ │ ├── components/ │ │ ├── UserList.tsx │ │ ├── UserCard.tsx │ │ └── UserProfile.tsx │ ├── hooks/ │ │ └── useUser.ts │ ├── states/ │ │ └── userStates.ts │ └── types/ │ └── user.ts ├── workspace/ │ ├── components/ │ ├── hooks/ │ └── states/ └── settings/ ├── components/ ├── hooks/ └── states/
- Place hooks in
hooks/
directory - Group by feature or global usage
hooks/ ├── useClickOutside.ts ├── useDebounce.ts └── features/ ├── users/ │ ├── useUserActions.ts │ └── useUserData.ts └── workspace/ └── useWorkspaceSettings.ts
- Place state definitions in
states/
directory - Organize by feature
states/ ├── global/ │ ├── theme.ts │ └── navigation.ts ├── users/ │ ├── atoms.ts │ └── selectors.ts └── workspace/ ├── atoms.ts └── selectors.ts
- Place types in
types/
directory - Group by domain or feature
types/ ├── common.ts ├── api.ts └── features/ ├── user.ts ├── workspace.ts └── settings.ts
- Use PascalCase for component files
- Use descriptive, feature-specific names
components/ ├── UserProfile.tsx ├── UserProfileHeader.tsx └── UserProfileContent.tsx
- Use camelCase for non-component files
- Use clear, descriptive names
hooks/ ├── useClickOutside.ts └── useDebounce.ts utils/ ├── dateFormatter.ts └── stringUtils.ts
- Consistent structure across features
- Clear separation of concerns
modules/users/ ├── components/ │ ├── UserList/ │ │ ├── UserList.tsx │ │ ├── UserListItem.tsx │ │ └── UserListHeader.tsx │ └── UserProfile/ │ ├── UserProfile.tsx │ └── UserProfileHeader.tsx ├── hooks/ │ ├── useUserList.ts │ └── useUserProfile.ts ├── states/ │ ├── atoms.ts │ └── selectors.ts ├── types/ │ └── user.ts └── utils/ └── userFormatter.ts
- Group imports by type
- Maintain consistent order
// External dependencies import { useState } from 'react'; import { styled } from '@emotion/styled'; // Internal modules import { useUser } from '~/modules/users/hooks'; import { userState } from '~/modules/users/states'; // Local imports import { UserAvatar } from './UserAvatar'; import { type UserProfileProps } from './types';
- Use path aliases for better imports
- Avoid deep relative paths
// ✅ Correct import { Button } from '~/components/Button'; import { useUser } from '~/modules/users/hooks'; // ❌ Incorrect import { Button } from '../../../components/Button'; import { useUser } from '../../../modules/users/hooks';
- Keep related files close together
- Use index files for public APIs
components/UserProfile/ ├── UserProfile.tsx ├── UserProfileHeader.tsx ├── UserProfileContent.tsx ├── styles.ts ├── types.ts └── index.ts
- Place test files next to implementation
- Use
.test.ts
or.spec.ts
extensioncomponents/ ├── UserProfile.tsx ├── UserProfile.test.tsx ├── UserProfile.stories.tsx └── types.ts