By the end of this article, you should have a working mix project that can generate a PDF from an template and payload. HTML json This tutorial assumes you have basic experience with the Elixir language. Generate a New Mix Project Obviously, you can call your project w/e you want. For the sake of this article, I’ll call mine “PDFer” because it PDFs things. No other reason… We’ll generate our project using . Running (or w/e you call your project) will produce something resembling the following output: mix mix new pdfer --sup Once the project is created, change into the project directory ( ) and open it in your editor — if you’re using (and have that ). cd pdfer code . VSCode configured Once open, you should see the following files: Install Dependencies We actually only need three dependencies (two depending on how you decide to do it). This will handle the actual generation of the PDF elixir-pdf-generator : This will be used to parse our template “mapping” data. jason : NOTE: I’d love some insight from the Elixir community on the differences between jason and poison , and if there is a growing preference. This handles merging our mapping with our template file. It’s all done using , so it’s super clean and simple. bbmustache : json mustache Initially, I tried using the library you’re linked to from mustache’s own website, however, I wasn’t able to get it working non-empty lists and inverted-selections (something I needed). After adding the above dependencies to your , it should look something like this: mix.exs [ { , }, { , }, { , } ] defp deps do :bbmustache github: "soranoba/bbmustache" :jason "~> 1.1" :pdf_generator ">=0.5.5" end Install all our dependencies with and get ready to write some code… mix deps.get Ready to Write Some Code! In the Pdfer module, you’ll see a hello method. We’re going to replace this with a generate method. generate will do a couple of things: Read both the and files from disk. This step is actually optional. If you wanted to, you could simply create the variables and and set their values inline to be and respectively. I’m reading from disk for now simply because it’s more useful out-of-the-box if you wanted to start generating PDFs right away. template mapping template mapping html json will take the and and “mustache” them together for us. This is actually really awesome because, otherwise, we’d have to do some messy string interpolation stuff. And frankly, it would be impossible if you were trying to use multiple templates and mappings to generate different PDFs. bbmustache template mapping Generate a PDF. For now, we’ll be using to generate our PDF, however, I’d love to explore using and headless chrome in the future. Luckily, gives us that flexibility. wkhtmltopdf puppeteer elixir-pdf-generator Write the resulting PDF to disk. In the future, we could send the resulting PDF somewhere like S3, but for now, we just want to see the result of all our hard work! (pdf_path, template_path, mapping_path) mapping = Jason.decode!(read_file(mapping_path)) template = read_file(template_path) template |> .render(mapping, ) |> PdfGenerator.generate_binary!() |> (&File.write( , & )).() (filepath) __DIR_ |> Path.join(filepath) |> File.read!() defmodule Pdfer do @moduledoc "" " Documentation for Pdfer. " "" # def generate do :bbmustache key_type: :binary " .pdf" #{pdf_path} 1 end # defp read_file do _ end end Last Step Depending on if you decided to read these from disk, or just drop them into the code inline, the final pieces to this may or may not be adding the and files. template.html mapping.json For now, we’ll just dump both of them in the file alongside our module. Create a and at with the following contents: template.html mapping.json pdfer/lib/ Hello {{ location }} < > html < > body < > h1 </ > h1 </ > body </ > html { : } "location" "World" Generate a PDF That’s it! We’re ready to generate a PDF. Run our code with to drop into . From there we’ll run our module, giving it three arguments. A PDF name, the template file name, and the mapping file name: iex -S mix iex iex(1)> Pdfer.generate( , , "test" "template.html" "mapping.json" Almost instantly, you should see a in the root of your project directory. test.pdf Conclusion It’s pretty awesome that, with barely 20 lines of code, we’re able to generate a PDF from a dynamic template and data set. From here you could set up an endpoint to accept a payload and generate the PDF that way. Or, as I’ll explain in another article, you could set up a sweet AWS messaging pipe that your PDFer reads from!