> For the complete documentation index, see [llms.txt](https://docs.skail.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.skail.dev/construir/escrever-fluxos/como-passar-dados-entre-funcao-e-commands.md).

# Como passar dados entre função e commands

Argumentos e retornos de functions e commands são gravados no histórico da execução e desserializados a cada replay. Este guia diz o que passar, o que não passar, e como desenhar os tipos.

## O que acontece com um argumento

Quando a function chama `await CobrarCartao(fatura)`, o runtime serializa `fatura` com `System.Text.Json`, grava no passo do command junto com o resultado, e no replay devolve o resultado gravado. O mesmo vale para os argumentos da function (o corpo do trigger) e para o payload dos eventos. Três consequências: o tipo precisa ser serializável; o tamanho pesa no histórico e no tempo de retomada; e o que está no passo sai da sua infraestrutura para o skail.

## Passe ids e DTOs pequenos

```csharp
public record DadosCobranca(Guid FaturaId, decimal Valor, string Moeda);
public enum ResultadoCobranca { Aprovado, Recusado }

[SkailFunction]
public async SkailTask ProcessarFatura(Guid faturaId)
{
    var dados = await CarregarDadosCobranca(faturaId);        // devolve só o que a function precisa
    var resultado = await CobrarCartao(dados);
    if (resultado == ResultadoCobranca.Aprovado) await LiberarPedido(faturaId);
}

[SkailCommand]
public async SkailTask<DadosCobranca> CarregarDadosCobranca(Guid faturaId)
{
    var fatura = await _db.Faturas.FindAsync(faturaId);       // a entidade fica aqui
    return new DadosCobranca(fatura!.Id, fatura.ValorTotal, fatura.Moeda);
}
```

A function recebe um `Guid` e trabalha com um record de três campos. A entidade `Fatura`, com cliente, itens, endereços e histórico, nunca sai do command. Se outro command precisar da fatura, ele recebe o `faturaId` e carrega de novo: uma leitura a mais no banco é mais barata que um passo gordo replayado por semanas.

## Tipos que funcionam

Primitivos, `string`, `Guid`, `DateTime`, `DateTimeOffset`, `decimal`, enums, `record`s e classes simples com propriedades públicas, coleções (`List<T>`, arrays, `Dictionary<string, T>`) desses tipos, e tipos anuláveis. Prefira `record` imutável: ele serializa bem, não tem estado escondido e comunica que é um dado, não um objeto vivo.

## O que não passar

| Não passe                                                 | Por quê                                                                              | Faça assim                                                                    |
| --------------------------------------------------------- | ------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------- |
| Entidades de ORM (`DbContext` entities)                   | Grafos grandes, referências circulares, lazy loading que dispara I/O na serialização | Um record com os campos necessários                                           |
| `Stream`, `HttpResponseMessage`, `FileInfo`, conexões     | Não são serializáveis; representam recursos vivos                                    | Salve o conteúdo em um lugar (blob, tabela) e passe a referência              |
| Listas com milhares de itens                              | Passo gigante; replay lento; limites                                                 | Passe o id do lote e carregue por página no command, ou uma function por item |
| `SkailTask`                                               | Não é serializável                                                                   | Nunca como argumento de function; componha com `WhenAll`/`WhenAny`            |
| Dados sensíveis que a function não usa para decidir       | Passam a fazer parte do histórico da execução, que aparece no Monitor                | Carregue e use dentro do command, sem devolver                                |
| Objetos com comportamento (services, delegates, closures) | Não serializam; e a function não deve executar comportamento externo                 | Injete o serviço na classe e use dentro do command                            |

## Retornos

O mesmo critério. Um command devolve o que a function precisa para decidir o próximo passo: um enum, um id, um record curto. `CobrarCartao` devolve `Aprovado` ou `Recusado`, não a resposta inteira do gateway. Se a function precisa de um dado do retorno mais tarde, ele está no passo e volta no replay; se não precisa, não devolva.

## Contratos estáveis

Os tipos usados em argumentos, retornos e payloads de evento são contratos entre versões do código: uma execução hibernada há dias vai desserializar passos gravados com a versão anterior do record. Adicionar uma propriedade opcional é seguro; renomear ou remover uma propriedade que execuções antigas vão ler não é. Trate mudanças nesses tipos como mudança de fluxo e versione. Ver [Versionamento](/aprender/fundamentos/versionamento-de-codigo-com-execucoes-em-andamento.md).

## Erros comuns

| Sintoma                                     | Causa                                                            | Correção                    |
| ------------------------------------------- | ---------------------------------------------------------------- | --------------------------- |
| Exceção de serialização ao chamar o command | Tipo não serializável (stream, entidade com ciclo)               | Record com os campos        |
| Retomada lenta em execuções longas          | Passos grandes                                                   | Ids e referências           |
| Propriedade nula depois de um deploy        | Record renomeou uma propriedade que execuções antigas ainda leem | Versione                    |
| Dado sensível visível no Monitor            | Passou como argumento ou retorno                                 | Mova para dentro do command |

## Próximos passos

[Limites e cotas](/aprender/garantias/limites-e-cotas.md) para os tamanhos. [Segurança](/aprender/garantias/seguranca.md) para o que trafega. [Modelo de programação](/aprender/fundamentos/modelo-de-programacao.md) para a divisão function e command.
