ShopperCove
Menu
All writingBlogTopicsCategoriesAboutRSS
Blog
Categories
Observability & SRE62All categories
About

Plate 92

  1. Blog
  2. /Observability & SRE

TemporaryFile vs NamedTemporaryFile Delete Modes Lab

Hands-on tempfile modes lab: TemporaryFile vs NamedTemporaryFile delete True/False vs mkstemp unlink patterns with real measured ops/s on localhost box.

Aditya Challa·30 September 2026·6 min read

Lab
On this page
  1. Intro — what this post promises
  2. APIs compared
  3. Lab topology
  4. Lead table (p50)
  5. How to read these numbers
  6. Pitfalls we hit (or avoided)
  7. Practical checklist
  8. Methodology footnote
  9. Versions / environment
  10. delete=True vs delete=False
  11. Relationship to atomic replace
  12. Ratio cheatsheet (vs TemporaryFile)
  13. SpooledTemporaryFile (not timed, but related)
  14. Security / predictability notes
  15. Capacity planning example
  16. Verdict

Intro — what this post promises

Need a scratch file? TemporaryFile, NamedTemporaryFile(delete=...), and mkstemp are not the same syscall story. One is often already anonymous; another keeps a visible path; fsync turns a cheap unlink into a barrier.

This is a hands-on lab with measured numbers:

  1. Create → write (~400 B) → read/flush → close for several tempfile APIs.
  2. NamedTemporaryFile(delete=True) vs delete=False + manual unlink.
  3. mkstemp unlink-while-open vs close-then-unlink (± fsync).

Related links:

  • atomic rename vs overwrite localhost lab
  • fsync vs fdatasync localhost lab
  • pipe vs tmpfile IPC localhost lab
  • posix fadvise sequential vs random localhost lab
  • Why your average latency graph is lying (p50 / p95 / p99)

Lab honesty (1 Oct 2026 IST): Python 3.13.5; dir under /tmp overlay. Affiliates: 0.

Verdict up front: TemporaryFile ~41100 ops/s; NamedTemporaryFile ~19600 (~0.48×). mkstemp+fsync+unlink ~3600; without fsync ~32k.


APIs compared

APIPath visible?Cleanup
TemporaryFileusually no (POSIX unlinked)on close
NamedTemporaryFile(delete=True)yes while openunlink on close
NamedTemporaryFile(delete=False)yesyou unlink
mkstemp + unlink while openno after unlinkanonymous fd
mkstemp + close + unlinkbriefly yesmanual
same + fsync—durable tax

Related links:

  • fsync vs fdatasync localhost lab

Lab topology

/tmp workdir · ~400 B payload · n=1000 ops/batch · 5 repeats
Timed region includes create/write/close (+unlink as specified)

Script: lab-evidence/45-tempfile-modes/results/run_lab.py.


Lead table (p50)

Armops/sµs/opvs TemporaryFile
TemporaryFile4110324.31.00×
mkstemp leave file (no unlink timed)4117424.31.00×
mkstemp close+unlink no fsync3250230.80.79×
mkstemp unlink-while-open3175531.50.77×
NamedTemporaryFile delete=False+unlink2017449.60.49×
NamedTemporaryFile delete=True1956351.10.48×
mkstemp close+unlink + fsync~3600~278~0.09×

Payload spot checks (NamedTemporaryFile delete=True): 64 B ~20835/s; 64 KiB ~14979/s.

Related links:

  • Why your average latency graph is lying (p50 / p95 / p99)
  • atomic rename vs overwrite localhost lab

How to read these numbers

  • No path needed → TemporaryFile (fastest convenient API here).
  • Need a name for a subprocess → NamedTemporaryFile (~2× slower) or mkstemp.
  • delete=True vs False+unlink ≈ same cost.
  • fsync on temps is a durability product decision — huge cliff.

Pitfalls we hit (or avoided)

  1. Putting fsync in the “default mkstemp” arm — rebenchmarked without it (~32k vs ~3.6k).
  2. Assuming NamedTemporaryFile ≈ TemporaryFile — ~0.48×.
  3. Leaking delete=False files — always unlink or use a context that does.
  4. Cross-device temps for atomic replace — see atomic-rename lab.
  5. Measuring only create without write/close — we included a small write.

Practical checklist

  • Scratch buffers: TemporaryFile or SpooledTemporaryFile.
  • External tools needing a path: NamedTemporaryFile(delete=False) + try/finally unlink, or mkstemp.
  • Don’t fsync temps unless the durability contract says so.
  • Prefer same filesystem as the final os.replace target.
  • Clean up crash leftovers for delete=False.

Related links:

  • pipe vs tmpfile IPC localhost lab
  • posix fadvise sequential vs random localhost lab
  • SQLite WAL vs DELETE journal localhost lab
  • json vs orjson vs msgpack localhost lab

Methodology footnote

