Skip to main content
Minecraft Creator Tools provides several storage implementations for different environments and use cases. All implementations share the same IStorage interface.

NodeStorage

For Node.js environments, providing access to the local file system.

Constructor

import { NodeStorage } from "@minecraft/creator-tools";

const storage = new NodeStorage(
  "/path/to/folder",  // Root path
  "MyProject"         // Storage name
);

Properties

class NodeStorage extends StorageBase implements IStorage {
  rootPath: string;                     // File system path
  name: string;                         // Storage name
  rootFolder: NodeFolder;               // Root folder
  static platformFolderDelimiter: string; // Path separator for platform
  
  get folderDelimiter(): string;        // Returns path.sep
}

Static Methods

// Create storage from a file or folder path
static async createFromPath(
  path: string
): Promise<NodeFile | NodeFolder>;

// Create storage, auto-detecting and extracting ZIP files
static async createFromPathIncludingZip(
  path: string
): Promise<IFolder | undefined>;

// Get parent folder path
static getParentFolderPath(parentPath: string): string;

// Ensure path ends with delimiter
static ensureEndsWithDelimiter(path: string): string;

// Ensure path starts with delimiter
static ensureStartsWithDelimiter(path: string): string;

Example Usage

import { NodeStorage } from "@minecraft/creator-tools";

// Create storage for a behavior pack
const storage = new NodeStorage(
  "/Users/me/minecraft/behavior_packs/my_pack",
  "MyBehaviorPack"
);

// Load and access files
await storage.rootFolder.load();
const manifestFile = await storage.rootFolder.getFileFromRelativePath("manifest.json");
if (manifestFile) {
  await manifestFile.loadContent();
  console.log(manifestFile.content);
}

// Auto-detect and extract .mcpack files
const folder = await NodeStorage.createFromPathIncludingZip(
  "/path/to/pack.mcpack"
);
if (folder) {
  await folder.load();
  console.log("Pack contains:", folder.fileCount, "files");
}
Source: ~/workspace/source/app/src/local/NodeStorage.ts:12-127

BrowserStorage

For browser environments, providing persistent client-side storage using IndexedDB via localforage.

Constructor

import { BrowserStorage } from "@minecraft/creator-tools";

const storage = new BrowserStorage(
  "myproject"  // Storage name (null for default)
);

Properties

class BrowserStorage extends StorageBase implements IStorage {
  rootFolder: BrowserFolder;
  static isConfigured: boolean;  // Whether localforage is configured
}

Static Methods

// Configure localforage (called automatically)
static ensureConfigured(): void;

Configuration

BrowserStorage automatically configures localforage with:
localforage.config({
  name: "Minecraft Creator Tools",
  storeName: "minecraft_creator_tools",
  version: 1.0,
});

Example Usage

import { BrowserStorage } from "@minecraft/creator-tools";

// Create browser storage
const storage = new BrowserStorage("myproject");

// Files persist across browser sessions
const file = await storage.rootFolder.ensureFileFromRelativePath("data.json");
file.setContent(JSON.stringify({ foo: "bar" }));
await file.saveContent();

// Later session - file is still there
await storage.rootFolder.load();
const loadedFile = await storage.rootFolder.getFileFromRelativePath("data.json");
if (loadedFile) {
  await loadedFile.loadContent();
  console.log(loadedFile.content); // { foo: "bar" }
}
Source: ~/workspace/source/app/src/storage/BrowserStorage.ts:9-44

HttpStorage

For read-only access to files served over HTTP/HTTPS.

Constructor

import { HttpStorage } from "@minecraft/creator-tools";

const storage = new HttpStorage(
  "https://example.com/packs/"  // Base URL
);

Properties

class HttpStorage extends StorageBase implements IStorage {
  rootFolder: HttpFolder;
  baseUrl: string;  // Base URL for all requests
}

Behavior

  • Automatically appends trailing slash to baseUrl
  • Read-only (save operations will fail)
  • Files are fetched on-demand via HTTP GET
  • Good for serving sample packs or templates

Example Usage

import { HttpStorage } from "@minecraft/creator-tools";

// Create storage pointing to a web-hosted pack
const storage = new HttpStorage(
  "https://cdn.example.com/minecraft/samples/hello-world/"
);

// Load files from the server
const manifest = await storage.rootFolder.getFileFromRelativePath("manifest.json");
if (manifest) {
  await manifest.loadContent();
  console.log(manifest.content);
}

// Read-only - saves will not persist to server
manifest.setContent("modified");
await manifest.saveContent(); // This is a no-op for HttpStorage
Source: ~/workspace/source/app/src/storage/HttpStorage.ts:8-30

GitHubStorage

