This guide covers efficient source-build patterns for Docker FaaS by runtime.
The key boundary is simple:
- Docker FaaS owns the generic source-build flow and the built-in manifest runtimes.
- Your function repository owns language-specific tooling choices such as
uv,ruff,pnpm, custom build caches, or release-only binaries.
If you need language-specific optimization, use a custom Dockerfile in the function repo. Docker FaaS will use it as-is.
| Use case | Recommended path |
|---|---|
| Quick start, simple handler, minimal dependencies | docker-faas.yaml manifest |
| Standard Python, Go, Node, or Bash example | Built-in manifest runtime |
Runtime-specific tooling (uv, ruff, pnpm, distroless, Rust/Cargo) |
Custom Dockerfile |
| Tight image-size or cold-start tuning | Custom Dockerfile |
| A runtime not built into Docker FaaS | Custom Dockerfile |
Regardless of runtime:
- Keep the build context small. Add a
.dockerignoreand exclude local caches, test output, VCS metadata, and virtual environments. - Pin base images and dependencies in the function repo. Reproducible builds matter more than shaving a few seconds off one local build.
- Put dependency installation before application copies where possible so Docker can reuse layers.
- Use lockfiles when the ecosystem supports them.
- Prefer multi-stage builds when the runtime compiler or package manager does not belong in production.
- Keep linting and formatting in the function repo CI, not in Docker FaaS itself.
Current manifest-generated builds behave like this:
| Runtime | Built-in manifest support | Current generated behavior | Move to custom Dockerfile when... |
|---|---|---|---|
| Python | Yes | python:3.11-slim; installs requirements.txt with uv pip install --system --compile when present |
You want repo-specific ruff policy, lockfiles, OS packages, or a fully custom build sequence |
| Go | Yes | golang:1.22 build stage with default go mod download and go build -o app ./ |
You want a smaller runtime image, a static binary, or stricter release flags |
| Node | Yes | node:20-slim; uses npm ci when package-lock.json exists, otherwise npm install |
You want pnpm, Yarn, native build packages, or aggressive dependency pruning |
| Bash | Yes | debian:bookworm-slim with Bash and of-watchdog |
You need a different shell toolchain or a smaller custom base image |
| Rust | No | Not built in today | Always use a custom Dockerfile |
Use the manifest runtime for simple handlers and examples. It is intentionally generic and easy to understand.
Move to a custom Dockerfile when your function repo needs:
- Repo-specific
ruffchecks or formatting in CI - Lockfile-driven dependency policy or extra Python build tooling
- Native system packages
- A tighter cold-start or image-size budget than the built-in runtime provides
Recommended repo-level process:
- Keep Python dependency and lint configuration in the function repo.
- Run lint and format checks before publishing a zip or Git source build.
- Use a custom
Dockerfileif the build must useuvor a non-default Python packaging flow.
Practical guidance:
- Put
pyproject.toml,requirements.txt, and any lockfile in the function repo. - Treat
ruffas a repo policy, even though Docker FaaS now usesuvfor built-in Python dependency installation. - Keep generated caches and virtual environments out of the build context.
- Run lint and format checks before packaging source builds.
Bundled example:
examples/source-packaging/python-uv/shows a custom-Dockerfile Python source build that keepsuvandruffownership in the function repo.scripts/run-python-checks.shandscripts/run-python-checks.ps1run the shared Ruff policy for the bundled Python examples and templates.
The built-in Go manifest runtime is already a good default for small handlers.
Use the manifest runtime when:
go mod downloadplusgo build -o app ./is enough- The handler is small and you want a low-friction source-build path
Move to a custom Dockerfile when you need:
- A distroless or scratch runtime image
- Static linking or stricter
CGO_ENABLEDcontrol - Custom compiler flags, private modules, or OS-level build dependencies
Practical guidance:
- Keep
go.modandgo.sumstable so the module-download layer stays cacheable. - Copy module files before application source in custom Dockerfiles.
- Strip the runtime image down to the final binary when image size matters.
The built-in Node manifest runtime is suitable for many simple functions.
Use the manifest runtime when:
package-lock.jsonis present andnpm ciis enough- You do not need a custom package manager or native build toolchain
Move to a custom Dockerfile when you need:
pnpmor Yarn- Native dependencies that require OS packages at build time
- More aggressive pruning between build and runtime stages
Practical guidance:
- Commit the lockfile so the generated build uses
npm ci. - Keep dev-only tooling out of the runtime image when using multi-stage builds.
- Avoid copying
node_modulesfrom the host into the build context.
The built-in Bash runtime is intentionally simple. It is usually good enough as-is.
Move to a custom Dockerfile only if:
- The script depends on extra CLI tools
- You want a smaller or more specialized base image
- You need a shell other than the default setup
Rust is a strong candidate for Docker FaaS, but it is not a built-in manifest runtime today.
For Rust functions:
- Put a
Dockerfileat the repo root. - Use a multi-stage build so Cargo stays out of the runtime image.
- Cache dependency resolution separately from application source where possible.
- Copy only the final release binary into the runtime stage.
If you want Rust to become a first-class docker-faas.yaml runtime later, treat that as a separate platform feature with its own template, tests, and documentation.
Good candidates for Docker FaaS itself:
- Documentation for runtime-specific build strategies
- Example manifests and
Dockerfilerecipes - Additional built-in runtimes only when the project is ready to maintain them
Better owned by downstream function repositories:
- Language-specific lint and formatting rules
- Custom package manager choices
- Repo-level CI quality gates
- App-specific build flags and dependency policies