---
title: Programmatic API
description: Use Better-T Stack programmatically in your Node.js applications
---

## Overview

The Better-T Stack CLI can be used programmatically in your Node.js applications, allowing you to create projects, add features, and manage configurations through JavaScript/TypeScript code instead of shell commands.

## Installation

Install the package in your Node.js project:

```bash
npm install create-better-t-stack
# or
pnpm add create-better-t-stack
# or
bun add create-better-t-stack
```

## Quick Start

### Basic Project Creation

```typescript
import { init } from "create-better-t-stack";

async function createProject() {
  const result = await init("my-app", {
    yes: true, // Use defaults, no prompts
    frontend: ["tanstack-router"],
    backend: "hono",
    database: "sqlite",
    orm: "drizzle",
    auth: true,
    packageManager: "bun",
    install: false, // Don't install deps automatically
    disableAnalytics: true, // Disable analytics
  });

  if (result.success) {
    console.log(`✅ Project created at: ${result.projectDirectory}`);
    console.log(`📝 Reproducible command: ${result.reproducibleCommand}`);
    console.log(`⏱️  Time taken: ${result.elapsedTimeMs}ms`);
  } else {
    console.error(`❌ Failed: ${result.error}`);
  }
}

createProject();
```

### Directory Conflict Handling

```typescript
import { init } from "create-better-t-stack";

const result = await init("existing-folder", {
  yes: true,
  directoryConflict: "increment", // Creates "existing-folder-1"
  renderTitle: false, // Hide ASCII art
});
```

### Disabling Analytics

You can disable analytics:

```typescript
import { init } from "create-better-t-stack";

const result = await init("my-private-project", {
  yes: true,
  disableAnalytics: true, // No analytics data will be sent
  frontend: ["tanstack-router"],
  backend: "hono",
});
```

> **Note:** Analytics help improve Better-T Stack by providing insights into usage patterns. When disabled, no data is collected or transmitted.

## API Reference

### `init(projectName?, options?)`

Creates a new Better-T Stack project.

**Parameters:**
- `projectName` (string, optional): Project name or directory path
- `options` (CreateInput, optional): Configuration options

**Returns:** `Promise<InitResult>`

**Example:**
```typescript
const result = await init("my-project", {
  frontend: ["next"],
  backend: "hono",
  database: "postgres",
  orm: "drizzle"
});
```

### `sponsors()`

Display Better-T Stack sponsors (same as CLI).

**Returns:** `Promise<void>`

### `docs()`

Open documentation in browser (same as CLI).

**Returns:** `Promise<void>`

### `builder()`

Open web-based stack builder (same as CLI).

**Returns:** `Promise<void>`

## Type Definitions

### `CreateInput`

Configuration options for project creation:

```typescript
interface CreateInput {
  projectName?: string;
  yes?: boolean;                    // Skip prompts, use defaults
  yolo?: boolean;                   // Bypass validations (not recommended)
  verbose?: boolean;               // Show JSON result (CLI only, programmatic always returns result)
  database?: Database;              // "none" | "sqlite" | "postgres" | "mysql" | "mongodb"
  orm?: ORM;                        // "none" | "drizzle" | "prisma" | "mongoose"
  auth?: boolean;                   // Include authentication
  frontend?: Frontend[];            // Array of frontend frameworks
  addons?: Addons[];               // Array of addons
  examples?: Examples[];           // Array of examples
  git?: boolean;                   // Initialize git repo
  packageManager?: PackageManager; // "npm" | "pnpm" | "bun"
  install?: boolean;               // Install dependencies
  dbSetup?: DatabaseSetup;         // Database hosting setup
  backend?: Backend;               // Backend framework
  runtime?: Runtime;               // Runtime environment
  api?: API;                       // API type
  webDeploy?: WebDeploy;          // Web deployment setup
  directoryConflict?: DirectoryConflict; // "merge" | "overwrite" | "increment" | "error"
  renderTitle?: boolean;           // Show ASCII art title
  disableAnalytics?: boolean;      // Disable analytics and telemetry
}
```

### `InitResult`

Result object returned by `init()`:

```typescript
interface InitResult {
  success: boolean;                // Whether operation succeeded
  projectConfig: ProjectConfig;    // Final project configuration
  reproducibleCommand: string;     // CLI command to recreate project
  timeScaffolded: string;          // ISO timestamp of creation
  elapsedTimeMs: number;          // Time taken in milliseconds
  projectDirectory: string;        // Absolute path to project
  relativePath: string;           // Relative path to project
  error?: string;                 // Error message if failed
}
```

## Configuration Options

### Directory Conflict Resolution

Control how existing directories are handled:

```typescript
// Merge with existing files (careful with conflicts)
directoryConflict: "merge"

// Completely overwrite existing directory
directoryConflict: "overwrite"

// Create new directory with incremented name (my-app-1)
directoryConflict: "increment"

// Throw error if directory exists
directoryConflict: "error"
```

### Title Rendering

Control CLI output appearance:

```typescript
// Hide ASCII art title (useful for automated scripts)
renderTitle: false

// Show ASCII art title (default)
renderTitle: true
```

### YOLO Mode

Bypass validation checks (not recommended):

```typescript
// Skip compatibility validations
yolo: true
```

## Error Handling

The programmatic API uses different error handling than the CLI:

### Directory Conflicts

Directory conflict errors return structured results instead of throwing:

```typescript
const result = await init("existing-dir", {
  directoryConflict: "error"
});

if (!result.success) {
  console.log(result.error); // "Directory exists and is not empty..."
  // Handle gracefully instead of process exit
}
```

### Validation Errors

Validation errors still throw exceptions (maintains CLI compatibility):

```typescript
try {
  await init("test", {
    database: "mongodb",
    orm: "drizzle" // Invalid combination
  });
} catch (error) {
  console.error(error.message); // "MongoDB requires Mongoose or Prisma ORM"
}
```

## Migration from CLI

### CLI Command to Programmatic API

Convert CLI commands to programmatic calls:

```bash
# CLI Command
create-better-t-stack my-app \
  --frontend tanstack-router \
  --backend hono \
  --database postgres \
  --orm drizzle \
  --auth \
  --yes
```

```typescript
// Programmatic Equivalent
const result = await init("my-app", {
  frontend: ["tanstack-router"],
  backend: "hono",
  database: "postgres",
  orm: "drizzle",
  auth: true,
  yes: true
});
```

### Handling Prompts

CLI prompts become explicit options:

```typescript
// Instead of interactive prompts, specify all options
const result = await init("my-app", {
  yes: true, // Skip all prompts
  frontend: ["tanstack-router"],
  backend: "hono",
  database: "postgres",
  orm: "drizzle",
  auth: true,
  addons: ["biome", "turborepo"],
  examples: ["todo"],
  packageManager: "bun",
  install: false,
  git: true
});
```
