Ruby code with gems on AWS Lambda
If you want to use ruby with AWS’s lambdas and that ruby code relies on gems then you’ll have to jump through a small hoop to get it running. Firstly, create a
.bundle/config file in your lambda code’s root directory. The contents of this file should be as follows:
--- BUNDLE_PATH: "vendor/bundle"
This will tell bundler to install the gems inside the
vendor/bundle directory in the root of your project rather than in your home directory as is default. This allows us to package the gems together with the code when uploading the package to Amazon. You may want to add the
vendor directory to your
Now, add/install the gem you want to use. For our example, let’s use
bundle init bundle add rest-client
Let’s create a handler file to make use of this gem called
main.rb as follows:
require 'rest-client' def handler response = RestClient.get 'https://jsonplaceholder.typicode.com/todos/1' puts response.body end
If you try to execute this lambda now you’ll get an error as follows:
cannot load such file -- rest-client
This is because while we’ve told bundler where to install the gems to, we haven’t told the ruby runtime where to find the gems when it is actually executing the code. To do this, we need to set an environment variable called
GEM_PATH and set it to
/var/task/vendor/bundle/ruby/2.7.0 (all the lambda files are placed into
/var/task so you need the path to the gems located inside your
vendor/bundle/RUBY_VERSION directory). Replace
2.7.0 with whatever version of ruby you’re using. If you run the code now, you should see a successful output. That’s it!
BONUS TIP 1: If you’re using multiple lambdas for the same project and they mostly require the same gems, I highly recommend building a gem layer that can be shared across all the lambdas. The process is more or less the same, but everything related to gems is put inside the layer (
Gemfile.lock, etc.) instead of the lambda package itself. In this case, you’ll need to update your
GEM_PATH to point to
/opt/ruby/2.7.0. See AWS Lambda Layer Docs for more information.
BONUS TIP 2: I highly recommend using Serverless Framework to manage all this as it makes it quite easy to keep track of everything and deploy it.
BONUS TIP 3: If you need gems that have native extensions, like nokogiri then you will need an even more involved process that includes building the gem on an AWS-lambda-like environment using docker. Basically everything above is the same, but instead of doing
bundle install you’d do something like
docker run -it --rm -v $PROJECT_DIR/gem_layer:/var/task lambci/lambda:build-ruby2.7 bundle install --without=development. For more info check out [lambci/lambda(https://hub.docker.com/r/lambci/lambda/).