# How to Optimize Production Builds with Custom esbuild Configuration in SXO

> Optimize SXO production builds using custom esbuild configuration. Inject any esbuild option via the BUILD environment variable to override defaults and enhance client-side bundling for better performance.

- Repository: [Víctor García/sxo](https://github.com/gc-victor/sxo)
- Tags: performance
- Published: 2026-03-02

---

**SXO exposes its internal esbuild pipeline through the `BUILD` environment variable, allowing you to inject any valid esbuild option that overrides defaults at runtime before the client-side bundle is generated.**

SXO ships with a built-in esbuild pipeline that automatically handles minification, hashing, and server-side rendering (SSR) wiring. While the default configuration in `gc-victor/sxo` handles most production scenarios, the architecture allows fine-grained control through environment-based configuration injection without modifying core source files.

## Understanding the Built-in esbuild Pipeline

The build system centers around [`src/js/esbuild/esbuild.config.js`](https://github.com/gc-victor/sxo/blob/main/src/js/esbuild/esbuild.config.js). This script assembles a default configuration object that includes sensible production defaults: `minify: true`, conditional sourcemaps based on development mode, entry-name patterns, public path resolution, and internal plugins for JSX and metafile generation.

When you run `sxo build` or `sxo dev`, the pipeline executes an esbuild process that bundles client assets while preserving the SSR module structure required by the framework.

## Using the BUILD Environment Variable to Override Defaults

SXO exposes an extension point through the `BUILD` environment variable. The system reads `process.env.BUILD` at lines 71-84 of [`src/js/esbuild/esbuild.config.js`](https://github.com/gc-victor/sxo/blob/main/src/js/esbuild/esbuild.config.js), parses the value as JSON, and stores it in a `buildConfig` variable. Immediately after the default configuration is assembled, the code spreads `buildConfig` into the final options object at lines 44-45:

```javascript
// Simplified excerpt from esbuild.config.js
const buildConfig = process.env.BUILD ? JSON.parse(process.env.BUILD) : {};
// ... default config assembly ...
await esbuild.build({
  ...defaultConfig,
  ...buildConfig, // Your overrides take precedence here
});

```

Because the spread operation occurs **after** all defaults are defined, any property you provide will override the built-in settings.

### Common Override Scenarios for Production Optimization

| Goal | BUILD JSON Value | Effect |
|------|----------------|--------|
| **Disable minification** for debugging | `{"minify":false}` | Removes code compression while preserving other optimizations |
| **Adjust hashing strategy** | `{"entryNames":"[dir]/[name]"}` | Eliminates content hashes for deterministic builds across deployments |
| **Externalize large dependencies** | `{"external":["react","react-dom"]}` | Prevents bundling of libraries served via CDN, reducing bundle size |
| **Enable source maps** | `{"sourcemap":true}` | Generates separate `.map` files for production debugging |
| **Inject compile-time constants** | `{"define":{"process.env.API_URL":"\"https://api.example.com\""}}` | Bakes environment variables into the bundle without client-side exposure |

## Practical Implementation Examples

### Quick One-Liner for Debugging

For immediate feedback during debugging sessions, pass a raw JSON string directly to the build command:

```bash
BUILD='{"minify":false}' sxo build

```

This disables minification temporarily without creating persistent configuration files.

### Full Custom Configuration File

Create a [`build-config.json`](https://github.com/gc-victor/sxo/blob/main/build-config.json) for complex, reusable configurations:

```json
{
  "minify": false,
  "sourcemap": true,
  "entryNames": "[dir]/[name]",
  "external": ["react", "react-dom"],
  "loader": {
    "\\.svg$": "text"
  },
  "define": {
    "process.env.API_URL": "\"https://api.example.com\""
  }
}

```

Execute the build by exporting the file contents into the environment variable:

```bash
BUILD=$(cat build-config.json) sxo build

```

### Reproducible Build Script for CI/CD

For production pipelines requiring consistent, documented configurations:

```bash
#!/usr/bin/env bash

# build-prod.sh – Reproducible production build with custom esbuild options

CONFIG=$(cat <<'EOF'
{
  "minify": true,
  "sourcemap": false,
  "entryNames": "[dir]/[name].[hash]",
  "publicPath": "/static/",
  "loader": { "\\.png$": "file" }
}
EOF
)

BUILD="$CONFIG" sxo build

```

## Verifying Your Configuration Changes

After executing a custom build, inspect the generated assets to confirm your overrides took effect:

1. Check [`dist/server/routes.json`](https://github.com/gc-victor/sxo/blob/main/dist/server/routes.json) to verify entry point naming and hash patterns match your `entryNames` specification
2. Examine `dist/client/` to confirm source map generation or absence thereof
3. Review bundle sizes to validate externalization of specified dependencies

To debug the effective configuration during development, temporarily add `console.log(buildConfig)` after line 73 in [`src/js/esbuild/esbuild.config.js`](https://github.com/gc-victor/sxo/blob/main/src/js/esbuild/esbuild.config.js) to visualize the merged object before it reaches esbuild.

## Key Source Files for Reference

Understanding these core files helps when crafting custom configurations:

- **[`src/js/esbuild/esbuild.config.js`](https://github.com/gc-victor/sxo/blob/main/src/js/esbuild/esbuild.config.js)** – The main build script where `process.env.BUILD` is parsed (lines 71-84) and merged into the final esbuild options (lines 44-45)
- **[`src/js/esbuild/entry-points-config.js`](https://github.com/gc-victor/sxo/blob/main/src/js/esbuild/entry-points-config.js)** – Defines how client and server entry points are discovered and named; custom `entryNames` in your BUILD config directly influence this logic
- **[`src/js/esbuild/esbuild-jsx.plugin.js`](https://github.com/gc-victor/sxo/blob/main/src/js/esbuild/esbuild-jsx.plugin.js)** – Handles JSX transformation for server bundles; advanced configurations may reference this for plugin ordering
- **[`src/js/esbuild/esbuild-metafile.plugin.js`](https://github.com/gc-victor/sxo/blob/main/src/js/esbuild/esbuild-metafile.plugin.js)** – Generates the asset manifest mapping routes to hashed filenames; affected by `entryNames` and public path settings

## Summary

- The `BUILD` environment variable accepts raw JSON that overrides any default esbuild option in SXO's pipeline
- Configuration merging happens at runtime in [`src/js/esbuild/esbuild.config.js`](https://github.com/gc-victor/sxo/blob/main/src/js/esbuild/esbuild.config.js) after defaults are established, ensuring your values take precedence
- Use `BUILD` to disable minification for debugging, adjust hashing strategies, externalize dependencies, or inject compile-time constants
- Production builds (`sxo build`) honor these settings during the asset generation phase, while `sxo start` serves pre-built assets and ignores runtime BUILD modifications
- Verify changes through the [`dist/server/routes.json`](https://github.com/gc-victor/sxo/blob/main/dist/server/routes.json) manifest and generated client assets

## Frequently Asked Questions

### What is the BUILD environment variable in SXO?

The `BUILD` environment variable is a runtime configuration hook exposed by SXO that accepts a JSON string representing valid esbuild options. When present, the build pipeline parses this value in [`src/js/esbuild/esbuild.config.js`](https://github.com/gc-victor/sxo/blob/main/src/js/esbuild/esbuild.config.js) and deep-merges it into the default esbuild configuration, allowing override of minification, entry naming, source maps, and loader behavior without modifying source code.

### How do I disable minification for debugging production builds?

Pass `{"minify":false}` through the BUILD variable: `BUILD='{"minify":false}' sxo build`. This preserves all other production optimizations while removing code obfuscation, making stack traces and bundle inspection meaningful during debugging sessions.

### Can I use the BUILD environment variable in development mode?

Yes. The `BUILD` variable is read unconditionally in [`src/js/esbuild/esbuild.config.js`](https://github.com/gc-victor/sxo/blob/main/src/js/esbuild/esbuild.config.js), meaning it affects both `sxo dev` and `sxo build` commands. However, since development mode typically enables inline source maps and disables minification by default, you will most commonly use BUILD overrides for production-specific tuning or specialized local debugging scenarios.

### Where does SXO merge custom esbuild options into the configuration?

The merge occurs in [`src/js/esbuild/esbuild.config.js`](https://github.com/gc-victor/sxo/blob/main/src/js/esbuild/esbuild.config.js) at two critical points: first, the raw JSON is parsed from `process.env.BUILD` between lines 71-84 and stored as `buildConfig`; second, this object is spread into the final esbuild options at lines 44-45, immediately after the default configuration object is assembled. This ordering ensures custom properties override SXO's built-in defaults.