Skip to content

[RFC]: Achieve Feature Parity with Node.js Built-in fs Module #214

@ImStillBlessed

Description

@ImStillBlessed

Full name

Ebosetale Blessed Oigbochie

University status

No

University name

No response

University program

No response

Expected graduation

No response

Short biography

I am a software engineer based in Benin City Nigeria, i have over 5 years of experience building and improving backend systems. I hold a degree in Medical Biochemistry and a masters in the same field and this background has trained me to work carefully with complex systems and treat precision in methodology as non-negotiable.

My programming journey began with C through the ALX Software Engineering program, giving me a solid foundation in systems thinking and low-level programming. Since then I have worked professionally with Python (4+ years), JavaScript/Node.js (5+ years), and Go my current primary language for backend work. I have taken on both lead and support engineering roles, helping companies improve the structure and efficiency of their backend codebases.

My technical competencies include backend system design, REST API development, file I/O and system-level programming, asynchronous patterns in Node.js, and working within large structured codebases with strict quality and style requirements. I am comfortable with Git-based contribution workflows, test-driven development, and technical documentation.

My primary interests within software engineering are systems programming, developer tooling, and open source infrastructure work that improves the foundation other developers build on. This is what draws me to stdlib specifically and to the fs namespace project in particular.

Timezone

West Africa Time (WAT, UTC+1)

Contact details

email:eprince1800@gmail.com,github:ImStillBlessed

Platform

Windows

Editor

Visual Studio Code. I've used it for a very long time and i am comfortable with the shortcuts and the ease of setup, plus it pairs really well with the stdlib project and linitng ESlint and configs EditorConfig.

Programming experience

I've been programming professionally for 5 years, building mostly websites and web applications, working across production codebase in both frontend and backend contexts.
some of the projects I've built over the years
School Management system: optimized for thousands of students and clear posterity of data and ease of operations in the school.

JavaScript experience

I have been writing JavaScript professionally for over 5 years across frontend and backend contexts. On the backend I have used it primarily through Node.js for REST APIs, file processing, and system tooling. I am comfortable with the full async landscape — callbacks, Promises, and async/await — and I understand the event loop well enough to reason about performance and timing in I/O-heavy code.

my favourite feature is how there is availability of everything in forms of packages, whatever niche feature oyu want someone out there has thought of it and implemented it optimised.

least favourite is that it is widely unstable and there are alot of standard features and functionalities that other programming languages have solved that are still a problem in even latest versions of js.

Node.js experience

