How to Use Libraries in Google Apps Script Bound to Google Docs

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

  1. Go to script.google.comNew project
  2. Name it something like DocUtils Library
  3. 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 (like DocUtils) makes your library feel cleaner.


Step 2: Publish the Library (Create a Version + Deploy)

Libraries must be versioned.

  1. In the library project: Project Settings → copy the Script ID (you’ll need it)
  2. Click DeployNew deployment
  3. Select Type: Library
  4. Create a version (e.g., 1)
  5. 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

  1. Open your Google Doc
  2. Extensions → Apps Script
  3. In the script editor: Project Settings → Libraries
  4. Paste the Script ID
  5. Choose the version (or “Head” while developing)
  6. Set an Identifier (example: DocUtilsLib)
  7. 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