docs/versioned_docs/version-1.0-beta/extending/how-dagger-works/execution.mdx
Now connect the pieces.
When a caller runs a function, Dagger does not just run a script. It loads a typed API and evaluates a graph.
That is the heart of Dagger.
A call moves through this path:
This is why clear APIs matter. The graph is built from your function names, inputs, outputs, objects, and defaults.
Dagger can describe work before it runs it.
A function can return a Container, Directory, File, service, object, or changeset. That value can keep flowing through the graph.
Dagger runs work when the caller needs a concrete result: a string, exported file, synced container, applied changeset, live service, or check status.
Return composable values until the user needs a final answer.
Modules should make boundaries visible:
File or Directory.Secret.Service.Changeset.File, Directory, or Container.No hidden host state. No surprise credentials. No local-only assumptions.
Every run creates a trace. A good trace reads like the user's workflow, not your private implementation notes.
Good module design makes traces useful:
Cloud does not change this model. It observes and automates it.
The same checks that run locally can run for pull requests. The same traces that help you debug locally can help a team understand CI.
That is why the platform feels powerful: one graph, many places to use it.
Next: Developer workflow.