Documentation Index Fetch the complete documentation index at: https://mintlify.com/amanvarshney01/create-better-t-stack/llms.txt
Use this file to discover all available pages before exploring further.
The template generator is the core engine that powers project scaffolding. You can use it directly for advanced use cases.
Overview
The template generator takes a project configuration and embedded templates, then generates a complete project structure in-memory using a virtual filesystem.
API
generate()
Generate a virtual project file tree from templates and configuration.
function generate (
options : GeneratorOptions
) : Promise < Result < VirtualFileTree , GeneratorError >>
Source : ~/workspace/source/packages/template-generator/src/generator.ts:50
Parameters
Generator configuration options. Complete project configuration.
templates
Map<string, string>
required
Map of template paths to template content. Example : EMBEDDED_TEMPLATES
Base path for template resolution (rarely needed).
CLI version string to write to bts.jsonc.
Return Type
Promise < Result < VirtualFileTree , GeneratorError >>
Returns a Result with either:
ok: VirtualFileTree - Generated project tree
err: GeneratorError - Generation error
Example
import {
generate ,
EMBEDDED_TEMPLATES ,
type ProjectConfig ,
} from "create-better-t-stack" ;
const config : ProjectConfig = {
projectName: "my-app" ,
projectDir: "/virtual" ,
relativePath: "./virtual" ,
frontend: [ "tanstack-router" ],
backend: "hono" ,
runtime: "bun" ,
database: "sqlite" ,
orm: "drizzle" ,
api: "trpc" ,
auth: "none" ,
payments: "none" ,
addons: [],
examples: [],
packageManager: "bun" ,
install: false ,
git: false ,
dbSetup: "none" ,
webDeploy: "none" ,
serverDeploy: "none" ,
};
const result = await generate ({
config ,
templates: EMBEDDED_TEMPLATES ,
version: "1.0.0" ,
});
result . match ({
ok : ( tree ) => console . log ( `Generated ${ tree . fileCount } files` ),
err : ( error ) => console . error ( error . message ),
});
EMBEDDED_TEMPLATES
Pre-bundled templates included with the CLI.
const EMBEDDED_TEMPLATES : Map < string , string >
Source : ~/workspace/source/packages/template-generator/src/templates.generated.ts
This is a generated file containing all Handlebars templates embedded at build time.
Example
import { EMBEDDED_TEMPLATES , TEMPLATE_COUNT } from "create-better-t-stack" ;
console . log ( ` ${ TEMPLATE_COUNT } templates available` );
console . log ( `Templates:` , Array . from ( EMBEDDED_TEMPLATES . keys ()));
TEMPLATE_COUNT
Number of embedded templates.
const TEMPLATE_COUNT : number
Source : ~/workspace/source/packages/template-generator/src/templates.generated.ts
Template Processing
The generator processes templates in phases:
Base Template - Root project structure
Frontend Templates - Frontend framework files
Backend Templates - Backend server files
Database Templates - Database configuration
API Templates - API layer (tRPC, etc.)
Config Package - Shared configuration
Env Package - Environment variables
Auth Templates - Authentication setup
Payments Templates - Payment integration
Addon Templates - Additional tools
Example Templates - Example code
Extras - Additional utilities
Deploy Templates - Deployment configuration
Post-processing - Dependencies, catalogs, README
Advanced Usage
Custom Templates
You can provide custom templates instead of using EMBEDDED_TEMPLATES:
import { generate } from "create-better-t-stack" ;
const customTemplates = new Map < string , string >([
[ "package.json.hbs" , JSON . stringify ({
name: "{{projectName}}" ,
version: "1.0.0" ,
scripts: {
dev: "{{#if (eq runtime 'bun')}}bun{{else}}node{{/if}} index.ts"
}
}, null , 2 )],
[ "index.ts.hbs" , `console.log('Hello {{projectName}}!');` ],
]);
const result = await generate ({
config: myConfig ,
templates: customTemplates ,
});
Template Helpers
Templates use Handlebars with custom helpers:
eq - Equality Check
{{ #if ( eq database "postgres" ) }}
// Postgres-specific code
{{ /if }}
ne - Not Equal
{{ #if ( ne database "none" ) }}
// Database is configured
{{ /if }}
and - Logical AND
{{ #if ( and ( eq database "postgres" ) ( eq orm "drizzle" )) }}
// Postgres + Drizzle
{{ /if }}
or - Logical OR
{{ #if ( or ( eq database "postgres" ) ( eq database "mysql" )) }}
// SQL database
{{ /if }}
includes - Array Contains
{{ #if ( includes frontend "next" ) }}
// Next.js is in frontend array
{{ /if }}
Accessing Template Content
Read generated file content from the virtual tree:
import { generate , EMBEDDED_TEMPLATES } from "create-better-t-stack" ;
const result = await generate ({
config: myConfig ,
templates: EMBEDDED_TEMPLATES ,
});
if ( result . isOk ()) {
const tree = result . value ;
function findFile ( node , path ) {
if ( node . type === "file" && node . path === path ) {
return node ;
}
if ( node . type === "directory" ) {
for ( const child of node . children ) {
const found = findFile ( child , path );
if ( found ) return found ;
}
}
return null ;
}
const packageJson = findFile ( tree . root , "package.json" );
if ( packageJson ) {
console . log ( packageJson . content );
}
}
Writing to Disk
Convert virtual tree to real files:
import { generate , EMBEDDED_TEMPLATES } from "create-better-t-stack" ;
import fs from "node:fs" ;
import path from "node:path" ;
const result = await generate ({
config: myConfig ,
templates: EMBEDDED_TEMPLATES ,
});
if ( result . isOk ()) {
const tree = result . value ;
const outputDir = "/path/to/output" ;
function writeNode ( node , parentPath ) {
const fullPath = path . join ( parentPath , node . name );
if ( node . type === "directory" ) {
fs . mkdirSync ( fullPath , { recursive: true });
for ( const child of node . children ) {
writeNode ( child , fullPath );
}
} else {
fs . writeFileSync ( fullPath , node . content , "utf-8" );
}
}
writeNode ( tree . root , outputDir );
console . log ( `Wrote ${ tree . fileCount } files to ${ outputDir } ` );
}
Template Data
All templates receive a TemplateData context:
type TemplateData = ProjectConfig & {
// Additional computed fields available in templates
}
Templates have access to all ProjectConfig fields:
{
"name": " {{ projectName }} ",
"scripts": {
"dev": " {{ #if ( eq runtime 'bun' ) }} bun {{ else }} node {{ /if }} dev"
},
"dependencies": {
{{ #if ( eq database "postgres" ) }}
"postgres": "^3.0.0",
{{ /if }}
}
}
Examples
Generate and Analyze
import { generate , EMBEDDED_TEMPLATES } from "create-better-t-stack" ;
const result = await generate ({
config: {
projectName: "my-app" ,
// ... full config
},
templates: EMBEDDED_TEMPLATES ,
version: "1.0.0" ,
});
if ( result . isOk ()) {
const { fileCount , directoryCount , root } = result . value ;
console . log ( `Files: ${ fileCount } ` );
console . log ( `Directories: ${ directoryCount } ` );
// Count file types
const extensions = new Map ();
function countTypes ( node ) {
if ( node . type === "file" ) {
const ext = node . extension || "no-ext" ;
extensions . set ( ext , ( extensions . get ( ext ) || 0 ) + 1 );
} else {
node . children . forEach ( countTypes );
}
}
countTypes ( root );
console . log ( "File types:" , Object . fromEntries ( extensions ));
}
Compare Configurations
import { generate , EMBEDDED_TEMPLATES } from "create-better-t-stack" ;
async function compareConfigs ( config1 , config2 ) {
const result1 = await generate ({
config: config1 ,
templates: EMBEDDED_TEMPLATES ,
});
const result2 = await generate ({
config: config2 ,
templates: EMBEDDED_TEMPLATES ,
});
if ( result1 . isOk () && result2 . isOk ()) {
console . log ( `Config 1: ${ result1 . value . fileCount } files` );
console . log ( `Config 2: ${ result2 . value . fileCount } files` );
console . log ( `Difference: ${ result2 . value . fileCount - result1 . value . fileCount } ` );
}
}