Back to blog

Technology

Everything Is a File: The Unix Idea That Still Runs the Internet

8/17/2026Duhon Young5 min read
Everything Is a File: The Unix Idea That Still Runs the Internet

Everything Is a File: The Unix Idea That Still Runs the Internet

There's a design decision baked into Unix from the early 1970s that most developers use every day without thinking about it: almost everything on the system is represented as a file. Not "file" in the folder-icon sense — file in the sense of "a thing you can open, read, write, and close using the same handful of operations." Your keyboard. Your webcam. A network connection. A running process. The kernel's own internal state. All files, or close enough to files that they behave like one.

It sounds like a simplification for simplification's sake. It isn't. It's the reason a shell one-liner can pipe a webcam feed into a video encoder, the reason curl and cat share half their mental model, and the reason "just read the file" is a legitimate debugging strategy on a system you've never seen before.

What "a file" actually means here

Strip away the folder metaphor and a file is just an interface: open(), read(), write(), close(), and a handful of neighbors like seek() and ioctl(). Unix's insight was that this tiny interface is general enough to describe almost any I/O — not just documents on disk, but hardware, kernel state, and communication channels between processes.

So instead of inventing a bespoke API for every kind of device — one for printers, one for terminals, one for network cards — Unix gives them all a file descriptor and lets them answer to the same four or five calls. The specifics of what reading or writing means are hidden behind that interface. Reading from a disk file returns bytes you wrote yesterday. Reading from /dev/random returns bytes nobody wrote at all. Same call, wildly different backend.

Devices: /dev is not a filing cabinet

/dev/sda isn't a file that describes your disk — writing to it writes to the disk itself. /dev/null isn't a file that logs what you send it — it's a file that discards it. /dev/tty is your terminal. On Linux, /dev/video0 is your webcam; piping it somewhere is how tools like ffmpeg grab a frame without a special driver API.

This is why cat somefile > /dev/usb/lp0 can print a document with zero printer-specific code, and why generating a quick random password can be head -c 16 /dev/urandom | base64. The device driver does the hard part; your shell just moves bytes between file descriptors like it always does.

/proc: the kernel narrating itself as files

Linux takes this further with /proc, a filesystem that doesn't correspond to anything on disk at all — it's a live view into kernel state, rendered as files on demand. /proc/[pid]/status shows a process's memory and state. /proc/cpuinfo shows what the CPU claims to support. /proc/[pid]/fd/ is a directory listing every file descriptor a process currently has open — including sockets and pipes, because those are files too.

This is the part that made me actually appreciate the design instead of just tolerating it: you can inspect deep kernel internals with cat and grep instead of a specialized introspection API. Tools like top and ps aren't doing anything magic — they're reading /proc the same way you could.

Sockets and pipes: files that move, not just sit

A pipe (| in your shell) is a file-like object with no persistent storage — bytes go in one end, come out the other, and that's the entire lifespan. A network socket is close enough to a file that in classic Unix, read() and write() work on it directly. This is why piping works as a universal composition tool: grep doesn't know or care whether its input came from a real file, a keyboard, or another process's output. It just reads a file descriptor.

That uniformity is the actual payoff of "everything is a file." It's not a philosophical purity thing — it's what lets producer | grep pattern | sort | uniq -c work at all, chaining tools that were never written with each other in mind.

Where the abstraction leaks

It's not literally everything, and it's worth knowing where it cracks. Network sockets needed extra calls — bind(), listen(), accept(), connect() — that don't fit the plain file model, because "who am I talking to" isn't a question a disk file has to answer. ioctl() exists specifically as an escape hatch for device-specific operations that read/write can't express — configuring a terminal's baud rate, for instance. And directories themselves are a special case of file that most programs aren't supposed to write() to directly.

Plan 9, built by some of the same people right after Unix, pushed the idea further and fixed a lot of these gaps — even network connections and window-system interactions became real, fully-behaved files. It's a good reminder that "everything is a file" was always an aspiration Unix approximated, not a law it fully satisfied.

Why it's worth knowing

You don't need to write a device driver for this to pay off. It changes how you debug: when something's misbehaving, checking whether there's a /proc or /sys entry that describes it is often faster than reaching for a specialized tool. It changes how you read other people's shell scripts, because half of what looks like special syntax is just ordinary file redirection pointed at an unordinary target. And it's a genuinely good instance of a design principle worth stealing for your own systems: pick a small, boring interface, and get as much of your system as possible to speak it. The payoff isn't elegance for its own sake — it's that pieces built for different purposes can suddenly compose.

Published 8/17/2026
Technology