# Frameworks
Entry point must be `index.js` (`aws lambda-web deploy` adds one that imports your entry file when it has another name). Bind the host and port from `AWS_LAMBDA_HTTP_ENDPOINT`. Use `"type": "module"` in package.json for ESM.
## Express.js (Default)
```bash
npm init -y && npm pkg set type=module && npm install express helmet
```
```javascript
// index.js
import express from 'express';
import helmet from 'helmet';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
const __dirname = dirname(fileURLToPath(import.meta.url));
const app = express();
app.use(helmet());
app.use(express.static(join(__dirname, 'public')));
app.use(express.json({ limit: '10mb' }));
app.get('/api/health', (req, res) => res.json({ status: 'ok' }));
app.use((req, res) => res.status(404).json({ error: 'not found' }));
const [HOST, PORT] = (process.env.AWS_LAMBDA_HTTP_ENDPOINT || '0.0.0.0:3000').split(':');
app.listen(PORT, HOST);
```
## Hono
```bash
npm init -y && npm pkg set type=module && npm install hono @hono/node-server
```
```javascript
// index.js
import { serve } from '@hono/node-server';
import { Hono } from 'hono';
import { serveStatic } from '@hono/node-server/serve-static';
import { secureHeaders } from 'hono/secure-headers';
const app = new Hono();
app.use(secureHeaders());
app.use('/static/*', serveStatic({ root: './' }));
app.get('/', (c) => c.html('
Hello from Web Functions
'));
app.get('/api/health', (c) => c.json({ status: 'ok' }));
const [HOST, PORT] = (process.env.AWS_LAMBDA_HTTP_ENDPOINT || '0.0.0.0:3000').split(':');
serve({ fetch: app.fetch, port: Number(PORT), hostname: HOST });
```
## Fastify
```bash
npm init -y && npm pkg set type=module && npm install fastify @fastify/static @fastify/helmet
```
```javascript
// index.js
import Fastify from 'fastify';
import fastifyStatic from '@fastify/static';
import fastifyHelmet from '@fastify/helmet';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
const __dirname = dirname(fileURLToPath(import.meta.url));
const fastify = Fastify({ logger: true });
fastify.register(fastifyHelmet);
fastify.register(fastifyStatic, { root: join(__dirname, 'public') });
fastify.get('/api/health', async () => ({ status: 'ok' }));
const [HOST, PORT] = (process.env.AWS_LAMBDA_HTTP_ENDPOINT || '0.0.0.0:3000').split(':');
fastify.listen({ port: Number(PORT), host: HOST });
```
## TypeScript (Native — No Build Step)
Node 24 type stripping is enabled. Use an `index.js` shim:
```javascript
// index.js (required entry point)
import './app.ts';
```
```typescript
// app.ts (your actual code)
import type { Request, Response } from 'express';
import express from 'express';
const app = express();
app.get('/api/health', (req: Request, res: Response) => res.json({ status: 'ok' }));
const [HOST, PORT] = (process.env.AWS_LAMBDA_HTTP_ENDPOINT || '0.0.0.0:3000').split(':');
app.listen(PORT, HOST);
```
Key: must use `import type` for type-only imports. No `tsc` needed.
**Packaging (required):** the `.ts` source is loaded at runtime, so it MUST be in the ZIP alongside `index.js`. Add your TypeScript source to the include list:
```bash
zip -r function.zip index.js app.ts package.json node_modules/ \
-x "*.test.*" -x ".git/*" -x ".env"
```
If `app.ts` is omitted from the archive, the deploy starts but crashes immediately with `ERR_MODULE_NOT_FOUND: Cannot find module '/var/task/app.ts'`. Include every `.ts` file your entry shim imports.
## Key Rules
- Entry point: `index.js` (runtime loads `/var/task/index.js`, nothing else)
- Port: bind the host and port from `AWS_LAMBDA_HTTP_ENDPOINT`; the runtime probes that exact address
- Bind to `0.0.0.0` (not localhost)
- Multi-concurrency: many concurrent requests per environment — avoid global mutable state
- Background tasks continue after response — the execution environment stays running
- Streaming/SSE works natively (chunked transfer-encoding)