Goal: Reuse code across multiple Docs projects by adding a library to a bound script (a script attached to a Google Doc), then calling library functions from the Doc.
What is a Google Apps Script Library?
A library is a reusable Apps Script project you publish so other scripts can include it. Instead of copy/pasting helper functions into every Doc project, you keep them in one place and update them centrally.
Use libraries when you want:
- Shared formatting utilities (Docs cleanup, styling, templates)
- Common API wrappers (Gemini calls, Slack, Airtable, etc.)
- Reusable menu/UX patterns
Step 1: Create the Library Script Project
- Go to
script.google.com→ New project - Name it something like DocUtils Library
- Add your reusable code (example below)
Example library code (Code.gs)
/**
* DocUtils Library
* Reusable helpers for Google Docs bound scripts.
*/
function createHeading_(text, headingType) {
const doc = DocumentApp.getActiveDocument();
const body = doc.getBody();
return body.appendParagraph(text).setHeading(headingType);
}
/**
* Adds a title + subtitle to the active doc.
* @param {string} title
* @param {string} subtitle
*/
function addTitleBlock(title, subtitle) {
const doc = DocumentApp.getActiveDocument();
const body = doc.getBody();
// Title
const t = body.appendParagraph(title)
.setHeading(DocumentApp.ParagraphHeading.TITLE);
// Subtitle
const s = body.appendParagraph(subtitle)
.setHeading(DocumentApp.ParagraphHeading.SUBTITLE);
body.appendParagraph(""); // spacer
return { title: t.getText(), subtitle: s.getText() };
}
/**
* Finds and highlights all matches of a word/phrase.
* @param {string} findText
* @return {number} count highlighted
*/
function highlightMatches(findText) {
if (!findText) throw new Error("findText is required.");
const doc = DocumentApp.getActiveDocument();
const body = doc.getBody();
let searchResult = null;
let count = 0;
while ((searchResult = body.findText(findText, searchResult))) {
const el = searchResult.getElement().asText();
el.setBackgroundColor(searchResult.getStartOffset(), searchResult.getEndOffsetInclusive(), "#fff2ac");
count++;
}
return count;
}
/**
* Adds a simple footer line to the doc.
* @param {string} footerText
*/
function addFooter(footerText) {
const doc = DocumentApp.getActiveDocument();
const footer = doc.addFooter();
footer.clear();
footer.appendParagraph(footerText).setFontSize(9).setItalic(true);
}
/**
* Expose a public API (optional but nice pattern).
*/
var DocUtils = {
addTitleBlock,
highlightMatches,
addFooter
};
Tip: If you plan to call functions like
DocUtils.addTitleBlock(), exporting an object (likeDocUtils) makes your library feel cleaner.
Step 2: Publish the Library (Create a Version + Deploy)
Libraries must be versioned.
- In the library project: Project Settings → copy the Script ID (you’ll need it)
- Click Deploy → New deployment
- Select Type: Library
- Create a version (e.g.,
1) - Deploy
Now you have:
- Script ID (used to add the library)
- Version number (used to pin a specific release)
Step 3: Add the Library to a Google Doc Bound Script
- Open your Google Doc
- Extensions → Apps Script
- In the script editor: Project Settings → Libraries
- Paste the Script ID
- Choose the version (or “Head” while developing)
- Set an Identifier (example:
DocUtilsLib) - Save
Now your bound script can call the library code using:
DocUtilsLib.DocUtils.addTitleBlock(...)- or
DocUtilsLib.addTitleBlock(...)depending on how you structured it
Step 4: Use the Library in the Doc Bound Script
Example bound script (Code.gs) in the Google Doc
function onOpen() {
DocumentApp.getUi()
.createMenu("Doc Tools")
.addItem("Insert Title Block", "insertTitleBlock")
.addItem("Highlight Word", "highlightWordPrompt")
.addItem("Add Footer", "addDocFooter")
.addToUi();
}
function insertTitleBlock() {
// Calling the library API object (recommended pattern)
DocUtilsLib.DocUtils.addTitleBlock(
"My Document Title",
"Generated with Apps Script Library"
);
}
function highlightWordPrompt() {
const ui = DocumentApp.getUi();
const res = ui.prompt("Highlight matches", "Enter a word/phrase to highlight:", ui.ButtonSet.OK_CANCEL);
if (res.getSelectedButton() !== ui.Button.OK) return;
const text = res.getResponseText().trim();
const count = DocUtilsLib.DocUtils.highlightMatches(text);
ui.alert(`Highlighted ${count} match(es) for: "${text}"`);
}
function addDocFooter() {
DocUtilsLib.DocUtils.addFooter("Confidential • Internal Use Only");
}
“Head” vs Version Numbers (Important)
When adding a library, you can choose:
- Head: always uses the latest code in the library project (great during development)
- Versioned release (1,2,3…): stable, predictable (best for production)
Recommended workflow
- Develop using Head
- Once stable, create a new version
- Update the bound scripts to use that version number
Common Gotchas (And Fixes)
1) “Function not found”
- You added the library but used the wrong identifier or function name.
- If you changed library code, ensure you saved it and (if using version numbers) created a new version.
2) Permissions issues
Library functions that access Docs/Drive/etc. require authorization from the user running the bound script.
Fix: run a function once from the bound script editor to trigger authorization.
3) DocumentApp.getActiveDocument() in a library
This works when called from a Doc-bound script, because the active document context exists.
If you call library code from a standalone script, getActiveDocument() may behave differently.
Extra Example: Library Function That Inserts a “Section Template”
Add to library
function insertSection(title, bullets) {
const doc = DocumentApp.getActiveDocument();
const body = doc.getBody();
body.appendParagraph(title)
.setHeading(DocumentApp.ParagraphHeading.HEADING2);
bullets.forEach(b => body.appendListItem(b).setGlyphType(DocumentApp.GlyphType.BULLET));
body.appendParagraph("");
}
Call from bound script
function addTemplateSection() {
DocUtilsLib.insertSection("Next Steps", [
"Review document structure",
"Clean up headings",
"Finalize formatting"
]);
}
Mini Checklist
- ✅ Library code written in standalone Apps Script project
- ✅ Version created + deployed as Library
- ✅ Script ID added to Doc bound script
- ✅ Library identifier set (ex:
DocUtilsLib) - ✅ Call library functions from bound script
- ✅ Use version numbers for production