> ## Documentation Index
> Fetch the complete documentation index at: https://sonamu.cartanova.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# build

> Building for production

export const FileItem = ({name, description, children}) => {
  const isLeaf = !children;
  const ext = getFileExtension(name);
  const extStyle = ext ? getExtensionStyle(ext) : null;
  return <div style={{
    marginLeft: "30px"
  }}>
      <div style={{
    display: "flex",
    alignItems: "center",
    gap: "4px"
  }}>
        <span style={{
    position: "relative",
    display: "inline-block"
  }}>
          <span className="file-icon">{isLeaf && !name.endsWith("/") ? "📄" : "📁"}</span>
          {ext && <span style={{
    position: "absolute",
    bottom: "2px",
    right: "0px",
    fontSize: "5px",
    fontWeight: "bold",
    padding: "1px",
    borderRadius: "2px",
    lineHeight: "1",
    minWidth: "8px",
    textAlign: "center",
    ...extStyle
  }}>
              {ext}
            </span>}
        </span>
        <code>{name}</code>
        {description && <span className="description"> - {description}</span>}
      </div>
      {children}
    </div>;
};

export const FileTree = ({children}) => {
  return <div className="file-tree" style={{
    margin: "20px",
    marginLeft: "-30px"
  }}>
      {children}
    </div>;
};

The `pnpm build` command **builds the project into optimized code** for deployment to production environments. It compiles TypeScript to JavaScript and removes unnecessary code to improve execution speed.

## Basic Usage

```bash theme={null}
pnpm build
```

Once the build completes, optimized JavaScript files are generated in the `dist` directory.

### Subcommands

You can build API and Web separately.

| Command          | Description                                                         |
| ---------------- | ------------------------------------------------------------------- |
| `pnpm build`     | Full API + Web build (default, skips Web build if no Web directory) |
| `pnpm build api` | Build API project only                                              |
| `pnpm build web` | Build Web project only                                              |

<FileTree>
  <FileItem name="my-project/">
    <FileItem name="dist/" description="Build output">
      <FileItem name="index.js" />

      <FileItem name="models/" />

      <FileItem name="api/" />
    </FileItem>

    <FileItem name="src/" description="Original source" />

    <FileItem name="package.json" />
  </FileItem>
</FileTree>

## Build Process

The build proceeds in the following steps:

### 1. Remove Existing Build Artifacts

Cleanly removes residual files from previous builds.

```
✓ Build artifacts removed successfully.
```

**Directories removed**:

* `dist/` - API build output
* `web/dist/` - Web build output
* `web-dist/` - Copied Web output

### 2. Prepare API Build Configuration

Determines the tsdown configuration file to use for the API build.

```typescript theme={null}
// Priority
// 1. tsdown.config.ts in project root (custom override)
// 2. Sonamu default tsdown API config (if none exists)
```

**Using custom config**:

```bash theme={null}
# Create tsdown.config.ts in project root
touch tsdown.config.ts
```

**Using default config**:

```
Using default tsdown API config from sonamu package...
```

### 3. Build API Project

Compiles TypeScript to JavaScript.

