Serverless functions in TypeScript: advanced work with AWS Lambda

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Serverless functions in TypeScript: advanced level in AWS Lambda

\n\n

Serverless architecture has become the de facto standard for building scalable and cost-effective applications. AWS Lambda is one of the most popular services for implementing serverless functions. If the basic syntax and triggers (API Gateway, S3, DynamoDB) are already mastered, it's time for advanced techniques. In this article, we will look at key aspects of professional Lambda function development in TypeScript: from cold start optimization to VPC integration and the use of complex patterns.

\n\n

1. Cold start optimization and memory management

\n\n

Cold start is the main enemy of serverless application performance. In TypeScript, this problem is exacerbated by the compilation stage. Let's consider three main methods of dealing with it.

\n\n

1.1. Reducing the deployment package size

\n

Use esbuild for building instead of the standard tsc. It performs tree-shaking and minification, which reduces the bundle size by 5-10 times. Example configuration for serverless.yml:

\n\n
plugins:\n  - serverless-esbuild\ncustom:\n  esbuild:\n    bundle: true\n    minify: true\n    sourcemap: false\n    target: 'node18'\n    exclude: ['aws-sdk'] # SDK is already in the Lambda environment
\n\n

1.2. Using Provisioned Concurrency

\n

For latency-critical functions (e.g., processing API requests), configure Provisioned Concurrency. This keeps a specified number of "warm" containers constantly running:

\n\n
functions:\n  apiHandler:\n    handler: src/handler.apiHandler\n    provisionedConcurrency: 5 # Always 5 ready instances
\n\n

1.3. Optimizing imports and code

\n

Avoid "heavy" libraries inside the function. For example, instead of importing the entire aws-sdk v3, import only the necessary clients:

\n\n
// Bad: import * as AWS from 'aws-sdk';\n// Good:\nimport { DynamoDBClient } from '@aws-sdk/client-dynamodb';\nimport { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
\n\n

2. Working with Lambda Layers and dependencies

\n\n

Lambda Layers allow you to extract common code and dependencies (e.g., ORM, validators) outside of the function. This speeds up deployment and reduces the size of each individual package.

\n\n

2.1. Creating a layer with shared utilities

\n

The project structure might look like this:

\n\n
project/\n├── layers/\n│   └── common/\n│       └── nodejs/\n│           ├── package.json\n│           └── node_modules/\n├── functions/\n│   ├── createUser.ts\n│   └── getUser.ts\n└── serverless.yml
\n\n

In serverless.yml we connect the layer:

\n\n
layers:\n  commonLibs:\n    path: layers/common\n    compatibleRuntimes:\n      - nodejs18.x\nfunctions:\n  createUser:\n    handler: functions/createUser.handler\n    layers:\n      - { Ref: CommonLibsLambdaLayer }
\n\n

2.2. Typing for layers

\n

To make TypeScript "see" the types from the layer, create a tsconfig.json with paths:

\n\n
{\n  "compilerOptions": {\n    "paths": {\n      "@common/*": ["layers/common/nodejs/*"]\n    }\n  }\n}
\n\n

Now in the function you can write:

\n
import { validateEmail } from '@common/validators';
\n\n

3. Working with VPC and security

\n\n

Lambda functions running inside a VPC lose access to the public internet (unless a NAT Gateway is configured). This is critical for connecting to RDS, ElastiCache, or private APIs.

\n\n

3.1. Configuring Lambda in a VPC

\n

Configuration via serverless.yml:

\n\n
provider:\n  vpc:\n    securityGroupIds:\n      - sg-12345\n    subnetIds:\n      - subnet-abc\n      - subnet-def\n\nfunctions:\n  dbHandler:\n    handler: src/db.handler\n    vpc: true # inherits provider settings
\n\n

3.2. "Thin Handler" pattern for connections

\n

Re

Blogs

Book Recommendations