Skip to main content


Build the application

The build stage of the pipeline creates a container image with a production build of the application. It also depends on the build-env stage. Let's look at its Dagger Function next.

Inspect the Dagger Function

package main

import "dagger/hello-dagger/internal/dagger"

type HelloDagger struct{}

// Build the application container
func (m *HelloDagger) Build(source *dagger.Directory) *dagger.Container {
// get the build environment container
// by calling another Dagger Function
build := m.BuildEnv(source).
// build the application
WithExec([]string{"npm", "run", "build"}).
// get the build output directory
// start from a slim NGINX container
return dag.Container().From("nginx:1.25-alpine").
// copy the build output directory to the container
WithDirectory("/usr/share/nginx/html", build).
// expose the container port

This Dagger Function performs a multi-stage build, as follows:

  • It starts with the build environment Container and executes the npm run build command in the container. This creates a compressed, production-ready build of the application and places the result in a dist/ directory in the container filesystem. This directory is stored and referenced as Dagger's special Directory type.
  • It initializes a new nginx:1.25-alpine image as a second Container and copies the directory to the NGINX Web server root directory in the container. It also exposes container port 80 (the default NGINX port).

The result of this Dagger Function is a Container representing the final production build of the application. This is an nginx:1.25-alpine container image with an NGINX Web server ready to host and serve the built application.

Call the Dagger Function

Call the Dagger Function as below:

dagger call build --source=.

Here's what you should see:

Final container

This output means that the build succeeded, and a Container type representing the built container image was returned. Since this is another just-in-time Container, you can use your knowledge of function chaining and just-in-time artifacts to inspect it "live" with the terminal function, as you did earlier. But this is a good place to explore another interesting built-in Container function: the as-service function.

Run a container as a local service

The as-service function can be used to start a just-in-time container as a local service and have any exposed ports forwarded to the host machine. This is similar to Docker Compose, except that you're using code instead of YAML to manage your services.

To see this in action, chain additional function calls to as-service and up on the returned Container:

dagger call \
build --source=. \
as-service \
up --ports=8080:80

By default, Dagger will map each exposed container service port to the same port on the host. Since NGINX operates on port 80, which is often a privileged port on the host, the additional --ports 8080:80 argument re-maps container port 80 to unprivileged host port 8080.

Here's what you should see:

Final container as service

You should now be able to access the application by browsing to http://localhost:8080 on the Dagger host (replace localhost with your Dagger host's network name or IP address if accessing it remotely). You should see a "Hello from Dagger!" welcome page, served by NGINX.

Test service


The ability to start any container as a local service has many potential use cases, such as manually testing web applications directly from the host browser or host system, or running integration tests that depend on API or database services.