<Steps>
  <Step title="Build start">
    ```
    📦 API Server
    Building production-ready API
    /path/to/project
    ```
  </Step>

  <Step title="Run compilation">
    ```bash theme={null}
    tsc --noEmit && pnpm exec tsdown --config /path/to/tsdown.config.ts
    ```

    **Build tool**: [tsdown](https://github.com/rolldown/tsdown) with OXC/Rolldown
  </Step>

  <Step title="Complete">
    ```
    ✓ build completed (2.5s)
    ✓ API build completed in 2.5s
    ```
  </Step>
</Steps>

### 4. Build Web Project (Optional)

If a Web project exists, builds it and copies to the API project.

<Steps>
  <Step title="Build start">
    ```
    🌐 Web Application
    Building static web assets
    /path/to/project/web
    ```
  </Step>

  <Step title="Vite build">
    ```bash theme={null}
    vite build
    ```

    Optimizes and bundles static assets.
  </Step>

  <Step title="Copy files">
    ```bash theme={null}
    web/dist → web-dist
    ```

    Copies for serving from API server.
  </Step>

  <Step title="Complete">
    ```
    ✓ build completed (8.2s)
    ✓ copy completed (0.1s)
    ✓ Web build completed in 8.3s
    ```
  </Step>
</Steps>

**Web build output**:

* `web/dist/` - Original build result
* `web-dist/` - Copy for serving from API server

## Build Configuration

### Customizing API Build Configuration

Create a `tsdown.config.ts` file in the project root to override the default API build.

```ts title="tsdown.config.ts" theme={null}
import { defineConfig } from "tsdown";

export default defineConfig({
  clean: true,
  entry: {
    index: "src/index.ts",
  },
  format: "esm",
  platform: "node",
  sourcemap: "inline",
  target: "esnext",
  unbundle: true,
});
```

**Key options**:

| Option       | Description          | Default  |
| ------------ | -------------------- | -------- |
| `target`     | Compilation target   | `esnext` |
| `decorators` | Decorator support    | `true`   |
| `sourceMaps` | Generate source maps | `inline` |
| `unbundle`   | Preserve file layout | `true`   |

<Tip>
  If no `tsdown.config.ts` file exists, Sonamu falls back to its bundled default API build config.
</Tip>

## Build Output

### API Build Result

<FileTree>
  <FileItem name="dist/">
    <FileItem name="index.js" description="Entry point" />

    <FileItem name="models/" description="Model files">
      <FileItem name="user.model.js" />

      <FileItem name="post.model.js" />
    </FileItem>

    <FileItem name="api/" description="API logic">
      <FileItem name="sonamu.js" />
    </FileItem>

    <FileItem name="entities/" description="Entity definitions">
      <FileItem name="entities.js" />
    </FileItem>

    <FileItem name="practices/" description="Practice scripts">
      <FileItem name="p1-test.js" />
    </FileItem>
  </FileItem>
</FileTree>

**Features**:

* TypeScript → JavaScript conversion
* Decorator transformation complete
* Source maps included (`.js.map`)
* Import path resolution complete

### Web Build Result (Optional)

<FileTree>
  <FileItem name="web-dist/">
    <FileItem name="index.html" description="HTML entry" />

    <FileItem name="assets/" description="Optimized assets">
      <FileItem name="index-abc123.js" />

      <FileItem name="index-def456.css" />
    </FileItem>

    <FileItem name="favicon.ico" />
  </FileItem>
</FileTree>

**Features**:

* Code minification
* Asset hashing (cache busting)
* Tree shaking (remove unused code)

## Build Optimization

### 1. Separate Type Checking

To speed up builds, perform type checking separately.

```bash theme={null}
# Type check only (fast)
pnpm tsc --noEmit

# Build only (no type check)
pnpm build
```

### 2. Incremental Builds

Use the development server to rebuild only changed files.

```bash theme={null}
# Full build (slow)
pnpm build

# HMR development server (fast)
pnpm dev
```

### 3. Cache Utilization

tsdown reuses incremental dependency analysis across builds.

```bash theme={null}
# First build (slow)
pnpm build  # 5 seconds

# Second build (fast)
pnpm build  # 2 seconds
```

## Troubleshooting

### Build Failure

**Problem**: Build fails with TypeScript error

```
Error: Cannot find module 'some-module'
```

**Solution**:

```bash theme={null}
# 1. Type check
pnpm tsc --noEmit

# 2. Check dependencies
pnpm install

# 3. Reinstall node_modules
rm -rf node_modules
pnpm install
```

### tsdown Configuration Error

**Problem**: `tsdown.config.ts` configuration error

```
Error: Failed to load tsdown config
```

**Solution**:

```bash theme={null}
# Restore to default config
rm tsdown.config.ts
pnpm build
```

### Web Build Failure

**Problem**: Vite build error

```
Error: Could not resolve './some-file'
```

**Solution**:

```bash theme={null}
# Move to Web project directory
cd web

# Check dependencies
pnpm install

# Test Web build only
pnpm build

# Return to root and build all
cd ..
pnpm build
```

## Running After Build

After build completes, run the production server with the `start` command.

```bash theme={null}
# Build
pnpm build

# Run
pnpm start
```

**Production execution features**:

* **Fast startup**: Run pre-compiled JavaScript
* **Low memory**: No TypeScript transformation overhead
* **Source map support**: Show original file location on errors

### Direct Execution

You can also run directly with Node.js instead of `pnpm start`:

```bash theme={null}
node --enable-source-maps dist/index.js
```

**Option description**:

* `--enable-source-maps`: Show original TypeScript file location on errors
* `dist/index.js`: Built entry point

### Loading Environment Variables

When environment variables are needed:

```bash theme={null}
# Load .env file with dotenv
node -r dotenv/config --enable-source-maps dist/index.js

# Or specify directly
NODE_ENV=production PORT=3000 node --enable-source-maps dist/index.js
```

## CI/CD Configuration

Setting up CI/CD pipelines enables **automatic building and deployment** whenever code is pushed. Various tools like GitHub Actions, GitLab CI, Jenkins, etc. can be used.

### Why is CI/CD Needed?

| Benefit           | Description                         |
| ----------------- | ----------------------------------- |
| **Automation**    | Eliminate manual build/deploy tasks |
| **Consistency**   | Always build the same way           |
| **Fast feedback** | Immediately detect build failures   |
| **Safety**        | Deploy only after tests pass        |
| **Traceability**  | Preserve all deployment records     |

### GitHub Actions

GitHub Actions is a CI/CD platform integrated with GitHub. Define workflows by writing YAML files in the `.github/workflows/` directory.

```yaml title=".github/workflows/deploy.yml" theme={null}
name: Deploy

on:
  push:
    branches: [main] # Run when pushing to main branch

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      # 1. Checkout code
      - uses: actions/checkout@v3

      # 2. Install pnpm
      - uses: pnpm/action-setup@v2
        with:
          version: 8

      # 3. Setup Node.js (enable pnpm cache)
      - uses: actions/setup-node@v3
        with:
          node-version: 20
          cache: "pnpm"

      # 4. Install dependencies
      - run: pnpm install

      # 5. Build
      - run: pnpm build

      # 6. Deploy
      - name: Deploy
        run: |
          # Upload build output with rsync
          rsync -avz dist/ server:/app/
```

**Key step descriptions**:

<Steps>
  <Step title="Code checkout">
    Use `actions/checkout@v3` to fetch repository code.
  </Step>

  <Step title="Install pnpm">Install pnpm package manager with `pnpm/action-setup@v2`.</Step>

  <Step title="Setup Node.js">
    Install Node.js and enable pnpm cache with `actions/setup-node@v3`. Cache makes dependency
    installation much faster.
  </Step>

  <Step title="Install dependencies">Install project dependencies with `pnpm install`.</Step>

  <Step title="Build">Perform production build with `pnpm build`.</Step>

  <Step title="Deploy">
    Upload build output to server. Various methods like rsync, scp, FTP can be used.
  </Step>
</Steps>

### Adding Tests

Run tests before deployment to catch bugs early:

```yaml title=".github/workflows/deploy.yml" theme={null}
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: pnpm/action-setup@v2
        with:
          version: 8
      - uses: actions/setup-node@v3
        with:
          node-version: 20
          cache: "pnpm"
      - run: pnpm install
      - run: pnpm test # Run tests

  build:
    needs: test # Build only after tests pass
    runs-on: ubuntu-latest
    steps:
      # ... build steps
```

### Environment-based Deployment

Separate Staging and Production environments:

```yaml theme={null}
on:
  push:
    branches:
      - develop # Deploy to Staging
      - main # Deploy to Production

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      # ... build steps

      - name: Deploy to Staging
        if: github.ref == 'refs/heads/develop'
        run: |
          rsync -avz dist/ staging-server:/app/

      - name: Deploy to Production
        if: github.ref == 'refs/heads/main'
        run: |
          rsync -avz dist/ prod-server:/app/
```

### Docker

Using Docker guarantees a **consistent execution environment**. Development, staging, and production all run in the same environment.

```dockerfile title="Dockerfile" theme={null}
# Stage 1: Build stage
FROM node:20-alpine AS builder

WORKDIR /app

# Install pnpm
RUN npm install -g pnpm

# Install dependencies (copy only package.json first for caching)
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile

# Copy source code
COPY . .

# Build
RUN pnpm build

# Stage 2: Production stage
FROM node:20-alpine

WORKDIR /app

# Install pnpm
RUN npm install -g pnpm

# Install production dependencies only
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --prod --frozen-lockfile

# Copy build output
COPY --from=builder /app/dist ./dist

# Environment variables
ENV NODE_ENV=production

# Expose port
EXPOSE 3000

# Run
CMD ["pnpm", "start"]
```

**Benefits of multi-stage builds**:

| Benefit              | Description                          |
| -------------------- | ------------------------------------ |
| **Small image size** | Exclude build tools from final image |
| **Fast deployment**  | Smaller images have faster pull/push |
| **Security**         | Remove unnecessary development tools |
| **Layer caching**    | Reuse if dependencies unchanged      |

### Docker Compose

Use Docker Compose to run with database:

```yaml title="docker-compose.yml" theme={null}
version: "3.8"

services:
  api:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgresql://postgres:password@db:5432/myapp
    depends_on:
      - db

  db:
    image: pgvector/pgvector:pg16
    environment:
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=myapp
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:
```

**Run**:

```bash theme={null}
# Build and run
docker-compose up --build

# Run in background
docker-compose up -d

# Stop
docker-compose down
```

## Performance Comparison

Production builds are **much faster and more efficient** than development server.

| Metric           | Development Server | Production Build | Difference         |
| ---------------- | ------------------ | ---------------- | ------------------ |
| Startup time     | 2-3s               | 0.5s             | **4-6x faster**    |
| Memory usage     | 200MB              | 100MB            | **50% reduction**  |
| Request handling | Slower             | Faster           | **2-3x faster**    |
| File size        | Original           | Compressed       | **30-50% smaller** |

**Why production is faster**:

1. **Pre-compiled**: Don't transform TypeScript in real-time
2. **Code optimization**: Remove unnecessary code, compression
3. **No HMR overhead**: No file watching and reloading costs
4. **Production mode**: Node.js and dependencies run in optimized mode

### Actual Performance Measurement

Compare development server and production build performance directly:

```bash theme={null}
# Measure development server startup time
time pnpm dev

# Measure production build + startup time
time (pnpm build && pnpm start)
```

**API response time comparison**:

```bash theme={null}
# Development server
curl -w "\n%{time_total}s\n" http://localhost:3000/api/users
# Example: 0.05s

# Production
curl -w "\n%{time_total}s\n" http://localhost:3000/api/users
# Example: 0.02s
```

## Next Steps

<CardGroup cols={2}>
  <Card title="start" icon="play" href="/en/tools-and-cli/sonamu-cli/start">
    Run the built server
  </Card>

  <Card title="dev" icon="code" href="/en/tools-and-cli/sonamu-cli/dev">
    Return to development server
  </Card>
</CardGroup>
