Self-hosted service
nytimes/library avatar
nytimes/library

NYT Library: a newsroom documentation site that renders Google Docs

A collaborative documentation site, powered by Google Docs.

1,182 stars149 forksJavaScriptApache-2.0

At a glance

What is it?
Library is the New York Times' Apache-2.0 licensed project that turns a Google Drive folder into a browsable internal documentation site, with Google sign-in restricted to approved domains, a Slack login option, customization through a separate git repository, and deployment paths for Heroku, App Engine and Docker. It suits a newsroom that already writes its docs in Google Docs, and it is the wrong tool if you want to own the file format.
Who is it for?
Library fits a newsroom or large editorial team whose documentation already lives in Google Docs and who want those pages to be readable by people without a Drive account, since the project handles the rendering, the search-free listing of the drive and the access control for you.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 72 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The drive is the database, and that is the whole architecture

Library is described as a collaborative newsroom documentation site powered by Google Docs, and the structural decision is that there is no separate content store. The site reads a Google Drive team drive or shared folder, parses the documents, and serves them. The package.json shows the shape of that: @google-cloud/datastore for the read history, googleapis for the Drive access, google-auth-library for credential handling, cheerio for HTML parsing, and xlsx for spreadsheets. The directory layout in the repository follows the same split, with a server/ directory for the Express application, layouts/ for the templates, styles/ for the Sass, and public/ for the compiled output. The consequence for an adopter is straightforward. There is no import step, no content migration and no export format, because the documents never leave Drive.

One service account and one drive share are the whole setup

The development workflow is five steps, and the second one carries the weight. From the Google API console you create or select a project, then create a service account with the Cloud Datastore User role, and it must have API access to Drive and Cloud Datastore. The credentials go into server/.auth.json. If you want to use OAuth you also create OAuth credentials, and if you want to read history through the Cloud Datastore API you add GCP_PROJECT_ID. Step four tells you to share your base drive or folder with the email address associated with that service account, which is the step people forget and then spend an afternoon debugging. The npm install uses the --no-optional flag, and the app starts with npm run watch on localhost:3000, with a note that Library requires Node v8 or higher.

The .env file carries access control as well as configuration

The example .env in the README shows what has to be set, and one of the entries is a security setting rather than a credential. APPROVED_DOMAINS takes a comma separated list of domains or email addresses, and the README notes that regex is supported, so an entry like (.*)?ar.org covers a family of domains. NODE_ENV is the other one that matters. The README puts a bold warning on it: setting NODE_ENV to development changes the built-in behaviour for site authentication to allow accounts other than those in the APPROVED_DOMAINS list, and it says never to use NODE_ENV=development for a deployed site, only locally. The remaining entries are the Google OAuth client id and secret, GCP_PROJECT_ID, a SESSION_SECRET, and the drive configuration with DRIVE_TYPE set to team or folder and a DRIVE_ID taken from the end of the drive or folder URL. There is a separate warning that comments must not be put on the same line as the DRIVE_TYPE and DRIVE_ID variables.

Two sign-in methods, and only one of them needs Google

The README does not spell out the auth flow, but the dependency list is informative. passport and passport-google-oauth20 handle the Google path, and passport-slack-oauth2 is also present, which is how a newsroom can let staff sign in with a Slack identity instead of a Google account. The deployment section repeats the requirement to set up an OAuth 2.0 client, and for Heroku it tells you to add your app URL as an authorized domain in the OAuth consent screen and to add the callback URL as http://<your-heroku-app-url>.com/auth/redirect in the OAuth credential settings. The approved-domain list then constrains who can actually get in, so the extension is that the list applies on top of whatever the identity provider allows.

Customisation lives in its own repository, not in a fork

The customisation model avoids forking, which is the right call for a project other organisations are expected to run. Styles, text, caching logic and middleware can all be customised to match an organisation's branding, and the mechanics are that you create a git repository with the files you want to include and set the CUSTOMIZATION_GIT_REPO environment variable to the cloning URL, with the files in that repo and the packages named in package.json included in your installation. A sample customisation repo is provided at nytimes/library-customization-example, and the build scripts show how it fits, with the main stylesheet compiled by Sass using custom/styles and styles/partials as load paths. That means branding changes do not require a fork, do not require a pull request upstream, and cannot be lost to a rebase.