For read-only access to GitHub repositories.

Constructor

import { GitHubStorage, GitHubManager } from "@minecraft/creator-tools";

const manager = new GitHubManager();
const storage = new GitHubStorage(
  manager,
  "minecraft-samples",  // Repository name
  "microsoft",          // Owner (must be 'microsoft' or 'mojang')
  "main",               // Branch (optional)
  "behavior_packs/"    // Sub-path (optional)
);

Properties

class GitHubStorage extends StorageBase implements IStorage {
  rootFolder: GitHubFolder;
  manager: GitHubManager;  // GitHub API manager
  repoName: string;        // Repository name
  ownerName: string;       // Owner name (microsoft or mojang only)
  branch?: string;         // Branch name
  subPath: string;         // Sub-path within repo
}

Security Restrictions

For security reasons, GitHubStorage only allows access to repositories owned by:
  • microsoft
  • mojang
Attempting to access other repositories will throw an error:
// ✅ Allowed
const storage1 = new GitHubStorage(manager, "samples", "microsoft");
const storage2 = new GitHubStorage(manager, "scripts", "mojang");

// ❌ Throws error
const storage3 = new GitHubStorage(manager, "repo", "other-user");
// Error: Unsupported GitHub action.

Example Usage

import { GitHubStorage, GitHubManager } from "@minecraft/creator-tools";

// Create manager and storage
const manager = new GitHubManager();
const storage = new GitHubStorage(
  manager,
  "minecraft-samples",
  "microsoft",
  "main",
  "behavior_packs/hello_world/"
);

// Access files from GitHub
await storage.rootFolder.load();
const manifest = await storage.rootFolder.getFileFromRelativePath("manifest.json");
if (manifest) {
  await manifest.loadContent();
  console.log(manifest.content);
}
Source: ~/workspace/source/app/src/github/GitHubStorage.ts:9-62

ZipStorage

For working with ZIP archives, including .mcpack, .mcaddon, .mcworld, and .mctemplate files.

Constructor

import { ZipStorage } from "@minecraft/creator-tools";

const storage = new ZipStorage();

Properties

class ZipStorage extends StorageBase implements IStorage {
  name?: string;
  rootFolder: ZipFolder;
  modified: Date | null;
  lastLoadedOrSaved: Date | null;
  allowAllFiles: boolean;  // Allow files not in AllowedExtensionsSet
  
  get updatedSinceLoad(): boolean;  // Check if modified since load
}

Loading Methods

// Load from base64 string
await storage.loadFromBase64(base64String, "pack.mcpack");

// Load from Uint8Array
await storage.loadFromUint8Array(bytes, "pack.zip");

// Load from an IFile
const zipStorage = await ZipStorage.loadFromFile(file);

Generating Methods

// Generate compressed archive as Uint8Array
const bytes = await storage.generateCompressedUint8ArrayAsync();

// Generate as base64 string
const base64 = await storage.generateCompressedBase64Async();

// Generate as blob (browser) or buffer (Node)
const blob = await storage.generateBlobAsync();

Static Factory Methods

// Create from JSON string
const storage = ZipStorage.fromJsonString(jsonString);

// Create from JavaScript object
const storage = ZipStorage.fromJsObject({ foo: "bar" });

// Load from IFile and extract to object
const obj = await ZipStorage.toJsObject(storage);

// Convert ZIP bytes to JSON object
const obj = await ZipStorage.fromZipBytesToJsonObject(bytes);

Security Validation

ZipStorage includes security checks:
// File size limits (configurable via SecurityUtilities.MAX_UPLOAD_SIZE)
// File count limits (configurable via SecurityUtilities.MAX_ZIP_FILES)
// Path validation (prevents directory traversal attacks)

if (storage.errorStatus === StorageErrorStatus.unprocessable) {
  console.error("ZIP validation failed:", storage.errorMessage);
}

Example Usage

import { ZipStorage } from "@minecraft/creator-tools";

// Load an existing .mcpack file
const file = await folder.getFileFromRelativePath("pack.mcpack");
if (file) {
  const zipStorage = await ZipStorage.loadFromFile(file);
  
  if (zipStorage) {
    // Access files inside the ZIP
    await zipStorage.rootFolder.load();
    const manifest = await zipStorage.rootFolder.getFileFromRelativePath("manifest.json");
    if (manifest) {
      await manifest.loadContent();
      console.log(manifest.content);
    }
    
    // Modify and regenerate
    manifest.setContent("modified content");
    const newBytes = await zipStorage.generateCompressedUint8ArrayAsync();
    
    // Save back to original file
    file.setContent(newBytes);
    await file.saveContent();
  }
}

