The "ftp" action

Useful for interacting with vendors, or simply for making logs or submitting backups, you can use Mechanic's "ftp" action to upload arbitrary content to any S/FTP host. And, by using a connecting service like Couchdrop, you can upload your files to most cloud storage providers (including Dropbox, Google Drive, S3, etc).


  • "host" – required, string
  • "port" – optional, integer, defaults to 21
  • "protocol" – optional, can be "ftp" or "sftp", uses an intelligent default based on other options
  • "user" – required, string
  • "password" – optional, string
  • "private_key_pem" – optional, string, used only for SFTP
  • "uploads" – required, object containing file paths mapped to file values
  • "mode" – optional, used only for FTP (not SFTP), can be set to "ascii" 

The "uploads" option is processed by Mechanic's file generators. This means that, in addition to defining simple text-based files, you can create PDFs and zip files to be uploaded to your FTP server (see Generating files).

To specify a destination path for an upload, add the path to the relevant "uploads" key. Use a leading slash for an absolute path, or omit the leading slash for a relative path. Explaining by example:

{% action "ftp" %}
    "uploads": {
      "/absolute/path/to/success.txt": "hooray!",
      "relative/path/to/success.txt": "hooray!",
      "../another/relative/path/to/success.txt": "hooray!"
{% endaction %}

In order, this results in (a) an upload to an absolute path, starting from the server root, (b) an upload to a nested directory within the FTP user's home folder, and (c) an upload to a nested directory in (perhaps, and assuming permissions work out) another user's home folder.


To verify that your task works properly, consider using Couchdrop. If you don't yet have an account, create one using their "Freebie" plan (see pricing), and connect to their hosted storage service. Configure your account with a user and password that you don't mind sharing with Mechanic, and start testing your Mechanic task with or This works extremely well for testing Mechanic tasks.

Alternatively, use ngrok to create a public tunnel to a FTP or SSH server that you control. By running ngrok tcp 22 (adjusting for the appropriate local port), you'll receive a temporary public host and port that's appropriate for use while testing.


The "user" option is always required.

When working with an FTP server, for a user that has a password (recommended!), add with the "password" option.

When working with an SFTP server, use either "password" or "private_key_pem" to authenticate your user. You can supply your private key value using something like this:

{% capture private_key_pem %}
{% endcapture %}

{% action "ftp" %}
    "host": "",
    "port": 22,
    "user": "sftp_user",
    "private_key_pem": {{ private_key_pem | json }}
    "uploads": {
      "success.txt": "hooray!"
{% endaction %}


This task compiles all SKUs with their titles and prices, and uploads it as a CSV every night.




{% assign csv = array %}

{% assign header = "SKU,Title,Price" | split: "," %}
{% assign csv[0] = header %}

{% for product in shop.products %}
  {% for variant in product.variants %}
    {% assign title = variant.title %}
    {% if title == "Default Title" %}
      {% assign title = product.title %}
    {% endif %}

    {% assign row = array %}
    {% assign row[row.size] = variant.sku %}
    {% assign row[row.size] = title %}
    {% assign row[row.size] = variant.price %}

    {% assign csv[csv.size] = row %}
  {% endfor %}
{% endfor %}

{% capture filename %}product-export-{{ "now" | date: "%Y-%m-%d" }}.csv{% endcapture %}

{% action "ftp" %}
    "host": "",
    "port": 21,
    "user": "anonymous",
    "password": null,
    "uploads": {
      {{ filename | json }}: {{ csv | csv | json }}
{% endaction %}
Did this answer your question? Thanks for the feedback There was a problem submitting your feedback. Please try again later.