Generate a printable employee handbook
Compile policy sections into one formatted Northwind handbook Doc.
Published Jan 4, 2026
Northwind keeps each HR policy in its own Doc — twelve of them, sitting in a
policies/ folder. That is the right way to maintain them: the person who owns
the leave policy edits the leave Doc, and nobody fights over one giant file.
But new starters do not want twelve links. They want one handbook they can read
top to bottom, or print.
This script compiles the folder into a single handbook Doc. It sorts the policy files by name, drops in a title and an auto-updating table of contents, then copies every policy in as its own Heading 1 section with a page break between them. Edit a policy Doc, run this again, and the handbook is regenerated from the current text — no copy-paste, no version drift.
What you’ll need
- A Drive folder containing your policy Docs, one policy per Doc. The script reads the folder by ID.
- A naming convention you can sort on. The script orders sections by file name,
so prefixing files like
01 Code of Conduct,02 Leavecontrols the running order. - Nothing else — the handbook Doc is created fresh on each run.
The script
// The Drive folder that holds the individual policy Docs.
const POLICIES_FOLDER_ID = '1abcPoliciesFolderId';
// The title printed at the top of the compiled handbook.
const HANDBOOK_TITLE = 'Northwind Studios — Employee Handbook';
/**
* Compiles every Google Doc in the policies folder into one handbook:
* a title, a table of contents, then one Heading 1 section per policy.
*/
function buildHandbook() {
// 1. Collect the policy Docs and sort them by file name.
const policies = DriveApp.getFolderById(POLICIES_FOLDER_ID)
.getFilesByType(MimeType.GOOGLE_DOCS);
const files = [];
while (policies.hasNext()) files.push(policies.next());
if (!files.length) {
Logger.log('No policy Docs in the folder — nothing to compile.');
return;
}
files.sort((a, b) => a.getName().localeCompare(b.getName()));
// 2. Create the handbook Doc and add the title.
const doc = DocumentApp.create(`${HANDBOOK_TITLE} — ${new Date().getFullYear()}`);
const body = doc.getBody();
body.appendParagraph(HANDBOOK_TITLE)
.setHeading(DocumentApp.ParagraphHeading.TITLE);
// 3. Insert an auto-updating table of contents, then a page break.
body.insertTableOfContents(1);
body.insertPageBreak(2);
// 4. Copy each policy in as its own Heading 1 section.
for (const f of files) {
body.appendParagraph(f.getName())
.setHeading(DocumentApp.ParagraphHeading.HEADING1);
// Copy the source Doc element by element so formatting is preserved.
const src = DocumentApp.openById(f.getId()).getBody();
for (let i = 0; i < src.getNumChildren(); i++) {
const c = src.getChild(i).copy();
if (c.getType() === DocumentApp.ElementType.PARAGRAPH) {
body.appendParagraph(c);
} else if (c.getType() === DocumentApp.ElementType.LIST_ITEM) {
body.appendListItem(c);
}
}
// Start the next policy on a fresh page.
body.appendPageBreak();
}
doc.saveAndClose();
Logger.log('Built handbook from ' + files.length + ' policies: ' + doc.getUrl());
}
How it works
buildHandbookopens the policies folder and pulls every Google Doc into an array. If the folder is empty it logs a message and stops.- It sorts the files with
localeCompareon their names, so a numeric prefix like01,02reliably controls section order. - It creates a new Doc named with the handbook title and the current year, and
adds the title as a
TITLE-styled paragraph. - It inserts a table of contents at the top. Because each policy is added as a Heading 1 in the next step, the TOC lists every section automatically — and it stays current if you regenerate.
- For each policy file, it appends the file name as a Heading 1, then opens the source Doc and copies its children one at a time. Paragraphs are re-appended as paragraphs and list items as list items, so headings, bold, and bullets survive the copy.
- After each policy it appends a page break, so every section starts on a fresh page when printed.
- It saves and closes the Doc, then logs the URL.
Example run
Say policies/ contains:
01 Code of Conduct
02 Working Hours
03 Leave and Holiday
...
12 IT and Security
After a run you get one Doc:
| Page | Content |
|---|---|
| 1 | ”Northwind Studios — Employee Handbook” + table of contents |
| 2 | Heading 1: “01 Code of Conduct” + the policy text |
| 3 | Heading 1: “02 Working Hours” + the policy text |
| … | one section per policy, each on its own page |
The table of contents on page 1 lists all twelve sections with page numbers, ready to print or share as a single file.
Run it
This is an on-demand job — run it whenever the policies change:
- In the Apps Script editor, set
POLICIES_FOLDER_ID, selectbuildHandbook, and click Run. - Approve the authorisation prompt the first time — it needs access to Docs and Drive.
- Open the new handbook from the logged URL and click into the table of contents, then Update, so the page numbers settle.
Watch out for
- It creates a new Doc every run. Old handbooks pile up in your Drive — delete
or archive the previous one, or open a fixed Doc by ID and clear its body
instead of calling
DocumentApp.create. - File names become section headings. Whatever the policy Doc is called appears verbatim as the Heading 1, prefix and all. Name the files exactly as you want the sections to read, or strip the numeric prefix in code before appending.
- Only paragraphs and list items are copied. Tables, images, and other elements
in a policy Doc are skipped. Add cases for
TABLEandINLINE_IMAGEif your policies rely on them. - The table of contents does not refresh itself. Apps Script inserts it, but Docs only recalculates page numbers when the Doc is opened and the TOC is updated by hand. Do that once before sharing.
- A folder of twelve large Docs can run close to the script time limit. If you add many more policies, the run may need splitting into batches.
Related
Generate personalized study guides from notes
Reformat raw notes into structured study guides — for Northwind's internal training programme.
Updated Feb 8, 2026
Build a contract-clause assembly system
Construct Northwind agreements from a library of approved clauses — drag-drop in code.
Updated Feb 1, 2026
Translate and resolve Doc comments
Localise reviewer feedback on a shared Doc so multilingual teams can collaborate.
Updated Jan 25, 2026
Auto-archive finalized Docs to dated folders
File completed Northwind Docs by month so the active folder stays focused on in-flight work.
Updated Jan 18, 2026
Build a fillable intake form inside a Doc
Create structured intake forms with placeholder fields readers can fill — for client briefs.
Updated Jan 11, 2026