Three deployment paths, and the Docker image is minimal

The deployment section covers Heroku, Google App Engine and Docker, and a standard deployment is described separately. The Heroku route is a one-click deploy button, and the instructions there reduce to setting GOOGLE_APPLICATION_JSON, GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET plus the OAuth consent screen and callback URL. The Dockerfile is short and worth reading in full, because it shows what is and is not in the image.

dockerfile
FROM node:24

RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

# Install NPMs
COPY package.json* package-lock.json* /usr/src/app/
RUN npm i --production

COPY . /usr/src/app
RUN npm run build

It installs production dependencies only, copies the source and builds. There is no multi-stage build, no distroless base and no non-root user, which is simpler than most Node images and also means the container runs as root by default, something to note if you run it in a hardened environment.

The demo site doubles as the user guide

The README is candid that it is not the best place to learn the project. It points to a working read-only demo hosted on Heroku at library-demo.newsdev.nytimes.com, and says to consult the site for more detailed instructions than the readme about how to get the most out of Library. The Getting Started section of that demo is also where the deployment guidance lives, and the contributing instructions point to CONTRIBUTING.md for code or documentation contributions on GitHub or on the demo site itself. The community section lists organisations using Library, including Marketplace, The New York Times, the Northwestern University Knight Lab, Star Tribune, WBEZ and the Los Angeles Times Data and Graphics Department, and the README offers two places to ask questions, a Google Group and the #proj-library channel in the News Nerdery Slack.

Apache-2.0 with tests that parse real Google Docs output

The licence is Apache-2.0, with a LICENSE file at the root, and the repository also carries a SECURITY.md, a CODE_OF_CONDUCT.md, a CODEOWNERS file and a contributing.md. The testing story is unusual and tells you something about the difficulty of the problem. The functional and unit tests cover HTML parsing and routing logic, and the HTML parsing tests are based on a Supported Formats document, a living Google Doc that the maintainers refresh when Google's output changes, with a script to download a fresh copy of the HTML after edits. That is an admission that the upstream format moves underneath you, and the test suite is kept honest by pulling the current version of the target. The dev dependencies reflect a mixed test stack, with jest, sinon, supertest, nock for HTTP mocking and nyc for coverage, and the test script is npm test with npm run test:cover for the coverage report.

Editorial conclusion

Library fits a newsroom or large editorial team whose documentation already lives in Google Docs and who want those pages to be readable by people without a Drive account, since the project handles the rendering, the search-free listing of the drive and the access control for you. It is a poor fit if you need to own your content in a format you control, because the source of truth stays in Google Drive, and a poor fit for a small team, since the setup asks for a Google Cloud service account, a Drive share and OAuth credentials before anything renders. Verify first that your organisation can create the service account and share the drive with it, and read the warning about NODE_ENV before deploying, because development mode relaxes the approved-domain check.

Frequently asked questions

What does NYT Library actually store?

The documents stay in Google Drive. Library lists and parses a Google Drive team drive or shared folder and serves the result as a site, with Cloud Datastore used for read history. There is no separate content store and no export format, because the source of truth remains in Drive.

What Google Cloud setup does Library require?

You create or select a project in the Google API console, create a service account with the Cloud Datastore User role and API access to Drive and Cloud Datastore, and store the credentials in server/.auth.json. You must also share your base drive or folder with the service account's email address, and add OAuth credentials if you want to sign in with Google.

How do I restrict who can use the site?

Through the APPROVED_DOMAINS environment variable, which takes a comma separated list of domains or email addresses and supports regex. The README also warns that NODE_ENV=development changes the authentication behaviour to allow accounts outside that list, and says never to use it for a deployed site.

Can I customise the look of Library without forking it?

Yes. You create a separate git repository with the files you want to include, set the CUSTOMIZATION_GIT_REPO environment variable to its cloning URL, and those files and the packages listed in package.json are included in your installation. A sample customisation repository is provided by the project.

Official sources

  1. License: Apache-2.0
  2. nytimes/library on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/nytimes-library.svg)](https://hysenlabs.com/projects/nytimes-library)

Was this useful?