CLI
Programmatic API
Use Better-T-Stack programmatically in your Node.js applications
Overview
You can call Better-T-Stack directly from TypeScript/JavaScript without shelling out to the CLI.
The programmatic API is exported from create-better-t-stack and is designed for automation tools, internal generators, and scripted workflows.
Installation
npm i create-better-t-stackQuick Start
import { create } from "create-better-t-stack";
const result = await create("my-app", {
frontend: ["tanstack-router"],
backend: "hono",
database: "sqlite",
orm: "drizzle",
auth: "better-auth",
packageManager: "bun",
install: false,
});
result.match({
ok: (data) => {
console.log(`Project created at: ${data.projectDirectory}`);
console.log(`Reproducible command: ${data.reproducibleCommand}`);
},
err: (error) => {
console.error(`Failed: ${error.message}`);
},
});API Reference
create(projectName?, options?)
Create a new project.
function create(
projectName?: string,
options?: Partial<CreateInput>,
): Promise<Result<InitResult, CreateError>>;Notes:
- Uses the same option model as the CLI
createcommand (frontend,backend,database,orm,api,auth,addons, etc.). - Runs in silent mode (no interactive prompts / no CLI UI output).
- Returns a
Result(ok/err) instead of exiting the process.
add(options?)
Add addons to an existing Better-T-Stack project.
function add(options?: {
addons?: Addons[];
install?: boolean;
packageManager?: PackageManager;
projectDir?: string;
}): Promise<AddResult | undefined>;Example:
import { add } from "create-better-t-stack";
const result = await add({
projectDir: "./my-app",
addons: ["biome", "mcp"],
install: true,
});
if (result?.success) {
console.log(`Added: ${result.addedAddons.join(", ")}`);
} else {
console.error(result?.error ?? "Failed to add addons");
}sponsors()
Show sponsors (same behavior as CLI command).
docs()
Open docs URL (same behavior as CLI command).
builder()
Open the web stack builder (same behavior as CLI command).
Result Types
InitResult (from create on ok)
type InitResult = {
success: boolean;
projectConfig: ProjectConfig;
reproducibleCommand: string;
timeScaffolded: string;
elapsedTimeMs: number;
projectDirectory: string;
relativePath: string;
error?: string;
};AddResult (from add)
type AddResult = {
success: boolean;
addedAddons: Addons[];
projectDir: string;
error?: string;
};CreateError
create() can return these error types in Result.err(...):
UserCancelledErrorCLIErrorProjectCreationError
Error Handling Pattern
import { create } from "create-better-t-stack";
const result = await create("existing-dir", {
directoryConflict: "error",
});
if (result.isErr()) {
console.error(result.error.message);
process.exit(1);
}
console.log(result.value.projectDirectory);Mapping CLI to Programmatic
CLI:
create-better-t-stack my-app \
--frontend tanstack-router \
--backend hono \
--database postgres \
--orm drizzle \
--auth better-authProgrammatic:
const result = await create("my-app", {
frontend: ["tanstack-router"],
backend: "hono",
database: "postgres",
orm: "drizzle",
auth: "better-auth",
});