Skip to main content

Node.js API

Use Simple Scaffold programmatically for more complex workflows, custom logic, or integration into build tools.

Basic Usage

import Scaffold from "simple-scaffold"

const scaffold = new Scaffold({
name: "MyComponent",
templates: ["templates/component"],
output: "src/components",
})
await scaffold.run()

Loading from a Config File

import Scaffold from "simple-scaffold"

const scaffold = await Scaffold.fromConfig(
"scaffold.config.js", // local path or HTTPS Git URL
{ name: "MyComponent", key: "component" },
{
/* optional config overrides */
},
)
await scaffold.run()

Config Interface

interface ScaffoldConfig {
name: string
templates: string[]
output: FileResponse<string>
subdir?: boolean
subdirHelper?: string
data?: Record<string, unknown>
overwrite?: FileResponse<boolean>
logLevel?: "none" | "debug" | "info" | "warn" | "error"
dryRun?: boolean
helpers?: Record<string, Helper>
inputs?: Record<string, ScaffoldInput>
beforeWrite?(
content: Buffer,
rawContent: Buffer,
outputPath: string,
): string | Buffer | undefined | Promise<string | Buffer | undefined>
afterScaffold?: AfterScaffoldHook
}

For the full API reference, see ScaffoldConfig.

Options

OptionTypeDescription
namestringName for generated files (required)
templatesstring[]Template paths or globs; prefix with ! to exclude (required)
outputstring | FunctionOutput directory, or a function for per-file control
dataRecord<string, unknown>Custom data available in templates
inputsRecord<string, ScaffoldInput>Interactive input definitions (see Inputs)
helpersRecord<string, Function>Custom Handlebars helpers
subdirbooleanCreate a parent directory with the input name (default: false)
subdirHelperstringHelper to transform the subdir name (e.g. "pascalCase")
overwriteboolean | FunctionOverwrite existing files (default: false); function for per-file logic
dryRunbooleanPreview without writing files (default: false)
logLevelstringLog verbosity (default: "info")
beforeWriteFunctionAsync hook before each file is written
afterScaffoldFunction | stringHook after all files are written

Hooks

Before Write

Runs before each file is written. Return a string or Buffer to replace the file contents, or undefined to keep the default (Handlebars-processed) output.

await new Scaffold({
name: "MyComponent",
templates: ["templates/component"],
output: "src/components",
beforeWrite: async (content, rawContent, outputPath) => {
// Format the output, transform it, or return undefined to keep as-is
return content.toString().trim()
},
}).run()

After Scaffold Hook

Runs after all files have been written. Pass a function for full control, or a string to run a shell command in the output directory.

Function:

await new Scaffold({
name: "my-app",
templates: ["templates/app"],
output: ".",
afterScaffold: async ({ config, files }) => {
console.log(`Created ${files.length} files`)
// e.g. run npm install, git init, open editor, etc.
},
}).run()

Shell command:

await new Scaffold({
name: "my-app",
templates: ["templates/app"],
output: "my-app",
afterScaffold: "npm install && git init",
}).run()

The context object:

interface AfterScaffoldContext {
config: ScaffoldConfig
files: string[] // absolute paths of written files
}

In dry-run mode, the hook is still called but the files array will be empty.

Inputs

Define interactive prompts that merge into template data:

await new Scaffold({
name: "component",
templates: ["templates/component"],
output: "src/components",
inputs: {
author: { message: "Author name", required: true },
license: {
type: "select",
message: "License",
options: ["MIT", "Apache-2.0", "GPL-3.0"],
},
private: { type: "confirm", message: "Private package?", default: false },
port: { type: "number", message: "Dev server port", default: 3000 },
},
}).run()
// In templates: {{ author }}, {{ license }}, {{ private }}, {{ port }}
interface ScaffoldInput {
type?: "text" | "select" | "confirm" | "number"
message?: string
required?: boolean
default?: string | boolean | number
options?: (string | { name: string; value: string })[] // for type: "select"
}
  • Required inputs are prompted if not already in data
  • Optional inputs with a default are applied silently
  • Pre-providing values in data skips the prompt for that input

Full Example

import path from "path"
import Scaffold from "simple-scaffold"

await new Scaffold({
name: "MyComponent",
templates: [path.join(__dirname, "scaffolds", "component")],
output: path.join(__dirname, "src", "components"),
subdir: true,
subdirHelper: "pascalCase",
data: {
property: "value",
},
helpers: {
twice: (text) => [text, text].join(" "),
},
inputs: {
author: { message: "Author name", required: true },
license: { message: "License", default: "MIT" },
},
beforeWrite: (content, rawContent, outputPath) => {
return content.toString().toUpperCase()
},
afterScaffold: async ({ config, files }) => {
console.log(`Created ${files.length} files in ${config.output}`)
},
}).run()