// Create a new ZIP from scratch
const newZip = new ZipStorage();
const newFile = newZip.rootFolder.ensureFile("test.txt");
newFile.setContent("Hello World");
await newFile.saveContent();

const bytes = await newZip.generateCompressedUint8ArrayAsync();
Source: ~/workspace/source/app/src/storage/ZipStorage.ts:14-253

Storage (In-Memory)

For temporary in-memory storage without persistence.

Constructor

import { Storage } from "@minecraft/creator-tools";

const storage = new Storage();

Properties

class Storage extends StorageBase implements IStorage {
  rootFolder: Folder;
  static readonly folderDelimiter = "/";
}

Behavior

  • Files and folders exist only in memory
  • No persistence between sessions
  • Fast for temporary operations
  • Good for testing and transformations

Example Usage

import { Storage } from "@minecraft/creator-tools";

// Create temporary storage
const tempStorage = new Storage();

// Create files
const file = await tempStorage.rootFolder.ensureFileFromRelativePath("temp.json");
file.setContent(JSON.stringify({ data: "test" }));

// Use for transformations
const result = processFile(file);

// Storage is discarded when no longer referenced
Source: ~/workspace/source/app/src/storage/Storage.ts:8-46

StorageBase

All storage implementations extend StorageBase, which provides common functionality:

Common Features

abstract class StorageBase implements IStorage {
  // Change tracking
  isContentUpdated: boolean;
  readOnly: boolean;
  
  // Version management
  priorVersions: IVersionContent[];
  currentVersionId?: string;
  
  // Events
  onFileAdded: IEvent<IStorage, IFile>;
  onFileRemoved: IEvent<IStorage, string>;
  onFileContentsUpdated: IEvent<IStorage, IFileUpdateEvent>;
  onFolderMoved: IEvent<IStorage, IFolderMove>;
  
  // Error handling
  errorStatus?: StorageErrorStatus;
  errorMessage?: string;
  
  // Availability
  available?: boolean;
  abstract getAvailable(): Promise<boolean>;
  
  // Path utilities
  static readonly slashFolderDelimiter = "/";
  joinPath(pathA: string, pathB: string): string;
  static getParentFolderPath(path: string): string;
}

Version Management

// Add a new version
storage.addVersion(versionContent, FileUpdateType.regularEdit);

// Navigate version history
storage.setToVersion(versionId);  // Jump to a specific version
storage.trimAfterVersion(versionId);  // Remove future versions

// Current version tracking
if (storage.currentVersionId) {
  console.log("Viewing historical version");
}

Scan for Changes

// Full scan of all folders and files
await storage.scanForChanges();

// Incremental scan (one folder at a time)
await storage.incrementalScanForChanges();

// Notify of external update to specific path
await storage.notifyPathWasUpdatedExternal("/path/to/file.json");
Source: ~/workspace/source/app/src/storage/StorageBase.ts:14-300

Choosing a Storage Implementation

Use CaseImplementationReason
Desktop app file accessNodeStorageDirect file system access
Web app data persistenceBrowserStorageClient-side storage with IndexedDB
Serving sample packsHttpStorageSimple HTTP hosting
Microsoft/Mojang samplesGitHubStorageAccess official repositories
Working with .mcpack filesZipStorageRead/write compressed archives
Temporary transformationsStorageNo persistence overhead
Unit testingStorageFast, no I/O

Cross-Platform Patterns

Detecting Environment and Creating Storage

import { 
  NodeStorage,
  BrowserStorage,
  Storage,
  CreatorToolsHost,
  HostType
} from "@minecraft/creator-tools";

function createStorage(path?: string): IStorage {
  if (CreatorToolsHost.hostType === HostType.electronNodeJs ||
      CreatorToolsHost.hostType === HostType.toolsNodejs) {
    // Node environment
    if (path) {
      return new NodeStorage(path, "Project");
    }
  } else {
    // Browser environment
    return new BrowserStorage("myapp");
  }
  
  // Fallback to in-memory
  return new Storage();
}

Unified Loading Pattern

import { IStorage } from "@minecraft/creator-tools";

async function loadProject(storage: IStorage) {
  // Same code works for all storage types
  await storage.rootFolder.load();
  
  const manifest = await storage.rootFolder.getFileFromRelativePath("manifest.json");
  if (manifest) {
    await manifest.loadContent();
    return manifest.content;
  }
}

// Works with any storage implementation
const nodeStorage = new NodeStorage("/path", "name");
const browserStorage = new BrowserStorage("name");
const httpStorage = new HttpStorage("https://example.com/");

await loadProject(nodeStorage);
await loadProject(browserStorage);
await loadProject(httpStorage);

Build docs developers (and LLMs) love