Deploy to AWS Lambda with Serverless Framework

This guide explains how to avoid common issues when deploying a project using Prisma with Serverless Framework.

The Serverless Framework simplifies deployment to AWS Lambda. It provides a CLI that helps with workflow automation and AWS resource provisioning. While Prisma works well with the Serverless Framework "out of the box", there are a few improvements that can be made within your project to ensure a smooth deployment and performance. There is also additional configuration that is needed if you are using the serverless-webpack or serverless-bundle libraries.

Prerequisites

This guide assumes you have an existing project using both Serverless Framework and Prisma. For a guide on how to get started with Serverless Framework, we recommend Setting Up Serverless Framework With AWS.

Binary targets in schema.prisma

The Prisma schema should contain the following in the generator block:

binaryTargets = ["native", "rhel-openssl-1.0.x"]

This is necessary because the runtime used in the development and when your application is deployed differ. Add the binaryTarget to make the compatible Prisma engine file available.

Lambda functions with arm64 architectures

Lambda functions that use arm64 architectures (AWS Graviton2 processor) must use an arm64 precompiled engine file.

In the generator block of your schema.prisma file, add the following:

schema.prisma
1binaryTargets = ["native", "linux-arm64-openssl-1.0.x"]

Loading environment variables via a .env file

Your functions will need the DATABASE_URL environment variable to access the database. The serverless-dotenv-plugin will allow you to use your .env file in your deployments.

First, make sure that the plugin is installed:

$npm install -D serverless-dotenv-plugin

Then, add serverless-dotenv-plugin to your list of plugins in serverless.yml:

serverless.yml
1plugins:
2 - serverless-dotenv-plugin

The environment variables in your .env file will now be automatically loaded on package or deployment.

$serverless package
Show CLI results

Connection pooling

Generally, when you use a FaaS (Function as a Service) environment to interact with a database, every function invocation can result in a new connection to the database. This is not a problem with a constantly running Node.js server. Therefore, it is beneficial to pool DB connections to get better performance. You can use Accelerate to solve this issue. For other solutions, see the connection management guide for serverless environments.

Deploy only the required files

To reduce your deployment footprint, you can update your deployment process to only upload the files your application needs. The Serverless configuration file, serverless.yml, below shows a package pattern that includes only the Prisma engine file relevant to the Lambda runtime and excludes the others. This means that when Serverless Framework packages your app for upload, it includes only one engine file. This ensures the packaged archive is as small as possible.

serverless.yml
1package:
2 patterns:
3 - '!node_modules/.prisma/client/libquery_engine-*'
4 - 'node_modules/.prisma/client/libquery_engine-rhel-*'
5 - '!node_modules/prisma/libquery_engine-*'
6 - '!node_modules/@prisma/engines/**'

If you are deploying to Lambda functions with ARM64 architecture you should update the Serverless configuration file to package the arm64 engine file, as follows:

serverless.yml
1package:
2 patterns:
3 - '!node_modules/.prisma/client/libquery_engine-*'
4 - 'node_modules/.prisma/client/libquery_engine-linux-arm64-*'
5 - '!node_modules/prisma/libquery_engine-*'
6 - '!node_modules/@prisma/engines/**'

If you use serverless-webpack, see Deployment with serverless webpack below.

Deployment with serverless-webpack

If you use serverless-webpack, you will need additional configuration so that your schema.prisma is properly bundled. You will need to:

  1. Copy your schema.prisma with copy-webpack-plugin.
  2. Run prisma generate via custom > webpack > packagerOptions > scripts in your serverless.yml.
  3. Only package the correct Prisma engine file to save more than 40mb of capacity.

1. Install webpack specific dependencies

First, ensure the following webpack dependencies are installed:

$npm install --save-dev webpack webpack-node-externals copy-webpack-plugin serverless-webpack

2. Update webpack.config.js

In your webpack.config.js, make sure that you set externals to nodeExternals() like the following:

webpack.config.js
1const nodeExternals = require('webpack-node-externals')
2
3module.exports = {
4 // ... other configuration
5 externals: [nodeExternals()],
6 // ... other configuration
7}

Update the plugins property in your webpack.config.js file to include the copy-webpack-plugin:

webpack.config.js
1const nodeExternals = require('webpack-node-externals')
2const CopyPlugin = require('copy-webpack-plugin')
3
4module.exports = {
5 // ... other configuration
6 externals: [nodeExternals()],
7 plugins: [
8 new CopyPlugin({
9 patterns: [
10 { from: './node_modules/.prisma/client/schema.prisma', to: './' }, // you may need to change `to` here.
11 ],
12 }),
13 ],
14 // ... other configuration
15}

This plugin will allow you to copy your schema.prisma file into your bundled code. Prisma requires that your schema.prisma be present in order make sure that queries are encoded and decoded according to your schema. In most cases, bundlers will not include this file by default and will cause your application to fail to run.

Depending on how your application is bundled, you may need to copy the schema file to a location other than ./. Use the serverless package command to package your code locally so you can review where your schema should be put.

Refer to the Serverless Webpack documentation for additional configuration.

3. Update serverless.yml

In your serverless.yml file, make sure that the custom > webpack block has prisma generate under packagerOptions > scripts as follows:

serverless.yml
1custom:
2 webpack:
3 packagerOptions:
4 scripts:
5 - prisma generate

This will ensure that, after webpack bundles your code, the Prisma Client is generated according to your schema. Without this step, your app will fail to run.

Lastly, you will want to exclude Prisma query engines that do not match the AWS Lambda runtime. Update your serverless.yml by adding the following script that makes sure only the required query engine, rhel-openssl-1.0.x, is included in the final packaged archive.

serverless.yml
1custom:
2 webpack:
3 packagerOptions:
4 scripts:
5 - prisma generate
+ - find . -name "libquery_engine-*" -not -name "libquery_engine-rhel-openssl-*" | xargs rm

If you are deploying to Lambda functions with ARM64 architecture you should update the find command to the following:

serverless.yml
1custom:
2 webpack:
3 packagerOptions:
4 scripts:
5 - prisma generate
+ - find . -name "libquery_engine-*" -not -name "libquery_engine-arm64-openssl-*" | xargs rm

4. Wrapping up

You can now re-package and re-deploy your application. To do so, run serverless deploy. Webpack output will show the schema file being moved with copy-webpack-plugin:

$serverless package
Show CLI results

Summary

You have successfully deployed a Prisma-backed Serverless Framework application. Congratulations!

Edit this page on GitHub