How DrawDB Implements Cloud Save and Sharing via GitHub Gists

DrawDB stores database diagrams in the cloud by treating each diagram as a GitHub Gist, using a lightweight REST API wrapper to create, update, version, and share JSON files without maintaining a dedicated backend infrastructure.

DrawDB is an open-source database diagramming tool that leverages GitHub's public Gist API to provide serverless persistence and collaboration features. By mapping each diagram to a version-controlled Gist, the application eliminates infrastructure costs while inheriting GitHub's native revision history and public sharing capabilities. The implementation centers on a thin API abstraction layer that treats diagram.json and share.json files as the single source of truth for diagram state and accessibility.

Core API Wrapper in src/api/gists.js

The cloud integration resides in src/api/gists.js, which exports a set of asynchronous functions wrapping the GitHub Gist REST API via axios. This module defines two critical filename constants that determine how data is organized within each Gist:

export const VERSION_FILENAME = "diagram.json";
export const SHARE_FILENAME   = "share.json";

The module exposes seven primary operations:

  • create(content) – POSTs to /gists to initialize a new diagram, storing the JSON payload in VERSION_FILENAME and returning the generated gistId.
  • get(gistId) – Retrieves the current state of a Gist, including all files and metadata.
  • patch(gistId, filename, content) – Updates a specific file within an existing Gist, used for both diagram updates and sharing.
  • del(gistId) – Permanently deletes the Gist and all associated versions.
  • getCommits(gistId, perPage, page) – Fetches the commit history for version tracking.
  • getVersion(gistId, sha) – Retrieves a specific historical snapshot using the commit SHA.
  • compare(gistId, file, versionA, versionB) – Generates diffs between two versions of a file.

State Management with DiagramContext

The application maintains cloud synchronization state through the IdContext defined in src/context/DiagramContext.jsx. This context provider stores the current gistId, the active version SHA, and setter functions that trigger API calls. Components throughout the editor consume this context to determine whether to initiate a create operation for new diagrams or patch operations for existing ones.

Saving Diagrams to the Cloud

When a user initiates a save operation from src/components/Workspace.jsx, the application checks for an existing gistId in the context. If absent, it invokes create() to generate a new Gist, storing the returned identifier for future updates. For subsequent saves, Workspace.jsx calls patch(gistId, VERSION_FILENAME, diagramToString()) to overwrite the diagram.json file with the current editor state.

Version Control Implementation

The version history panel in src/components/EditorHeader/SideSheet/Versions.jsx leverages GitHub's native versioning capabilities. The component calls getCommits() to retrieve the chronological history of changes, then uses getVersion() with specific commit SHAs to fetch historical snapshots. When a user selects a previous version, the application hydrates the editor by loading that specific file content. An in-memory cache prevents redundant network requests for previously loaded commits.

Public Sharing via Gist Files

The sharing mechanism in src/components/EditorHeader/Modal/Share.jsx utilizes the SHARE_FILENAME constant to enable public access. When sharing is activated, the component writes a JSON payload to share.json within the existing Gist using patch(). The application then generates a public URL following the pattern:

const baseUrl = window.location.origin + "/editor?shareId=" + gistId;

Recipients opening this URL trigger a get(gistId) call that reads the shared file and populates the workspace, enabling collaboration without requiring authentication.

Practical Implementation Examples

Creating a new cloud-backed diagram:

import { create } from "@/api/gists";

async function saveNewDiagram(diagram) {
  const content = JSON.stringify(diagram, null, 2);
  const { gistId } = await create(content);
  setGistId(gistId); // Store in context for subsequent updates
}

Updating an existing diagram:

import { patch } from "@/api/gists";

async function updateDiagram(gistId, diagram) {
  const content = JSON.stringify(diagram, null, 2);
  await patch(gistId, "diagram.json", content);
}

Loading a shared diagram:

import { get } from "@/api/gists";

async function loadSharedDiagram(gistId) {
  const { files } = await get(gistId);
  const diagramJson = files["diagram.json"].content;
  return JSON.parse(diagramJson);
}

Retrieving version history:

import { getCommits, getVersion } from "@/api/gists";

async function listVersions(gistId) {
  const { commits } = await getCommits(gistId);
  return Promise.all(
    commits.map(c => getVersion(gistId, c.version))
  );
}

Summary

  • DrawDB uses GitHub Gists as a serverless persistence layer, storing diagrams as JSON files within Gists to eliminate backend infrastructure requirements.
  • The src/api/gists.js module provides a typed interface over the GitHub REST API, handling create, read, update, delete, and versioning operations through seven core functions.
  • State management via DiagramContext tracks the active gistId and version history across the application, coordinating saves through Workspace.jsx.
  • Version control leverages Git's underlying machinery through getCommits() and getVersion(), providing native diff capabilities without custom implementation.
  • Public sharing writes to a dedicated share.json file and generates query-parameter-based URLs that load diagrams directly via shareId parameters.

Frequently Asked Questions

How does DrawDB handle version history without a custom backend?

DrawDB leverages GitHub's built-in versioning system by calling getCommits() and getVersion() from src/api/gists.js. Each time patch() updates the diagram.json file, GitHub automatically creates a new commit. The application retrieves these commits to display a chronological history, allowing users to restore any previous state by loading the file content from a specific commit SHA.

What files are created inside a DrawDB GitHub Gist?

Each DrawDB Gist contains at least one file named diagram.json (defined by VERSION_FILENAME), which stores the complete diagram state. When public sharing is enabled, the application adds a second file named share.json (defined by SHARE_FILENAME) that contains a snapshot of the diagram intended for public distribution.

How does the sharing mechanism work technically?

When a user clicks share in src/components/EditorHeader/Modal/Share.jsx, the application calls patch(gistId, SHARE_FILENAME, diagramContent) to write the current diagram to share.json. The modal then constructs a URL with the format https://drawdb.app/editor?shareId={gistId}. When another user visits this URL, the application extracts the shareId, calls get(gistId), and loads the diagram from the Gist files into the editor workspace.

Where is the gistId stored during an editing session?

The current gistId is stored in the IdContext provided by src/context/DiagramContext.jsx. This context wraps the application and makes the identifier available to components like Workspace.jsx for save operations and Versions.jsx for history retrieval. The ID persists only for the duration of the session unless explicitly saved to browser storage or the URL query parameters.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →