Do you work on Elixir projects that need to handle file uploads from users?

Waffle is a flexible library, developed by one of our engineers — Boris Kuznetsov — which does the hard work of handling file uploads for you, whilst providing easy integration with storage services such as Amazon S3, Google Cloud Storage, Azure, RackSpace Cloud, as well as image manipulation tools such as ImageMagick, so that uploaded files can be optimised on-the-fly!

Waffle grew out of a fork of a now-unsupported library, to which we've added complete documentation, fixed outstanding issues, merged open pull requests, added integrations with other parts of the Elixir ecosystem (in particular Phoenix and Ecto). We've also working on new features, such as file validation based upon content rather than the type supplied by the browser.

This release of Waffle is v1.0.0. If you've previously used Arc, you'll find the transition to Waffle very straightforward, although note that the dependencies have been upgraded, and Poison has been removed in favour of Jason.

Getting started with Waffle

To get started, first add the latest stable release of Waffle to your mix.exs file. Add in the required dependencies for ExAws as well if you want to store files in an S3 bucket:

defp deps do [ {:waffle, "~> 1.0.0"}, # If using S3: {:ex_aws, "~> 2.1"}, {:ex_aws_s3, "~> 2.0"}, {:hackney, "~> 1.9"}, {:sweet_xml, "~> 0.6"} ] end

Then you can run mix deps.get in your shell to fetch the dependencies. This is all you need to get Waffle up and running!

Let's also look at the configuration and see what Waffle is capable of. Waffle expects certain properties to be configured at the application level:

# Configuration for Waffle itself: config :waffle, storage: Waffle.Storage.S3, # or Waffle.Storage.Local bucket: {:system, "AWS_S3_BUCKET"}, # if using S3 asset_host: "http://static.example.com" # or {:system, "ASSET_HOST"} # If you're using S3, configure ExAws too: config :ex_aws, json_codec: Jason

Waffle requires a definition module which contains the relevant configuration to store and retrieve your files. This definition module contains relevant functions to determine optional transformations of the uploaded file, the storage directory, the name of the files, default placeholders and making your files private or publicly accessible.

Let's generate an attachment definition for an avatar uploader:

mix waffle.g avatar_uploader

This will create a skeleton definition for your uploader in:

web/uploaders/avatar_uploader.ex

Have a look through this file to see the available configuration options. Check out the full example in the Waffle documentation for a flavour of what Waffle can do!

Storage providers

Out of the box, Waffle comes with integrations for writing uploads to a local filesystem path (Waffle.Storage.Local), and to Amazon S3 (Waffle.Storage.S3), but there are additional storage providers supported by the community which you can easily add to your project: Google Cloud Storage, Rackspace, Manta, OVH, and Microsoft Azure Storage.

Waffle + Ecto

The Waffle comes with a companion package for use with Ecto, an Elixir toolkit for interfacing with data stores, enabling changeset integration and versioned URLs for cache-busting. You can enable this by adding the waffle_ecto dependency to your mix.exs file.

Dive into the docs

We’ve put together a comprehensive guide to Waffle with tons of articles, code samples, and guidelines to help you get up and running with Waffle as quickly as possible.

Waffle in action

We're actively using Waffle in several projects, one of them is a web app to help with learning English vocabulary and to practise pronunciation. We’re very proud of how far this idea has come, and we’re continuing to work hard to make Waffle the best file upload handling solution for Elixir — and your projects!