Each op writes a fixed payload, flushes, and closes. NamedTemporaryFile(delete=False) unlinks after close inside the timed op. The fsync mkstemp arm calls os.fsync(fd) before close. Leftover files from the “leave file” arm are unlinked outside the timed window.


Versions / environment

  • Python 3.13.5 tempfile / os
  • Workdir under /tmp on overlay lab VM

Anonymous temps are the speed default; named temps buy a path for about half the throughput here.


delete=True vs delete=False

Throughput nearly matched (~19.6k vs ~20.2k). The product difference is failure mode: delete=False survives across process crashes until something unlinks the path — useful for debugging postmortems, dangerous for /tmp fill-ups. Prefer delete=True unless a child process must reopen by name after you close (then pass the name carefully and unlink in a finally).

Relationship to atomic replace

Named temps often feed os.replace into a config path (atomic-rename lab). Create the named temp in the destination directory so replace stays same-FS atomic. Using TemporaryFile cannot supply that path; that is the feature trade, not a bug.

Ratio cheatsheet (vs TemporaryFile)

NamedTemporaryFile delete=True 0.48× · delete=False+unlink 0.49× · mkstemp unlink-while-open 0.77× · mkstemp close+unlink no fsync 0.79× · mkstemp+fsync ~0.09×

If a profile shows temp creation hot, switching Named→Temporary (when safe) is a plausible 2×; adding fsync is how you accidentally get a 10× regression.

On busy shared /tmp, also watch inode limits and sticky-bit permissions — throughput numbers assume a quiet lab workdir.

SpooledTemporaryFile (not timed, but related)

For small blobs that might grow, SpooledTemporaryFile keeps bytes in RAM until a size threshold, then rolls to disk. That path can beat any of today’s disk arms for sub-threshold sizes — and looks nothing like NamedTemporaryFile in profiles. If your “temp file” is usually under a few KiB, consider spooling before paying named-path costs.

Security / predictability notes

Named temps use predictable directory listings if permissions are wrong. Keep dir= on a private directory when secrets touch disk. TemporaryFile’s anonymous POSIX pattern reduces the rename/race window because there is often no lasting directory entry — another reason it is the default scratch tool.

Capacity planning example

At ~20k NamedTemporaryFile ops/s, one core could theoretically open ~20 million named temps per second in a microbench — reality will be lock contention on the directory and page cache. Still, if a job creates 100k temps, budget ~5 s of create/close overhead from this lab’s µs/op before counting useful work. TemporaryFile would be ~2.4 s for the same count on these numbers.

Verdict

TemporaryFile (~41k ops/s) beat NamedTemporaryFile (~20k, ~0.48×) for small write/close cycles. mkstemp without fsync sat ~32k; with fsync ~3.6k. Pick anonymous when you can; pay for names deliberately; fsync only with a durability story.

Evidence: lab-evidence/45-tempfile-modes/results/. Affiliates: 0.

temporaryfilenamedtemporaryfilemkstemptempfile deleteanonymous temp filelocalhost labsrepython

Lab evidence

What I found running this

Lab 1 Oct 2026 IST. Python 3.13.5; /tmp; ~400 B payload. TemporaryFile ~41103 ops/s; NamedTemporaryFile(delete=True) ~19563 (~0.48x); delete=False+unlink ~20174; mkstemp unlink-while-open ~31755; mkstemp close+unlink (no fsync) ~32502; mkstemp+fsync+unlink ~3600. Affiliates: 0. Evidence: lab-evidence/45-tempfile-modes/.

Notes when a lab post goes up

Occasional email for new hands-on reviews. No sequence and no sponsors.

Related links

  • Plate 18

    fnmatch vs re Name Filter: Localhost Lab

    Hands-on fnmatch.filter vs re.compile name-list filtering measured on Linux localhost.

    Observability & SRE · 30 Sept 2026

  • Plate 84

    tarfile vs zipfile Create+Extract: Localhost Lab

    Hands-on tarfile vs zipfile create+extract lab: real MB/s on a mixed small-file fixture (uncompressed tar vs zip), measured on Linux localhost for SREs.

    Observability & SRE · 30 Sept 2026

  • Plate 85

    scandir vs listdir vs iterdir: Localhost Lab

    Hands-on os.scandir vs listdir vs Path.iterdir lab: real entries/s for names and is_file on a synthetic tree, measured on Linux localhost (lab) for SREs.

    Observability & SRE · 30 Sept 2026

On this page

  1. Intro — what this post promises
  2. APIs compared
  3. Lab topology
  4. Lead table (p50)
  5. How to read these numbers
  6. Pitfalls we hit (or avoided)
  7. Practical checklist
  8. Methodology footnote
  9. Versions / environment
  10. delete=True vs delete=False
  11. Relationship to atomic replace
  12. Ratio cheatsheet (vs TemporaryFile)
  13. SpooledTemporaryFile (not timed, but related)
  14. Security / predictability notes
  15. Capacity planning example
  16. Verdict
All writingBlogCategoriesTopicsAboutPrivacyRSS

© 2026 ShopperCove