Skip to main content
SFTP (SSH File Transfer Protocol) provides secure file transfer capabilities over SSH. This guide covers directory operations and file management using the React Native SSH SFTP library.

Connecting to SFTP

While not strictly required, you can explicitly connect to the SFTP subsystem:
await client.connectSFTP();
The SFTP connection is established automatically when you call any SFTP method (like sftpLs(), sftpUpload(), etc.), so calling connectSFTP() explicitly is optional.

Listing Directories

Use sftpLs() to list files and directories:
const files = await client.sftpLs('/home/user');
console.log(files);

Understanding the Response

The sftpLs() method returns an array of LsResult objects with detailed file information:
interface LsResult {
  filename: string;           // Name of the file or directory
  isDirectory: boolean;       // true if it's a directory
  modificationDate: string;   // Last modification timestamp
  lastAccess: string;         // Last access timestamp
  fileSize: number;           // Size in bytes
  ownerUserID: number;        // Owner's user ID
  ownerGroupID: number;       // Owner's group ID
  flags: number;              // File flags/permissions
}

Practical Examples

// List files in current directory (user's home)
const files = await client.sftpLs('.');

files.forEach(file => {
  const type = file.isDirectory ? 'DIR' : 'FILE';
  console.log(`${type}: ${file.filename} (${file.fileSize} bytes)`);
});

Creating Directories

Create a new directory on the remote server:
await client.sftpMkdir('/home/user/new-folder');
console.log('Directory created successfully');
sftpMkdir() will fail if:
  • The directory already exists
  • The parent directory doesn’t exist
  • You don’t have write permissions

Creating Nested Directories

To create nested directories, you need to create each level individually:
const createNestedDirectory = async (client, path) => {
  const parts = path.split('/').filter(p => p);
  let currentPath = '';
  
  for (const part of parts) {
    currentPath += '/' + part;
    
    try {
      await client.sftpMkdir(currentPath);
      console.log(`Created: ${currentPath}`);
    } catch (error) {
      // Directory might already exist, check with sftpLs
      const parent = currentPath.split('/').slice(0, -1).join('/') || '/';
      const files = await client.sftpLs(parent);
      const exists = files.some(f => 
        f.filename === part && f.isDirectory
      );
      
      if (!exists) {
        throw error; // Re-throw if it's not an "already exists" error
      }
    }
  }
};

// Usage
await createNestedDirectory(client, '/home/user/path/to/deep/folder');

Removing Directories

Remove an empty directory:
await client.sftpRmdir('/home/user/old-folder');
console.log('Directory removed');
sftpRmdir() only removes empty directories. To remove a directory with contents, you must first delete all files and subdirectories.

Removing Directory Recursively

Here’s a helper function to remove a directory and all its contents:
const removeDirectoryRecursive = async (client, path) => {
  const files = await client.sftpLs(path);
  
  for (const file of files) {
    // Skip . and .. entries
    if (file.filename === '.' || file.filename === '..') {
      continue;
    }
    
    const filePath = `${path}/${file.filename}`;
    
    if (file.isDirectory) {
      // Recursively remove subdirectory
      await removeDirectoryRecursive(client, filePath);
    } else {
      // Remove file
      await client.sftpRm(filePath);
      console.log(`Deleted file: ${filePath}`);
    }
  }
  
  // Remove the now-empty directory
  await client.sftpRmdir(path);
  console.log(`Deleted directory: ${path}`);
};

// Usage
await removeDirectoryRecursive(client, '/home/user/temp-folder');

File Operations

Removing Files

Delete a single file:
await client.sftpRm('/home/user/document.txt');
console.log('File removed');

Renaming Files and Directories

Rename or move files and directories:
// Rename a file
await client.sftpRename(
  '/home/user/old-name.txt',
  '/home/user/new-name.txt'
);

// Move a file to different directory
await client.sftpRename(
  '/home/user/file.txt',
  '/home/user/documents/file.txt'
);

// Rename a directory
await client.sftpRename(
  '/home/user/old-folder',
  '/home/user/new-folder'
);

Changing File Permissions (Android Only)

The sftpChmod() method is only available on Android.
Change file or directory permissions using octal notation:
import { Platform } from 'react-native';

if (Platform.OS === 'android') {
  // Make file readable and writable by owner only (0600)
  await client.sftpChmod('/home/user/private.txt', 0o600);
  
  // Make directory accessible to everyone (0755)
  await client.sftpChmod('/home/user/public', 0o755);
  
  // Make file executable (0755)
  await client.sftpChmod('/home/user/script.sh', 0o755);
}

Common Permission Values

OctalBinaryDescription
0644rw-r—r—Standard file permissions (owner read/write, others read)
0755rwxr-xr-xStandard directory/executable permissions
0600rw-------Private file (owner read/write only)
0700rwx------Private directory (owner access only)
0666rw-rw-rw-World-writable file
0777rwxrwxrwxWorld-writable directory

Error Handling

All SFTP operations return promises that reject on error:
try {
  const files = await client.sftpLs('/restricted');
  console.log(files);
} catch (error) {
  console.error('Failed to list directory:', error);
  // Handle permission denied, path not found, etc.
}

Disconnecting SFTP

Explicitly close the SFTP connection:
client.disconnectSFTP();
  • Disconnecting SFTP will unregister upload/download progress listeners
  • The SSH connection remains active after disconnecting SFTP
  • On iOS, disconnectSFTP() has limited functionality; use disconnect() to close both SSH and SFTP

Best Practices

1

Check before operations

Use sftpLs() to verify paths exist before performing operations:
const files = await client.sftpLs('/home/user');
const exists = files.some(f => f.filename === 'target-folder');

if (!exists) {
  await client.sftpMkdir('/home/user/target-folder');
}
2

Handle errors gracefully

Different errors require different handling strategies:
try {
  await client.sftpRmdir(path);
} catch (error) {
  if (error.message.includes('not empty')) {
    console.log('Directory contains files, use recursive delete');
  } else if (error.message.includes('permission')) {
    console.log('Insufficient permissions');
  } else {
    console.error('Unknown error:', error);
  }
}
3

Use absolute paths

Always use absolute paths when possible to avoid confusion:
// Good
await client.sftpLs('/home/user/documents');

// Less reliable (depends on current directory)
await client.sftpLs('documents');

Next Steps