---
title: "Modules | Grafana Alloy documentation"
description: "Learn about modules"
---

# Modules

You learned about components, expressions, and the configuration syntax in the previous sections. Now you’ll learn about modules, the organizational structure that lets you package and reuse Alloy configurations.

Modules enable powerful configuration management capabilities:

1. **Code reuse**: Package common pipeline patterns into reusable custom components.
2. **Organization**: Structure complex configurations into maintainable units.
3. **Sharing**: Distribute configurations across teams and projects.
4. **Composition**: Combine multiple modules to build sophisticated data collection systems.

> Note
> 
> Most Alloy users don’t need modules when they first get started. You can collect, process, and export metrics, logs, traces, and profiles using built-in components directly in your configuration. Modules don’t add capabilities to Alloy or enable signal types, they’re purely a way to organize and reuse configuration. Think of a module as a function in programming: it packages logic you already have so you can reuse it cleanly.
> 
> If you’re just getting started, you can skip modules for now and return to them when your configuration grows or you need reuse. However, if you plan to use [Fleet Management](/docs/grafana-cloud/send-data/fleet-management/) to manage multiple collectors, understanding modules helps you create reusable configurations that can be distributed across your fleet.

A *module* is a unit of Alloy configuration that contains components, custom component definitions, and import statements. The module you pass to [the `run` command](../../reference/cli/run/) becomes the *main configuration* that Alloy executes.

You can [import modules](#import-modules) to reuse [custom components](../components/custom-components/) defined by that module.

## When to use a module

Create a module when you want to:

- Reuse the same pipeline pattern multiple times
- Reduce duplicated configuration
- Hide complex pipelines behind a single interface
- Standardize pipelines across teams or environments
- Make large Alloy configurations easier to maintain

If your configuration is small and each pipeline is unique, you probably don’t need a module. If you find yourself copying and pasting the same group of components with small changes, a module can help.

## Why modules help

Without modules, repeated pipelines can look like this:

Alloy ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```alloy
otelcol.receiver.otlp "app1" { ... }
otelcol.processor.batch "app1" { ... }
otelcol.exporter.otlp "app1" { ... }

otelcol.receiver.otlp "app2" { ... }
otelcol.processor.batch "app2" { ... }
otelcol.exporter.otlp "app2" { ... }
```

With a module, you define the pipeline once and reuse it:

Alloy ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```alloy
import.file "pipeline" {
  filename = "pipeline.alloy"
}

pipeline.app "app1" { ... }
pipeline.app "app2" { ... }
```

This reduces duplication, improves readability, and makes updates safer because you only change the logic in one place.

## Example

This example demonstrates how modules integrate with the component and expression concepts you learned earlier. The module defines a reusable log filtering component that showcases:

1. **Custom component definition**: Using `declare` to create reusable logic.
2. **Arguments**: Accepting configuration from component users.
3. **Exports**: Exposing values for other components to reference.
4. **Internal pipeline**: Using built-in components within the custom component.

**Module definition** `helpers.alloy`:

Alloy ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```alloy
declare "log_filter" {
  // argument.write_to is a required argument that specifies where filtered
  // log lines are sent.
  //
  // The value of the argument is retrieved in this file with
  // argument.write_to.value.
  argument "write_to" {
    optional = false
  }

  // loki.process.filter is our component which executes the filtering,
  // passing filtered logs to argument.write_to.value.
  loki.process "filter" {
    // Drop all debug- and info-level logs.
    stage.match {
      selector = `{job!=""} |~ "level=(debug|info)"`
      action   = "drop"
    }

    // Send processed logs to our argument.
    forward_to = argument.write_to.value
  }

  // export.filter_input exports a value to the module consumer.
  export "filter_input" {
    // Expose the receiver of loki.process so the module importer can send
    // logs to our loki.process component.
    value = loki.process.filter.receiver
  }
}
```

**Use the module** `main.alloy`:

Alloy ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```alloy
// Import our helpers.alloy module, exposing its custom components as
// helpers.COMPONENT_NAME.
import.file "helpers" {
  filename = "helpers.alloy"
}

loki.source.file "self" {
  targets = LOG_TARGETS

  // Forward collected logs to the input of our filter.
  forward_to = [helpers.log_filter.default.filter_input]
}

helpers.log_filter "default" {
  // Configure the filter to forward filtered logs to loki.write below.
  write_to = [loki.write.default.receiver]
}

loki.write "default" {
  endpoint {
    url = LOKI_URL
  }
}
```

This example shows how:

1. **Modules encapsulate logic**: The filtering logic is contained within the module.
2. **Arguments provide flexibility**: The `write_to` argument lets users specify where filtered logs go.
3. **Exports enable connections**: The `filter_input` export allows other components to send data to the filter.
4. **Component references work across modules**: The main configuration references exports from the imported module using `helpers.log_filter.default.filter_input`.

## Import modules

To use modules in your configuration, you import them using one of the `import` configuration blocks. The component controller processes import statements during configuration loading to make custom components available in the importing module’s namespace.

1. [`import.file`](../../reference/config-blocks/import.file/): Imports a module from a file on disk.
2. [`import.git`](../../reference/config-blocks/import.git/): Imports a module from a file in a Git repository.
3. [`import.http`](../../reference/config-blocks/import.http/): Imports a module from an HTTP request response.
4. [`import.string`](../../reference/config-blocks/import.string/): Imports a module from a string.

> Warning
> 
> You can’t import a module that contains top-level blocks other than `declare` or `import`.

You import modules into a *namespace*. This exposes the top-level custom components of the imported module to the importing module. The label of the import block specifies the namespace of an import.

For example, if a configuration contains a block called `import.file "my_module"`, then custom components defined by that module appear as `my_module.CUSTOM_COMPONENT_NAME`. Namespaces for imports must be unique within a given importing module.

> Warning
> 
> If you use a label for an `import` or `declare` block that matches a built-in component namespace, such as `prometheus` or `mimir`, the built-in namespace becomes shadowed and unavailable in your configuration. For example, if you use the label `import.file "mimir"`, you can’t use components starting with `mimir`, such as `mimir.rules.kubernetes`, because the label refers to the imported module.

## Security

Since modules can load arbitrary configurations from potentially remote sources, you must carefully consider the security implications. The component controller executes all module content with the same privileges as the main Alloy process.

Best practices for secure module usage:

1. **Protect main configuration**: Ensure attackers can’t modify the Alloy configuration files.
2. **Secure remote sources**: Protect modules fetched from remote locations, such as Git repositories or HTTP servers.
3. **Validate module content**: Review imported modules for malicious or unintended behavior.
4. **Use authentication**: When fetching modules over HTTP or Git, use appropriate authentication mechanisms.
5. **Network security**: Restrict network access for Alloy processes that load remote modules.
6. **File permissions**: Set appropriate file system permissions for module files and directories.

## Next steps

To learn more about modules, explore these resources:

- [Custom components](../components/custom-components/) - Learn how to create reusable components that you can package in modules
- [Component configuration](../components/) - Understand how built-in components work within module contexts
- [Import configuration blocks](../../reference/config-blocks/) - Detailed reference for different module import methods
- [Run command reference](../../reference/cli/run/) - Module configuration and execution options
