Reader Stacks

Reading, Writing, and Appending File Content in Laravel

File::put() and File::append() do genuinely different things despite the similar-sounding names — one replaces a file's entire contents, the other adds to whatever's already there.

Reading, Writing, and Appending File Content in Laravel

Laravel's File facade (for local disk paths) and the Storage facade (for the abstracted filesystem, covered elsewhere on this site) both wrap plain PHP file functions with a slightly more convenient API for reading, replacing, and appending content.

Reading a file's full contents

use Illuminate\Support\Facades\File;

$content = File::get(storage_path('app/notes.txt'));

File::get() throws a FileNotFoundException if the path doesn't exist — checking File::exists() first, or wrapping the call in a try/catch, avoids an unhandled exception when the file's presence isn't already guaranteed.

Creating a file, or completely replacing its contents

File::put(storage_path('app/notes.txt'), 'This is the new content.');

File::put() creates the file if it doesn't exist, or completely overwrites its existing contents if it does — this is a genuinely destructive operation for an existing file, replacing everything previously there rather than adding to it.

Appending to an existing file, without overwriting it

File::append(storage_path('app/log.txt'), "New log entry: {$message}\n");

File::append() is the genuinely different operation from put() despite the similarly short method name — it adds the given content to the end of whatever's already in the file, leaving the existing content untouched, correct for a running log rather than a value meant to be replaced each time.

Prepending content to the beginning of a file

$existing = File::get(storage_path('app/notes.txt'));
File::put(storage_path('app/notes.txt'), "New first line\n".$existing);

There's no dedicated File::prepend() method — prepending requires manually reading the existing content first, then writing the new content followed by the original, since inserting at the very beginning of a file isn't a native filesystem-level operation the way appending to the end is.

Checking if a file exists before operating on it

if (File::exists(storage_path('app/notes.txt'))) {
    $content = File::get(storage_path('app/notes.txt'));
}

Deleting a file

File::delete(storage_path('app/notes.txt'));

A practical use case: a simple custom log file, separate from Laravel's own logging

function logToCustomFile(string $message): void
{
    $timestamp = now()->format('Y-m-d H:i:s');
    File::append(storage_path('logs/custom-events.log'), "[{$timestamp}] {$message}\n");
}

For most application logging, Laravel's own Log facade (with its channel configuration, log rotation, and severity levels) is the better-suited tool — a raw File::append() loop like this is occasionally useful for a genuinely separate, simple output stream that doesn't need the full logging system's structure.

Why File:: operates on local paths, unlike Storage::

File:: methods take a literal filesystem path (like storage_path() or base_path()) and only ever work with the local disk directly — Storage::, by contrast, works through Laravel's filesystem abstraction layer, which can transparently target local disk, S3, or another cloud provider depending on configuration; File:: is the right choice specifically when the operation is known to always be local and doesn't need that portability.