DEV Community

Cover image for How I Deployed an Express + Prisma + Supabase API on AWS Lambda Using Serverless Framework
George Arthur
George Arthur

Posted on

How I Deployed an Express + Prisma + Supabase API on AWS Lambda Using Serverless Framework

How I Deployed an Express + Prisma + Supabase API on AWS Lambda Using Serverless Framework

Deploying a full-featured Express API on AWS Lambda with Prisma and Supabase integration can be tricky — especially when you want everything to run serverlessly, scale seamlessly, and stay cost-efficient.

In this guide, I’ll walk you through the exact steps I took to deploy my TypeScript Express API to AWS Lambda using the Serverless Framework, integrating Prisma ORM, Supabase, and Amazon S3 for file storage.


🧰 Tech Stack Overview

Here’s what we’ll use:

  • Node.js (TypeScript) — backend runtime
  • Express.js — API framework
  • Prisma ORM — database access and migrations
  • Supabase (PostgreSQL) — database provider
  • AWS S3 — file uploads
  • AWS Lambda + API Gateway — serverless deployment
  • Serverless Framework — deployment and configuration tool

📁 Project Structure

Our project structure looks like this:

├── src
│   ├── controllers/
│   ├── middlewares/
│   ├── prisma/
│   ├── app.ts
│   └── index.ts
├── serverless.yml
├── package.json
└── .env
Enter fullscreen mode Exit fullscreen mode

⚙️ Step 1. Initialize the Project

Start a new Node project and install dependencies:

npm init -y
npm install express cors dotenv prisma @prisma/client
npm install serverless serverless-http serverless-offline serverless-esbuild
Enter fullscreen mode Exit fullscreen mode

Then initialize Prisma:

npx prisma init
Enter fullscreen mode Exit fullscreen mode

Update your Prisma schema (prisma/schema.prisma):

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
  directUrl = env("DIRECT_URL")
}
Enter fullscreen mode Exit fullscreen mode

🧩 Step 2. Connect Prisma to Supabase

Go to your Supabase DashboardProject SettingsDatabaseConnection stringNode.js, and copy the connection string.

Use the connection pooling option for Lambda functions:

DATABASE_URL="postgresql://postgres.<user_id>:<password>@aws-0-us-east-1.pooler.supabase.com:6543/postgres?pgbouncer=true"
Enter fullscreen mode Exit fullscreen mode

⚠️ Important:
If your password contains special characters (like @, #, or $), wrap it in encodeURIComponent() before using it, or the connection will fail.


🚀 Step 3. Create the Express App

Here’s the main Express setup in src/app.ts:

import express from 'express';
import cors from 'cors';
import { register, login } from './controllers/auth.controller';
import { uploadFile, listFiles, deleteFile } from './controllers/file.controller';
import { authMiddleware } from './middlewares/auth.middleware';
import { errorMiddleware } from './middlewares/error.middleware';

export const app = express();
app.use(cors());
app.use(express.json({ limit: '10mb' }));

// Auth routes
app.post('/api/register', register);
app.post('/api/login', login);

// File routes
app.post('/api/files', authMiddleware, uploadFile);
app.get('/api/files', authMiddleware, listFiles);
app.delete('/api/files/:id', authMiddleware, deleteFile);

// Error handling
app.use(errorMiddleware);

Enter fullscreen mode Exit fullscreen mode

🧱 Step 4. Wrap Express with Serverless HTTP

To make Express compatible with AWS Lambda, use the serverless-http package.

// src/index.ts
import serverless from 'serverless-http';
import { app } from './app';

export const handler = serverless(app);
Enter fullscreen mode Exit fullscreen mode

📦 Step 5. Configure Serverless Framework

Your serverless.yml defines how AWS will run and expose your Lambda function:

service: backend-api

frameworkVersion: "4"

provider:
  name: aws
  runtime: nodejs20.x
  region: us-east-1
  stage: dev

  environment:
    JWT_SECRET: ${env:JWT_SECRET}
    DATABASE_URL: ${env:DATABASE_URL}
    AWS_S3_BUCKET: ${env:AWS_S3_BUCKET}
    AWS_REGION_L: ${env:AWS_REGION_L}

functions:
  app:
    handler: src/index.handler
    events:
      - httpApi: "*"

plugins:
  - serverless-esbuild
  - serverless-offline

package:
  patterns:
    - "!node_modules/.prisma/client/query_engine-*"
    - "node_modules/.prisma/client/libquery_engine-rhel-openssl-3.0.x.so.node"
Enter fullscreen mode Exit fullscreen mode

Key Points

  • httpApi: "*" tells API Gateway to route all requests to your Express app (no need to manually add routes).

  • Prisma binary inclusion ensures the right engine is packaged for AWS Lambda (Linux environment).


🌍 Step 6. Deploy to AWS

Deploy with one command:

npx serverless deploy
Enter fullscreen mode Exit fullscreen mode

Once complete, you’ll see an output similar to this:

✔ Service deployed to AWS
endpoint: https://xyz123.execute-api.us-east-1.amazonaws.com
functions:
  app: backend-api-dev-app
Enter fullscreen mode Exit fullscreen mode

Now you can hit:

https://xyz123.execute-api.us-east-1.amazonaws.com/api/[route-name]
Enter fullscreen mode Exit fullscreen mode

or any other route you defined.

Keep only the $default route in API Gateway — it acts as a catch-all for your Express routes.


🧠 Step 7. Common Issues (and How I Solved Them)

Issue Cause Fix
Invalid DB URL Password had unescaped characters Used encodeURIComponent()
Empty database warning No tables created in Supabase Added at least one table before introspection
Prisma binary missing Local OS mismatch Included Linux binary in serverless.yml
404 routes Missing $default route in API Gateway Configured httpApi: "*"
esbuild “Invalid option” error Mismatch in plugin configuration Switched to serverless-esbuild

🔍 Step 8. Test the Deployment

Use Postman or curl to test endpoints:

curl -X POST https://xyz123.execute-api.us-east-1.amazonaws.com/api/register \
-H "Content-Type: application/json" \
-d '{"email": "test@example.com", "password": "secret"}'
Enter fullscreen mode Exit fullscreen mode

If everything’s configured correctly, you should see your API responding from AWS Lambda!

✅ Conclusion

Deploying an Express + Prisma + Supabase backend on AWS Lambda using the Serverless Framework provides:

  • Cost-efficient, pay-per-execution architecture
  • Automatic scaling
  • No server maintenance
  • Easy integration with AWS services like S3 Through this process, I learned how crucial it is to manage environment variables, match Prisma binaries, and configure $default routes for Express APIs on API Gateway.

📚 Next Steps

You can extend this setup by:

  • Adding CI/CD with GitHub Actions
  • Using AWS Secrets Manager for credentials
  • Integrating CloudWatch for logging and metrics
  • Implementing signed S3 URLs for secure uploads

Top comments (0)