Node.js is my primary server-side runtime. I have used it professionally in backend systems, including file I/O, stream processing, and system-level scripting. I am familiar with the fs module API in depth, both the callback and synchronous variants, and I have studied how the API surface has evolved across Node.js versions. My fs/stat implementation for stdlib (PR #11069) is the most concrete example of that knowledge applied in practice.

C/Fortran experience

My foundation in C came through the ALX Software Engineering program, where I built projects covering memory management, data structures, and system-level programming. I have not worked with Fortran. My C background is directly relevant to this project because understanding how file descriptors, permission modes, and system calls work at the C level helps me reason correctly about what Node's fs APIs are doing under the hood and why certain behaviors differ across operating systems.

Interest in stdlib

What draws me to stdlib is the ambition of the project. JavaScript has always lacked what Python and Go take for granted: a reliable, well-tested standard library that developers can depend on without reaching for a dozen third-party packages. stdlib is the most serious attempt I have seen to fix that, and contributing to it feels like work that matters beyond any single project.
The fs namespace is specifically what pulled me in. I have used file system APIs professionally for years but never had to understand them at the depth that implementing them requires. The existing stdlib fs packages showed me exactly what that depth looks like in practice, and I wanted to contribute to expanding i

Version control

Yes

Contributions to stdlib

My first open source contribution is #10998
I also have an ongoing fs/stat implementation (PR #11069), which gave me hands-on familiarity with stdlib's package structure, conventions, review process, and the specific patterns used across the fs namespace.

stdlib showcase

  • [stdlib-demo](https://github.com/ImStillBlessed/stdlib-demo)
    A CLI tool that reads a JSON file of math operations, evaluates them using stdlib math packages, and conditionally writes selected results to a report file using stdlib fs packages. Built specifically to explore the existing @stdlib/fs namespace hands-on before extending it as part of this proposal.
    stdlib packages used: @stdlib/fs/exists to validate the input file before doing any work, @stdlib/fs/read-json to load and parse the operations list, @stdlib/fs/write-file to write filtered output only when results match defined conditions, plus @stdlib/math-base-special-abs, pow, sqrt, log, exp, sin, and cos for the numeric evaluations.
    The tool deliberately follows stdlib's error-as-value callback pattern throughout — errors from read-json and write-file are handled as return values rather than exceptions, consistent with how all @stdlib/fs packages are designed to work.

Goals

Node.js ships with a built-in fs module that provides a comprehensive set of file system operations. stdlib currently implements a carefully selected subset of these read-file, write-file, open, close, unlink, read-dir, append-file, exists, stat (pending review in PR #11069), and several utilities — but a significant portion of the fs API surface remains unimplemented. This means developers using stdlib for file system work must fall back to Node's native fs module directly, losing the consistency guarantees, error-as-value convention, and cross-version reliability that stdlib's existing fs packages provide.

The goal of this project is to meaningfully advance stdlib's fs namespace toward feature parity with Node.js's built-in fs module, by implementing 9 new packages covering the most commonly used file system operations not yet available in stdlib. Each package will follow stdlib's established conventions precisely: an asynchronous default export using the callback pattern, a .sync method that returns errors as values rather than throwing, full JSDoc documentation, tests using the Tape framework, TAP-compatible benchmarks, and a CLI where applicable.

Beyond simply wrapping Node's native APIs, a core part of this work involves building a compatibility abstraction layer ensuring that each package behaves consistently across all Node.js versions that stdlib supports, including versions predating certain options or behaviours. For packages where newer Node.js versions introduced additional options (such as mkdir's recursive option, added in v10.12.0, or copyFile's mode constants, added in v14.0.0), the implementation will include version detection and appropriate fallback logic, so that consumers of these stdlib packages can write version-agnostic code.

The concrete deliverables, ordered from least to most complex, are:

Package Description Complexity
@stdlib/fs/stat File/directory statistics (PR #11069 in review) Low
@stdlib/fs/truncate Truncate a file to a specified length Low
@stdlib/fs/link Create a hard link between two paths Low
@stdlib/fs/symlink Create a symbolic link Low
@stdlib/fs/chmod Change file or directory permissions Low
@stdlib/fs/append-file Complete missing callback and sync variants Low
@stdlib/fs/copy-file Copy a file from source to destination Medium
@stdlib/fs/write Write buffer or string to a file descriptor Medium
@stdlib/fs/mkdir Create a directory with recursive support Medium

Each package will be submitted as an individual pull request, enabling incremental review and merge throughout the program rather than a large submission at the end. More complex APIs fs.cp (Node v16.7.0, requires stream-based fallback) and fs.glob (Node v22, requires full reimplementation for older versions) — are intentionally scoped as stretch goals, with honest reasoning provided in the schedule below.

Why this project?

The honest answer is that this project sits at the intersection of everything I already do professionally and everything I want to get better at.
I have been using Node.js's fs module for years in production scripts, backend tooling, file processing pipelines. I know the API well as a user, but there is a real difference between using something and understanding it deeply enough to implement it.
Beyond personal growth, the project matters. stdlib is trying to do for JavaScript what standard libraries in Python and Go do for those languages, give developers a consistent, reliable foundation.

Qualifications

I am a software engineer with over 5 years of professional JavaScript and Node.js experience, with additional professional experience in Python and Go. My programming foundation began with C through the ALX Software Engineering program, giving me a systems-level understanding of how file operations, memory, and OS interfaces work directly relevant to this project's lower-level requirements.
I have worked in both lead and support backend engineering roles, helping companies improve the structure and efficiency of their codebases. That experience has made me comfortable reading and reasoning about large, unfamiliar codebases a necessary skill for contributing to a monorepo as structured and convention-driven as stdlib.
Most directly, I have already implemented fs/stat for stdlib (PR #11069), which required me to understand and apply every convention this project depends on: the async/sync split, error-as-value return pattern, JSDoc documentation style, Tape-based testing, and the package structure expected across the fs namespace. I received and addressed reviewer feedback from the core maintainer, and the PR is currently awaiting final review. That work is the most concrete evidence I can offer that I understand what this project requires and can execute on it.
The packages I am proposing to implement do not require expertise outside my existing skill set. File permission management chmod, hard and symbolic links link, symlink, file truncation (truncate), and directory creation (mkdir) are operations I have used professionally and understand at both the JavaScript and system call level. The compatibility work — detecting Node.js version capabilities and falling back gracefully — is a pattern I studied carefully in the readable-stream package and in how stdlib's existing fs packages handle environment differences.

Prior art

The main reference for this project is the Node.js fs module documentation and source code at [nodejs.org/api/fs.html](https://nodejs.org/api/fs.html), which serve as the authoritative guide for API signatures, option behavior, and version-specific changes across all packages I plan to implement.

Within stdlib itself, there are already 15 integrated fs packages: close, exists, open, read-dir, read-file, read-file-list, read-json, read-ndjson, read-wasm, rename, resolve-parent-path, resolve-parent-path-by, resolve-parent-paths, unlink, and write-file, plus my own fs/stat implementation currently in review (PR [#11069](stdlib-js/stdlib#11069)). These existing packages are the most direct prior art for this project. They define the conventions, patterns, and structure that every new package must follow and I have studied them closely.

Beyond stdlib, several userland packages are relevant. [graceful-fs](https://www.npmjs.com/package/graceful-fs) is a drop-in replacement for Node's fs that patches edge-case behaviors like EMFILE retries and normalizes inconsistencies across Node versions. It is a useful reference for understanding what breaks across versions, though it does not follow stdlib's error-as-value conventions. [fs-extra](https://www.npmjs.com/package/fs-extra) extends Node's fs with higher-level utilities like copy, move, and ensureDir, and is a useful reference for option handling and recursive operation design, particularly for mkdir and copy-file. This project stays within Node's native fs surface rather than extending into fs-extra territory. [readable-stream](https://www.npmjs.com/package/readable-stream) reimplements Node's stream API in userland for cross-version consistency. The pattern it uses, detecting native capability and falling back to a manual implementation, is directly applicable to packages like mkdir (where options.recursive requires a fallback for Node < v10.12.0) and copy-file (where mode constants require a fallback for Node < v14.0.0). [mkdirp](https://github.com/isaacs/node-mkdirp) implements recursive directory creation manually and was referenced directly by C0ldSmi1e in PR [#2198](stdlib-js/stdlib#2198) for error code handling. I have studied both that PR and mkdirp's approach to EEXIST and ENOENT handling as reference for my own fs/mkdir implementation.

Two prior GSoC 2024 proposals addressed this same issue, [#72](#72) by C0ldSmi1e and [#73](#73) by HRIDYANSHU054. Both produced useful work: C0ldSmi1e submitted fs/mkdir (PR [#2198](stdlib-js/stdlib#2198)) and HRIDYANSHU054 submitted fs/append-file (PR [#1967](stdlib-js/stdlib#1967)), both of which I have read through carefully.

Commitment

I am available full-time for the duration of the GSoC program. I do work part-time for a startup but my schedule is flexible and the majority of my week is free. I am committing to a minimum of 15 hours per week across the 12-week program, with capacity to go beyond that during lighter weeks or when a package is mid-implementation and benefits from sustained focus.
I have no planned travel, examinations, or significant personal commitments between May and August that would affect my availability. I am fully grounded and treat this project as my primary professional focus during the program period.
I also intend to remain an active stdlib contributor after GSoC ends. The stretch goals identified in this proposal fs/rm, fs/cp, and the Promise API variants under @stdlib/fs/promises/* represent natural next steps that I plan to continue working toward regardless of GSoC outcomes.

Schedule

Assuming a 12 week schedule,

  • Community Bonding Period:
    Rather than spending this time on environment setup (which will be done before the program starts), I plan to use the bonding period to engage directly with the maintainers on the technical design of each planned package. Specifically, I will open RFC issues on the stdlib repository for fs/truncate, fs/link, fs/symlink, fs/chmod, fs/copy-file, fs/write, and fs/mkdir one per package outlining my proposed API signatures, compatibility approach, and any open design questions. This gives mentors visibility into my thinking before I write a line of code, and surfaces any corrections early rather than mid-implementation. I will also use this time to push fs/stat PR #11069 to merge by addressing any outstanding reviewer feedback promptly.

  • Week 1:
    fs/truncate and fs/link

    fs.truncate(path[, len], callback) truncates a file to len bytes (default 0). Available since Node v0.8.6 with no meaningful version divergence no compatibility work needed beyond the standard stdlib wrapper pattern. fs.link(existingPath, newPath, callback) creates a hard link and has been stable since Node v0.1.31. Both are structurally simple: no options objects, predictable error surfaces, and clean sync counterparts (fs.truncateSync, fs.linkSync). Tackling both in week 1 is realistic and sets a productive pace.

    Each package includes: async wrapper, .sync method returning errors as values, full JSDoc, Tape tests, TAP benchmarks, README, and CLI.

    Deliverables: PR for @stdlib/fs/truncate, PR for @stdlib/fs/link

  • Week 2:
    fs/symlink

    fs.symlink(target, path[, type], callback) creates a symbolic link. Stable since Node v0.1.31. The type parameter ('file', 'dir', 'junction') is Windows-specific and ignored on POSIX systems this needs to be documented clearly and handled gracefully. The sync counterpart is fs.symlinkSync. This is a standalone week because symlink behavior has more platform-specific nuance than link or truncate and deserves focused testing across environments.

    Deliverable: PR for @stdlib/fs/symlink

  • Week 3:
    fs/chmod

    fs.chmod(path, mode, callback) changes file mode bits. Available since Node v0.1.30. The mode argument accepts either an integer (e.g., 0o755) or a string representing octal permission bits. The sync counterpart is fs.chmodSync. No version compatibility concerns. This week also involves reviewing fs.fchmod (file-descriptor-based variant, available since Node v0.4.7) as a natural companion if time permits after full testing and documentation of chmod, fchmod will be started.

    Deliverable: PR for @stdlib/fs/chmod

  • Week 4:
    fs/copy-file

    fs.copyFile(src, dest[, mode], callback) copies a file. Introduced in Node v8.5.0. The mode parameter controls copy behavior using constants fs.constants.COPYFILE_EXCL (fail if dest exists), fs.constants.COPYFILE_FICLONE (copy-on-write reflink), and fs.constants.COPYFILE_FICLONE_FORCE but these constants were only added in Node v14.0.0. For older versions, the implementation needs to fall back gracefully: detect whether the constants exist on fs.constants and handle the absence without throwing. The sync counterpart is fs.copyFileSync. This is the first package in the schedule requiring real compatibility work, which is why it sits in week 4 after the pattern is well established.

    Deliverable: PR for @stdlib/fs/copy-file

  • Week 5:
    fs/write

    fs.write has three distinct callback signatures:

    • fs.write(fd, buffer, offset[, length[, position]], callback) writes a buffer at a given offset
    • fs.write(fd, buffer[, options], callback) buffer write with an options object (added Node v18.3.0)
    • fs.write(fd, string[, position[, encoding]], callback) writes a string to a file descriptor

    The sync counterpart fs.writeSync mirrors all three. All six signatures will be implemented in a single package. The options-object overload requires version detection since it was added in v18.3.0 on older versions, the options will be extracted manually and passed as positional arguments. This week is allocated fully to write because of the overload complexity and the thoroughness of testing needed across all call signatures.

    Deliverable: PR for @stdlib/fs/write

  • Week 6 (midterm):
    Buffer week and midterm evaluation

    No new package this week. The first five weeks will have produced five PRs. This week is used to address any review feedback that has accumulated, ensure all submitted packages are in a mergeable state, and write the midterm progress report. If all PRs are clean and no feedback is outstanding, preliminary research begins on fs/mkdir's recursive compatibility problem specifically studying how mkdirp handles EEXIST and ENOENT edge cases in recursive creation.

    Deliverable: All prior PRs in clean, reviewable state; midterm report submitted

  • Week 7:
    fs/mkdir (design and core implementation)

    fs.mkdir(path[, options], callback) creates a directory. The core operation has been available since Node v0.1.8, but the options.recursive flag was added in Node v10.12.0, and before v12.12.0 it did not return the first created directory path. For older Node versions, recursive directory creation needs to be implemented manually walking the path segments, calling mkdir on each, and handling EEXIST errors appropriately (not treating an existing directory as a failure when recursive is true). This is the most technically involved package in the core scope. Week 7 focuses on getting the core logic and recursive fallback right. Reference: C0ldSmi1e's prior implementation in PR #2198 and the mkdirp package [1].

    No PR yet implementation in progress

  • Week 8:
    fs/mkdir (testing, edge cases, PR)

    Complete @stdlib/fs/mkdir. Thorough testing of: non-recursive creation on existing path (should error), recursive creation when intermediate directories exist (should not error), deeply nested paths, permission errors, and cross-platform path separator handling. Document mkdirSync behavior differences across Node versions in the README. Submit PR.

    Deliverable: PR for @stdlib/fs/mkdir

  • Week 9: Review, feedback, and stretch goal research

    Dedicated to addressing any accumulated review feedback across all open PRs. If all packages are in good shape, this week begins the design phase for fs/rm the first stretch goal. fs.rm(path[, options], callback) was added in Node v14.14.0. For older versions, a recursive fallback using fs.unlink and fs.rmdir is needed. The design of this fallback will be discussed with mentors before any code is written.

    Deliverable: Outstanding PR feedback addressed; design notes for fs/rm shared with mentors

  • Week 10: Stretch goal fs/rm (if on track)

    Implement @stdlib/fs/rm and fs.rmSync. The recursive fallback for older Node versions requires: stat the path to determine if it is a file or directory, if directory read its entries and recurse, then call rmdir on the now-empty directory. The force option (ignore ENOENT) must be handled in both the native and fallback paths. This is only attempted if all core scope PRs are merged or actively in review.

    Deliverable: PR for @stdlib/fs/rm (stretch)

  • Week 11: Code freeze and documentation pass

    No new implementations. Every submitted package gets a final review pass: verify JSDoc completeness, check that README examples actually run, confirm benchmarks produce sensible output, and ensure all packages are correctly listed in the stdlib fs namespace index. Any failing tests get fixed here, not in the final week.

    Deliverable: All packages fully documented and tested

  • Week 12:
    Final submission

    Address any last reviewer comments. Write the final GSoC project summary documenting what was completed, what remains, and clear next steps for future contributors particularly for the Promise API variants under @stdlib/fs/promises/* which require @stdlib/promise/ctor as a prerequisite and represent the logical next phase of this work.

    Deliverable: Final project report submitted; all PRs in mergeable state

Notes:

  • The community bonding period is a 3 week period built into GSoC to help you get to know the project community and participate in project discussion. This is an opportunity for you to setup your local development environment, learn how the project's source control works, refine your project plan, read any necessary documentation, and otherwise prepare to execute on your project project proposal.
  • Usually, even week 1 deliverables include some code.
  • By week 6, you need enough done at this point for your mentor to evaluate your progress and pass you. Usually, you want to be a bit more than halfway done.
  • By week 11, you may want to "code freeze" and focus on completing any tests and/or documentation.
  • During the final week, you'll be submitting your project.

Related issues

GSoC idea issue: stdlib-js/google-summer-of-code #10
fs/stat RFC: stdlib-js/stdlib #2233
fs/stat PR: stdlib-js/stdlib #11069
fs/mkdir prior PR: stdlib-js/stdlib #2198
Previous proposal #72: stdlib-js/google-summer-of-code #72
Previous proposal #73: stdlib-js/google-summer-of-code #73

Checklist

  • I have read and understood the Code of Conduct.
  • I have read and understood the application materials found in this repository.
  • I understand that plagiarism will not be tolerated, and I have authored this application in my own words.
  • I have read and understood the patch requirement which is necessary for my application to be considered for acceptance.
  • I have read and understood the stdlib showcase requirement which is necessary for my application to be considered for acceptance.
  • The issue name begins with [RFC]: and succinctly describes your proposal.
  • I understand that, in order to apply to be a GSoC contributor, I must submit my final application to https://summerofcode.withgoogle.com/ before the submission deadline.

Metadata

Metadata

Assignees

No one assigned

    Labels

    20262026 GSoC proposal.received feedbackA proposal which has received feedback.rfcProject proposal.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions