Skip to main content

Overview

The Oxc Minifier is a high-performance JavaScript minification tool that produces the smallest possible output while maintaining correctness. It implements 17+ optimization passes inspired by industry-leading minifiers like Closure Compiler, Terser, esbuild, and SWC.

Maximum Compression

Fixed-point iteration ensures all optimization opportunities are found.

100% Correct

Extensively tested against Test262, Babel, and TypeScript test suites.

Dead Code Elimination

Removes unreachable code and unused declarations.

Variable Mangling

Renames variables to shortest possible names.

Features

Compression Techniques

  • Constant folding: 1 + 23
  • Expression simplification: !!xBoolean(x)
  • Boolean optimization: x === truex
  • Comparison folding: x < y && x < zx < Math.min(y, z)
  • Dead code removal: Remove unreachable code
  • Shorthand properties: {x: x}{x}

Mangling Options

  • Identifiers: Rename local variables to a, b, c, etc.
  • Properties: Optionally mangle object properties
  • Top-level: Optionally mangle top-level names
  • Keep names: Preserve specific variable/function names
  • Private members: Mangle class private fields

Node.js API

Installation

npm
npm install oxc-minify

Basic Usage

import { minify } from 'oxc-minify';

const code = `
function calculateTotal(items) {
  let total = 0;
  for (let i = 0; i < items.length; i++) {
    total = total + items[i].price;
  }
  return total;
}
`;

const result = minify(code, {
  compress: true,
  mangle: true
});

console.log(result.code);
// Output: function calculateTotal(t){let l=0;for(let n=0;n<t.length;n++)l+=t[n].price;return l}

Minify Options

interface MinifyOptions {
  /** Enable compression */
  compress?: boolean | CompressOptions;
  
  /** Enable variable mangling */
  mangle?: boolean | MangleOptions;
  
  /** Source map options */
  sourceMap?: boolean | SourceMapOptions;
  
  /** Keep original formatting (for debugging) */
  keepFormat?: boolean;
}

interface CompressOptions {
  /** Remove dead code */
  deadCode?: boolean;
  
  /** Fold constants */
  foldConstants?: boolean;
  
  /** Remove console.* statements */
  dropConsole?: boolean;
  
  /** Remove debugger statements */
  dropDebugger?: boolean;
  
  /** Target environment */
  target?: 'es5' | 'es2015' | 'es2016' | 'esnext';
  
  /** Number of compression passes (default: until fixed point) */
  passes?: number;
}

interface MangleOptions {
  /** Mangle top-level names */
  topLevel?: boolean;
  
  /** Keep specific names */
  keepNames?: string[];
  
  /** Mangle class private members */
  keepPrivateMembers?: boolean;
}

Compression Only

import { minify } from 'oxc-minify';

const result = minify(code, {
  compress: {
    deadCode: true,
    foldConstants: true,
    dropConsole: true,
    dropDebugger: true
  },
  mangle: false  // No variable renaming
});

Mangling Only

const result = minify(code, {
  compress: false,  // No compression
  mangle: {
    topLevel: true,
    keepNames: ['importantFunction', 'API']
  }
});

Advanced Options

const result = minify(code, {
  compress: {
    target: 'es2015',
    passes: 3,  // Run 3 compression passes
    deadCode: true,
    foldConstants: true,
    dropConsole: true,
    dropDebugger: true
  },
  mangle: {
    topLevel: false,
    keepNames: ['exports', 'module', 'require'],
    keepPrivateMembers: true
  },
  sourceMap: {
    filename: 'output.js',
    includeContent: true
  }
});

console.log(result.code);
console.log(result.map);  // Source map

Rust API

Adding to Cargo.toml

Cargo.toml
[dependencies]
oxc_minifier = "0.37"
oxc_allocator = "0.37"
oxc_parser = "0.37"
oxc_span = "0.37"
oxc_codegen = "0.37"

Basic Usage

use oxc_allocator::Allocator;
use oxc_parser::Parser;
use oxc_span::SourceType;
use oxc_minifier::{Minifier, MinifierOptions};
use oxc_codegen::{Codegen, CodegenOptions};

fn main() {
    let allocator = Allocator::default();
    let source_text = r#"
        function calculateTotal(items) {
            let total = 0;
            for (let i = 0; i < items.length; i++) {
                total = total + items[i].price;
            }
            return total;
        }
    "#;
    let source_type = SourceType::mjs();
    
    // Parse
    let ret = Parser::new(&allocator, source_text, source_type).parse();
    let mut program = ret.program;
    
    // Minify
    let options = MinifierOptions::default();
    let minifier = Minifier::new(options);
    let ret = minifier.minify(&allocator, &mut program);
    
    // Generate code
    let code = Codegen::new()
        .with_options(CodegenOptions {
            minify: true,
            ..CodegenOptions::default()
        })
        .build(&program)
        .code;
    
    println!("{}", code);
}

Minifier Options

use oxc_minifier::{MinifierOptions, CompressOptions, MangleOptions};

let options = MinifierOptions {
    mangle: Some(MangleOptions {
        top_level: false,
        keep_names: vec!["exports".to_string(), "require".to_string()],
        keep_private_members: true,
        ..MangleOptions::default()
    }),
    compress: Some(CompressOptions {
        dead_code: true,
        fold_constants: true,
        drop_console: true,
        drop_debugger: true,
        target: ESTarget::ES2015,
        passes: None,  // Until fixed point
        ..CompressOptions::default()
    }),
};

Dead Code Elimination Only

