Skip to content

oscaroca/DriveCMS

Repository files navigation

drive-cms

Turn a Google Drive folder into a static JSON index — a framework-agnostic headless CMS with zero runtime dependencies.

How it works

You organize your content in a Google Drive folder. drive-cms scans the folder and writes a JSON file you can serve statically alongside your app. Each Google Doc (or HTML/PDF file) becomes one entry in the array.

Folder convention:

my-drive-folder/
├── My First Article          ← Google Doc → becomes an entry
├── My First Article.jpg      ← Same name → used as previewImage
└── Another Project           ← No image → previewImage is ""

Install

npm install -D drive-cms

Or use without installing:

npx drive-cms init
npx drive-cms sync

Setup

1. Scaffold a config file:

npx drive-cms init

This creates drive-cms.config.js in your project root.

2. Edit the config:

// drive-cms.config.js
import 'dotenv/config';

export default {
  apiKey: process.env.DRIVE_API_KEY,
  output: './public/data',
  collections: [
    {
      name: 'projects-en',
      folderId: process.env.DRIVE_FOLDER_ID_EN,
    },
    {
      name: 'projects-es',
      folderId: process.env.DRIVE_FOLDER_ID_ES,
    },
  ],
};

3. Make your Drive folder public:

Right-click the folder in Google Drive → Share → Anyone with the link → Viewer.

4. Run:

npx drive-cms sync

This writes public/data/projects-en.json and public/data/projects-es.json.

Getting a Google Drive API key

  1. Go to console.cloud.google.com
  2. Enable the Google Drive API
  3. Create an API Key under Credentials
  4. (Optional) Restrict the key to the Google Drive API

Tip: Create a separate unrestricted key for the CLI and a referrer-restricted key for your browser app.

Default output shape

Each entry in the JSON array has this shape by default:

{
  id: string;           // Google Drive file ID
  mimeType: string;     // e.g. "application/vnd.google-apps.document"
  title: string;        // File name (extension stripped)
  description: string;  // Drive file description field
  previewImage: string; // Drive ID of the paired image file (or "")
}

Set the description in Google Drive via right-click → File information → Details.

Custom output shape

Supply a transform function to control exactly what goes into the JSON:

export default {
  apiKey: process.env.DRIVE_API_KEY,
  output: './public/data',
  collections: [{ name: 'posts', folderId: process.env.FOLDER_ID }],
  transform: (doc, image) => ({
    slug: doc.name.toLowerCase().replace(/\s+/g, '-').replace(/\.[^.]+$/, ''),
    title: doc.name.replace(/\.[^.]+$/, ''),
    summary: doc.description ?? '',
    cover: image ? `https://lh3.googleusercontent.com/d/${image.id}=w800` : null,
    driveId: doc.id,
  }),
};

The transform function receives:

  • doc — the Google Drive file object ({ id, name, mimeType, description, thumbnailLink })
  • image — the paired image file, or null if none was found

CLI reference

drive-cms sync                          # sync all collections
drive-cms sync --collection posts       # sync a single collection by name
drive-cms init                          # scaffold drive-cms.config.js

Programmatic usage

import { loadConfig, syncAll } from 'drive-cms';

const config = await loadConfig();
const results = await syncAll(config);

for (const result of results) {
  console.log(`${result.collection}: ${result.entryCount} entries → ${result.outputPath}`);
}

Config reference

Field Type Required Default
apiKey string Yes
output string No "./public/data"
collections Collection[] Yes
transform (doc, image) => T No Default shape above

Collection:

Field Type Required
name string Yes — used as output filename
folderId string Yes — Google Drive folder ID

License

MIT

About

Turn a Google Drive folder into a static JSON index — a framework-agnostic headless CMS with zero runtime dependencies.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors