Serverless Framework Setup for Web Applications
Serverless Framework is a deployment and management tool for serverless functions across providers (AWS, GCP, Azure, Cloudflare). It doesn't completely abstract the cloud—you still work with provider-specific resources, but configuration, deployment, and environment management are unified in one serverless.yml.
Unlike Terraform or CDK, Serverless Framework is purpose-built for functions. Unlike AWS SAM, it supports multiple cloud providers.
Installation and Basic Structure
npm install -g serverless
serverless --version
serverless create --template aws-nodejs-typescript --path my-service
cd my-service
npm install
Project structure:
my-service/
├── serverless.yml
├── serverless.env.yml
├── src/
│ ├── functions/
│ │ ├── api/handler.ts
│ │ └── worker/handler.ts
│ └── libs/
├── tsconfig.json
└── package.json
serverless.yml Configuration
service: my-web-service
frameworkVersion: '3'
plugins:
- serverless-esbuild
- serverless-offline
- serverless-dotenv-plugin
provider:
name: aws
runtime: nodejs20.x
region: eu-west-1
stage: ${opt:stage, 'dev'}
memorySize: 512
timeout: 10
environment:
NODE_ENV: ${self:provider.stage}
DATABASE_URL: ${env:DATABASE_URL}
JWT_SECRET: ${env:JWT_SECRET}
iam:
role:
statements:
- Effect: Allow
Action:
- s3:GetObject
- s3:PutObject
Resource: 'arn:aws:s3:::my-bucket/*'
httpApi:
cors:
allowedOrigins:
- https://my-site.com
- http://localhost:3000
allowedHeaders: [Content-Type, Authorization]
allowedMethods: [GET, POST, PUT, DELETE]
custom:
esbuild:
bundle: true
minify: true
target: node20
serverless-offline:
httpPort: 3001
functions:
- ${file(src/functions/api/index.ts)}
- ${file(src/functions/worker/index.ts)}
Function Configuration
// src/functions/api/index.ts
import type { AWS } from '@serverless/typescript';
const apiFunction: AWS['functions'] = {
api: {
handler: 'src/functions/api/handler.main',
events: [
{
httpApi: {
method: 'ANY',
path: '/api/{proxy+}',
},
},
],
},
};
export default apiFunction;
Handler with Middleware
// src/libs/lambda.ts
import middy from '@middy/core';
import middyJsonBodyParser from '@middy/http-json-body-parser';
import httpErrorHandler from '@middy/http-error-handler';
import cors from '@middy/http-cors';
type Handler = (event) => Promise<any>;
export const middyfy = (handler: Handler) =>
middy(handler)
.use(middyJsonBodyParser())
.use(httpErrorHandler())
.use(cors());
Environment Management
serverless deploy --stage dev
serverless deploy --stage prod
serverless logs --function api --tail --stage prod
Optimization
esbuild significantly reduces cold start. Bundle carefully:
custom:
esbuild:
bundle: true
exclude:
- '@aws-sdk/*'
external:
- 'sharp'
Timeframe
Basic setup with one function and dev/prod deployment — 1 day. Full structure with multiple functions and CI/CD — 3–4 days.







