Generate Temporary Files
How to create temporary files and directories safely with automatic cleanup across Python, Node.js, Java, and Bash.
Note: This guide follows English-language naming conventions and terminology standards common in international development teams. Examples use English identifiers and comments to maximize compatibility across codebases and tooling.
Overview
Temporary files are essential for caching intermediate data, storing uploads during processing, or holding secrets that should not persist on disk. Creating them incorrectly can lead to security vulnerabilities (predictable filenames), resource leaks (files never deleted), or cross-platform incompatibility.
When to Use
- Staging uploaded files before validation and permanent storage
- Holding decrypted data or secrets briefly during processing
- Caching intermediate computation results within a single process lifetime
- Running tests that need isolated filesystem state
- Swapping data that does not fit in memory during batch processing
When NOT to Use
- Long-term storage of user data — use permanent paths with proper backups
- Data that must survive process restarts — temp directories may be wiped on reboot
- Highly sensitive secrets on shared systems — use memory-only approaches or encrypted volumes
- Files that multiple processes need to discover by name — temp names are randomized
Step-by-Step Implementation
Python
import tempfile
import os
# Temporary file (auto-deleted when closed)
with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=True) as f:
f.write('{"key": "value"}')
f.flush()
print(f"Temp file: {f.name}")
# File is automatically deleted when exiting the context
# Temporary directory (auto-deleted with cleanup=True)
with tempfile.TemporaryDirectory() as tmpdir:
path = os.path.join(tmpdir, 'report.txt')
with open(path, 'w') as f:
f.write('Temporary report data')
print(f"Temp dir: {tmpdir}")
# Directory and all contents deleted on context exit
# Manual cleanup (use when passing path to external process)
tmp = tempfile.NamedTemporaryFile(mode='w', suffix='.csv', delete=False)
try:
tmp.write('id,name\n1,Alice\n')
tmp.close()
# Pass tmp.name to external tool...
finally:
os.unlink(tmp.name)
Node.js
import os from 'os';
import fs from 'fs';
import path from 'path';
// Using built-in fs promises with custom cleanup
async function withTempFile(data, suffix = '.tmp') {
const tmpPath = path.join(os.tmpdir(), `tmp-${Date.now()}-${Math.random().toString(36).slice(2)}${suffix}`);
try {
await fs.promises.writeFile(tmpPath, data);
return tmpPath;
} catch (err) {
await fs.promises.unlink(tmpPath).catch(() => {});
throw err;
}
}
// Using the tmp package (recommended for production)
import tmp from 'tmp';
// Auto-cleanup on process exit
const tmpObj = tmp.fileSync({ postfix: '.json' });
fs.writeFileSync(tmpObj.name, '{"key": "value"}');
// tmpObj.removeCallback() deletes the file
const tmpDir = tmp.dirSync({ unsafeCleanup: true });
// Recursively removes dir on cleanup
Java
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
// Java 7+ NIO.2 (recommended)
public class TempFileExample {
public static void main(String[] args) throws IOException {
// Create temp file in default temp directory
Path tempFile = Files.createTempFile("prefix-", ".txt");
System.out.println("Created: " + tempFile);
Files.writeString(tempFile, "temporary data");
// Create temp directory
Path tempDir = Files.createTempDirectory("myapp-");
Path nested = tempDir.resolve("nested.txt");
Files.writeString(nested, "nested content");
// Register for deletion on JVM exit (best effort)
tempFile.toFile().deleteOnExit();
tempDir.toFile().deleteOnExit();
// Explicit cleanup
Files.deleteIfExists(tempFile);
Files.walk(tempDir)
.sorted((a, b) -> -a.compareTo(b))
.forEach(p -> {
try { Files.deleteIfExists(p); }
catch (IOException e) { /* ignore */ }
});
}
}
Bash
#!/bin/bash
set -euo pipefail
# Create temp file (portable, POSIX-compliant)
TMPFILE=$(mktemp "${TMPDIR:-/tmp}/XXXXXX.json")
trap 'rm -f "$TMPFILE"' EXIT
echo '{"status": "ok"}' > "$TMPFILE"
# Process file...
echo "Using: $TMPFILE"
# Create temp directory
TMPDIR_PATH=$(mktemp -d "${TMPDIR:-/tmp}/myapp.XXXXXX")
trap 'rm -rf "$TMPDIR_PATH"' EXIT
# Multiple temp resources — use a cleanup function
cleanup() {
rm -f "$TMPFILE" 2>/dev/null || true
rm -rf "$TMPDIR_PATH" 2>/dev/null || true
}
trap cleanup EXIT
# Advanced: generate unique temp path without creating file
UNIQUE_PATH="${TMPDIR:-/tmp}/batch_$(date +%s)_$$_$RANDOM.csv"
What Works
- Always use
mktempor language-native temp APIs. Never build temp paths manually with predictable patterns like/tmp/myapp.pid— they are vulnerable to race conditions and symlink attacks. - Set
trapin Bash ordeleteOnExitin Java for cleanup guarantees, but prefer explicit cleanup in try-finally or try-with-resources. - Use descriptive prefixes and suffixes (
mktemp prefix.XXXXXX.ext) to identify temp file purpose in logs and filesystem tools. - Avoid writing secrets to temp files when possible. If unavoidable, set restrictive permissions (
chmod 600) immediately after creation. - Respect
$TMPDIRenvironment variable for portability. Do not hardcode/tmp— macOS and some Linux distros use alternate paths.
Common Mistakes
- Hardcoding
/tmpwith predictable names. An attacker can create a symlink at the expected path to overwrite arbitrary files. - Relying solely on
deleteOnExitin long-running processes. Files accumulate until JVM or process exits. - Forgetting cleanup in error paths. An exception before cleanup leaves orphaned temp files that fill the disk over time.
- Using
Date.now()as the only randomizer in Node.js. Millisecond collisions are possible under load — combine with crypto-random bytes. - Creating temp files in the working directory. Pollutes the project and may be committed accidentally.
Additional Best Practices
- For a deeper guide, see Rotate Log Files.
- Create temp files in the same directory as the target for atomic writes.
os.rename()is atomic only within the same filesystem. If the temp file is on a different mount point, the rename becomes a copy, which is not atomic:
import tempfile
import os
# Good: temp file in same dir as target
target = "/var/app/config.json"
fd, tmp = tempfile.mkstemp(dir=os.path.dirname(target), prefix=".config.", suffix=".tmp")
os.close(fd)
# ... write data ...
os.rename(tmp, target) # Atomic on same filesystem
# Bad: temp file in /tmp, target on /var (different filesystem)
# fd, tmp = tempfile.mkstemp(suffix=".tmp") # /tmp may be a different mount
# os.rename(tmp, "/var/app/config.json") # Not atomic if cross-filesystem
- Use
fsyncafter writing critical data. The OS may buffer writes. If the process crashes, buffered data is lost. Callfsyncto force data to disk before renaming:
import os
fd, tmp_path = tempfile.mkstemp(suffix=".dat")
with os.fdopen(fd, "wb") as f:
f.write(b"critical data")
f.flush()
os.fsync(f.fileno()) # Force to disk
os.rename(tmp_path, "important.dat")
- Clean up temp files on signal interruption. In Bash,
trapon EXIT does not fire onSIGKILL, but it does onSIGINTandSIGTERM:
#!/bin/bash
set -euo pipefail
TMPDIR_PATH=$(mktemp -d)
cleanup() {
rm -rf "$TMPDIR_PATH"
exit 0
}
trap cleanup EXIT INT TERM
# Long-running process
for i in $(seq 1 100); do
echo "Processing $i..." > "$TMPDIR_PATH/log.txt"
sleep 1
done
Additional Common Mistakes
- Using
tempfile.mktemp()(deprecated). It generates a filename without creating the file, creating a race condition. Usemkstemp()instead:
import tempfile
import os
# Bad: mktemp() is deprecated, race condition vulnerable
# path = tempfile.mktemp(suffix=".txt") # Don't use this
# Good: mkstemp() creates the file atomically
fd, path = tempfile.mkstemp(suffix=".txt")
os.close(fd)
print(f"Safe temp file: {path}")
os.unlink(path)
- Not handling temp directory cleanup in recursive structures. If you create nested temp directories, a simple
os.rmdir()fails because it only removes empty directories. Useshutil.rmtree():
import tempfile
import shutil
import os
tmpdir = tempfile.mkdtemp()
try:
nested = os.path.join(tmpdir, "a", "b", "c")
os.makedirs(nested)
with open(os.path.join(nested, "file.txt"), "w") as f:
f.write("data")
# Bad: os.rmdir fails because dir is not empty
# os.rmdir(tmpdir) # OSError: Directory not empty
# Good: shutil.rmtree removes recursively
shutil.rmtree(tmpdir)
finally:
if os.path.exists(tmpdir):
shutil.rmtree(tmpdir, ignore_errors=True)
- Leaking temp file descriptors. On Windows, files with open descriptors cannot be deleted. Always close before unlinking:
import tempfile
import os
# Bad: file still open, unlink fails on Windows
# f = tempfile.NamedTemporaryFile(delete=False)
# f.write("data")
# os.unlink(f.name) # May fail on Windows
# Good: close first, then unlink
f = tempfile.NamedTemporaryFile(delete=False, suffix=".txt")
try:
f.write("data".encode())
f.close() # Close before unlink
os.unlink(f.name)
except Exception:
f.close()
if os.path.exists(f.name):
os.unlink(f.name)
raise Related Resources
Rotate Log Files
How to implement log rotation by size, date, and count to prevent disk exhaustion across Python, Node.js, Java, and Linux systems.
RecipeRead Large Files
How to read large files efficiently without running out of memory.
GuideCaching Strategies: From Browser to Database, a Complete
A practical guide to caching strategies: browser caching, CDN edge caching, application caching with Redis, and database query caching. Learn when to use each and how to avoid cache invalidation nightmares.
Frequently Asked Questions
- Why is mktemp safer than creating files in /tmp manually?
- mktemp generates unique filenames with restrictive permissions, preventing race conditions and predictable paths that attackers could exploit.
- What happens to temporary files after the script exits?
- They remain unless you delete them. Use a trap to clean up on exit, or store files in a directory created with mktemp -d and remove the whole directory.
- Can I use temporary files in a CI pipeline?
- Yes, but ensure the runner has enough disk space and that sensitive data is never left in artifacts or shared caches.