Skip to main content
The commandkit build command creates an optimized production bundle of your Discord bot, ready for deployment.

Basic Usage

Build your bot for production:
commandkit build
This will:
  1. Run TypeScript type checking
  2. Bundle your code with optimizations
  3. Output to the dist/ directory (configurable)
  4. Generate source maps (configurable)
  5. Copy locale files if present
Production builds are optimized for performance with minification and tree-shaking.

Command Options

Custom Config Path

Specify a custom config file:
commandkit build --config ./configs/commandkit.js
commandkit build -c ./custom-config.js

Build Output

By default, production builds are written to dist/ directory:
project/
├── dist/                 # Production build output
│   ├── index.js         # Entry point with bootstrap code
│   ├── app.js           # Your main bot file
│   └── app/             # Bundled commands and events
│       ├── commands/
│       └── events/
├── src/                 # Your source code
└── commandkit.js        # Config file

Entry Point Generation

The CLI automatically generates an optimized entry point (dist/index.js) that:
  • Loads environment variables
  • Imports Discord.js and CommandKit
  • Bootstraps your application
  • Handles initialization errors
// Generated entry point structure

// Load environment variables
process.loadEnvFile('.env')
process.loadEnvFile('.env.production')

// Bootstrap application
async function bootstrap() {
  const { Client } = await import('discord.js')
  const { commandkit } = await import('commandkit')
  const app = await import('./app.js')
  
  commandkit.setClient(app.default)
  await commandkit.start()
}

bootstrap().catch(console.error)

Configuration Options

Customize the build in your commandkit.js config:

Output Directory

export default {
  distDir: 'build', // Default: 'dist'
}

Source Maps

Control source map generation:
export default {
  sourceMap: {
    development: true,  // Default: true
    production: true,   // Default: true
  },
}
# Enables debugging in production
sourceMap: { production: true }
Pros:
  • Better error stack traces
  • Easier debugging
Cons:
  • Slightly larger bundle size

Disable Chunking

Control code splitting:
export default {
  compilerOptions: {
    disableChunking: false, // Default: false
  },
}
Chunking is enabled by default in production to optimize bundle size through code splitting.

Anti-Crash Script

Control whether to include the anti-crash monitor:
export default {
  antiCrashScript: {
    development: true,  // Default: true
    production: false,  // Default: false
  },
}
The anti-crash monitor is disabled by default in production. Use proper error handling instead of relying on uncaught exception handlers.

TypeScript Type Checking

Production builds include full TypeScript type checking by default:
# Type checking is performed before building
commandkit build

Disable Type Checking

If you want to skip type checking:
export default {
  typescript: {
    ignoreBuildErrors: true, // Default: false
  },
}
Disabling type checking may lead to runtime errors. Only use this for quick deployments or when you have a separate type checking step.

Environment Variables

Production builds automatically load:
.env                 # Base variables
.env.production      # Production-specific
These environment variables are injected at build time:
process.env.NODE_ENV = 'production'
process.env.COMMANDKIT_BOOTSTRAP_MODE = 'production'
process.env.COMMANDKIT_IS_DEV = 'false'

Public Variables

Variables prefixed with COMMANDKIT_PUBLIC_ are embedded in the bundle:
# .env
COMMANDKIT_PUBLIC_BOT_VERSION=1.0.0
COMMANDKIT_PUBLIC_API_URL=https://api.example.com
// Available in your code
console.log(process.env.COMMANDKIT_PUBLIC_BOT_VERSION)
Only use COMMANDKIT_PUBLIC_ for non-sensitive data. Never expose API keys or secrets.

Custom Entry Points

Add additional entry points to the build:
export default {
  entrypoints: [
    'src/scripts/deploy-commands.ts',
    'src/scripts/database-migrate.ts',
  ],
}
These will be built alongside your main application:
dist/
├── index.js
├── app.js
└── scripts/
    ├── deploy-commands.js
    └── database-migrate.js

Compiler Plugins

Extend the build process with compiler plugins:
import { defineConfig } from 'commandkit/config'
import myPlugin from './plugins/my-plugin.js'

export default defineConfig({
  plugins: [myPlugin()],
})

Advanced Configuration

Custom Rolldown Options

Access the underlying bundler configuration:
export default {
  compilerOptions: {
    tsdown: {
      // Custom tsdown/rolldown options
      minify: true,
      target: 'node20',
    },
  },
}

Custom Rolldown Plugins

Add Rolldown plugins directly:
import json from '@rollup/plugin-json'

export default {
  rolldownPlugins: [
    json(),
  ],
}

Running the Production Build

After building, start your bot:
commandkit start
Or run the bundle directly:
node dist/index.js
commandkit start
Benefits:
  • Validates build exists
  • Respects config file settings
  • Consistent with development workflow

Sharding Support

If you have a sharding manager, the CLI will automatically use it:
dist/
├── index.js              # Default entry point
└── sharding-manager.js   # Auto-detected and used instead
If sharding-manager.js exists in the output directory, it will be used as the entry point instead of index.js.

Build Performance

Production builds are optimized for output quality:
# Example build output
Creating an optimized production build

Building src/app.ts, src/app/commands/*, src/app/events/*...

Production build completed!
Typical build times:
  • Small project (under 50 files): ~2-5 seconds
  • Medium project (50-200 files): ~5-15 seconds
  • Large project (over 200 files): ~15-30 seconds

Deployment Checklist

1

Build your project

commandkit build
2

Test the production build locally

commandkit start
3

Verify environment variables

Ensure .env.production is properly configured
4

Deploy the dist/ directory

Copy dist/, node_modules/, and .env.production to your server
5

Start on the server

node dist/index.js

Continuous Integration

Example GitHub Actions workflow:
name: Build and Deploy

on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - uses: actions/setup-node@v3
        with:
          node-version: '20'
          
      - run: npm ci
      
      - run: npm run build # commandkit build
      
      - name: Upload build artifacts
        uses: actions/upload-artifact@v3
        with:
          name: dist
          path: dist/

Troubleshooting

If the build fails due to TypeScript errors:
  1. Fix the type errors in your code
  2. Or temporarily disable type checking:
    typescript: { ignoreBuildErrors: true }
    
  3. Run tsc --noEmit separately to check types
If modules are missing when running the build:
  1. Ensure all dependencies are in dependencies, not devDependencies
  2. Check that node_modules/ is included in your deployment
  3. Run npm ci on the server to install dependencies
If environment variables aren’t working:
  1. Ensure .env.production exists
  2. Check that variable names are correct
  3. Remember: only COMMANDKIT_PUBLIC_* vars are embedded
  4. Other vars must be present at runtime
If your build is too large:
  1. Enable chunking (default behavior)
  2. Disable source maps for production
  3. Check for accidentally bundled dev dependencies
  4. Use skipNodeModulesBundle for native modules

Next Steps

Development Mode

Return to development with hot reloading

Code Generators

Generate commands and events

Build docs developers (and LLMs) love