Discover OfficeForge: Enhance Microsoft Office with Open-Source Automation
Source: Dev.to
Part I: For Any Developer in Any Language
A Lightweight CLI That Works From Any Language
OfficeForge comes with a CLI tool that lets you automate Microsoft Office documents without touching Go. Whether you code in Python, Node.js, PHP, or Bash, you can generate Word files, fill templates, or batch‑process documents while keeping the formatting intact and without juggling parameters.
Get started by downloading the binary for your Windows architecture from the Releases page.
Replace a single keyword in a template
officeforge docx-single --input template.docx --output output.docx --key "{{NAME}}" --value "John Doe"
Generate multiple documents from CSV/JSON
officeforge docx-batch --input template.docx --output ./contracts --data employees.csv
Flexible Naming Patterns
Control how your generated documents are named using patterns:
# Sequential numbering
officeforge docx-batch --input template.docx --output ./output --data employees.csv --pattern "contract_%03d.docx"
# Creates: contract_001.docx, contract_002.docx, contract_003.docx
# Data‑based naming (CSV must have NAME column)
officeforge docx-batch --input template.docx --output ./output --data employees.csv --pattern "{NAME}_contract.docx"
# Creates: Alice_contract.docx, Bob_contract.docx
# Multiple fields (CSV has ID and COMPANY columns)
officeforge docx-batch --input template.docx --output ./output --data clients.csv --pattern "{COMPANY}_{ID}_agreement.docx"
# Creates: Acme_001_agreement.docx, TechCorp_002_agreement.docx
# Combine data and index
officeforge docx-batch --input template.docx --output ./output --data employees.csv --pattern "{DEPARTMENT}_report_{INDEX}.docx"
# Creates: Engineering_report_1.docx, Sales_report_2.docx
Because OfficeForge is a standalone binary with zero dependencies, you can call it from any language that can run system commands.
Node.js Example (using child_process)
import { exec } from "node:child_process";
import { promisify } from "node:util";
const execAsync = promisify(exec);
(async () => {
try {
const { stdout, stderr } = await execAsync(
`officeforge docx-batch --input template.docx --output ./contracts --data employees.csv --pattern "{EMPLOYEE_NAME} Contract.docx"`
);
if (stderr) console.error("CLI stderr:", stderr);
console.log("Success:", stdout);
} catch (err) {
console.error("Error:", err);
}
})();
Python Example (using subprocess)
import subprocess
cmd = [
"officeforge",
"docx-batch",
"--input", "template.docx",
"--output", "./contracts",
"--data", "employees.csv",
"--pattern", "{EMPLOYEE_NAME} Contract.docx"
]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
print("Error:", result.stderr)
else:
print("Success:", result.stdout)
PHP Example (using exec)
&1", $output, $returnCode);
if ($returnCode !== 0) {
echo "Error:\n";
echo implode("\n", $output);
} else {
echo "Success:\n";
echo implode("\n", $output);
}
?>
Whether you’re working in Node.js, Python, PHP, Bash, Go, or anything else, OfficeForge’s CLI gives you a language‑agnostic way to automate DOCX generation at high speeds.
Part II: For Go Developers Who Want Native Integration
Integrate OfficeForge Directly in Your Go Code
For Go developers, OfficeForge is also a fully programmatic library that can be embedded in your applications.
Installation
go get github.com/siliconcatalyst/officeforge@latest
Or install the CLI for mixed usage:
go install github.com/siliconcatalyst/officeforge/cmd/officeforge@latest
Single Keyword Replacement
import "github.com/siliconcatalyst/officeforge/docx"
err := docx.ProcessDocxSingle("template.docx", "output.docx", "{{NAME}}", "John Doe")
if err != nil {
log.Fatal(err)
}
Multiple Replacements
import "github.com/siliconcatalyst/officeforge/docx"
replacements := map[string]string{
"{{NAME}}": "John Doe",
"{{EMAIL}}": "john@example.com",
"{{DATE}}": "2025-12-07",
}
err := docx.ProcessDocxMulti("template.docx", "output.docx", replacements)
if err != nil {
log.Fatal(err)
}
Batch Document Generation
import "github.com/siliconcatalyst/officeforge/docx"
records := []map[string]string{
{"NAME": "Alice", "EMAIL": "alice@example.com"},
{"NAME": "Bob", "EMAIL": "bob@example.com"},
}
// Sequential numbering
err := docx.ProcessDocxMultipleRecords("template.docx", "./output", records, "contract_%03d.docx")
// Creates: contract_001.docx, contract_002.docx
// Data‑based naming using fields from records
err = docx.ProcessDocxMultipleRecords("template.docx", "./output", records, "{NAME}_contract.docx")
// Creates: Alice_contract.docx, Bob_contract.docx
// Multiple fields
err = docx.ProcessDocxMultipleRecords("template.docx", "./output", records, "{NAME}_{EMAIL}.docx")
// Creates: Alice_alice@example.com.docx, Bob_bob@example.com.docx
// Combine data and index
err = docx.ProcessDocxMultipleRecords("template.docx", "./output", records, "employee_{INDEX}_{NAME}.docx")
// Creates: employee_1_Alice.docx, employee_2_Bob.docx
Advanced Naming Logic
import (
"fmt"
"github.com/siliconcatalyst/officeforge/docx"
)
nameFunc := func(record map[string]string, index int) string {
// Custom logic based on data
if record["PRIORITY"] == "high" {
return fmt.Sprintf("urgent_%s_%d.docx", record["NAME"], index)
}
return fmt.Sprintf("standard_%s_%d.docx", record["NAME"], index)
}
err := docx.ProcessDocxMultipleRecordsWithNames("template.docx", "./output", records, nameFunc)