# How Nodeterm Implements Atomic File Operations for Safe Persistence

> Discover how Nodeterm ensures safe persistence using atomic file operations like writeFileAtomic and renameAtomic. Learn about temporary files and retry logic for data integrity.

- Repository: [eneskirca/nodeterm](https://github.com/eneskirca/nodeterm)
- Tags: internals
- Published: 2026-08-26

---

**Nodeterm guarantees data integrity by funneling every persistent write through two atomic utility functions—`writeFileAtomic` and `renameAtomic`—that use temporary files and retry logic instead of direct filesystem renames.**

Nodeterm is a terminal workspace manager that must reliably save layouts, settings, and credentials across Windows, macOS, and Linux. According to the eneskirca/nodeterm source code, the project avoids low-level `fs.rename` calls in favor of a centralized atomic persistence layer implemented in [`src/core/fs-atomic.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/core/fs-atomic.ts). This design ensures that a failed write never corrupts existing data and that transient file locks—common on Windows—do not cause silent data loss.

## The Atomic Write Pattern

Instead of overwriting files directly, Nodeterm writes all content to a temporary file and renames it into place. This pattern ensures that readers always see a complete, valid file or the previous version—never a partially written state.

On Windows, direct renames often fail when antivirus software or cloud sync tools hold file locks. Nodeterm's implementation detects these failures and retries the operation, preventing the silent data loss that would occur with naive persistence code.

## Core Utility Functions in [`src/core/fs-atomic.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/core/fs-atomic.ts)

The persistence layer exports two primary functions that handle every atomic operation in the codebase.

### `writeFileAtomic`

This function writes data to a temporary file before moving it to the final destination. The implementation follows this sequence:

1. Generates a temporary filename using the pattern `<target>.tmp.<uuid>`.
2. Writes the full content using `fs.promises.writeFile`.
3. Renames the temporary file to the target path using `fs.promises.rename`.
4. If the rename fails due to a file lock, the function retries a bounded number of times before rejecting with a clear error.

This approach guarantees that the original file remains untouched until the new content is fully committed to disk.

### `renameAtomic`

For operations that must rename existing files, the `renameAtomic` function wraps `fs.promises.rename` in a retry loop. It sleeps for 10 milliseconds between attempts and limits retries to three. This bounded retry logic ensures that transient locks—caused by Windows Defender or OneDrive sync—do not destabilize the application, while still surfacing permanent errors to the user interface.

## Enforcing Atomic Constraints with Guard Tests

To prevent developers from accidentally introducing unsafe filesystem calls, Nodeterm includes a specialized test suite in **[`src/core/fs-atomic.guard.test.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/core/fs-atomic.guard.test.ts)**. This file scans the entire codebase for direct invocations of `fs.rename` and fails the build if any are found outside the atomic utilities.

By treating atomic persistence as a linting rule, the project ensures that every future feature—whether saving workspace layouts or rotating credential files—automatically inherits cross-platform reliability.

## Remote Atomic Operations

The atomic guarantee extends beyond the local filesystem. When Nodeterm copies files over SSH, it uses the pattern defined in **[`src/main/remote-atomic-write.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/main/remote-atomic-write.ts)**. The remote implementation:

- Creates a temporary file named `.nodeterm-<uuid>.tmp` on the remote host.
- Streams the content to the temporary location.
- Executes an atomic rename to move the file to its final path.

This mirrors the local `writeFileAtomic` behavior and prevents race conditions when network latency or remote filesystem locks delay the operation.

## Practical Usage Examples

The following patterns demonstrate how Nodeterm consumes these utilities in production code.

### Persisting Workspace State

```typescript
import { writeFileAtomic } from '@/core/fs-atomic';
import { workspaceFilePath } from '@/core/workspace-files';

async function persistWorkspace(state: any) {
  const data = JSON.stringify(state, null, 2);
  await writeFileAtomic(workspaceFilePath, data);
}

```

### Rotating Settings Files

```typescript
import { renameAtomic } from '@/core/fs-atomic';

async function rotateSettings(oldPath: string, newPath: string) {
  // Attempts the rename up to three times; throws on permanent failure
  await renameAtomic(oldPath, newPath);
}

```

### Remote Configuration Deployment

```typescript
import { remoteAtomicWrite } from '@/main/remote-atomic-write';

async function uploadConfig(remotePath: string, content: string) {
  // Internally creates .nodeterm-<uuid>.tmp on the host,
  // writes the content, then renames it atomically.
  await remoteAtomicWrite(remotePath, content);
}

```

## Summary

- **Nodeterm centralizes persistence** through `writeFileAtomic` and `renameAtomic` in [`src/core/fs-atomic.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/core/fs-atomic.ts), ensuring that all file writes are atomic across platforms.
- **Temporary file patterns** (`<target>.tmp.<uuid>` locally, `.nodeterm-<uuid>.tmp` remotely) prevent partial writes from corrupting user data.
- **Bounded retry logic** (three attempts with 10ms delays) handles transient Windows file locks without silent failures.
- **Guard tests** in [`src/core/fs-atomic.guard.test.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/core/fs-atomic.guard.test.ts) enforce the architectural constraint that no code may call `fs.rename` directly.
- **Remote operations** replicate the atomic pattern over SSH, maintaining consistency between local and remote persistence paths.

## Frequently Asked Questions

### Why does Nodeterm use atomic file operations instead of direct writes?

Direct filesystem writes risk leaving partially written files if the process crashes or if the operating system buffers are not flushed. By writing to a temporary file and renaming it into place, Nodeterm ensures that readers always see a complete, valid file or the previous version—never a corrupted intermediate state. This pattern is especially critical on Windows, where abrupt termination during a write could otherwise truncate user settings or workspace layouts.

### How does Nodeterm handle file locks on Windows?

Windows often locks files when antivirus software or cloud sync tools scan or upload them. Instead of failing immediately, the `renameAtomic` function retries the rename operation up to three times with 10-millisecond intervals. If the lock persists beyond these retries, the function throws an explicit error that the UI can display, rather than silently discarding the user's data.

### What prevents developers from accidentally using unsafe file operations?

The codebase includes [`src/core/fs-atomic.guard.test.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/core/fs-atomic.guard.test.ts), a dedicated test suite that statically analyzes the source for any direct calls to `fs.rename`. If a developer introduces a non-atomic rename, the build fails immediately. This guard ensures that all persistence paths—local and remote—must flow through the audited atomic utilities in [`src/core/fs-atomic.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/core/fs-atomic.ts).

### Does the atomic persistence strategy work for remote SSH connections?

Yes. When saving files to remote hosts, Nodeterm applies the same temporary-file-then-rename pattern via [`src/main/remote-atomic-write.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/main/remote-atomic-write.ts). It creates a file with the `.nodeterm-<uuid>.tmp` suffix on the remote filesystem, writes the complete content, and then executes an atomic rename. This prevents race conditions and partial writes caused by network latency or remote filesystem locks.