File Extension
A file extension is the short suffix at the end of a filename, after the final dot, that conventionally signals what kind of content the file holds: .txt for plain text, .jpg for a JPEG image, .py for Python source, .csv for comma-separated values. It is a label attached to the name, not a property of the content, and that gap between label and reality is the source of both the extension's usefulness and nearly all of its pitfalls.
The extension is a convention, and the operating system and applications merely choose to honour it. The habit comes from early systems: CP/M and then MS-DOS limited filenames to eight characters plus a three-character extension (the 8.3 format), which made a short type code part of every name, and Windows kept the practice, using the extension to decide which program opens a double-clicked file through a table of file associations. Unix never required extensions at all, since executables and many data files carry none, and macOS identifies types with its own uniform type identifiers while still consulting extensions. Many modern formats use multiple dots, as in archive.tar.gz, where only the final part names the outermost layer, and the extension need not be three characters, as in .html, .json or .parquet.
The true format of a file is determined by its content, and the reliable fingerprint is the magic number. Most binary formats begin with a fixed byte signature: PNG images start with the bytes 89 50 4E 47 (the letters PNG after a high byte), JPEG with FF D8 FF, PDF with the text %PDF-, GIF with GIF87a or GIF89a, ELF executables on Linux with 7F followed by the letters ELF, and ZIP archives with the letters PK, after the format's creator Phil Katz. The Unix file command, built on the libmagic library, identifies content by matching these signatures instead of trusting the name, as do browsers, antivirus scanners and upload filters. Some formats share a container: a .docx, .xlsx, .jar or .apk file is really a ZIP archive with a specific internal layout, so renaming it to .zip genuinely opens it.
Renaming an extension changes the label and leaves the content untouched, which is the most common misconception about it. Changing photo.png to photo.jpg does not convert anything; it produces a PNG with a misleading name, and strict programs will refuse to open it, while lenient ones sniff the real format and succeed. Converting between formats requires software that decodes one format and encodes the other. Similarly, an extension tells little about how a file was made: a .csv could use commas, semicolons or tabs, any text encoding and any line ending, and a .txt may contain anything at all. Servers add another layer by sending a MIME type such as image/png or text/html in the HTTP header, and browsers historically second-guessed those labels by sniffing the content, a behaviour that has itself caused security bugs.
Extensions have been a durable tool of deception. Windows long hid the extensions of known file types by default, so a file named invoice.pdf.exe appears to the unwary as invoice.pdf while actually being a program; this double-extension trick has been used in countless email attachments. A related trick inserts the Unicode right-to-left override character into a name so that the displayed text is reversed and an executable appears to end in a harmless extension. Document types with macros or scripts (.docm, .xlsm, .js, .vbs, .lnk) have been abused in a similar way, and good practice is to turn on visible extensions, to treat unexpected attachments warily, and, in programs that accept uploads, to validate content signatures and re-encode images rather than trusting a filename.
The extension also matters in programming and data science, where it signals a format with consequences. A .pkl file is typically a Python pickle, which can execute arbitrary code when loaded, so loading model weights from untrusted sources in that format is dangerous; the .safetensors extension, designed for machine-learning weights, stores only tensors and a header and was created partly to avoid this risk. Likewise .parquet implies columnar compressed storage, .npy a NumPy array and .ipynb a JSON notebook, and libraries often choose their reader by extension, so a wrong suffix produces confusing errors rather than a graceful fallback.
Read a file extension as a hint written on the outside of the envelope: useful for routing and quick recognition, fully editable by anyone, and never a substitute for the magic number inside, which is the only part of the name-and-content pair that actually describes what the bytes are.