Filesystem Adapter
@trokky/adapter-filesystem stores content as JSON files on the local filesystem, making it ideal for development and Git-based content workflows.
Installation
Section titled “Installation”npm install @trokky/adapter-filesystemimport { FilesystemAdapter } from '@trokky/adapter-filesystem';
const storage = new FilesystemAdapter({ contentDir: './content', mediaDir: './uploads',});With TrokkyExpress
Section titled “With TrokkyExpress”const trokky = await TrokkyExpress.create({ storage: { adapter: 'filesystem', contentDir: './content', mediaDir: './uploads', }, // ...});Configuration
Section titled “Configuration”| Option | Type | Default | Description |
|---|---|---|---|
contentDir | string | './content' | Directory for document JSON files |
mediaDir | string | './uploads' | Directory for media files |
pretty | boolean | true | Pretty-print JSON (easier to read in Git) |
indexing | boolean | true | Enable index cache for faster queries |
File Structure
Section titled “File Structure”Documents are stored as JSON files organized by schema:
content/├── post/│ ├── abc123.json│ ├── def456.json│ └── ghi789.json├── author/│ ├── author-001.json│ └── author-002.json├── siteSettings/│ └── singleton.json└── _users/ └── admin.json
uploads/├── images/│ ├── photo-abc123.jpg│ ├── photo-abc123-thumb.webp│ └── photo-abc123-medium.webp└── files/ └── document-def456.pdfDocument File Example
Section titled “Document File Example”{ "_id": "abc123", "_type": "post", "_createdAt": "2024-01-15T10:00:00.000Z", "_updatedAt": "2024-01-16T14:30:00.000Z", "title": "My First Post", "slug": { "current": "my-first-post" }, "content": "Hello world!", "author": { "_type": "reference", "_ref": "author-001" }, "status": "published"}Git Integration
Section titled “Git Integration”The filesystem adapter is designed for Git workflows:
.gitignore
Section titled “.gitignore”# Ignore cache and temporary filescontent/.cache/uploads/.tmp/
# Optionally ignore uploads in Git# uploads/Version Control Content
Section titled “Version Control Content”With content as files, you can:
- Track content changes in Git
- Use pull requests for content review
- Roll back to previous versions
- Branch for content experiments
Example Workflow
Section titled “Example Workflow”# Create a content branchgit checkout -b content/new-blog-post
# Make changes in Studio# ...
# Commit content changesgit add content/git commit -m "Add new blog post about Trokky"
# Create PR for reviewgh pr create --title "New blog post" --body "Review the content"Caching
Section titled “Caching”The adapter maintains an index cache for faster queries:
content/└── .cache/ └── index.jsonCache Structure
Section titled “Cache Structure”{ "post": { "abc123": { "title": "My First Post", "_createdAt": "2024-01-15T10:00:00.000Z", "_updatedAt": "2024-01-16T14:30:00.000Z" } }}Disable Caching
Section titled “Disable Caching”const storage = new FilesystemAdapter({ contentDir: './content', indexing: false, // Disable cache});API Reference
Section titled “API Reference”Constructor
Section titled “Constructor”new FilesystemAdapter(options: FilesystemAdapterOptions)Methods
Section titled “Methods”createDocument(collection, data)
Section titled “createDocument(collection, data)”Creates a new document.
const doc = await storage.createDocument('post', { title: 'New Post', content: 'Content here',});getDocument(collection, id)
Section titled “getDocument(collection, id)”Retrieves a document by ID.
const doc = await storage.getDocument('post', 'abc123');updateDocument(collection, id, data)
Section titled “updateDocument(collection, id, data)”Updates an existing document.
const doc = await storage.updateDocument('post', 'abc123', { title: 'Updated Title',});deleteDocument(collection, id)
Section titled “deleteDocument(collection, id)”Deletes a document.
await storage.deleteDocument('post', 'abc123');listDocuments(collection, options)
Section titled “listDocuments(collection, options)”Lists documents with optional filtering.
const docs = await storage.listDocuments('post', { limit: 10, offset: 0, orderBy: '_createdAt', order: 'desc',});uploadMedia(file, metadata)
Section titled “uploadMedia(file, metadata)”Uploads a media file.
const asset = await storage.uploadMedia(buffer, { filename: 'photo.jpg', mimeType: 'image/jpeg',});getMedia(id)
Section titled “getMedia(id)”Retrieves media metadata.
const asset = await storage.getMedia('media-abc123');deleteMedia(id)
Section titled “deleteMedia(id)”Deletes a media file and all variants.
await storage.deleteMedia('media-abc123');Performance Considerations
Section titled “Performance Considerations”Suitable For
Section titled “Suitable For”- Development environments
- Small to medium content volumes (hundreds of documents)
- Git-based workflows
- Static site generation
- Local-first applications
Not Suitable For
Section titled “Not Suitable For”- High-traffic production sites
- Large content volumes (thousands of documents)
- Multi-server deployments
- Real-time collaboration
Optimization Tips
Section titled “Optimization Tips”- Enable indexing for faster list queries
- Use SSD storage for better I/O performance
- Limit media variants to reduce disk usage
- Archive old content periodically
Migration
Section titled “Migration”Export to JSON
Section titled “Export to JSON”const storage = new FilesystemAdapter({ contentDir: './content' });
const schemas = ['post', 'author', 'category'];const backup = {};
for (const schema of schemas) { backup[schema] = await storage.listDocuments(schema);}
fs.writeFileSync('backup.json', JSON.stringify(backup, null, 2));Import from JSON
Section titled “Import from JSON”const backup = JSON.parse(fs.readFileSync('backup.json', 'utf-8'));
for (const [schema, docs] of Object.entries(backup)) { for (const doc of docs) { await storage.createDocument(schema, doc); }}Troubleshooting
Section titled “Troubleshooting”Permission Errors
Section titled “Permission Errors”# Ensure write permissionschmod -R 755 content/chmod -R 755 uploads/Cache Corruption
Section titled “Cache Corruption”# Clear the cacherm -rf content/.cache/The cache will be rebuilt automatically on next query.
File Locking Issues
Section titled “File Locking Issues”If you see file locking errors on concurrent writes, consider:
- Using a database adapter for high-concurrency scenarios
- Implementing a queue for write operations
Next Steps
Section titled “Next Steps”- S3 Adapter - Cloud storage for production
- Cloudflare Adapter - Edge storage
- Storage Guide - Choosing an adapter