OfficeForge – A pure Go library and CLI for generating Word, Excel, and PowerPoint documents with zero external dependencies. Built on the standard library for maximum portability, security, and control.
- 🚀 Zero Dependencies – Pure Go using only
zip,xml, andbytes - ⚡ High Performance – Process 12,000+ word replacements per second
- 🔧 Dual Interface – Use as a Go library or standalone CLI tool
- 🌍 Cross-Platform – Works on Windows, macOS, and Linux
- 🔒 Secure – No external dependencies means smaller attack surface
- 📦 Easy Integration – Works with any programming language via CLI
- 12,000 words replaced in ~1 second
Option 1: Download Pre-built Binary
Download the latest binary for your platform from the Releases page:
Option 2: Install via Go
go install github.com/siliconcatalyst/officeforge/cmd/officeforge@latestgo get github.com/siliconcatalyst/officeforge@latest# Single keyword replacement
officeforge-windows-amd64.exe docx-single \
--input template.docx \
--output contract.docx \
--key "{{NAME}}" \
--value "John Doe"
# Multiple replacements from JSON
officeforge-windows-amd64.exe docx-multi \
--input template.docx \
--output contract.docx \
--data replacements.json
# Batch generation from CSV
officeforge-windows-amd64.exe docx-batch \
--input template.docx \
--output ./contracts \
--data employees.csv \
--pattern "{NAME}_contract.docx"(Note: If you are on Windows, and the input, output or data files contain spaces in their name, you must use Quotation marks in the command, example:
.\officeforge-windows-amd64.exe docx-multi --input "Proforma Invoice.docx" --output "Decembers' Invoice.docx" --data "Remaining Inventory.csv")
import "github.com/siliconcatalyst/officeforge/docx"
// Single replacement
docx.ProcessDocxSingle("template.docx", "output.docx", "{{NAME}}", "John Doe")
// Multiple replacements
replacements := map[string]string{
"{{NAME}}": "John Doe",
"{{EMAIL}}": "john@example.com",
"{{DATE}}": "2024-12-04",
}
docx.ProcessDocxMulti("template.docx", "output.docx", replacements)| Command | Description |
|---|---|
docx-single |
Replace a single keyword in a template |
docx-multi |
Replace multiple keywords from a JSON file |
docx-batch |
Generate multiple documents from CSV/JSON data |
version |
Display version information |
help |
Show help message |
Replace one keyword in a template document.
officeforge-windows-amd64.exe docx-single \
--input template.docx \
--output result.docx \
--key "{{CLIENT}}" \
--value "Acme Corporation"Flags:
--input, -i: Path to template DOCX file (required)--output, -o: Path for output file (required)--key, -k: Keyword to replace (required)--value, -v: Replacement value (required)
Replace multiple keywords using a JSON configuration file.
Create data.json:
{
"{{NAME}}": "John Doe",
"{{EMAIL}}": "john@example.com",
"{{PHONE}}": "555-1234",
"{{COMPANY}}": "Tech Solutions Inc.",
"{{DATE}}": "2024-12-04"
}Run command:
officeforge-windows-amd64.exe docx-multi \
--input template.docx \
--output completed_form.docx \
--data data.jsonFlags:
--input, -i: Path to template DOCX file (required)--output, -o: Path for output file (required)--data, -d: Path to JSON file with replacements (required)
Generate multiple documents from CSV or JSON data.
Create employees.csv:
NAME,EMAIL,PHONE,POSITION,START_DATE
John Doe,john@company.com,555-1234,Engineer,2024-01-15
Jane Smith,jane@company.com,555-5678,Manager,2024-02-20
Bob Johnson,bob@company.com,555-9999,Designer,2024-03-10
Run command:
officeforge-windows-amd64.exe docx-batch \
--input contract_template.docx \
--output ./contracts \
--data employees.csv \
--pattern "{NAME}_contract.docx"With JSON data (records.json):
[
{
"{{NAME}}": "John Doe",
"{{EMAIL}}": "john@example.com",
"{{POSITION}}": "Software Engineer"
},
{
"{{NAME}}": "Jane Smith",
"{{EMAIL}}": "jane@example.com",
"{{POSITION}}": "Product Manager"
}
]officeforge-windows-amd64.exe docx-batch \
--input template.docx \
--output ./output \
--data records.jsonFlags:
--input, -i: Path to template DOCX file (required)--output, -o: Output directory path (required)--data, -d: Path to CSV or JSON file (required)--pattern, -p: File naming pattern (optional, defaults todocument_N.docx)
Pattern Examples:
{NAME}_contract.docx→John_Doe_contract.docx{EMAIL}_{DATE}.docx→john@example.com_2024-12-04.docxinvoice_{ID}.docx→invoice_001.docx
import "github.com/siliconcatalyst/officeforge/docx"Replace a single keyword in a document.
func ProcessDocxSingle(inputPath, outputPath, keyword, replacement string) errorExample:
err := docx.ProcessDocxSingle(
"contract_template.docx",
"contract_john_smith.docx",
"{{CLIENT_NAME}}",
"John Smith",
)
if err != nil {
log.Fatal(err)
}Use Cases:
- Quick personalization of documents
- Testing individual replacements
- Simple one-off document generation
Replace multiple keywords in a document.
func ProcessDocxMulti(inputPath, outputPath string, replacements map[string]string) errorExample:
contractData := map[string]string{
"{{CLIENT_NAME}}": "John Smith",
"{{CLIENT_ADDRESS}}": "123 Main St, City, State 12345",
"{{CONTRACT_DATE}}": "2024-12-04",
"{{CONTRACT_AMOUNT}}": "$5,000",
"{{PROJECT_NAME}}": "Website Development",
"{{DEADLINE}}": "2024-12-31",
}
err := docx.ProcessDocxMulti(
"contract_template.docx",
"john_smith_contract.docx",
contractData,
)Use Cases:
- Mail merge operations
- Form filling
- Complete document population
- Contract generation
Generate multiple documents with sequential naming.
func ProcessDocxMultipleRecords(
inputPath, outputDir string,
records []map[string]string,
fileNamePattern string,
) errorExample:
records := []map[string]string{
{
"{{CLIENT_NAME}}": "John Smith",
"{{CONTRACT_DATE}}": "2024-12-04",
"{{CONTRACT_AMOUNT}}": "$5,000",
},
{
"{{CLIENT_NAME}}": "Jane Doe",
"{{CONTRACT_DATE}}": "2024-12-05",
"{{CONTRACT_AMOUNT}}": "$7,500",
},
}
// Creates: contract_1.docx, contract_2.docx
err := docx.ProcessDocxMultipleRecords(
"contract_template.docx",
"./contracts",
records,
"contract_%d.docx",
)Use Cases:
- Bulk document generation
- Certificate creation
- Invoice generation
- Report automation
Generate multiple documents with custom naming function.
func ProcessDocxMultipleRecordsWithNames(
inputPath, outputDir string,
records []map[string]string,
nameFunc func(map[string]string, int) string,
) errorExample:
records := []map[string]string{
{
"{{INVOICE_NUMBER}}": "INV-2024-001",
"{{CLIENT_NAME}}": "ABC Corporation",
"{{TOTAL_AMOUNT}}": "$2,500.00",
},
{
"{{INVOICE_NUMBER}}": "INV-2024-002",
"{{CLIENT_NAME}}": "XYZ Industries",
"{{TOTAL_AMOUNT}}": "$3,750.00",
},
}
nameFunc := func(record map[string]string, index int) string {
return record["{{INVOICE_NUMBER}}"] + ".docx"
}
// Creates: INV-2024-001.docx, INV-2024-002.docx
err := docx.ProcessDocxMultipleRecordsWithNames(
"invoice_template.docx",
"./invoices",
records,
nameFunc,
)Use Cases:
- Custom file naming conventions
- Date-based organization
- Client-specific naming
- Complex naming logic
| Use Case | Recommended Function | CLI Command |
|---|---|---|
| Single personalized letter | ProcessDocxSingle |
docx-single |
| Complete contract | ProcessDocxMulti |
docx-multi |
| 100 employee certificates | ProcessDocxMultipleRecords |
docx-batch |
| Invoices with custom IDs | ProcessDocxMultipleRecordsWithNames |
docx-batch with pattern |
| Monthly reports | ProcessDocxMulti |
docx-multi |
| Mail merge | ProcessDocxMultipleRecords |
docx-batch |
import subprocess
import json
# Single replacement
subprocess.run([
"officeforge-windows-amd64.exe", "single",
"--input", "template.docx",
"--output", "output.docx",
"--key", "{{NAME}}",
"--value", "John Doe"
])
# Multiple replacements
data = {
"{{NAME}}": "John Doe",
"{{EMAIL}}": "john@example.com"
}
with open("data.json", "w") as f:
json.dump(data, f)
subprocess.run([
"officeforge-windows-amd64.exe", "docx-multi",
"--input", "template.docx",
"--output", "output.docx",
"--data", "data.json"
])const { execSync } = require("child_process");
const fs = require("fs");
// Single replacement
execSync(
`officeforge-windows-amd64.exe docx-single --input template.docx --output output.docx --key "{{NAME}}" --value "John Doe"`,
);
// Multiple replacements
const data = {
"{{NAME}}": "John Doe",
"{{EMAIL}}": "john@example.com",
};
fs.writeFileSync("data.json", JSON.stringify(data));
execSync(
`officeforge-windows-amd64.exe docx-multi --input template.docx --output output.docx --data data.json`,
);<?php
// Single replacement
shell_exec('officeforge-windows-amd64.exe docx-single --input template.docx --output output.docx --key "{{NAME}}" --value "John Doe"');
// Multiple replacements
$data = [
"{{NAME}}" => "John Doe",
"{{EMAIL}}" => "john@example.com"
];
file_put_contents('data.json', json_encode($data));
shell_exec('officeforge-windows-amd54.exe docx-multi --input template.docx --output output.docx --data data.json');
?>#!/bin/bash
# Batch process from CSV
officeforge-windows-amd64.exe docx-batch \
--input template.docx \
--output ./contracts \
--data employees.csv \
--pattern "{NAME}_contract.docx"
# Check exit status
if [ $? -eq 0 ]; then
echo "✓ Documents generated successfully"
else
echo "✗ Error generating documents"
exit 1
fi✅ Good:
{{NAME}}- Clear delimiters[[EMAIL]]- Unique brackets__PHONE__- Underscores
❌ Avoid:
NAME- Could match regular text<NAME>- Conflicts with XML{NAME}- Single braces might appear naturally
-
Use descriptive keywords
✅ {{CLIENT_FULL_NAME}} ❌ {{N}} -
Keep keywords visible
- Use ALL CAPS or special formatting
- Makes templates easy to review
-
Test with sample data
officeforge-windows-amd64.exe docx-single \ --input template.docx \ --output test.docx \ --key "{{TEST}}" \ --value "SAMPLE"
// Check if template exists
if _, err := os.Stat("template.docx"); os.IsNotExist(err) {
log.Fatal("Template file not found")
}
// Ensure output directory exists
os.MkdirAll("./output", 0755)
// Process with error handling
err := docx.ProcessDocxMulti("template.docx", "output.docx", data)
if err != nil {
log.Printf("Processing failed: %v", err)
// Handle error appropriately
}Cause: Keyword spelling mismatch or formatting issues
Solution:
# Check your template for exact keyword spelling
# Ensure no extra spaces: "{{ NAME }}" vs "{{NAME}}"Cause: Missing output directory or insufficient permissions
Solution:
# Create output directory first
mkdir -p ./output
# Check permissions
ls -la ./outputCause: Incorrect file path
Solution:
# Use absolute paths
officeforge-windows-amd64.exe docx-single --input /full/path/to/template.docx ...
# Or relative paths from current directory
officeforge-windows-amd64.exe docx-single --input ./templates/template.docx ...Solution: Process in smaller chunks
// Instead of processing 10,000 records at once
// Process in batches of 100
for i := 0; i < len(allRecords); i += 100 {
batch := allRecords[i:min(i+100, len(allRecords))]
docx.ProcessDocxMultipleRecords(template, output, batch, pattern)
}- Word (DOCX) support
- CLI tool
- Batch processing
- Table manipulation
- Excel (XLSX) support
- PowerPoint (PPTX) support
- Image insertion
- Package managers (Homebrew, Chocolatey, Scoop)
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
# Clone the repository
git clone https://github.com/siliconcatalyst/officeforge.git
cd officeforge
# Install dependencies
go mod download
# Run tests
cd tests
go test -v
# Or use gotestsum for prettier output
gotestsum --format testnameMIT License - see LICENSE file for details
If you find this project useful, please consider giving it a ⭐ on GitHub!