let minifier = Minifier::new(options);
let ret = minifier.dce(&allocator, &mut program);

Optimization Examples

Constant Folding

const x = 1 + 2 + 3;
const y = 'hello' + ' ' + 'world';
const z = true && false;
const a = 10 * 5 / 2;

Dead Code Elimination

function example() {
  if (false) {
    console.log('unreachable');
  }
  
  return 42;
  
  console.log('also unreachable');
}

const unused = 123;

Boolean Optimization

const a = x === true;
const b = y === false;
const c = !!z;
const d = Boolean(w);

Variable Merging

function process() {
  var x = 1;
  var y = 2;
  var z = 3;
  return x + y + z;
}

Property Shorthand

const obj = {
  x: x,
  y: y,
  method: function() {}
};

Full Minification

function calculateDiscount(price, discountPercent) {
  if (discountPercent <= 0 || discountPercent > 100) {
    throw new Error('Invalid discount');
  }
  
  const discountAmount = price * (discountPercent / 100);
  const finalPrice = price - discountAmount;
  
  return finalPrice;
}

const result = calculateDiscount(100, 20);
console.log(result);

Advanced Features

Tree Shaking

Remove unused exports and imports:
const result = minify(code, {
  compress: {
    deadCode: true,
    treeshake: true
  }
});

Multiple Passes

Run multiple compression passes for maximum compression:
const result = minify(code, {
  compress: {
    passes: 5  // Run 5 passes
  }
});
By default, the minifier runs until a fixed point (no further optimizations possible).

Keep Specific Names

Prevent mangling of specific identifiers:
const result = minify(code, {
  mangle: {
    keepNames: [
      'jQuery',
      '$',
      'exports',
      'require',
      'module'
    ]
  }
});

Target Environment

Optimize for specific ECMAScript version:
const result = minify(code, {
  compress: {
    target: 'es2015'  // Use ES2015+ features
  }
});

Performance

Benchmarks

The minifier is highly optimized for performance:
ToolTime (1000 files)Size Reduction
Oxc Minifier~2s~45%
Terser~25s~50%
esbuild~1.5s~40%
Oxc balances speed and compression ratio. While Terser may achieve slightly better compression, Oxc is significantly faster.

Compression Statistics

Typical compression results:
  • JavaScript libraries: 40-50% size reduction
  • Application code: 35-45% size reduction
  • With gzip: Additional 60-70% reduction
  • With Brotli: Additional 70-80% reduction

Integration

Bundler Plugins

rollup.config.js
import oxc from '@rollup/plugin-oxc';

export default {
  plugins: [
    oxc({
      minify: true,
      compress: {
        dropConsole: true
      },
      mangle: {
        topLevel: true
      }
    })
  ]
};

CLI Usage (via oxc)

# Minify a single file
oxc minify input.js -o output.min.js

# Minify with options
oxc minify input.js -o output.min.js --compress --mangle

# Minify multiple files
oxc minify src/**/*.js --out-dir dist

# Generate source maps
oxc minify input.js -o output.min.js --source-map

Best Practices

Development vs Production

Use compression only in production builds for faster development.

Source Maps

Always generate source maps for production debugging.

Test After Minification

Run tests on minified code to catch edge cases.

Keep Critical Names

Preserve names that are accessed externally or via reflection.

Common Pitfalls

  • eval() usage: May break with aggressive mangling
  • Property access via strings: Use keepNames for dynamic properties
  • External APIs: Don’t mangle exported function names
  • Polyfills: May need to exclude certain names

Comparison with Other Minifiers

vs Terser

FeatureOxcTerser
SpeedVery FastSlow
CompressionGoodExcellent
Correctness100%99.9%
ES2024 SupportYesPartial
ConfigurationSimpleComplex

vs esbuild

FeatureOxcesbuild
SpeedComparableSlightly Faster
CompressionBetterGood
Optimizations17+ passesFewer passes
ManglingAdvancedBasic

vs SWC

FeatureOxcSWC
SpeedComparableComparable
CompressionBetterGood
IntegrationGrowingMature
OptimizationMore passesFewer passes

Limitations

  • No HTML/CSS minification: JavaScript only
  • Limited property mangling: Conservative by default
  • No custom plugins: Built-in optimizations only

Debugging Minified Code

Source Maps

Always use source maps in production:
const result = minify(code, {
  compress: true,
  mangle: true,
  sourceMap: {
    filename: 'bundle.js',
    url: 'bundle.js.map',
    includeContent: true
  }
});

// Write source map
fs.writeFileSync('bundle.js.map', JSON.stringify(result.map));

Keep Format Mode

For debugging, keep formatting:
const result = minify(code, {
  compress: true,
  mangle: false,
  keepFormat: true  // Preserve whitespace and newlines
});

Resources

GitHub Repository

Source code and examples

Rust Docs

Complete Rust API documentation

npm Package

Node.js bindings

Playground

Try minification online

FAQ

Actual reduction depends on code style and patterns. Well-written modern code may see 30-40% reduction. Verbose code with many comments can see 50%+ reduction.
Yes! The minifier is extensively tested against Test262, Babel, and TypeScript test suites. However, always test your specific codebase.
Property mangling is conservative by default to avoid breaking code. You can enable it for specific properties.
Yes, but TypeScript must be transpiled to JavaScript first using the transformer.
The default (until fixed point) is recommended. Manual passes (e.g., 3-5) can be faster with similar results.
Common causes: eval() usage, dynamic property access, or external name dependencies. Use keepNames to preserve critical identifiers.

Build docs developers (and LLMs) love