Busca en todas las páginas de la documentación
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
npm install @aws-sdk/client-lambda// lib/lambda.ts
import { LambdaClient } from "@aws-sdk/client-lambda";
export const lambdaClient = new LambdaClient({
region: process.env.AWS_REGION!,
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
},
});// lib/invoke-lambda.ts
import { InvokeCommand } from "@aws-sdk/client-lambda";
import { lambdaClient } from "./lambda";
export async function invokeLambda<TInput, TOutput>(
functionName: string,
payload: TInput
): Promise<TOutput> {
const command = new InvokeCommand({
FunctionName: functionName,
Payload: new TextEncoder().encode(JSON.stringify(payload)),
});
const response = await lambdaClient.send(command);
if (response.FunctionError) {
const errorPayload = JSON.parse(
new TextDecoder().decode(response.Payload)
);
throw new Error(
`Lambda error: ${errorPayload.errorMessage ?? response.FunctionError}`
);
}
return JSON.parse(new TextDecoder().decode(response.Payload)) as TOutput;
}Cuándo usarlo: Necesitas invocar funciones AWS Lambda desde una aplicación Next.js para procesamiento en segundo plano, cómputo pesado o acceso a servicios nativos de AWS.
// app/components/ImageProcessor.tsx
"use client";
import { useState } from "react";
import { processImage } from "../actions/image-actions";
export default function ImageProcessor() {
const [result, setResult] = useState<{
thumbnailUrl: string;
dimensions: { width: number; height: number };
} | null>(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
async function handleProcess(formData: FormData) {
setLoading(true);
setError(null);
try {
const data = await processImage(formData);
setResult(data);
} catch (err) {
setError(err instanceof Error ? err.message : "Processing failed");
} finally {
setLoading(false);
}
}
return (
<div className="max-w-md mx-auto p-6 space-y-4">
<form action={handleProcess}>
<input name="imageUrl" placeholder="Image URL" required className="w-full border rounded px-3 py-2" />
<input name="width" type="number" placeholder="Target width" defaultValue={200} className="w-full border rounded px-3 py-2 mt-2" />
<button
type="submit"
disabled={loading}
className="mt-3 bg-blue-600 text-white px-4 py-2 rounded disabled:opacity-50"
>
{loading ? "Processing..." : "Process Image"}
</button>
</form>
{error && <p className="text-red-600">{error}</p>}
{result && (
<div>
<p>Thumbnail: {result.dimensions.width}x{result.dimensions.height}</p>
<img src={result.thumbnailUrl} alt="Processed thumbnail" className="border rounded" />
</div>
)}
</div>
);
}// app/actions/image-actions.ts
"use server";
import { invokeLambda } from "@/lib/invoke-lambda";
interface ProcessImageInput {
imageUrl: string;
targetWidth: number;
}
interface ProcessImageOutput {
thumbnailUrl: string;
dimensions: { width: number; height: number };
}
export async function processImage(formData: FormData) {
const imageUrl = formData.get("imageUrl") as string;
const targetWidth = Number(formData.get("width")) || 200;
const result = await invokeLambda<ProcessImageInput, ProcessImageOutput>(
"image-processor",
{ imageUrl, targetWidth }
);
return result;
}Qué demuestra esto:
InvokeCommand envía el payload como Uint8Array y recibe la respuesta de la misma maneraFunctionError en la respuesta indica si la función Lambda lanzó un errorInvocación asíncrona (fire-and-forget):
import { InvokeCommand, InvocationType } from "@aws-sdk/client-lambda";
const command = new InvokeCommand({
FunctionName: "email-sender",
InvocationType: InvocationType.Event, // async, devuelve 202 inmediatamente
Payload: new TextEncoder().encode(
JSON.stringify({ to: "user@example.com", subject: "Welcome!" })
),
});
await lambdaClient.send(command); // Devuelve inmediatamente, sin payload de respuestaEjecución en seco (validar permisos e entrada):
const command = new InvokeCommand({
FunctionName: "my-function",
InvocationType: InvocationType.DryRun,
Payload: new TextEncoder().encode(JSON.stringify({ test: true })),
});
// Devuelve 204 si es válido, lanza excepción si los permisos son incorrectos
await lambdaClient.send(command);Listar funciones disponibles:
import { ListFunctionsCommand } from "@aws-sdk/client-lambda";
const command = new ListFunctionsCommand({ MaxItems: 50 });
const response = await lambdaClient.send(command);
const functions = response.Functions?.map((fn) => ({
name: fn.FunctionName,
runtime: fn.Runtime,
memory: fn.MemorySize,
lastModified: fn.LastModified,
}));Invocar con cualificador (versión o alias):
const command = new InvokeCommand({
FunctionName: "my-function",
Qualifier: "production", // nombre de alias o número de versión
Payload: new TextEncoder().encode(JSON.stringify(payload)),
});InvokeCommandOutput.Payload es Uint8Array | undefined - siempre verifica indefinido antes de decodificarInvocationType enum proporciona RequestResponse (síncrono), Event (asíncrono) y DryRunimport type { InvokeCommandOutput } from "@aws-sdk/client-lambda";
function decodePayload<T>(response: InvokeCommandOutput): T | null {
if (!response.Payload) return null;
return JSON.parse(new TextDecoder().decode(response.Payload)) as T;
}Codificación de payload - Pasar una cadena o objeto simple como Payload lanza un error de tipo. Solución: Siempre codifica con new TextEncoder().encode(JSON.stringify(data)) y decodifica respuestas con new TextDecoder().decode(response.Payload).
Latencia de arranque en frío - Las primeras invocaciones después de períodos inactivos tardan varios segundos. Solución: Usa concurrencia aprovisionada para funciones sensibles a la latencia, o acepta arranques en frío y muestra estados de carga en la UI.
Desajuste de timeout - Las funciones Lambda tienen un timeout predeterminado de 3 segundos, pero el procesamiento puede tardar más. Solución: Establece el timeout de la función Lambda apropiadamente en AWS. También considera invocación asíncrona para tareas de larga duración.
Fallos silenciosos con invocación asíncrona - InvocationType: "Event" devuelve 202 sin detalles de error. Solución: Configura una Dead Letter Queue (DLQ) en la función Lambda para capturar invocaciones asíncronas fallidas.
Límite de tamaño de payload - Los payloads síncronos se limitan a 6MB. Solución: Para datos más grandes, almacénalos en S3 y pasa la clave de S3 en el payload.
Permisos faltantes - El usuario o rol de IAM necesita permiso lambda:InvokeFunction. Solución: Añade el permiso a tu política de IAM para el ARN de función específico.
| Librería | Mejor para | Compromiso |
|---|---|---|
| @aws-sdk/client-lambda | Invocación directa de Lambda | Requiere configuración de AWS, permisos IAM |
| Next.js API Routes | Lógica del lado del servidor en la misma aplicación | Tiempo de ejecución limitado, recursos compartidos |
| Vercel Functions | Serverless en Vercel | Específico de Vercel, menos control |
| AWS API Gateway + Lambda | Puntos finales de API pública | Más infraestructura para administrar |
| Step Functions | Orquestar múltiples Lambdas | Mayor complejidad, costo adicional |
InvokeCommand espera Payload como Uint8Array, no un objeto simple o cadenanew TextEncoder().encode(JSON.stringify(data)) para convertirUint8Array y necesitan new TextDecoder().decode()InvocationType: "Event"): Devuelve HTTP 202 inmediatamente, sin payload de respuestaconst response = await lambdaClient.send(command);
if (response.FunctionError) {
const error = JSON.parse(
new TextDecoder().decode(response.Payload)
);
throw new Error(error.errorMessage);
}El campo FunctionError se establece cuando Lambda lanza; el payload contiene detalles del error.
InvocationType: "Event" devuelve 202 sin detalles de error incluso si la función fallaasync function invokeLambda<TInput, TOutput>(
functionName: string,
payload: TInput
): Promise<TOutput> {
const command = new InvokeCommand({
FunctionName: functionName,
Payload: new TextEncoder().encode(JSON.stringify(payload)),
});
const response = await lambdaClient.send(command);
return JSON.parse(
new TextDecoder().decode(response.Payload)
) as TOutput;
}Payload se tipifica como Uint8Array | undefinedundefined antes de decodificaras T para tu tipo de retorno esperadoconst command = new InvokeCommand({
FunctionName: "my-function",
Qualifier: "production", // alias o número de versión
Payload: new TextEncoder().encode(JSON.stringify(payload)),
});lambda:InvokeFunctionlambda:ListFunctions si también necesitas listar funciones disponibles"use server";
import { invokeLambda } from "@/lib/invoke-lambda";
export async function processImage(formData: FormData) {
const imageUrl = formData.get("imageUrl") as string;
return invokeLambda("image-processor", { imageUrl });
}Server Actions mantienen credenciales de AWS en el servidor y proporcionan una API limpia para componentes de cliente.
InvocationType: "DryRun" valida permisos e entrada sin ejecutar la funciónRevisado por Chris St. John·Última actualización: 10 jul 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