Multimodal Deployment

The Stacks.js reference implementation can target the web, desktop, CLIs, libraries, and serverless from a single codebase, with infrastructure managed by ts-cloud.

Protocol context — This page describes Stacks.js-specific tooling related to the draft Infrastructure and deployment contract. Provider support must be verified against the installed integration; no formal conformance report exists yet.

Web Applications

Standard web application deployment:

buddy build:web
buddy deploy

Output structure:

dist/
├── client/
│   ├── index.html
│   ├── assets/
│   │   ├── main-[hash].js
│   │   └── style-[hash].css
│   └── manifest.json
└── server/
    └── index.js

Desktop Applications (Craft)

Build native desktop apps from web codebase using Craft, Stacks' Zig-based desktop framework:

buddy build:desktop

Generates:

  • macOS: .app bundle and .dmg installer
  • Windows: .exe installer and .msi package
  • Linux: .deb, .rpm, and .AppImage

Craft Configuration

// config/desktop.ts
export default {
  productName: 'My App',
  identifier: 'com.example.myapp',

  windows: {
    main: {
      width: 1200,
      height: 800,
      resizable: true,
    },
  },

  security: {
    csp: "default-src 'self'",
  },
}

APIs & Serverless

Standalone API deployment:

buddy build:api
buddy deploy:serverless

In serverless mode, ts-cloud packages a single build artifact into three coordinated AWS Lambda functions — rather than one function per route:

serverless artifact
├── http   → API Gateway HTTP API v2   (handles all routes)
├── queue  → SQS event-source worker   (background jobs)
└── cli    → EventBridge scheduler      (migrations, cron, commands)

CLI Applications

Build and distribute CLI tools:

buddy build:cli

Output:

dist/
├── cli-linux-x64
├── cli-linux-arm64
├── cli-darwin-x64
├── cli-darwin-arm64
└── cli-windows-x64.exe

Publishing to npm:

buddy publish:cli
# Users install via: npm install -g @yourorg/cli

Library Publishing

Publish reusable packages:

# Component library
buddy build:components
buddy publish:components

# Function library
buddy build:functions
buddy publish:functions

Generated package:

{
  "name": "@yourorg/components",
  "exports": {
    ".": "./dist/index.js",
    "./Button": "./dist/Button.js",
    "./Card": "./dist/Card.js"
  },
  "types": "./dist/index.d.ts"
}

Cross-Platform Binary Distribution

Stacks can use Bun's native compilation for selected executable targets. Test each operating system and architecture explicitly; a compiled launcher may still depend on external services, system libraries, assets, or a companion runtime.

Supported Platforms

PlatformArchitectureBinary
Linuxx64app-linux-x64
Linuxarm64app-linux-arm64
macOSx64 (Intel)app-darwin-x64
macOSarm64 (Apple Silicon)app-darwin-arm64
Windowsx64app-windows-x64.exe

Building Binaries

# Build for current platform
buddy build:binary

# Build for all platforms
buddy build:binary --all

# Build for specific platform
buddy build:binary --target linux-x64
buddy build:binary --target darwin-arm64
buddy build:binary --target windows-x64

Binary Configuration

// config/binary.ts
export default {
  name: 'my-app',

  // Entry point
  entry: './src/cli.ts',

  // Output directory
  outDir: './dist/binaries',

  // Target platforms
  targets: [
    'linux-x64',
    'linux-arm64',
    'darwin-x64',
    'darwin-arm64',
    'windows-x64',
  ],

  // Embed assets
  assets: [
    './templates/**/*',
    './config/defaults.json',
  ],

  // Minification
  minify: true,

  // Source maps (for debugging)
  sourcemap: 'external',

  // Bun compile options
  compile: {
    bytecode: true,
    define: {
      'process.env.NODE_ENV': '"production"',
    },
  },
}

Asset Embedding

Binaries can embed static assets for truly self-contained distribution:

// Access embedded assets at runtime
import template from './templates/default.html' with { type: 'file' }
import config from './config/defaults.json'

// Assets are available without external files
const html = await Bun.file(template).text()

Distribution Strategies

npm Distribution:

{
  "name": "@yourorg/cli",
  "bin": {
    "mycli": "./dist/cli.js"
  },
  "optionalDependencies": {
    "@yourorg/cli-linux-x64": "*",
    "@yourorg/cli-darwin-arm64": "*",
    "@yourorg/cli-windows-x64": "*"
  }
}

GitHub Releases:

# Upload binaries to GitHub release
buddy release --upload-binaries

Homebrew Formula (macOS/Linux):

class MyApp < Formula
  desc "My application description"
  homepage "https://github.com/yourorg/my-app"

  on_macos do
    if Hardware::CPU.arm?
      url "https://github.com/yourorg/my-app/releases/download/v1.0.0/my-app-darwin-arm64.tar.gz"
    else
      url "https://github.com/yourorg/my-app/releases/download/v1.0.0/my-app-darwin-x64.tar.gz"
    end
  end

  on_linux do
    url "https://github.com/yourorg/my-app/releases/download/v1.0.0/my-app-linux-x64.tar.gz"
  end

  def install
    bin.install "my-app"
  end
end

Binary Size Optimization

// config/binary.ts
export default {
  // Tree-shaking
  treeshake: true,

  // Exclude unused modules
  external: ['fsevents'],

  // Minification level
  minify: {
    whitespace: true,
    identifiers: true,
    syntax: true,
  },

  // Strip debug info
  strip: true,
}

Typical binary sizes:

Application TypeApproximate Size
Simple CLI15-25 MB
Full Framework App30-50 MB
With Embedded Assets35-60 MB

Code Signing

// config/signing.ts
export default {
  darwin: {
    identity: 'Developer ID Application: Your Name',
    entitlements: './entitlements.plist',
    notarize: {
      appleId: process.env.APPLE_ID,
      teamId: process.env.APPLE_TEAM_ID,
    },
  },

  windows: {
    certificate: './cert.pfx',
    password: process.env.CERT_PASSWORD,
    timestampServer: 'http://timestamp.digicert.com',
  },
}

Self-Update Mechanism

import { checkForUpdates, downloadUpdate, applyUpdate } from '@stacksjs/self-update'

// Check for updates
const update = await checkForUpdates({
  currentVersion: '1.0.0',
  repository: 'yourorg/my-app',
})

if (update.available) {
  console.log(`Update available: ${update.version}`)

  // Download update binary
  await downloadUpdate(update)

  // Apply update (restart required)
  await applyUpdate()
}