On this page
storage
introduction
dframework provides a file system abstraction through the Storage facade. it allows you to easily read, write, and manage files across multiple configured "disks". the storage service automatically manages path traversal protection, symlinking public assets, concurrent operation queuing, and even disk space verification.
configuration
the storage configuration is defined within the storage.disks configuration namespace in config/storage.js. a typical configuration might include a local disk for private files, a public disk for assets meant to be publicly accessible, and a secure disk for encrypted files.
1// config/storage.js2import { Env } from 'dframework';3 4export default {5 disks: {6 local: {7 root: './storage/local', // private files8 },9 public: {10 root: './storage/public', // web accessible files11 },12 secure: {13 root: './storage/secure',14 encryptionKey: Env.value('APP_KEY'), // enables automatic aes-256-gcm encryption15 },16 },17};dframework automatically creates a symbolic link from public/storage to storage/public upon boot, allowing files stored on the public disk to be served directly to the browser.
obtaining a disk
the preferred canonical pattern is calling Storage.disk(name) to obtain a disk instance. omitting the disk name resolves the default disk configured in config/storage.js (falling back to public).
for convenience, the Storage facade also proxies operations directly (Storage.put(), Storage.get(), Storage.delete(), etc.) to the default disk.
1import { Storage } from 'dframework';2 3// preferred canonical pattern on default disk4await Storage.disk().put('notes.txt', 'hello');5 6// direct proxy shorthand to default disk7await Storage.put('notes.txt', 'hello');8 9// target a specific configured disk10const disk = Storage.disk('local');
storing files
to write a file to a disk, use the put method. it accepts the relative file path as the first argument, and the file contents (as a string or buffer) as the second argument. the method will automatically create any necessary directories.
1await Storage.disk().put('avatars/1.jpg', imageBuffer);2await Storage.disk('local').put('exports/report.csv', 'id,name\n1,tarou');
file uploads
the put method is fully aware of multipart file objects generated during http uploads. you can pass the uploaded file object directly to the put method, and the framework will stream it to its destination without requiring manual buffer extraction.
1// assuming `req.file('avatar')` is a multiparty file upload2const path = await Storage.disk().put('avatars/user.jpg', req.file('avatar'));
retrieving files
use the get method to read a file's contents. by default, it returns a raw Buffer. if you prefer a string, you can pass the desired encoding (like utf8) as the second argument.
1const raw = await Storage.disk('local').get('documents/contract.pdf');2const text = await Storage.disk('local').get('reports/summary.txt', 'utf8');you can verify if a file exists on the disk using the exists method.
1if (await Storage.disk().exists('avatars/1.jpg')) {2 // file exists3}if you need the absolute server path to a file on the disk, use the path method.
1const absolutePath = Storage.disk('local').path('exports/report.csv');
deleting files
to remove a file, pass the path to the delete method. it returns true if the file was deleted, and false if the file did not exist.
1await Storage.disk().delete('avatars/1.jpg');
file management
the framework provides convenience methods for moving and copying files within the same disk.
1// rename or move a file2await Storage.disk().move('temp/draft.txt', 'published/final.txt');3 4// duplicate a file5await Storage.disk().copy('templates/invoice.pdf', 'invoices/123.pdf');
encryption
disks configured with an encryptionKey automatically encrypt on write and decrypt on read. the algorithm is aes-256-gcm. the key is derived from the provided string via sha256. the encryption key is never stored in the file. it lives only in the environment configuration (APP_KEY). the api is identical to unencrypted disks.
the on disk format is: 12 byte iv + 16 byte auth tag + ciphertext. the auth tag provides tamper detection. reads will fail if the file has been modified.
1// write, encrypted transparently2await Storage.disk('secure').put('keys/api-key.txt', 'my-secret-value');3 4// read, decrypted transparently5const value = await Storage.disk('secure').get('keys/api-key.txt', 'utf8');
disk space protection
to prevent the application from crashing due to disk exhaustion, the storage service performs active health checks before writing data.
before writing data with `put()`, the storage service verifies that the target disk has sufficient capacity for the payload plus a 100 megabyte safety buffer. if space is insufficient, the operation is safely aborted.

