{"id":15538,"library":"basic-ftp","title":"Basic FTP Client for Node.js","description":"basic-ftp is a robust and actively maintained FTP/FTPS client library designed specifically for Node.js environments. Currently stable at version 5.3.0, it demonstrates a consistent release cadence with frequent patch and minor updates addressing bugs and security enhancements, as evidenced by recent 5.x releases. A key differentiator is its modern Promise-based API, leveraging `async/await` for asynchronous operations, alongside native TypeScript support for improved developer experience and type safety. The library provides comprehensive features including FTPS over TLS for secure connections, IPv6 support, and convenient methods for performing directory-level operations like uploading and downloading entire folders. It explicitly supports Passive Mode but does not support Active Mode. Users are strongly advised to prefer FTPS (FTP over TLS) for any security-sensitive transfers, or ideally, alternative protocols like HTTPS or SFTP, as plain FTP is an inherently insecure and older protocol. The library maintains a lean dependency tree, requiring only Node.js 10.0 or later.","status":"active","version":"5.3.0","language":"javascript","source_language":"en","source_url":"https://github.com/patrickjuchli/basic-ftp","tags":["javascript","ftp","ftps","promise","async","await","tls","ipv6","typescript"],"install":[{"cmd":"npm install basic-ftp","lang":"bash","label":"npm"},{"cmd":"yarn add basic-ftp","lang":"bash","label":"yarn"},{"cmd":"pnpm add basic-ftp","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"Use ESM `import` for modern Node.js module systems (type: 'module' in package.json) or bundlers. CommonJS `require` is also supported but `import` is preferred for TypeScript and newer setups.","wrong":"const { Client } = require('basic-ftp')","symbol":"Client","correct":"import { Client } from 'basic-ftp'"},{"note":"Use CommonJS `require` for traditional Node.js scripts without ESM enabled. Mixing CommonJS and ESM in certain environments can lead to issues.","wrong":"import { Client } from 'basic-ftp'","symbol":"Client (CommonJS)","correct":"const { Client } = require('basic-ftp')"}],"quickstart":{"code":"import { Client } from 'basic-ftp';\nimport fs from 'node:fs';\n\nconst FTP_HOST = process.env.FTP_HOST ?? 'myftpserver.com';\nconst FTP_USER = process.env.FTP_USER ?? 'very';\nconst FTP_PASSWORD = process.env.FTP_PASSWORD ?? 'password';\n\n// Create a dummy README.md for the example\nfs.writeFileSync('README.md', '# Local README\\n\\nThis is a test file for basic-ftp example.');\n\nasync function runFtpExample() {\n    const client = new Client();\n    client.ftp.verbose = true; // Enable verbose logging\n    try {\n        await client.access({\n            host: FTP_HOST,\n            user: FTP_USER,\n            password: FTP_PASSWORD,\n            secure: true // Use FTPS over TLS\n        });\n        console.log('Connected and logged in. Remote directory listing:');\n        console.log(await client.list());\n\n        const remoteFileName = 'README_FTP.md';\n        const localFileName = 'README.md';\n        const copiedFileName = 'README_COPY.md';\n\n        console.log(`Uploading ${localFileName} to ${remoteFileName}...`);\n        await client.uploadFrom(localFileName, remoteFileName);\n        console.log('Upload complete.');\n\n        console.log(`Downloading ${remoteFileName} to ${copiedFileName}...`);\n        await client.downloadTo(copiedFileName, remoteFileName);\n        console.log('Download complete.');\n\n        // Clean up local dummy file\n        fs.unlinkSync(localFileName);\n        fs.unlinkSync(copiedFileName);\n\n    } catch (err) {\n        console.error('FTP Operation failed:', err);\n    } finally {\n        if (!client.closed) {\n            client.close();\n            console.log('FTP client closed.');\n        }\n    }\n}\n\nrunFtpExample();","lang":"typescript","description":"Demonstrates connecting to an FTPS server, logging in, retrieving a directory listing, uploading a local file, and then downloading it back as a copy. Includes verbose logging and error handling."},"warnings":[{"fix":"If experiencing truncated directory listings for legitimate reasons, you can increase the `directoryListingResponseLimit` option in the `Client` constructor. For example: `new Client(timeout, { directoryListingResponseLimit: 10 * 1024 * 1024 })` for 10MB.","message":"Version 5.3.0 introduced an upper bound on the total bytes of directory listing data to mitigate a security vulnerability (GHSA-rp42-5vxx-qpwr). Large listings might now be truncated by default. An option to increase this limit (`Client` constructor) was added concurrently.","severity":"breaking","affected_versions":">=5.3.0"},{"fix":"Ensure all paths and filenames passed to `basic-ftp` methods are properly sanitized and do not contain malicious or unexpected control characters. Always use valid, clean paths.","message":"Versions 5.2.1 and 5.2.2 addressed critical security advisories (GHSA-chqc-8p9q-pq6q, GHSA-6v7q-wjvx-w8wg) by rejecting control character injection attempts in paths and improving control character rejection, respectively. This might cause previously 'working' but insecure path manipulations to now fail.","severity":"breaking","affected_versions":">=5.2.1"},{"fix":"Always set `secure: true` in `client.access()` to enable FTPS. Re-evaluate if FTP is the appropriate protocol for your use case and consider SFTP or HTTPS if security is a primary concern.","message":"FTP is an old and inherently insecure protocol. Users are strongly advised to use FTPS (FTP over TLS) by setting `secure: true` in the `client.access()` options, or to prefer alternative, more secure protocols like SFTP or HTTPS for data transfer, especially for sensitive information. Plain FTP does not provide any encryption.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Set `allowSeparateTransferHost: false` in the `Client` constructor to prevent the client from connecting to different IP addresses for data transfers. Example: `new Client(30000, { allowSeparateTransferHost: false })`.","message":"The `allowSeparateTransferHost` option in the `Client` constructor defaults to `true` for backwards compatibility. This allows the server to instruct the client to use a different IP address for data transfers, which can be a security risk (FTP bounce attacks) or cause issues in NAT environments.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Ensure that your FTP server is configured to support Passive Mode. If your environment strictly requires Active Mode, basic-ftp will not be a suitable client.","message":"basic-ftp does not support Active Mode FTP. It exclusively operates in Passive Mode (and EPSV).","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-21T00:00:00.000Z","next_check":"2026-07-20T00:00:00.000Z","problems":[{"fix":"If you need to reconnect or perform new operations, create a new `Client` instance. If an error or timeout occurs, `basic-ftp` automatically closes the client, and you must instantiate a new one to reconnect.","cause":"Attempting to perform an operation (e.g., upload, list) on a `Client` instance after `client.close()` has been called or after a connection error/timeout has occurred. A client cannot be reused after being closed.","error":"Error: Client has been closed"},{"fix":"Ensure your project's `package.json` correctly defines `\"type\": \"module\"` for ESM, or use CommonJS `const { Client } = require('basic-ftp')` if not using ESM. Check your bundler configuration to correctly transpile or resolve module imports for `basic-ftp`.","cause":"This error typically occurs in bundled environments (like Webpack, Rollup, Vite) or when mixing CommonJS `require` with ESM `import` syntax, where the bundler incorrectly handles the module import for `basic-ftp`.","error":"TypeError: (0 , basic_ftp__WEBPACK_IMPORTED_MODULE_0__.Client) is not a constructor"},{"fix":"Double-check your `host`, `user`, and `password` credentials. Verify them against the FTP server's configuration or by attempting to log in with another client. Ensure the user has appropriate directory access.","cause":"The username or password provided in the `client.access()` method is incorrect, or the user lacks the necessary permissions on the FTP server.","error":"Error: 530 Login authentication failed"},{"fix":"Verify the `host` and `port` (default 21 for FTP, 990 for implicit FTPS) in your `client.access()` options. Check if the FTP server is running and accessible from your network. Inspect any firewalls (local or network) that might be blocking the connection.","cause":"The client failed to establish a TCP connection to the specified FTP host and port. This could be due to an incorrect host/port, the server being offline, a firewall blocking the connection, or network issues.","error":"Error: connect ECONNREFUSED <IP_ADDRESS>:<PORT>"}],"ecosystem":"npm"}